From dcce4eae31bf798949a7991cac165bcd6d0a0eef Mon Sep 17 00:00:00 2001 From: Tomasz Boczkowski Date: Wed, 21 May 2014 18:03:59 +0200 Subject: SPColorSlider c++-sification: added ColorSlider class (bzr r13341.6.1) --- src/widgets/sp-color-scales.cpp | 4 +- src/widgets/sp-color-scales.h | 8 ++ src/widgets/sp-color-slider.cpp | 202 ++++++++++++++++++++++++++++++-- src/widgets/sp-color-slider.h | 81 ++++++++++++- src/widgets/sp-color-wheel-selector.cpp | 4 +- src/widgets/sp-color-wheel-selector.h | 8 ++ 6 files changed, 294 insertions(+), 13 deletions(-) (limited to 'src') diff --git a/src/widgets/sp-color-scales.cpp b/src/widgets/sp-color-scales.cpp index c3f9d511c..a7d458561 100644 --- a/src/widgets/sp-color-scales.cpp +++ b/src/widgets/sp-color-scales.cpp @@ -5,11 +5,13 @@ #ifdef HAVE_CONFIG_H # include "config.h" #endif + +#include "sp-color-scales.h" + #include #include #include #include "../dialogs/dialog-events.h" -#include "sp-color-scales.h" #include "svg/svg-icc-color.h" #define CSC_CHANNEL_R (1 << 0) diff --git a/src/widgets/sp-color-scales.h b/src/widgets/sp-color-scales.h index 3b11bc05e..cd3900f85 100644 --- a/src/widgets/sp-color-scales.h +++ b/src/widgets/sp-color-scales.h @@ -1,6 +1,14 @@ #ifndef SEEN_SP_COLOR_SCALES_H #define SEEN_SP_COLOR_SCALES_H +#ifdef HAVE_CONFIG_H +# include +#endif + +#if GLIBMM_DISABLE_DEPRECATED && HAVE_GLIBMM_THREADS_H +#include +#endif + #include #include diff --git a/src/widgets/sp-color-slider.cpp b/src/widgets/sp-color-slider.cpp index 9b13ba1c5..07e1d79fb 100644 --- a/src/widgets/sp-color-slider.cpp +++ b/src/widgets/sp-color-slider.cpp @@ -1,7 +1,8 @@ -/* - * A slider with colored background - * - * Author: +/** + * @file + * A slider with colored background - implementation. + */ +/* Author: * Lauris Kaplinski * bulia byak * @@ -10,13 +11,200 @@ * This code is in public domain */ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include "sp-color-slider.h" + #include +#include +#include +#include + #include "sp-color-scales.h" #include "preferences.h" -#define SLIDER_WIDTH 96 -#define SLIDER_HEIGHT 8 -#define ARROW_SIZE 7 +static const gint SLIDER_WIDTH = 96; +static const gint SLIDER_HEIGHT = 8; +static const gint ARROW_SIZE = 7; + + +ColorSlider::ColorSlider(Gtk::Adjustment* adjustment) + : _dragging(false) + , _adjustment(NULL) + , _value(0.0) + , _oldvalue(0.0) + , _mapsize(0) + , _map(NULL) +{ + _c0[0] = 0x00; + _c0[1] = 0x00; + _c0[2] = 0x00; + _c0[3] = 0xff; + + _cm[0] = 0xff; + _cm[1] = 0x00; + _cm[2] = 0x00; + _cm[3] = 0xff; + + _c0[0] = 0xff; + _c0[1] = 0xff; + _c0[2] = 0xff; + _c0[3] = 0xff; + + _b0 = 0x5f; + _b1 = 0xa0; + _bmask = 0x08; + + set_adjustment(adjustment); +} + +ColorSlider::~ColorSlider() { + if (_adjustment) { + //TODO: disconnect all connections + delete _adjustment; + _adjustment = NULL; + } +} + +void ColorSlider::on_realize() { + set_realized(); + + if(!_refGdkWindow) + { + GdkWindowAttr attributes; + gint attributes_mask; + Gtk::Allocation allocation = get_allocation(); + + memset(&attributes, 0, sizeof(attributes)); + attributes.x = allocation.get_x(); + attributes.y = allocation.get_y(); + attributes.width = allocation.get_width(); + attributes.height = allocation.get_height(); + attributes.window_type = GDK_WINDOW_CHILD; + attributes.wclass = GDK_INPUT_OUTPUT; + attributes.visual = gdk_screen_get_system_visual(gdk_screen_get_default()); +#if !GTK_CHECK_VERSION(3,0,0) + attributes.colormap = gdk_screen_get_system_colormap(gdk_screen_get_default()); +#endif + attributes.event_mask = get_events (); + attributes.event_mask |= (Gdk::EXPOSURE_MASK | + Gdk::BUTTON_PRESS_MASK | + Gdk::BUTTON_RELEASE_MASK | + Gdk::POINTER_MOTION_MASK | + Gdk::ENTER_NOTIFY_MASK | + Gdk::LEAVE_NOTIFY_MASK); + +#if GTK_CHECK_VERSION(3,0,0) + attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL; +#else + attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP; +#endif + + _refGdkWindow = Gdk::Window::create(get_parent_window(), &attributes, + attributes_mask); + set_window(_refGdkWindow); + _refGdkWindow->set_user_data(gobj()); + + style_attach(); + } +} + +void ColorSlider::on_unrealize() { + _refGdkWindow.reset(); + + Gtk::Widget::on_unrealize(); +} + +void ColorSlider::on_size_request(Gtk::Requisition* requisition) { + GtkStyle *style = gtk_widget_get_style(gobj()); + requisition->width = SLIDER_WIDTH + style->xthickness * 2; + requisition->height = SLIDER_HEIGHT + style->ythickness * 2; +} + +//TODO: GTK3 prefferred width/height + +void ColorSlider::on_size_allocate(Gtk::Allocation& allocation) { + if (get_realized()) { + _refGdkWindow->move_resize(allocation.get_x(), allocation.get_y(), + allocation.get_width(), allocation.get_height()); + } +} + +//TODO: if not GTK3 +bool ColorSlider::on_expose_event(GdkEventExpose* event) { + bool result = false; + + if (get_is_drawable()) { + Cairo::RefPtr cr = _refGdkWindow->create_cairo_context(); + result = on_draw(cr); + } + return result; +} + +bool ColorSlider::on_button_press_event(GdkEventButton *event) { + //TODO: implementation + return false; +} + +bool ColorSlider::on_button_release_event(GdkEventButton *event) { + //TODO: implementation + return false; +} + +bool ColorSlider::on_motion_notify_event(GdkEventMotion *event) { + //TODO: implementation + return false; +} + +void ColorSlider::set_adjustment(Gtk::Adjustment* /*adjustment*/) { + //TODO: implementation +} + +void ColorSlider::set_colors(guint32 start, guint32 min, guint32 end) { + +} + +void ColorSlider::set_map(const guchar *map) { + +} + +void ColorSlider::set_background(guint dark, guint light, guint size) { + +} + +bool ColorSlider::on_draw(const Cairo::RefPtr& cr) { + return false; +} + + + + + + + + + + + + + + + + + + + + + + + + + + + + enum { GRABBED, diff --git a/src/widgets/sp-color-slider.h b/src/widgets/sp-color-slider.h index 591d8368a..6821c8fe4 100644 --- a/src/widgets/sp-color-slider.h +++ b/src/widgets/sp-color-slider.h @@ -1,10 +1,7 @@ #ifndef __SP_COLOR_SLIDER_H__ #define __SP_COLOR_SLIDER_H__ -/* - * A slider with colored background - * - * Author: +/* Author: * Lauris Kaplinski * * Copyright (C) 2001-2002 Lauris Kaplinski @@ -12,6 +9,82 @@ * This code is in public domain */ +#ifdef HAVE_CONFIG_H +# include +#endif + +#if GLIBMM_DISABLE_DEPRECATED && HAVE_GLIBMM_THREADS_H +#include +#endif + +#include + +#include + + +/* + * A slider with colored background + */ +class ColorSlider: public Gtk::Widget { +public: + //if GTK2 + ColorSlider(Gtk::Adjustment *adjustment); + ~ColorSlider(); + + void set_adjustment(Gtk::Adjustment *adjustment); + + void set_colors(guint32 start, guint32 mid, guint32 end); + + void set_map(const guchar* map); + + void set_background(guint dark, guint light, guint size); + + sigc::signal signal_grabbed; + sigc::signal signal_dragged; + sigc::signal signal_released; + sigc::signal signal_value_changed; + +protected: + void on_size_allocate(Gtk::Allocation& allocation); + void on_realize(); + void on_unrealize(); + bool on_button_press_event(GdkEventButton *event); + bool on_button_release_event(GdkEventButton *event); + bool on_motion_notify_event(GdkEventMotion *event); + + //if GTK2 + void on_size_request(Gtk::Requisition* requisition); + bool on_expose_event(GdkEventExpose* event); + //if GTK3 + //request mode, get preffered width/height vfunc + //endif + + bool on_draw(const Cairo::RefPtr& cr); + + //TODO: on_adjustment_changed method + //TODO: on_adjustment value changed method + connection + +private: + bool _dragging; + + Gtk::Adjustment *_adjustment; + + gfloat _value; + gfloat _oldvalue; + guchar _c0[4], _cm[4], _c1[4]; + guchar _b0, _b1; + guchar _bmask; + + gint _mapsize; + guchar *_map; + + Glib::RefPtr _refGdkWindow; +}; + + + + + #include #include diff --git a/src/widgets/sp-color-wheel-selector.cpp b/src/widgets/sp-color-wheel-selector.cpp index 7c8bb1df7..1cc2e06d6 100644 --- a/src/widgets/sp-color-wheel-selector.cpp +++ b/src/widgets/sp-color-wheel-selector.cpp @@ -1,11 +1,13 @@ #ifdef HAVE_CONFIG_H # include "config.h" #endif + +#include "sp-color-wheel-selector.h" + #include #include #include #include "../dialogs/dialog-events.h" -#include "sp-color-wheel-selector.h" #include "sp-color-scales.h" #include "sp-color-icc-selector.h" #include "../svg/svg-icc-color.h" diff --git a/src/widgets/sp-color-wheel-selector.h b/src/widgets/sp-color-wheel-selector.h index bbd377422..6f45b6bba 100644 --- a/src/widgets/sp-color-wheel-selector.h +++ b/src/widgets/sp-color-wheel-selector.h @@ -1,6 +1,14 @@ #ifndef SEEN_SP_COLOR_WHEEL_SELECTOR_H #define SEEN_SP_COLOR_WHEEL_SELECTOR_H +#ifdef HAVE_CONFIG_H +# include +#endif + +#if GLIBMM_DISABLE_DEPRECATED && HAVE_GLIBMM_THREADS_H +#include +#endif + #include #include -- cgit v1.2.3 From a06f51f786230bfd26ddd34d27be438d4bebbd04 Mon Sep 17 00:00:00 2001 From: Tomasz Boczkowski Date: Fri, 23 May 2014 11:09:05 +0200 Subject: moved widgets/sp-color-slider to ui/widget/color-slider (bzr r13341.6.2) --- src/ui/CMakeLists.txt | 2 + src/ui/widget/Makefile_insert | 2 + src/ui/widget/color-slider.cpp | 961 ++++++++++++++++++++++++++++++++ src/ui/widget/color-slider.h | 146 +++++ src/widgets/CMakeLists.txt | 2 - src/widgets/Makefile_insert | 2 - src/widgets/sp-color-icc-selector.cpp | 2 +- src/widgets/sp-color-scales.cpp | 1 + src/widgets/sp-color-scales.h | 3 +- src/widgets/sp-color-slider.cpp | 959 ------------------------------- src/widgets/sp-color-slider.h | 140 ----- src/widgets/sp-color-wheel-selector.cpp | 1 + src/widgets/sp-color-wheel-selector.h | 4 +- 13 files changed, 1117 insertions(+), 1108 deletions(-) create mode 100644 src/ui/widget/color-slider.cpp create mode 100644 src/ui/widget/color-slider.h delete mode 100644 src/widgets/sp-color-slider.cpp delete mode 100644 src/widgets/sp-color-slider.h (limited to 'src') diff --git a/src/ui/CMakeLists.txt b/src/ui/CMakeLists.txt index 7d80f1e36..883ba3427 100644 --- a/src/ui/CMakeLists.txt +++ b/src/ui/CMakeLists.txt @@ -109,6 +109,7 @@ set(ui_SRC widget/button.cpp widget/color-picker.cpp widget/color-preview.cpp + widget/color-slider.cpp widget/dock-item.cpp widget/dock.cpp widget/entity-entry.cpp @@ -270,6 +271,7 @@ set(ui_SRC widget/button.h widget/color-picker.h widget/color-preview.h + widget/color-slider.h widget/combo-enums.h widget/dock-item.h widget/dock.h diff --git a/src/ui/widget/Makefile_insert b/src/ui/widget/Makefile_insert index 608dd5334..6deaf6671 100644 --- a/src/ui/widget/Makefile_insert +++ b/src/ui/widget/Makefile_insert @@ -10,6 +10,8 @@ ink_common_sources += \ ui/widget/color-picker.h \ ui/widget/color-preview.cpp \ ui/widget/color-preview.h \ + ui/widget/color-slider.cpp \ + ui/widget/color-slider.h \ ui/widget/combo-enums.h \ ui/widget/dock.h \ ui/widget/dock.cpp \ diff --git a/src/ui/widget/color-slider.cpp b/src/ui/widget/color-slider.cpp new file mode 100644 index 000000000..430239f00 --- /dev/null +++ b/src/ui/widget/color-slider.cpp @@ -0,0 +1,961 @@ +/** + * @file + * A slider with colored background - implementation. + */ +/* Author: + * Lauris Kaplinski + * bulia byak + * + * Copyright (C) 2001-2002 Lauris Kaplinski + * + * This code is in public domain + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include "color-slider.h" + +#include +#include +#include +#include + +#include "widgets/sp-color-scales.h" +#include "preferences.h" + +static const gint SLIDER_WIDTH = 96; +static const gint SLIDER_HEIGHT = 8; +static const gint ARROW_SIZE = 7; + +namespace Inkscape { +namespace UI { +namespace Widget { + +ColorSlider::ColorSlider(Gtk::Adjustment* adjustment) + : _dragging(false) + , _adjustment(NULL) + , _value(0.0) + , _oldvalue(0.0) + , _mapsize(0) + , _map(NULL) +{ + _c0[0] = 0x00; + _c0[1] = 0x00; + _c0[2] = 0x00; + _c0[3] = 0xff; + + _cm[0] = 0xff; + _cm[1] = 0x00; + _cm[2] = 0x00; + _cm[3] = 0xff; + + _c0[0] = 0xff; + _c0[1] = 0xff; + _c0[2] = 0xff; + _c0[3] = 0xff; + + _b0 = 0x5f; + _b1 = 0xa0; + _bmask = 0x08; + + set_adjustment(adjustment); +} + +ColorSlider::~ColorSlider() { + if (_adjustment) { + //TODO: disconnect all connections + delete _adjustment; + _adjustment = NULL; + } +} + +void ColorSlider::on_realize() { + set_realized(); + + if(!_refGdkWindow) + { + GdkWindowAttr attributes; + gint attributes_mask; + Gtk::Allocation allocation = get_allocation(); + + memset(&attributes, 0, sizeof(attributes)); + attributes.x = allocation.get_x(); + attributes.y = allocation.get_y(); + attributes.width = allocation.get_width(); + attributes.height = allocation.get_height(); + attributes.window_type = GDK_WINDOW_CHILD; + attributes.wclass = GDK_INPUT_OUTPUT; + attributes.visual = gdk_screen_get_system_visual(gdk_screen_get_default()); +#if !GTK_CHECK_VERSION(3,0,0) + attributes.colormap = gdk_screen_get_system_colormap(gdk_screen_get_default()); +#endif + attributes.event_mask = get_events (); + attributes.event_mask |= (Gdk::EXPOSURE_MASK | + Gdk::BUTTON_PRESS_MASK | + Gdk::BUTTON_RELEASE_MASK | + Gdk::POINTER_MOTION_MASK | + Gdk::ENTER_NOTIFY_MASK | + Gdk::LEAVE_NOTIFY_MASK); + +#if GTK_CHECK_VERSION(3,0,0) + attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL; +#else + attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP; +#endif + + _refGdkWindow = Gdk::Window::create(get_parent_window(), &attributes, + attributes_mask); + set_window(_refGdkWindow); + _refGdkWindow->set_user_data(gobj()); + + style_attach(); + } +} + +void ColorSlider::on_unrealize() { + _refGdkWindow.reset(); + + Gtk::Widget::on_unrealize(); +} + +void ColorSlider::on_size_request(Gtk::Requisition* requisition) { + GtkStyle *style = gtk_widget_get_style(gobj()); + requisition->width = SLIDER_WIDTH + style->xthickness * 2; + requisition->height = SLIDER_HEIGHT + style->ythickness * 2; +} + +//TODO: GTK3 prefferred width/height + +void ColorSlider::on_size_allocate(Gtk::Allocation& allocation) { + if (get_realized()) { + _refGdkWindow->move_resize(allocation.get_x(), allocation.get_y(), + allocation.get_width(), allocation.get_height()); + } +} + +//TODO: if not GTK3 +bool ColorSlider::on_expose_event(GdkEventExpose* event) { + bool result = false; + + if (get_is_drawable()) { + Cairo::RefPtr cr = _refGdkWindow->create_cairo_context(); + result = on_draw(cr); + } + return result; +} + +bool ColorSlider::on_button_press_event(GdkEventButton *event) { + //TODO: implementation + return false; +} + +bool ColorSlider::on_button_release_event(GdkEventButton *event) { + //TODO: implementation + return false; +} + +bool ColorSlider::on_motion_notify_event(GdkEventMotion *event) { + //TODO: implementation + return false; +} + +void ColorSlider::set_adjustment(Gtk::Adjustment* /*adjustment*/) { + //TODO: implementation +} + +void ColorSlider::set_colors(guint32 start, guint32 min, guint32 end) { + +} + +void ColorSlider::set_map(const guchar *map) { + +} + +void ColorSlider::set_background(guint dark, guint light, guint size) { + +} + +bool ColorSlider::on_draw(const Cairo::RefPtr& cr) { + return false; +} + +}//namespace Widget +}//namespace UI +}//namespace Inkscape + + + + + + + + + + + + + + + + + + + + + + + + +enum { + GRABBED, + DRAGGED, + RELEASED, + CHANGED, + LAST_SIGNAL +}; + +static void sp_color_slider_class_init (SPColorSliderClass *klass); +static void sp_color_slider_init (SPColorSlider *slider); +static void sp_color_slider_dispose(GObject *object); + +static void sp_color_slider_realize (GtkWidget *widget); +static void sp_color_slider_size_request (GtkWidget *widget, GtkRequisition *requisition); + +#if GTK_CHECK_VERSION(3,0,0) +static void sp_color_slider_get_preferred_width(GtkWidget *widget, + gint *minimal_width, + gint *natural_width); + +static void sp_color_slider_get_preferred_height(GtkWidget *widget, + gint *minimal_height, + gint *natural_height); +#else +static gboolean sp_color_slider_expose(GtkWidget *widget, GdkEventExpose *event); +#endif + +static void sp_color_slider_size_allocate (GtkWidget *widget, GtkAllocation *allocation); + +static gboolean sp_color_slider_draw(GtkWidget *widget, cairo_t *cr); + +static gint sp_color_slider_button_press (GtkWidget *widget, GdkEventButton *event); +static gint sp_color_slider_button_release (GtkWidget *widget, GdkEventButton *event); +static gint sp_color_slider_motion_notify (GtkWidget *widget, GdkEventMotion *event); + +static void sp_color_slider_adjustment_changed (GtkAdjustment *adjustment, SPColorSlider *slider); +static void sp_color_slider_adjustment_value_changed (GtkAdjustment *adjustment, SPColorSlider *slider); + +static const guchar *sp_color_slider_render_gradient (gint x0, gint y0, gint width, gint height, + gint c[], gint dc[], guint b0, guint b1, guint mask); +static const guchar *sp_color_slider_render_map (gint x0, gint y0, gint width, gint height, + guchar *map, gint start, gint step, guint b0, guint b1, guint mask); + +static GtkWidgetClass *parent_class; +static guint slider_signals[LAST_SIGNAL] = {0}; + +GType +sp_color_slider_get_type (void) +{ + static GType type = 0; + if (!type) { + GTypeInfo info = { + sizeof (SPColorSliderClass), + NULL, NULL, + (GClassInitFunc) sp_color_slider_class_init, + NULL, NULL, + sizeof (SPColorSlider), + 0, + (GInstanceInitFunc) sp_color_slider_init, + NULL + }; + type = g_type_register_static (GTK_TYPE_WIDGET, "SPColorSlider", &info, (GTypeFlags)0); + } + return type; +} + +static void sp_color_slider_class_init(SPColorSliderClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS(klass); + GtkWidgetClass *widget_class = GTK_WIDGET_CLASS(klass); + + parent_class = GTK_WIDGET_CLASS(g_type_class_peek_parent(klass)); + + slider_signals[GRABBED] = g_signal_new ("grabbed", + G_TYPE_FROM_CLASS(object_class), + (GSignalFlags)(G_SIGNAL_RUN_FIRST | G_SIGNAL_NO_RECURSE), + G_STRUCT_OFFSET (SPColorSliderClass, grabbed), + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); + slider_signals[DRAGGED] = g_signal_new ("dragged", + G_TYPE_FROM_CLASS(object_class), + (GSignalFlags)(G_SIGNAL_RUN_FIRST | G_SIGNAL_NO_RECURSE), + G_STRUCT_OFFSET (SPColorSliderClass, dragged), + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); + slider_signals[RELEASED] = g_signal_new ("released", + G_TYPE_FROM_CLASS(object_class), + (GSignalFlags)(G_SIGNAL_RUN_FIRST | G_SIGNAL_NO_RECURSE), + G_STRUCT_OFFSET (SPColorSliderClass, released), + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); + slider_signals[CHANGED] = g_signal_new ("changed", + G_TYPE_FROM_CLASS(object_class), + (GSignalFlags)(G_SIGNAL_RUN_FIRST | G_SIGNAL_NO_RECURSE), + G_STRUCT_OFFSET (SPColorSliderClass, changed), + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); + + object_class->dispose = sp_color_slider_dispose; + + widget_class->realize = sp_color_slider_realize; +#if GTK_CHECK_VERSION(3,0,0) + widget_class->get_preferred_width = sp_color_slider_get_preferred_width; + widget_class->get_preferred_height = sp_color_slider_get_preferred_height; + widget_class->draw = sp_color_slider_draw; +#else + widget_class->size_request = sp_color_slider_size_request; + widget_class->expose_event = sp_color_slider_expose; +#endif + widget_class->size_allocate = sp_color_slider_size_allocate; +/* widget_class->draw_focus = sp_color_slider_draw_focus; */ +/* widget_class->draw_default = sp_color_slider_draw_default; */ + + widget_class->button_press_event = sp_color_slider_button_press; + widget_class->button_release_event = sp_color_slider_button_release; + widget_class->motion_notify_event = sp_color_slider_motion_notify; +} + +static void +sp_color_slider_init (SPColorSlider *slider) +{ + /* We are widget with window */ + gtk_widget_set_has_window (GTK_WIDGET(slider), TRUE); + + slider->dragging = FALSE; + + slider->adjustment = NULL; + slider->value = 0.0; + + slider->c0[0] = 0x00; + slider->c0[1] = 0x00; + slider->c0[2] = 0x00; + slider->c0[3] = 0xff; + + slider->cm[0] = 0xff; + slider->cm[1] = 0x00; + slider->cm[2] = 0x00; + slider->cm[3] = 0xff; + + slider->c1[0] = 0xff; + slider->c1[1] = 0xff; + slider->c1[2] = 0xff; + slider->c1[3] = 0xff; + + slider->b0 = 0x5f; + slider->b1 = 0xa0; + slider->bmask = 0x08; + + slider->map = NULL; +} + +static void sp_color_slider_dispose(GObject *object) +{ + SPColorSlider *slider = SP_COLOR_SLIDER (object); + + if (slider->adjustment) { + g_signal_handlers_disconnect_matched (G_OBJECT (slider->adjustment), G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, slider); + g_object_unref (slider->adjustment); + slider->adjustment = NULL; + } + + if ((G_OBJECT_CLASS(parent_class))->dispose) + (* (G_OBJECT_CLASS(parent_class))->dispose) (object); +} + +static void +sp_color_slider_realize (GtkWidget *widget) +{ + GdkWindowAttr attributes; + gint attributes_mask; + GtkAllocation allocation; + + gtk_widget_get_allocation(widget, &allocation); + gtk_widget_set_realized (widget, TRUE); + + attributes.window_type = GDK_WINDOW_CHILD; + attributes.x = allocation.x; + attributes.y = allocation.y; + attributes.width = allocation.width; + attributes.height = allocation.height; + attributes.wclass = GDK_INPUT_OUTPUT; + attributes.visual = gdk_screen_get_system_visual(gdk_screen_get_default()); + +#if !GTK_CHECK_VERSION(3,0,0) + attributes.colormap = gdk_screen_get_system_colormap(gdk_screen_get_default()); +#endif + + attributes.event_mask = gtk_widget_get_events (widget); + attributes.event_mask |= (GDK_EXPOSURE_MASK | + GDK_BUTTON_PRESS_MASK | + GDK_BUTTON_RELEASE_MASK | + GDK_POINTER_MOTION_MASK | + GDK_ENTER_NOTIFY_MASK | + GDK_LEAVE_NOTIFY_MASK); +#if GTK_CHECK_VERSION(3,0,0) + attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL; +#else + attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP; +#endif + + gtk_widget_set_window(widget, + gdk_window_new(gtk_widget_get_parent_window(widget), + &attributes, attributes_mask)); + + gdk_window_set_user_data(gtk_widget_get_window(widget), widget); + +#if !GTK_CHECK_VERSION(3,0,0) + // This doesn't do anything in GTK+ 3 + gtk_widget_set_style(widget, + gtk_style_attach(gtk_widget_get_style(widget), + gtk_widget_get_window(widget))); +#endif +} + +static void +sp_color_slider_size_request (GtkWidget *widget, GtkRequisition *requisition) +{ + GtkStyle *style = gtk_widget_get_style(widget); + requisition->width = SLIDER_WIDTH + style->xthickness * 2; + requisition->height = SLIDER_HEIGHT + style->ythickness * 2; +} + +#if GTK_CHECK_VERSION(3,0,0) +static void sp_color_slider_get_preferred_width(GtkWidget *widget, gint *minimal_width, gint *natural_width) +{ + GtkRequisition requisition; + sp_color_slider_size_request(widget, &requisition); + *minimal_width = *natural_width = requisition.width; +} + +static void sp_color_slider_get_preferred_height(GtkWidget *widget, gint *minimal_height, gint *natural_height) +{ + GtkRequisition requisition; + sp_color_slider_size_request(widget, &requisition); + *minimal_height = *natural_height = requisition.height; +} +#endif + +static void +sp_color_slider_size_allocate (GtkWidget *widget, GtkAllocation *allocation) +{ + gtk_widget_set_allocation(widget, allocation); + + if (gtk_widget_get_realized (widget)) { + /* Resize GdkWindow */ + gdk_window_move_resize(gtk_widget_get_window(widget), + allocation->x, allocation->y, + allocation->width, allocation->height); + } +} + +#if !GTK_CHECK_VERSION(3,0,0) +static gboolean sp_color_slider_expose(GtkWidget *widget, GdkEventExpose * /*event*/) +{ + gboolean result = FALSE; + + if (gtk_widget_is_drawable(widget)) { + GdkWindow *window = gtk_widget_get_window(widget); + cairo_t *cr = gdk_cairo_create(window); + result = sp_color_slider_draw(widget, cr); + cairo_destroy(cr); + } + + return result; +} +#endif + +static gint +sp_color_slider_button_press (GtkWidget *widget, GdkEventButton *event) +{ + SPColorSlider *slider; + + slider = SP_COLOR_SLIDER (widget); + + if (event->button == 1) { + GtkAllocation allocation; + gtk_widget_get_allocation(widget, &allocation); + gint cx, cw; + cx = gtk_widget_get_style(widget)->xthickness; + cw = allocation.width - 2 * cx; + g_signal_emit (G_OBJECT (slider), slider_signals[GRABBED], 0); + slider->dragging = TRUE; + slider->oldvalue = slider->value; + ColorScales::setScaled( slider->adjustment, CLAMP ((gfloat) (event->x - cx) / cw, 0.0, 1.0) ); + g_signal_emit (G_OBJECT (slider), slider_signals[DRAGGED], 0); + +#if GTK_CHECK_VERSION(3,0,0) + gdk_device_grab(gdk_event_get_device(reinterpret_cast(event)), + gtk_widget_get_window(widget), + GDK_OWNERSHIP_NONE, + FALSE, + static_cast(GDK_POINTER_MOTION_MASK | GDK_BUTTON_RELEASE_MASK), + NULL, + event->time); +#else + gdk_pointer_grab(gtk_widget_get_window(widget), FALSE, + static_cast(GDK_POINTER_MOTION_MASK | GDK_BUTTON_RELEASE_MASK), + NULL, NULL, event->time); +#endif + } + + return FALSE; +} + +static gint +sp_color_slider_button_release (GtkWidget *widget, GdkEventButton *event) +{ + SPColorSlider *slider; + + slider = SP_COLOR_SLIDER (widget); + + if (event->button == 1) { + +#if GTK_CHECK_VERSION(3,0,0) + gdk_device_ungrab(gdk_event_get_device(reinterpret_cast(event)), + gdk_event_get_time(reinterpret_cast(event))); +#else + gdk_pointer_ungrab (event->time); +#endif + + slider->dragging = FALSE; + g_signal_emit (G_OBJECT (slider), slider_signals[RELEASED], 0); + if (slider->value != slider->oldvalue) g_signal_emit (G_OBJECT (slider), slider_signals[CHANGED], 0); + } + + return FALSE; +} + +static gint +sp_color_slider_motion_notify (GtkWidget *widget, GdkEventMotion *event) +{ + SPColorSlider *slider; + + slider = SP_COLOR_SLIDER (widget); + + if (slider->dragging) { + gint cx, cw; + GtkAllocation allocation; + gtk_widget_get_allocation(widget, &allocation); + cx = gtk_widget_get_style(widget)->xthickness; + cw = allocation.width - 2 * cx; + ColorScales::setScaled( slider->adjustment, CLAMP ((gfloat) (event->x - cx) / cw, 0.0, 1.0) ); + g_signal_emit (G_OBJECT (slider), slider_signals[DRAGGED], 0); + } + + return FALSE; +} + +GtkWidget *sp_color_slider_new(GtkAdjustment *adjustment) +{ + SPColorSlider *slider = SP_COLOR_SLIDER(g_object_new(SP_TYPE_COLOR_SLIDER, NULL)); + + sp_color_slider_set_adjustment (slider, adjustment); + + return GTK_WIDGET (slider); +} + +void sp_color_slider_set_adjustment(SPColorSlider *slider, GtkAdjustment *adjustment) +{ + g_return_if_fail (slider != NULL); + g_return_if_fail (SP_IS_COLOR_SLIDER (slider)); + + if (!adjustment) { + adjustment = GTK_ADJUSTMENT(gtk_adjustment_new(0.0, 0.0, 1.0, 0.01, 0.0, 0.0)); + } else { + gtk_adjustment_set_page_increment(adjustment, 0.0); + gtk_adjustment_set_page_size(adjustment, 0.0); + } + + if (slider->adjustment != adjustment) { + if (slider->adjustment) { + g_signal_handlers_disconnect_matched (G_OBJECT (slider->adjustment), G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, slider); + g_object_unref (slider->adjustment); + } + + slider->adjustment = adjustment; + g_object_ref (adjustment); + g_object_ref_sink (adjustment); + + g_signal_connect (G_OBJECT (adjustment), "changed", + G_CALLBACK (sp_color_slider_adjustment_changed), slider); + g_signal_connect (G_OBJECT (adjustment), "value_changed", + G_CALLBACK (sp_color_slider_adjustment_value_changed), slider); + + slider->value = ColorScales::getScaled( adjustment ); + + sp_color_slider_adjustment_changed (adjustment, slider); + } +} + +void +sp_color_slider_set_colors (SPColorSlider *slider, guint32 start, guint32 mid, guint32 end) +{ + g_return_if_fail (slider != NULL); + g_return_if_fail (SP_IS_COLOR_SLIDER (slider)); + + // Remove any map, if set + slider->map = 0; + + slider->c0[0] = start >> 24; + slider->c0[1] = (start >> 16) & 0xff; + slider->c0[2] = (start >> 8) & 0xff; + slider->c0[3] = start & 0xff; + + slider->cm[0] = mid >> 24; + slider->cm[1] = (mid >> 16) & 0xff; + slider->cm[2] = (mid >> 8) & 0xff; + slider->cm[3] = mid & 0xff; + + slider->c1[0] = end >> 24; + slider->c1[1] = (end >> 16) & 0xff; + slider->c1[2] = (end >> 8) & 0xff; + slider->c1[3] = end & 0xff; + + gtk_widget_queue_draw (GTK_WIDGET (slider)); +} + +void +sp_color_slider_set_map (SPColorSlider *slider, const guchar *map) +{ + g_return_if_fail (slider != NULL); + g_return_if_fail (SP_IS_COLOR_SLIDER (slider)); + + slider->map = const_cast(map); + + gtk_widget_queue_draw (GTK_WIDGET (slider)); +} + +void +sp_color_slider_set_background (SPColorSlider *slider, guint dark, guint light, guint size) +{ + g_return_if_fail (slider != NULL); + g_return_if_fail (SP_IS_COLOR_SLIDER (slider)); + + slider->b0 = dark; + slider->b1 = light; + slider->bmask = size; + + gtk_widget_queue_draw (GTK_WIDGET (slider)); +} + +static void +sp_color_slider_adjustment_changed (GtkAdjustment */*adjustment*/, SPColorSlider *slider) +{ + gtk_widget_queue_draw (GTK_WIDGET (slider)); +} + +static void +sp_color_slider_adjustment_value_changed (GtkAdjustment *adjustment, SPColorSlider *slider) +{ + GtkWidget *widget; + + widget = GTK_WIDGET (slider); + + if (slider->value != ColorScales::getScaled( adjustment )) { + gint cx, cy, cw, ch; + GtkStyle *style = gtk_widget_get_style(widget); + GtkAllocation allocation; + gtk_widget_get_allocation(widget, &allocation); + cx = style->xthickness; + cy = style->ythickness; + cw = allocation.width - 2 * cx; + ch = allocation.height - 2 * cy; + if ((gint) (ColorScales::getScaled( adjustment ) * cw) != (gint) (slider->value * cw)) { + gint ax, ay; + gfloat value; + value = slider->value; + slider->value = ColorScales::getScaled( adjustment ); + ax = (int)(cx + value * cw - ARROW_SIZE / 2 - 2); + ay = cy; + gtk_widget_queue_draw_area (widget, ax, ay, ARROW_SIZE + 4, ch); + ax = (int)(cx + slider->value * cw - ARROW_SIZE / 2 - 2); + ay = cy; + gtk_widget_queue_draw_area (widget, ax, ay, ARROW_SIZE + 4, ch); + } else { + slider->value = ColorScales::getScaled( adjustment ); + } + } +} + +static gboolean sp_color_slider_draw(GtkWidget *widget, cairo_t *cr) +{ + SPColorSlider *slider = SP_COLOR_SLIDER(widget); + + gboolean colorsOnTop = Inkscape::Preferences::get()->getBool("/options/workarounds/colorsontop", false); + + GtkAllocation allocation; + gtk_widget_get_allocation(widget, &allocation); + +#if GTK_CHECK_VERSION(3,0,0) + GtkStyleContext *context = gtk_widget_get_style_context(widget); +#else + GdkWindow *window = gtk_widget_get_window(widget); + GtkStyle *style = gtk_widget_get_style(widget); +#endif + + // Draw shadow + if (colorsOnTop) { +#if GTK_CHECK_VERSION(3,0,0) + gtk_render_frame(context, + cr, + 0, 0, + allocation.width, allocation.height); +#else + gtk_paint_shadow( style, window, + gtk_widget_get_state(widget), GTK_SHADOW_IN, + NULL, widget, "colorslider", + 0, 0, + allocation.width, allocation.height); +#endif + } + + /* Paintable part of color gradient area */ + GdkRectangle carea; + +#if GTK_CHECK_VERSION(3,0,0) + GtkBorder padding; + + gtk_style_context_get_padding(context, + gtk_widget_get_state_flags(widget), + &padding); + + carea.x = padding.left; + carea.y = padding.top; +#else + carea.x = style->xthickness; + carea.y = style->ythickness; +#endif + + carea.width = allocation.width - 2 * carea.x; + carea.height = allocation.height - 2 * carea.y; + + if (slider->map) { + /* Render map pixelstore */ + gint d = (1024 << 16) / carea.width; + gint s = 0; + + const guchar *b = sp_color_slider_render_map(0, 0, carea.width, carea.height, + slider->map, s, d, + slider->b0, slider->b1, slider->bmask); + + if (b != NULL && carea.width > 0) { + GdkPixbuf *pb = gdk_pixbuf_new_from_data (b, GDK_COLORSPACE_RGB, + 0, 8, carea.width, carea.height, carea.width * 3, NULL, NULL); + + gdk_cairo_set_source_pixbuf(cr, pb, carea.x, carea.y); + cairo_paint(cr); + g_object_unref(pb); + } + + } else { + gint c[4], dc[4]; + + /* Render gradient */ + + // part 1: from c0 to cm + if (carea.width > 0) { + for (gint i = 0; i < 4; i++) { + c[i] = slider->c0[i] << 16; + dc[i] = ((slider->cm[i] << 16) - c[i]) / (carea.width/2); + } + guint wi = carea.width/2; + const guchar *b = sp_color_slider_render_gradient(0, 0, wi, carea.height, + c, dc, slider->b0, slider->b1, slider->bmask); + + /* Draw pixelstore 1 */ + if (b != NULL && wi > 0) { + GdkPixbuf *pb = gdk_pixbuf_new_from_data (b, GDK_COLORSPACE_RGB, + 0, 8, wi, carea.height, wi * 3, NULL, NULL); + + gdk_cairo_set_source_pixbuf(cr, pb, carea.x, carea.y); + cairo_paint(cr); + g_object_unref(pb); + } + } + + // part 2: from cm to c1 + if (carea.width > 0) { + for (gint i = 0; i < 4; i++) { + c[i] = slider->cm[i] << 16; + dc[i] = ((slider->c1[i] << 16) - c[i]) / (carea.width/2); + } + guint wi = carea.width/2; + const guchar *b = sp_color_slider_render_gradient(carea.width/2, 0, wi, carea.height, + c, dc, + slider->b0, slider->b1, slider->bmask); + + /* Draw pixelstore 2 */ + if (b != NULL && wi > 0) { + GdkPixbuf *pb = gdk_pixbuf_new_from_data (b, GDK_COLORSPACE_RGB, + 0, 8, wi, carea.height, wi * 3, NULL, NULL); + + gdk_cairo_set_source_pixbuf(cr, pb, carea.width/2 + carea.x, carea.y); + cairo_paint(cr); + + g_object_unref(pb); + } + } + } + + /* Draw shadow */ + if (!colorsOnTop) { +#if GTK_CHECK_VERSION(3,0,0) + gtk_render_frame(context, + cr, + 0, 0, + allocation.width, allocation.height); +#else + gtk_paint_shadow( style, window, + gtk_widget_get_state(widget), GTK_SHADOW_IN, + NULL, widget, "colorslider", + 0, 0, + allocation.width, allocation.height); +#endif + } + + /* Draw arrow */ + gint x = (int)(slider->value * (carea.width - 1) - ARROW_SIZE / 2 + carea.x); + gint y1 = carea.y; + gint y2 = carea.y + carea.height - 1; + cairo_set_line_width(cr, 1.0); + + // Define top arrow + cairo_move_to(cr, x - 0.5, y1 + 0.5); + cairo_line_to(cr, x + ARROW_SIZE - 0.5, y1 + 0.5); + cairo_line_to(cr, x + (ARROW_SIZE-1)/2.0, y1 + ARROW_SIZE/2.0 + 0.5); + cairo_line_to(cr, x - 0.5, y1 + 0.5); + + // Define bottom arrow + cairo_move_to(cr, x - 0.5, y2 + 0.5); + cairo_line_to(cr, x + ARROW_SIZE - 0.5, y2 + 0.5); + cairo_line_to(cr, x + (ARROW_SIZE-1)/2.0, y2 - ARROW_SIZE/2.0 + 0.5); + cairo_line_to(cr, x - 0.5, y2 + 0.5); + + // Render both arrows + cairo_set_source_rgb(cr, 1.0, 1.0, 1.0); + cairo_stroke_preserve(cr); + cairo_set_source_rgb(cr, 0.0, 0.0, 0.0); + cairo_fill(cr); + + return FALSE; +} + +/* Colors are << 16 */ + +static const guchar * +sp_color_slider_render_gradient (gint x0, gint y0, gint width, gint height, + gint c[], gint dc[], guint b0, guint b1, guint mask) +{ + static guchar *buf = NULL; + static gint bs = 0; + guchar *dp; + gint x, y; + guint r, g, b, a; + + if (buf && (bs < width * height)) { + g_free (buf); + buf = NULL; + } + if (!buf) { + buf = g_new (guchar, width * height * 3); + bs = width * height; + } + + dp = buf; + r = c[0]; + g = c[1]; + b = c[2]; + a = c[3]; + for (x = x0; x < x0 + width; x++) { + gint cr, cg, cb, ca; + guchar *d; + cr = r >> 16; + cg = g >> 16; + cb = b >> 16; + ca = a >> 16; + d = dp; + for (y = y0; y < y0 + height; y++) { + guint bg, fc; + /* Background value */ + bg = ((x & mask) ^ (y & mask)) ? b0 : b1; + fc = (cr - bg) * ca; + d[0] = bg + ((fc + (fc >> 8) + 0x80) >> 8); + fc = (cg - bg) * ca; + d[1] = bg + ((fc + (fc >> 8) + 0x80) >> 8); + fc = (cb - bg) * ca; + d[2] = bg + ((fc + (fc >> 8) + 0x80) >> 8); + d += 3 * width; + } + r += dc[0]; + g += dc[1]; + b += dc[2]; + a += dc[3]; + dp += 3; + } + + return buf; +} + +/* Positions are << 16 */ + +static const guchar * +sp_color_slider_render_map (gint x0, gint y0, gint width, gint height, + guchar *map, gint start, gint step, guint b0, guint b1, guint mask) +{ + static guchar *buf = NULL; + static gint bs = 0; + guchar *dp; + gint x, y; + + if (buf && (bs < width * height)) { + g_free (buf); + buf = NULL; + } + if (!buf) { + buf = g_new (guchar, width * height * 3); + bs = width * height; + } + + dp = buf; + for (x = x0; x < x0 + width; x++) { + gint cr, cg, cb, ca; + guchar *d = dp; + guchar *sp = map + 4 * (start >> 16); + cr = *sp++; + cg = *sp++; + cb = *sp++; + ca = *sp++; + for (y = y0; y < y0 + height; y++) { + guint bg, fc; + /* Background value */ + bg = ((x & mask) ^ (y & mask)) ? b0 : b1; + fc = (cr - bg) * ca; + d[0] = bg + ((fc + (fc >> 8) + 0x80) >> 8); + fc = (cg - bg) * ca; + d[1] = bg + ((fc + (fc >> 8) + 0x80) >> 8); + fc = (cb - bg) * ca; + d[2] = bg + ((fc + (fc >> 8) + 0x80) >> 8); + d += 3 * width; + } + dp += 3; + start += step; + } + + return buf; +} + diff --git a/src/ui/widget/color-slider.h b/src/ui/widget/color-slider.h new file mode 100644 index 000000000..d8be7d111 --- /dev/null +++ b/src/ui/widget/color-slider.h @@ -0,0 +1,146 @@ +#ifndef __SP_COLOR_SLIDER_H__ +#define __SP_COLOR_SLIDER_H__ + +/* Author: + * Lauris Kaplinski + * + * Copyright (C) 2001-2002 Lauris Kaplinski + * + * This code is in public domain + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#if GLIBMM_DISABLE_DEPRECATED && HAVE_GLIBMM_THREADS_H +#include +#endif + +#include +#include + +namespace Inkscape +{ +namespace UI +{ +namespace Widget +{ + +/* + * A slider with colored background + */ +class ColorSlider: public Gtk::Widget { +public: + //if GTK2 + ColorSlider(Gtk::Adjustment *adjustment); + ~ColorSlider(); + + void set_adjustment(Gtk::Adjustment *adjustment); + + void set_colors(guint32 start, guint32 mid, guint32 end); + + void set_map(const guchar* map); + + void set_background(guint dark, guint light, guint size); + + sigc::signal signal_grabbed; + sigc::signal signal_dragged; + sigc::signal signal_released; + sigc::signal signal_value_changed; + +protected: + void on_size_allocate(Gtk::Allocation& allocation); + void on_realize(); + void on_unrealize(); + bool on_button_press_event(GdkEventButton *event); + bool on_button_release_event(GdkEventButton *event); + bool on_motion_notify_event(GdkEventMotion *event); + + //if GTK2 + void on_size_request(Gtk::Requisition* requisition); + bool on_expose_event(GdkEventExpose* event); + //if GTK3 + //request mode, get preffered width/height vfunc + //endif + + bool on_draw(const Cairo::RefPtr& cr); + + //TODO: on_adjustment_changed method + //TODO: on_adjustment value changed method + connection + +private: + bool _dragging; + + Gtk::Adjustment *_adjustment; + + gfloat _value; + gfloat _oldvalue; + guchar _c0[4], _cm[4], _c1[4]; + guchar _b0, _b1; + guchar _bmask; + + gint _mapsize; + guchar *_map; + + Glib::RefPtr _refGdkWindow; +}; + +}//namespace Widget +}//namespace UI +}//namespace Inkscape + + +#include + +#include + + + +struct SPColorSlider; +struct SPColorSliderClass; + +#define SP_TYPE_COLOR_SLIDER (sp_color_slider_get_type ()) +#define SP_COLOR_SLIDER(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), SP_TYPE_COLOR_SLIDER, SPColorSlider)) +#define SP_COLOR_SLIDER_CLASS(k) (G_TYPE_CHECK_CLASS_CAST ((k), SP_TYPE_COLOR_SLIDER, SPColorSliderClass)) +#define SP_IS_COLOR_SLIDER(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), SP_TYPE_COLOR_SLIDER)) +#define SP_IS_COLOR_SLIDER_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), SP_TYPE_COLOR_SLIDER)) + +struct SPColorSlider { + GtkWidget widget; + + guint dragging : 1; + + GtkAdjustment *adjustment; + + gfloat value; + gfloat oldvalue; + guchar c0[4], cm[4], c1[4]; + guchar b0, b1; + guchar bmask; + + gint mapsize; + guchar *map; +}; + +struct SPColorSliderClass { + GtkWidgetClass parent_class; + + void (* grabbed) (SPColorSlider *slider); + void (* dragged) (SPColorSlider *slider); + void (* released) (SPColorSlider *slider); + void (* changed) (SPColorSlider *slider); +}; + +GType sp_color_slider_get_type (void); + +GtkWidget *sp_color_slider_new (GtkAdjustment *adjustment); + +void sp_color_slider_set_adjustment (SPColorSlider *slider, GtkAdjustment *adjustment); +void sp_color_slider_set_colors (SPColorSlider *slider, guint32 start, guint32 mid, guint32 end); +void sp_color_slider_set_map (SPColorSlider *slider, const guchar *map); +void sp_color_slider_set_background (SPColorSlider *slider, guint dark, guint light, guint size); + + + +#endif diff --git a/src/widgets/CMakeLists.txt b/src/widgets/CMakeLists.txt index fe4433153..b65e0b1db 100644 --- a/src/widgets/CMakeLists.txt +++ b/src/widgets/CMakeLists.txt @@ -40,7 +40,6 @@ set(widgets_SRC sp-color-notebook.cpp sp-color-scales.cpp sp-color-selector.cpp - sp-color-slider.cpp sp-color-wheel-selector.cpp sp-widget.cpp sp-xmlview-attr-list.cpp @@ -97,7 +96,6 @@ set(widgets_SRC sp-color-notebook.h sp-color-scales.h sp-color-selector.h - sp-color-slider.h sp-color-wheel-selector.h sp-widget.h sp-xmlview-attr-list.h diff --git a/src/widgets/Makefile_insert b/src/widgets/Makefile_insert index 97713cbee..a4a3bb61b 100644 --- a/src/widgets/Makefile_insert +++ b/src/widgets/Makefile_insert @@ -74,8 +74,6 @@ ink_common_sources += \ widgets/sp-color-scales.h \ widgets/sp-color-selector.cpp \ widgets/sp-color-selector.h \ - widgets/sp-color-slider.cpp \ - widgets/sp-color-slider.h \ widgets/sp-color-wheel-selector.cpp \ widgets/sp-color-wheel-selector.h \ widgets/spinbutton-events.cpp \ diff --git a/src/widgets/sp-color-icc-selector.cpp b/src/widgets/sp-color-icc-selector.cpp index 53e73dd57..baed7e3b6 100644 --- a/src/widgets/sp-color-icc-selector.cpp +++ b/src/widgets/sp-color-icc-selector.cpp @@ -13,7 +13,7 @@ #include "../dialogs/dialog-events.h" #include "sp-color-icc-selector.h" #include "sp-color-scales.h" -#include "sp-color-slider.h" +#include "ui/widget/color-slider.h" #include "svg/svg-icc-color.h" #include "colorspace.h" #include "document.h" diff --git a/src/widgets/sp-color-scales.cpp b/src/widgets/sp-color-scales.cpp index a7d458561..7d5874506 100644 --- a/src/widgets/sp-color-scales.cpp +++ b/src/widgets/sp-color-scales.cpp @@ -13,6 +13,7 @@ #include #include "../dialogs/dialog-events.h" #include "svg/svg-icc-color.h" +#include "ui/widget/color-slider.h" #define CSC_CHANNEL_R (1 << 0) #define CSC_CHANNEL_G (1 << 1) diff --git a/src/widgets/sp-color-scales.h b/src/widgets/sp-color-scales.h index cd3900f85..65925fecb 100644 --- a/src/widgets/sp-color-scales.h +++ b/src/widgets/sp-color-scales.h @@ -13,12 +13,13 @@ #include #include -#include #include struct SPColorScales; struct SPColorScalesClass; +struct SPColorSlider; + typedef enum { SP_COLOR_SCALES_MODE_NONE = 0, diff --git a/src/widgets/sp-color-slider.cpp b/src/widgets/sp-color-slider.cpp deleted file mode 100644 index 07e1d79fb..000000000 --- a/src/widgets/sp-color-slider.cpp +++ /dev/null @@ -1,959 +0,0 @@ -/** - * @file - * A slider with colored background - implementation. - */ -/* Author: - * Lauris Kaplinski - * bulia byak - * - * Copyright (C) 2001-2002 Lauris Kaplinski - * - * This code is in public domain - */ - -#ifdef HAVE_CONFIG_H -# include "config.h" -#endif - -#include "sp-color-slider.h" - -#include -#include -#include -#include - -#include "sp-color-scales.h" -#include "preferences.h" - -static const gint SLIDER_WIDTH = 96; -static const gint SLIDER_HEIGHT = 8; -static const gint ARROW_SIZE = 7; - - -ColorSlider::ColorSlider(Gtk::Adjustment* adjustment) - : _dragging(false) - , _adjustment(NULL) - , _value(0.0) - , _oldvalue(0.0) - , _mapsize(0) - , _map(NULL) -{ - _c0[0] = 0x00; - _c0[1] = 0x00; - _c0[2] = 0x00; - _c0[3] = 0xff; - - _cm[0] = 0xff; - _cm[1] = 0x00; - _cm[2] = 0x00; - _cm[3] = 0xff; - - _c0[0] = 0xff; - _c0[1] = 0xff; - _c0[2] = 0xff; - _c0[3] = 0xff; - - _b0 = 0x5f; - _b1 = 0xa0; - _bmask = 0x08; - - set_adjustment(adjustment); -} - -ColorSlider::~ColorSlider() { - if (_adjustment) { - //TODO: disconnect all connections - delete _adjustment; - _adjustment = NULL; - } -} - -void ColorSlider::on_realize() { - set_realized(); - - if(!_refGdkWindow) - { - GdkWindowAttr attributes; - gint attributes_mask; - Gtk::Allocation allocation = get_allocation(); - - memset(&attributes, 0, sizeof(attributes)); - attributes.x = allocation.get_x(); - attributes.y = allocation.get_y(); - attributes.width = allocation.get_width(); - attributes.height = allocation.get_height(); - attributes.window_type = GDK_WINDOW_CHILD; - attributes.wclass = GDK_INPUT_OUTPUT; - attributes.visual = gdk_screen_get_system_visual(gdk_screen_get_default()); -#if !GTK_CHECK_VERSION(3,0,0) - attributes.colormap = gdk_screen_get_system_colormap(gdk_screen_get_default()); -#endif - attributes.event_mask = get_events (); - attributes.event_mask |= (Gdk::EXPOSURE_MASK | - Gdk::BUTTON_PRESS_MASK | - Gdk::BUTTON_RELEASE_MASK | - Gdk::POINTER_MOTION_MASK | - Gdk::ENTER_NOTIFY_MASK | - Gdk::LEAVE_NOTIFY_MASK); - -#if GTK_CHECK_VERSION(3,0,0) - attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL; -#else - attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP; -#endif - - _refGdkWindow = Gdk::Window::create(get_parent_window(), &attributes, - attributes_mask); - set_window(_refGdkWindow); - _refGdkWindow->set_user_data(gobj()); - - style_attach(); - } -} - -void ColorSlider::on_unrealize() { - _refGdkWindow.reset(); - - Gtk::Widget::on_unrealize(); -} - -void ColorSlider::on_size_request(Gtk::Requisition* requisition) { - GtkStyle *style = gtk_widget_get_style(gobj()); - requisition->width = SLIDER_WIDTH + style->xthickness * 2; - requisition->height = SLIDER_HEIGHT + style->ythickness * 2; -} - -//TODO: GTK3 prefferred width/height - -void ColorSlider::on_size_allocate(Gtk::Allocation& allocation) { - if (get_realized()) { - _refGdkWindow->move_resize(allocation.get_x(), allocation.get_y(), - allocation.get_width(), allocation.get_height()); - } -} - -//TODO: if not GTK3 -bool ColorSlider::on_expose_event(GdkEventExpose* event) { - bool result = false; - - if (get_is_drawable()) { - Cairo::RefPtr cr = _refGdkWindow->create_cairo_context(); - result = on_draw(cr); - } - return result; -} - -bool ColorSlider::on_button_press_event(GdkEventButton *event) { - //TODO: implementation - return false; -} - -bool ColorSlider::on_button_release_event(GdkEventButton *event) { - //TODO: implementation - return false; -} - -bool ColorSlider::on_motion_notify_event(GdkEventMotion *event) { - //TODO: implementation - return false; -} - -void ColorSlider::set_adjustment(Gtk::Adjustment* /*adjustment*/) { - //TODO: implementation -} - -void ColorSlider::set_colors(guint32 start, guint32 min, guint32 end) { - -} - -void ColorSlider::set_map(const guchar *map) { - -} - -void ColorSlider::set_background(guint dark, guint light, guint size) { - -} - -bool ColorSlider::on_draw(const Cairo::RefPtr& cr) { - return false; -} - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -enum { - GRABBED, - DRAGGED, - RELEASED, - CHANGED, - LAST_SIGNAL -}; - -static void sp_color_slider_class_init (SPColorSliderClass *klass); -static void sp_color_slider_init (SPColorSlider *slider); -static void sp_color_slider_dispose(GObject *object); - -static void sp_color_slider_realize (GtkWidget *widget); -static void sp_color_slider_size_request (GtkWidget *widget, GtkRequisition *requisition); - -#if GTK_CHECK_VERSION(3,0,0) -static void sp_color_slider_get_preferred_width(GtkWidget *widget, - gint *minimal_width, - gint *natural_width); - -static void sp_color_slider_get_preferred_height(GtkWidget *widget, - gint *minimal_height, - gint *natural_height); -#else -static gboolean sp_color_slider_expose(GtkWidget *widget, GdkEventExpose *event); -#endif - -static void sp_color_slider_size_allocate (GtkWidget *widget, GtkAllocation *allocation); - -static gboolean sp_color_slider_draw(GtkWidget *widget, cairo_t *cr); - -static gint sp_color_slider_button_press (GtkWidget *widget, GdkEventButton *event); -static gint sp_color_slider_button_release (GtkWidget *widget, GdkEventButton *event); -static gint sp_color_slider_motion_notify (GtkWidget *widget, GdkEventMotion *event); - -static void sp_color_slider_adjustment_changed (GtkAdjustment *adjustment, SPColorSlider *slider); -static void sp_color_slider_adjustment_value_changed (GtkAdjustment *adjustment, SPColorSlider *slider); - -static const guchar *sp_color_slider_render_gradient (gint x0, gint y0, gint width, gint height, - gint c[], gint dc[], guint b0, guint b1, guint mask); -static const guchar *sp_color_slider_render_map (gint x0, gint y0, gint width, gint height, - guchar *map, gint start, gint step, guint b0, guint b1, guint mask); - -static GtkWidgetClass *parent_class; -static guint slider_signals[LAST_SIGNAL] = {0}; - -GType -sp_color_slider_get_type (void) -{ - static GType type = 0; - if (!type) { - GTypeInfo info = { - sizeof (SPColorSliderClass), - NULL, NULL, - (GClassInitFunc) sp_color_slider_class_init, - NULL, NULL, - sizeof (SPColorSlider), - 0, - (GInstanceInitFunc) sp_color_slider_init, - NULL - }; - type = g_type_register_static (GTK_TYPE_WIDGET, "SPColorSlider", &info, (GTypeFlags)0); - } - return type; -} - -static void sp_color_slider_class_init(SPColorSliderClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS(klass); - GtkWidgetClass *widget_class = GTK_WIDGET_CLASS(klass); - - parent_class = GTK_WIDGET_CLASS(g_type_class_peek_parent(klass)); - - slider_signals[GRABBED] = g_signal_new ("grabbed", - G_TYPE_FROM_CLASS(object_class), - (GSignalFlags)(G_SIGNAL_RUN_FIRST | G_SIGNAL_NO_RECURSE), - G_STRUCT_OFFSET (SPColorSliderClass, grabbed), - NULL, NULL, - g_cclosure_marshal_VOID__VOID, - G_TYPE_NONE, 0); - slider_signals[DRAGGED] = g_signal_new ("dragged", - G_TYPE_FROM_CLASS(object_class), - (GSignalFlags)(G_SIGNAL_RUN_FIRST | G_SIGNAL_NO_RECURSE), - G_STRUCT_OFFSET (SPColorSliderClass, dragged), - NULL, NULL, - g_cclosure_marshal_VOID__VOID, - G_TYPE_NONE, 0); - slider_signals[RELEASED] = g_signal_new ("released", - G_TYPE_FROM_CLASS(object_class), - (GSignalFlags)(G_SIGNAL_RUN_FIRST | G_SIGNAL_NO_RECURSE), - G_STRUCT_OFFSET (SPColorSliderClass, released), - NULL, NULL, - g_cclosure_marshal_VOID__VOID, - G_TYPE_NONE, 0); - slider_signals[CHANGED] = g_signal_new ("changed", - G_TYPE_FROM_CLASS(object_class), - (GSignalFlags)(G_SIGNAL_RUN_FIRST | G_SIGNAL_NO_RECURSE), - G_STRUCT_OFFSET (SPColorSliderClass, changed), - NULL, NULL, - g_cclosure_marshal_VOID__VOID, - G_TYPE_NONE, 0); - - object_class->dispose = sp_color_slider_dispose; - - widget_class->realize = sp_color_slider_realize; -#if GTK_CHECK_VERSION(3,0,0) - widget_class->get_preferred_width = sp_color_slider_get_preferred_width; - widget_class->get_preferred_height = sp_color_slider_get_preferred_height; - widget_class->draw = sp_color_slider_draw; -#else - widget_class->size_request = sp_color_slider_size_request; - widget_class->expose_event = sp_color_slider_expose; -#endif - widget_class->size_allocate = sp_color_slider_size_allocate; -/* widget_class->draw_focus = sp_color_slider_draw_focus; */ -/* widget_class->draw_default = sp_color_slider_draw_default; */ - - widget_class->button_press_event = sp_color_slider_button_press; - widget_class->button_release_event = sp_color_slider_button_release; - widget_class->motion_notify_event = sp_color_slider_motion_notify; -} - -static void -sp_color_slider_init (SPColorSlider *slider) -{ - /* We are widget with window */ - gtk_widget_set_has_window (GTK_WIDGET(slider), TRUE); - - slider->dragging = FALSE; - - slider->adjustment = NULL; - slider->value = 0.0; - - slider->c0[0] = 0x00; - slider->c0[1] = 0x00; - slider->c0[2] = 0x00; - slider->c0[3] = 0xff; - - slider->cm[0] = 0xff; - slider->cm[1] = 0x00; - slider->cm[2] = 0x00; - slider->cm[3] = 0xff; - - slider->c1[0] = 0xff; - slider->c1[1] = 0xff; - slider->c1[2] = 0xff; - slider->c1[3] = 0xff; - - slider->b0 = 0x5f; - slider->b1 = 0xa0; - slider->bmask = 0x08; - - slider->map = NULL; -} - -static void sp_color_slider_dispose(GObject *object) -{ - SPColorSlider *slider = SP_COLOR_SLIDER (object); - - if (slider->adjustment) { - g_signal_handlers_disconnect_matched (G_OBJECT (slider->adjustment), G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, slider); - g_object_unref (slider->adjustment); - slider->adjustment = NULL; - } - - if ((G_OBJECT_CLASS(parent_class))->dispose) - (* (G_OBJECT_CLASS(parent_class))->dispose) (object); -} - -static void -sp_color_slider_realize (GtkWidget *widget) -{ - GdkWindowAttr attributes; - gint attributes_mask; - GtkAllocation allocation; - - gtk_widget_get_allocation(widget, &allocation); - gtk_widget_set_realized (widget, TRUE); - - attributes.window_type = GDK_WINDOW_CHILD; - attributes.x = allocation.x; - attributes.y = allocation.y; - attributes.width = allocation.width; - attributes.height = allocation.height; - attributes.wclass = GDK_INPUT_OUTPUT; - attributes.visual = gdk_screen_get_system_visual(gdk_screen_get_default()); - -#if !GTK_CHECK_VERSION(3,0,0) - attributes.colormap = gdk_screen_get_system_colormap(gdk_screen_get_default()); -#endif - - attributes.event_mask = gtk_widget_get_events (widget); - attributes.event_mask |= (GDK_EXPOSURE_MASK | - GDK_BUTTON_PRESS_MASK | - GDK_BUTTON_RELEASE_MASK | - GDK_POINTER_MOTION_MASK | - GDK_ENTER_NOTIFY_MASK | - GDK_LEAVE_NOTIFY_MASK); -#if GTK_CHECK_VERSION(3,0,0) - attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL; -#else - attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP; -#endif - - gtk_widget_set_window(widget, - gdk_window_new(gtk_widget_get_parent_window(widget), - &attributes, attributes_mask)); - - gdk_window_set_user_data(gtk_widget_get_window(widget), widget); - -#if !GTK_CHECK_VERSION(3,0,0) - // This doesn't do anything in GTK+ 3 - gtk_widget_set_style(widget, - gtk_style_attach(gtk_widget_get_style(widget), - gtk_widget_get_window(widget))); -#endif -} - -static void -sp_color_slider_size_request (GtkWidget *widget, GtkRequisition *requisition) -{ - GtkStyle *style = gtk_widget_get_style(widget); - requisition->width = SLIDER_WIDTH + style->xthickness * 2; - requisition->height = SLIDER_HEIGHT + style->ythickness * 2; -} - -#if GTK_CHECK_VERSION(3,0,0) -static void sp_color_slider_get_preferred_width(GtkWidget *widget, gint *minimal_width, gint *natural_width) -{ - GtkRequisition requisition; - sp_color_slider_size_request(widget, &requisition); - *minimal_width = *natural_width = requisition.width; -} - -static void sp_color_slider_get_preferred_height(GtkWidget *widget, gint *minimal_height, gint *natural_height) -{ - GtkRequisition requisition; - sp_color_slider_size_request(widget, &requisition); - *minimal_height = *natural_height = requisition.height; -} -#endif - -static void -sp_color_slider_size_allocate (GtkWidget *widget, GtkAllocation *allocation) -{ - gtk_widget_set_allocation(widget, allocation); - - if (gtk_widget_get_realized (widget)) { - /* Resize GdkWindow */ - gdk_window_move_resize(gtk_widget_get_window(widget), - allocation->x, allocation->y, - allocation->width, allocation->height); - } -} - -#if !GTK_CHECK_VERSION(3,0,0) -static gboolean sp_color_slider_expose(GtkWidget *widget, GdkEventExpose * /*event*/) -{ - gboolean result = FALSE; - - if (gtk_widget_is_drawable(widget)) { - GdkWindow *window = gtk_widget_get_window(widget); - cairo_t *cr = gdk_cairo_create(window); - result = sp_color_slider_draw(widget, cr); - cairo_destroy(cr); - } - - return result; -} -#endif - -static gint -sp_color_slider_button_press (GtkWidget *widget, GdkEventButton *event) -{ - SPColorSlider *slider; - - slider = SP_COLOR_SLIDER (widget); - - if (event->button == 1) { - GtkAllocation allocation; - gtk_widget_get_allocation(widget, &allocation); - gint cx, cw; - cx = gtk_widget_get_style(widget)->xthickness; - cw = allocation.width - 2 * cx; - g_signal_emit (G_OBJECT (slider), slider_signals[GRABBED], 0); - slider->dragging = TRUE; - slider->oldvalue = slider->value; - ColorScales::setScaled( slider->adjustment, CLAMP ((gfloat) (event->x - cx) / cw, 0.0, 1.0) ); - g_signal_emit (G_OBJECT (slider), slider_signals[DRAGGED], 0); - -#if GTK_CHECK_VERSION(3,0,0) - gdk_device_grab(gdk_event_get_device(reinterpret_cast(event)), - gtk_widget_get_window(widget), - GDK_OWNERSHIP_NONE, - FALSE, - static_cast(GDK_POINTER_MOTION_MASK | GDK_BUTTON_RELEASE_MASK), - NULL, - event->time); -#else - gdk_pointer_grab(gtk_widget_get_window(widget), FALSE, - static_cast(GDK_POINTER_MOTION_MASK | GDK_BUTTON_RELEASE_MASK), - NULL, NULL, event->time); -#endif - } - - return FALSE; -} - -static gint -sp_color_slider_button_release (GtkWidget *widget, GdkEventButton *event) -{ - SPColorSlider *slider; - - slider = SP_COLOR_SLIDER (widget); - - if (event->button == 1) { - -#if GTK_CHECK_VERSION(3,0,0) - gdk_device_ungrab(gdk_event_get_device(reinterpret_cast(event)), - gdk_event_get_time(reinterpret_cast(event))); -#else - gdk_pointer_ungrab (event->time); -#endif - - slider->dragging = FALSE; - g_signal_emit (G_OBJECT (slider), slider_signals[RELEASED], 0); - if (slider->value != slider->oldvalue) g_signal_emit (G_OBJECT (slider), slider_signals[CHANGED], 0); - } - - return FALSE; -} - -static gint -sp_color_slider_motion_notify (GtkWidget *widget, GdkEventMotion *event) -{ - SPColorSlider *slider; - - slider = SP_COLOR_SLIDER (widget); - - if (slider->dragging) { - gint cx, cw; - GtkAllocation allocation; - gtk_widget_get_allocation(widget, &allocation); - cx = gtk_widget_get_style(widget)->xthickness; - cw = allocation.width - 2 * cx; - ColorScales::setScaled( slider->adjustment, CLAMP ((gfloat) (event->x - cx) / cw, 0.0, 1.0) ); - g_signal_emit (G_OBJECT (slider), slider_signals[DRAGGED], 0); - } - - return FALSE; -} - -GtkWidget *sp_color_slider_new(GtkAdjustment *adjustment) -{ - SPColorSlider *slider = SP_COLOR_SLIDER(g_object_new(SP_TYPE_COLOR_SLIDER, NULL)); - - sp_color_slider_set_adjustment (slider, adjustment); - - return GTK_WIDGET (slider); -} - -void sp_color_slider_set_adjustment(SPColorSlider *slider, GtkAdjustment *adjustment) -{ - g_return_if_fail (slider != NULL); - g_return_if_fail (SP_IS_COLOR_SLIDER (slider)); - - if (!adjustment) { - adjustment = GTK_ADJUSTMENT(gtk_adjustment_new(0.0, 0.0, 1.0, 0.01, 0.0, 0.0)); - } else { - gtk_adjustment_set_page_increment(adjustment, 0.0); - gtk_adjustment_set_page_size(adjustment, 0.0); - } - - if (slider->adjustment != adjustment) { - if (slider->adjustment) { - g_signal_handlers_disconnect_matched (G_OBJECT (slider->adjustment), G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, slider); - g_object_unref (slider->adjustment); - } - - slider->adjustment = adjustment; - g_object_ref (adjustment); - g_object_ref_sink (adjustment); - - g_signal_connect (G_OBJECT (adjustment), "changed", - G_CALLBACK (sp_color_slider_adjustment_changed), slider); - g_signal_connect (G_OBJECT (adjustment), "value_changed", - G_CALLBACK (sp_color_slider_adjustment_value_changed), slider); - - slider->value = ColorScales::getScaled( adjustment ); - - sp_color_slider_adjustment_changed (adjustment, slider); - } -} - -void -sp_color_slider_set_colors (SPColorSlider *slider, guint32 start, guint32 mid, guint32 end) -{ - g_return_if_fail (slider != NULL); - g_return_if_fail (SP_IS_COLOR_SLIDER (slider)); - - // Remove any map, if set - slider->map = 0; - - slider->c0[0] = start >> 24; - slider->c0[1] = (start >> 16) & 0xff; - slider->c0[2] = (start >> 8) & 0xff; - slider->c0[3] = start & 0xff; - - slider->cm[0] = mid >> 24; - slider->cm[1] = (mid >> 16) & 0xff; - slider->cm[2] = (mid >> 8) & 0xff; - slider->cm[3] = mid & 0xff; - - slider->c1[0] = end >> 24; - slider->c1[1] = (end >> 16) & 0xff; - slider->c1[2] = (end >> 8) & 0xff; - slider->c1[3] = end & 0xff; - - gtk_widget_queue_draw (GTK_WIDGET (slider)); -} - -void -sp_color_slider_set_map (SPColorSlider *slider, const guchar *map) -{ - g_return_if_fail (slider != NULL); - g_return_if_fail (SP_IS_COLOR_SLIDER (slider)); - - slider->map = const_cast(map); - - gtk_widget_queue_draw (GTK_WIDGET (slider)); -} - -void -sp_color_slider_set_background (SPColorSlider *slider, guint dark, guint light, guint size) -{ - g_return_if_fail (slider != NULL); - g_return_if_fail (SP_IS_COLOR_SLIDER (slider)); - - slider->b0 = dark; - slider->b1 = light; - slider->bmask = size; - - gtk_widget_queue_draw (GTK_WIDGET (slider)); -} - -static void -sp_color_slider_adjustment_changed (GtkAdjustment */*adjustment*/, SPColorSlider *slider) -{ - gtk_widget_queue_draw (GTK_WIDGET (slider)); -} - -static void -sp_color_slider_adjustment_value_changed (GtkAdjustment *adjustment, SPColorSlider *slider) -{ - GtkWidget *widget; - - widget = GTK_WIDGET (slider); - - if (slider->value != ColorScales::getScaled( adjustment )) { - gint cx, cy, cw, ch; - GtkStyle *style = gtk_widget_get_style(widget); - GtkAllocation allocation; - gtk_widget_get_allocation(widget, &allocation); - cx = style->xthickness; - cy = style->ythickness; - cw = allocation.width - 2 * cx; - ch = allocation.height - 2 * cy; - if ((gint) (ColorScales::getScaled( adjustment ) * cw) != (gint) (slider->value * cw)) { - gint ax, ay; - gfloat value; - value = slider->value; - slider->value = ColorScales::getScaled( adjustment ); - ax = (int)(cx + value * cw - ARROW_SIZE / 2 - 2); - ay = cy; - gtk_widget_queue_draw_area (widget, ax, ay, ARROW_SIZE + 4, ch); - ax = (int)(cx + slider->value * cw - ARROW_SIZE / 2 - 2); - ay = cy; - gtk_widget_queue_draw_area (widget, ax, ay, ARROW_SIZE + 4, ch); - } else { - slider->value = ColorScales::getScaled( adjustment ); - } - } -} - -static gboolean sp_color_slider_draw(GtkWidget *widget, cairo_t *cr) -{ - SPColorSlider *slider = SP_COLOR_SLIDER(widget); - - gboolean colorsOnTop = Inkscape::Preferences::get()->getBool("/options/workarounds/colorsontop", false); - - GtkAllocation allocation; - gtk_widget_get_allocation(widget, &allocation); - -#if GTK_CHECK_VERSION(3,0,0) - GtkStyleContext *context = gtk_widget_get_style_context(widget); -#else - GdkWindow *window = gtk_widget_get_window(widget); - GtkStyle *style = gtk_widget_get_style(widget); -#endif - - // Draw shadow - if (colorsOnTop) { -#if GTK_CHECK_VERSION(3,0,0) - gtk_render_frame(context, - cr, - 0, 0, - allocation.width, allocation.height); -#else - gtk_paint_shadow( style, window, - gtk_widget_get_state(widget), GTK_SHADOW_IN, - NULL, widget, "colorslider", - 0, 0, - allocation.width, allocation.height); -#endif - } - - /* Paintable part of color gradient area */ - GdkRectangle carea; - -#if GTK_CHECK_VERSION(3,0,0) - GtkBorder padding; - - gtk_style_context_get_padding(context, - gtk_widget_get_state_flags(widget), - &padding); - - carea.x = padding.left; - carea.y = padding.top; -#else - carea.x = style->xthickness; - carea.y = style->ythickness; -#endif - - carea.width = allocation.width - 2 * carea.x; - carea.height = allocation.height - 2 * carea.y; - - if (slider->map) { - /* Render map pixelstore */ - gint d = (1024 << 16) / carea.width; - gint s = 0; - - const guchar *b = sp_color_slider_render_map(0, 0, carea.width, carea.height, - slider->map, s, d, - slider->b0, slider->b1, slider->bmask); - - if (b != NULL && carea.width > 0) { - GdkPixbuf *pb = gdk_pixbuf_new_from_data (b, GDK_COLORSPACE_RGB, - 0, 8, carea.width, carea.height, carea.width * 3, NULL, NULL); - - gdk_cairo_set_source_pixbuf(cr, pb, carea.x, carea.y); - cairo_paint(cr); - g_object_unref(pb); - } - - } else { - gint c[4], dc[4]; - - /* Render gradient */ - - // part 1: from c0 to cm - if (carea.width > 0) { - for (gint i = 0; i < 4; i++) { - c[i] = slider->c0[i] << 16; - dc[i] = ((slider->cm[i] << 16) - c[i]) / (carea.width/2); - } - guint wi = carea.width/2; - const guchar *b = sp_color_slider_render_gradient(0, 0, wi, carea.height, - c, dc, slider->b0, slider->b1, slider->bmask); - - /* Draw pixelstore 1 */ - if (b != NULL && wi > 0) { - GdkPixbuf *pb = gdk_pixbuf_new_from_data (b, GDK_COLORSPACE_RGB, - 0, 8, wi, carea.height, wi * 3, NULL, NULL); - - gdk_cairo_set_source_pixbuf(cr, pb, carea.x, carea.y); - cairo_paint(cr); - g_object_unref(pb); - } - } - - // part 2: from cm to c1 - if (carea.width > 0) { - for (gint i = 0; i < 4; i++) { - c[i] = slider->cm[i] << 16; - dc[i] = ((slider->c1[i] << 16) - c[i]) / (carea.width/2); - } - guint wi = carea.width/2; - const guchar *b = sp_color_slider_render_gradient(carea.width/2, 0, wi, carea.height, - c, dc, - slider->b0, slider->b1, slider->bmask); - - /* Draw pixelstore 2 */ - if (b != NULL && wi > 0) { - GdkPixbuf *pb = gdk_pixbuf_new_from_data (b, GDK_COLORSPACE_RGB, - 0, 8, wi, carea.height, wi * 3, NULL, NULL); - - gdk_cairo_set_source_pixbuf(cr, pb, carea.width/2 + carea.x, carea.y); - cairo_paint(cr); - - g_object_unref(pb); - } - } - } - - /* Draw shadow */ - if (!colorsOnTop) { -#if GTK_CHECK_VERSION(3,0,0) - gtk_render_frame(context, - cr, - 0, 0, - allocation.width, allocation.height); -#else - gtk_paint_shadow( style, window, - gtk_widget_get_state(widget), GTK_SHADOW_IN, - NULL, widget, "colorslider", - 0, 0, - allocation.width, allocation.height); -#endif - } - - /* Draw arrow */ - gint x = (int)(slider->value * (carea.width - 1) - ARROW_SIZE / 2 + carea.x); - gint y1 = carea.y; - gint y2 = carea.y + carea.height - 1; - cairo_set_line_width(cr, 1.0); - - // Define top arrow - cairo_move_to(cr, x - 0.5, y1 + 0.5); - cairo_line_to(cr, x + ARROW_SIZE - 0.5, y1 + 0.5); - cairo_line_to(cr, x + (ARROW_SIZE-1)/2.0, y1 + ARROW_SIZE/2.0 + 0.5); - cairo_line_to(cr, x - 0.5, y1 + 0.5); - - // Define bottom arrow - cairo_move_to(cr, x - 0.5, y2 + 0.5); - cairo_line_to(cr, x + ARROW_SIZE - 0.5, y2 + 0.5); - cairo_line_to(cr, x + (ARROW_SIZE-1)/2.0, y2 - ARROW_SIZE/2.0 + 0.5); - cairo_line_to(cr, x - 0.5, y2 + 0.5); - - // Render both arrows - cairo_set_source_rgb(cr, 1.0, 1.0, 1.0); - cairo_stroke_preserve(cr); - cairo_set_source_rgb(cr, 0.0, 0.0, 0.0); - cairo_fill(cr); - - return FALSE; -} - -/* Colors are << 16 */ - -static const guchar * -sp_color_slider_render_gradient (gint x0, gint y0, gint width, gint height, - gint c[], gint dc[], guint b0, guint b1, guint mask) -{ - static guchar *buf = NULL; - static gint bs = 0; - guchar *dp; - gint x, y; - guint r, g, b, a; - - if (buf && (bs < width * height)) { - g_free (buf); - buf = NULL; - } - if (!buf) { - buf = g_new (guchar, width * height * 3); - bs = width * height; - } - - dp = buf; - r = c[0]; - g = c[1]; - b = c[2]; - a = c[3]; - for (x = x0; x < x0 + width; x++) { - gint cr, cg, cb, ca; - guchar *d; - cr = r >> 16; - cg = g >> 16; - cb = b >> 16; - ca = a >> 16; - d = dp; - for (y = y0; y < y0 + height; y++) { - guint bg, fc; - /* Background value */ - bg = ((x & mask) ^ (y & mask)) ? b0 : b1; - fc = (cr - bg) * ca; - d[0] = bg + ((fc + (fc >> 8) + 0x80) >> 8); - fc = (cg - bg) * ca; - d[1] = bg + ((fc + (fc >> 8) + 0x80) >> 8); - fc = (cb - bg) * ca; - d[2] = bg + ((fc + (fc >> 8) + 0x80) >> 8); - d += 3 * width; - } - r += dc[0]; - g += dc[1]; - b += dc[2]; - a += dc[3]; - dp += 3; - } - - return buf; -} - -/* Positions are << 16 */ - -static const guchar * -sp_color_slider_render_map (gint x0, gint y0, gint width, gint height, - guchar *map, gint start, gint step, guint b0, guint b1, guint mask) -{ - static guchar *buf = NULL; - static gint bs = 0; - guchar *dp; - gint x, y; - - if (buf && (bs < width * height)) { - g_free (buf); - buf = NULL; - } - if (!buf) { - buf = g_new (guchar, width * height * 3); - bs = width * height; - } - - dp = buf; - for (x = x0; x < x0 + width; x++) { - gint cr, cg, cb, ca; - guchar *d = dp; - guchar *sp = map + 4 * (start >> 16); - cr = *sp++; - cg = *sp++; - cb = *sp++; - ca = *sp++; - for (y = y0; y < y0 + height; y++) { - guint bg, fc; - /* Background value */ - bg = ((x & mask) ^ (y & mask)) ? b0 : b1; - fc = (cr - bg) * ca; - d[0] = bg + ((fc + (fc >> 8) + 0x80) >> 8); - fc = (cg - bg) * ca; - d[1] = bg + ((fc + (fc >> 8) + 0x80) >> 8); - fc = (cb - bg) * ca; - d[2] = bg + ((fc + (fc >> 8) + 0x80) >> 8); - d += 3 * width; - } - dp += 3; - start += step; - } - - return buf; -} - diff --git a/src/widgets/sp-color-slider.h b/src/widgets/sp-color-slider.h deleted file mode 100644 index 6821c8fe4..000000000 --- a/src/widgets/sp-color-slider.h +++ /dev/null @@ -1,140 +0,0 @@ -#ifndef __SP_COLOR_SLIDER_H__ -#define __SP_COLOR_SLIDER_H__ - -/* Author: - * Lauris Kaplinski - * - * Copyright (C) 2001-2002 Lauris Kaplinski - * - * This code is in public domain - */ - -#ifdef HAVE_CONFIG_H -# include -#endif - -#if GLIBMM_DISABLE_DEPRECATED && HAVE_GLIBMM_THREADS_H -#include -#endif - -#include - -#include - - -/* - * A slider with colored background - */ -class ColorSlider: public Gtk::Widget { -public: - //if GTK2 - ColorSlider(Gtk::Adjustment *adjustment); - ~ColorSlider(); - - void set_adjustment(Gtk::Adjustment *adjustment); - - void set_colors(guint32 start, guint32 mid, guint32 end); - - void set_map(const guchar* map); - - void set_background(guint dark, guint light, guint size); - - sigc::signal signal_grabbed; - sigc::signal signal_dragged; - sigc::signal signal_released; - sigc::signal signal_value_changed; - -protected: - void on_size_allocate(Gtk::Allocation& allocation); - void on_realize(); - void on_unrealize(); - bool on_button_press_event(GdkEventButton *event); - bool on_button_release_event(GdkEventButton *event); - bool on_motion_notify_event(GdkEventMotion *event); - - //if GTK2 - void on_size_request(Gtk::Requisition* requisition); - bool on_expose_event(GdkEventExpose* event); - //if GTK3 - //request mode, get preffered width/height vfunc - //endif - - bool on_draw(const Cairo::RefPtr& cr); - - //TODO: on_adjustment_changed method - //TODO: on_adjustment value changed method + connection - -private: - bool _dragging; - - Gtk::Adjustment *_adjustment; - - gfloat _value; - gfloat _oldvalue; - guchar _c0[4], _cm[4], _c1[4]; - guchar _b0, _b1; - guchar _bmask; - - gint _mapsize; - guchar *_map; - - Glib::RefPtr _refGdkWindow; -}; - - - - - -#include - -#include - - - -struct SPColorSlider; -struct SPColorSliderClass; - -#define SP_TYPE_COLOR_SLIDER (sp_color_slider_get_type ()) -#define SP_COLOR_SLIDER(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), SP_TYPE_COLOR_SLIDER, SPColorSlider)) -#define SP_COLOR_SLIDER_CLASS(k) (G_TYPE_CHECK_CLASS_CAST ((k), SP_TYPE_COLOR_SLIDER, SPColorSliderClass)) -#define SP_IS_COLOR_SLIDER(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), SP_TYPE_COLOR_SLIDER)) -#define SP_IS_COLOR_SLIDER_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), SP_TYPE_COLOR_SLIDER)) - -struct SPColorSlider { - GtkWidget widget; - - guint dragging : 1; - - GtkAdjustment *adjustment; - - gfloat value; - gfloat oldvalue; - guchar c0[4], cm[4], c1[4]; - guchar b0, b1; - guchar bmask; - - gint mapsize; - guchar *map; -}; - -struct SPColorSliderClass { - GtkWidgetClass parent_class; - - void (* grabbed) (SPColorSlider *slider); - void (* dragged) (SPColorSlider *slider); - void (* released) (SPColorSlider *slider); - void (* changed) (SPColorSlider *slider); -}; - -GType sp_color_slider_get_type (void); - -GtkWidget *sp_color_slider_new (GtkAdjustment *adjustment); - -void sp_color_slider_set_adjustment (SPColorSlider *slider, GtkAdjustment *adjustment); -void sp_color_slider_set_colors (SPColorSlider *slider, guint32 start, guint32 mid, guint32 end); -void sp_color_slider_set_map (SPColorSlider *slider, const guchar *map); -void sp_color_slider_set_background (SPColorSlider *slider, guint dark, guint light, guint size); - - - -#endif diff --git a/src/widgets/sp-color-wheel-selector.cpp b/src/widgets/sp-color-wheel-selector.cpp index 1cc2e06d6..de2d030d4 100644 --- a/src/widgets/sp-color-wheel-selector.cpp +++ b/src/widgets/sp-color-wheel-selector.cpp @@ -11,6 +11,7 @@ #include "sp-color-scales.h" #include "sp-color-icc-selector.h" #include "../svg/svg-icc-color.h" +#include "ui/widget/color-slider.h" #include "ui/widget/gimpcolorwheel.h" G_BEGIN_DECLS diff --git a/src/widgets/sp-color-wheel-selector.h b/src/widgets/sp-color-wheel-selector.h index 6f45b6bba..b7b86438c 100644 --- a/src/widgets/sp-color-wheel-selector.h +++ b/src/widgets/sp-color-wheel-selector.h @@ -12,14 +12,12 @@ #include #include -#include "sp-color-slider.h" #include "sp-color-selector.h" - - typedef struct _GimpColorWheel GimpColorWheel; struct SPColorWheelSelector; struct SPColorWheelSelectorClass; +struct SPColorSlider; class ColorWheelSelector: public ColorSelector { -- cgit v1.2.3 From fe272ea3f531111c3ab361ca31ded84b1e7106df Mon Sep 17 00:00:00 2001 From: Tomasz Boczkowski Date: Fri, 23 May 2014 11:59:24 +0200 Subject: SPColorWheelSelector uses refactored ColorSlider class (bzr r13341.6.3) --- src/widgets/sp-color-wheel-selector.cpp | 92 ++++++++++++++------------------- src/widgets/sp-color-wheel-selector.h | 21 ++++++-- 2 files changed, 56 insertions(+), 57 deletions(-) (limited to 'src') diff --git a/src/widgets/sp-color-wheel-selector.cpp b/src/widgets/sp-color-wheel-selector.cpp index de2d030d4..0ef669aca 100644 --- a/src/widgets/sp-color-wheel-selector.cpp +++ b/src/widgets/sp-color-wheel-selector.cpp @@ -7,6 +7,7 @@ #include #include #include +#include #include "../dialogs/dialog-events.h" #include "sp-color-scales.h" #include "sp-color-icc-selector.h" @@ -160,28 +161,26 @@ void ColorWheelSelector::init() _adj = GTK_ADJUSTMENT(gtk_adjustment_new(0.0, 0.0, 255.0, 1.0, 10.0, 10.0)); /* Slider */ - _slider = sp_color_slider_new (_adj); - gtk_widget_set_tooltip_text (_slider, _("Alpha (opacity)")); - gtk_widget_show (_slider); + _slider = Gtk::manage(new Inkscape::UI::Widget::ColorSlider(Glib::wrap(_adj))); + _slider->set_tooltip_text(_("Alpha (opacity)")); + _slider->show(); #if GTK_CHECK_VERSION(3,0,0) - gtk_widget_set_margin_left(_slider, XPAD); - gtk_widget_set_margin_right(_slider, XPAD); - gtk_widget_set_margin_top(_slider, YPAD); - gtk_widget_set_margin_bottom(_slider, YPAD); - gtk_widget_set_hexpand(_slider, TRUE); - gtk_widget_set_halign(_slider, GTK_ALIGN_FILL); - gtk_widget_set_valign(_slider, GTK_ALIGN_FILL); - gtk_grid_attach(GTK_GRID(t), _slider, 1, row, 1, 1); + _slider->set_margin_left(XPAD); + _slider->set_margin_right(XPAD); + _slider->set_margin_top(YPAD); + _slider->set_margin_bottom(YPAD); + _slider->set_hexpand(true); + _slider->set_halign(Gtk::ALIGN_FILL); + _slider->set_valign(Gtk::ALIGN_FILL); + gtk_grid_attach(GTK_GRID(t), _slider->gobj(), 1, row, 1, 1); #else - gtk_table_attach(GTK_TABLE (t), _slider, 1, 2, row, row + 1, (GtkAttachOptions)(GTK_EXPAND | GTK_FILL), GTK_FILL, XPAD, YPAD); + gtk_table_attach(GTK_TABLE (t), _slider->gobj(), 1, 2, row, row + 1, (GtkAttachOptions)(GTK_EXPAND | GTK_FILL), GTK_FILL, XPAD, YPAD); #endif - sp_color_slider_set_colors (SP_COLOR_SLIDER (_slider), - SP_RGBA32_F_COMPOSE (1.0, 1.0, 1.0, 0.0), - SP_RGBA32_F_COMPOSE (1.0, 1.0, 1.0, 0.5), - SP_RGBA32_F_COMPOSE (1.0, 1.0, 1.0, 1.0)); - + _slider->set_colors(SP_RGBA32_F_COMPOSE (1.0, 1.0, 1.0, 0.0), + SP_RGBA32_F_COMPOSE (1.0, 1.0, 1.0, 0.5), + SP_RGBA32_F_COMPOSE (1.0, 1.0, 1.0, 1.0)); /* Spinbutton */ _sbtn = gtk_spin_button_new (GTK_ADJUSTMENT (_adj), 1.0, 0); @@ -206,12 +205,9 @@ void ColorWheelSelector::init() g_signal_connect (G_OBJECT (_adj), "value_changed", G_CALLBACK (_adjustmentChanged), _csel); - g_signal_connect (G_OBJECT (_slider), "grabbed", - G_CALLBACK (_sliderGrabbed), _csel); - g_signal_connect (G_OBJECT (_slider), "released", - G_CALLBACK (_sliderReleased), _csel); - g_signal_connect (G_OBJECT (_slider), "changed", - G_CALLBACK (_sliderChanged), _csel); + _slider->signal_grabbed.connect(sigc::mem_fun(*this, &ColorWheelSelector::_sliderGrabbed)); + _slider->signal_released.connect(sigc::mem_fun(*this, &ColorWheelSelector::_sliderReleased)); + _slider->signal_value_changed.connect(sigc::mem_fun(*this, &ColorWheelSelector::_sliderChanged)); g_signal_connect( G_OBJECT(_wheel), "changed", G_CALLBACK (_wheelChanged), _csel ); @@ -243,9 +239,8 @@ GtkWidget *sp_color_wheel_selector_new() /* Helpers for setting color value */ -static void preserve_icc(SPColor *color, SPColorWheelSelector *cs){ - ColorSelector* selector = static_cast(SP_COLOR_SELECTOR(cs)->base); - color->icc = selector->getColor().icc ? new SVGICCColor(*selector->getColor().icc) : 0; +void ColorWheelSelector::_preserve_icc(SPColor *color) const { + color->icc = getColor().icc ? new SVGICCColor(*getColor().icc) : 0; } void ColorWheelSelector::_colorChanged() @@ -264,7 +259,7 @@ void ColorWheelSelector::_colorChanged() guint32 mid = _color.toRGBA32( 0x7f ); guint32 end = _color.toRGBA32( 0xff ); - sp_color_slider_set_colors(SP_COLOR_SLIDER(_slider), start, mid, end); + _slider->set_colors(start, mid, end); ColorScales::setScaled(_adj, _alpha); @@ -287,45 +282,38 @@ void ColorWheelSelector::_adjustmentChanged( GtkAdjustment *adjustment, SPColorW wheelSelector->_updating = TRUE; - preserve_icc(&wheelSelector->_color, cs); + wheelSelector->_preserve_icc(&wheelSelector->_color); wheelSelector->_updateInternals( wheelSelector->_color, ColorScales::getScaled( wheelSelector->_adj ), wheelSelector->_dragging ); wheelSelector->_updating = FALSE; } -void ColorWheelSelector::_sliderGrabbed( SPColorSlider *slider, SPColorWheelSelector *cs ) +void ColorWheelSelector::_sliderGrabbed() { - (void)slider; - ColorWheelSelector* wheelSelector = static_cast(SP_COLOR_SELECTOR(cs)->base); - if (!wheelSelector->_dragging) { - wheelSelector->_dragging = TRUE; - wheelSelector->_grabbed(); + if (!_dragging) { + _dragging = TRUE; + _grabbed(); - preserve_icc(&wheelSelector->_color, cs); - wheelSelector->_updateInternals( wheelSelector->_color, ColorScales::getScaled( wheelSelector->_adj ), wheelSelector->_dragging ); + _preserve_icc(&_color); + _updateInternals( _color, ColorScales::getScaled( _adj ), _dragging ); } } -void ColorWheelSelector::_sliderReleased( SPColorSlider *slider, SPColorWheelSelector *cs ) +void ColorWheelSelector::_sliderReleased() { - (void)slider; - ColorWheelSelector* wheelSelector = static_cast(SP_COLOR_SELECTOR(cs)->base); - if (wheelSelector->_dragging) { - wheelSelector->_dragging = FALSE; - wheelSelector->_released(); + if (_dragging) { + _dragging = FALSE; + _released(); - preserve_icc(&wheelSelector->_color, cs); - wheelSelector->_updateInternals( wheelSelector->_color, ColorScales::getScaled( wheelSelector->_adj ), wheelSelector->_dragging ); + _preserve_icc(&_color); + _updateInternals( _color, ColorScales::getScaled( _adj ), _dragging ); } } -void ColorWheelSelector::_sliderChanged( SPColorSlider *slider, SPColorWheelSelector *cs ) +void ColorWheelSelector::_sliderChanged() { - (void)slider; - ColorWheelSelector* wheelSelector = static_cast(SP_COLOR_SELECTOR(cs)->base); - - preserve_icc(&wheelSelector->_color, cs); - wheelSelector->_updateInternals( wheelSelector->_color, ColorScales::getScaled( wheelSelector->_adj ), wheelSelector->_dragging ); + _preserve_icc(&_color); + _updateInternals( _color, ColorScales::getScaled( _adj ), _dragging ); } void ColorWheelSelector::_wheelChanged( GimpColorWheel *wheel, SPColorWheelSelector *cs ) @@ -346,9 +334,9 @@ void ColorWheelSelector::_wheelChanged( GimpColorWheel *wheel, SPColorWheelSelec guint32 mid = color.toRGBA32( 0x7f ); guint32 end = color.toRGBA32( 0xff ); - sp_color_slider_set_colors (SP_COLOR_SLIDER(wheelSelector->_slider), start, mid, end); + wheelSelector->_slider->set_colors(start, mid, end); - preserve_icc(&color, cs); + wheelSelector->_preserve_icc(&color); wheelSelector->_updateInternals( color, wheelSelector->_alpha, gimp_color_wheel_is_adjusting(wheel) ); } diff --git a/src/widgets/sp-color-wheel-selector.h b/src/widgets/sp-color-wheel-selector.h index b7b86438c..bb6078906 100644 --- a/src/widgets/sp-color-wheel-selector.h +++ b/src/widgets/sp-color-wheel-selector.h @@ -17,7 +17,16 @@ typedef struct _GimpColorWheel GimpColorWheel; struct SPColorWheelSelector; struct SPColorWheelSelectorClass; -struct SPColorSlider; + +namespace Inkscape { +namespace UI { +namespace Widget { + +class ColorSlider; + +} +} +} class ColorWheelSelector: public ColorSelector { @@ -32,9 +41,9 @@ protected: static void _adjustmentChanged ( GtkAdjustment *adjustment, SPColorWheelSelector *cs ); - static void _sliderGrabbed( SPColorSlider *slider, SPColorWheelSelector *cs ); - static void _sliderReleased( SPColorSlider *slider, SPColorWheelSelector *cs ); - static void _sliderChanged( SPColorSlider *slider, SPColorWheelSelector *cs ); + void _sliderGrabbed(); + void _sliderReleased(); + void _sliderChanged(); static void _wheelChanged( GimpColorWheel *wheel, SPColorWheelSelector *cs ); static void _fooChanged( GtkWidget foo, SPColorWheelSelector *cs ); @@ -45,7 +54,7 @@ protected: gboolean _dragging : 1; GtkAdjustment* _adj; // Channel adjustment GtkWidget* _wheel; - GtkWidget* _slider; + Inkscape::UI::Widget::ColorSlider* _slider; GtkWidget* _sbtn; // Spinbutton GtkWidget* _label; // Label @@ -53,6 +62,8 @@ private: // By default, disallow copy constructor and assignment operator ColorWheelSelector( const ColorWheelSelector& obj ); ColorWheelSelector& operator=( const ColorWheelSelector& obj ); + + void _preserve_icc(SPColor *color) const; }; -- cgit v1.2.3 From 07ce2371a81e1393032c2ce4e0c0373282df204b Mon Sep 17 00:00:00 2001 From: Tomasz Boczkowski Date: Fri, 23 May 2014 12:53:33 +0200 Subject: ported draw method (bzr r13341.6.4) --- src/ui/widget/color-slider.cpp | 173 +++++++++++++++++++++++++++++++++++++++-- 1 file changed, 167 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/ui/widget/color-slider.cpp b/src/ui/widget/color-slider.cpp index 430239f00..d927a7f67 100644 --- a/src/ui/widget/color-slider.cpp +++ b/src/ui/widget/color-slider.cpp @@ -29,6 +29,11 @@ static const gint SLIDER_WIDTH = 96; static const gint SLIDER_HEIGHT = 8; static const gint ARROW_SIZE = 7; +static const guchar *sp_color_slider_render_gradient (gint x0, gint y0, gint width, gint height, + gint c[], gint dc[], guint b0, guint b1, guint mask); +static const guchar *sp_color_slider_render_map (gint x0, gint y0, gint width, gint height, + guchar *map, gint start, gint step, guint b0, guint b1, guint mask); + namespace Inkscape { namespace UI { namespace Widget { @@ -165,8 +170,26 @@ void ColorSlider::set_adjustment(Gtk::Adjustment* /*adjustment*/) { //TODO: implementation } -void ColorSlider::set_colors(guint32 start, guint32 min, guint32 end) { +void ColorSlider::set_colors(guint32 start, guint32 mid, guint32 end) { + // Remove any map, if set + _map = 0; + + _c0[0] = start >> 24; + _c0[1] = (start >> 16) & 0xff; + _c0[2] = (start >> 8) & 0xff; + _c0[3] = start & 0xff; + _cm[0] = mid >> 24; + _cm[1] = (mid >> 16) & 0xff; + _cm[2] = (mid >> 8) & 0xff; + _cm[3] = mid & 0xff; + + _c1[0] = end >> 24; + _c1[1] = (end >> 16) & 0xff; + _c1[2] = (end >> 8) & 0xff; + _c1[3] = end & 0xff; + + queue_draw(); } void ColorSlider::set_map(const guchar *map) { @@ -178,6 +201,149 @@ void ColorSlider::set_background(guint dark, guint light, guint size) { } bool ColorSlider::on_draw(const Cairo::RefPtr& cr) { + gboolean colorsOnTop = Inkscape::Preferences::get()->getBool("/options/workarounds/colorsontop", false); + + Gtk::Allocation allocation = get_allocation(); + +#if GTK_CHECK_VERSION(3,0,0) + Glib::RefPtr context = get_style_context(); +#else + Glib::RefPtr window = get_window(); + Glib::RefPtr style = get_style(); +#endif + + // Draw shadow + if (colorsOnTop) { +#if GTK_CHECK_VERSION(3,0,0) + context->render_frame(cr, 0, 0, + allocation.get_width(), allocation.get_height()); +#else + style->paint_shadow(window, get_state(), Gtk::SHADOW_IN, + Gdk::Rectangle(), *this, "colorslider", + 0, 0, + allocation.get_width(), allocation.get_height()); +#endif + } + + /* Paintable part of color gradient area */ + Gdk::Rectangle carea; + +#if GTK_CHECK_VERSION(3,0,0) + Gtk::Border padding; + + padding = style_context->get_padding(get_state_flags()); + + carea.set_x(padding.get_left()); + carea.set_y(padding.get_top());; +#else + carea.set_x(style->get_xthickness()); + carea.set_y(style->get_ythickness()); +#endif + + carea.set_width(allocation.get_width() - 2 * carea.get_x()); + carea.set_height(allocation.get_height() - 2 * carea.get_y()); + + if (_map) { + /* Render map pixelstore */ + gint d = (1024 << 16) / carea.get_width(); + gint s = 0; + + const guchar *b = sp_color_slider_render_map(0, 0, carea.get_width(), carea.get_height(), + _map, s, d, + _b0, _b1, _bmask); + + if (b != NULL && carea.get_width() > 0) { + Glib::RefPtr pb = Gdk::Pixbuf::create_from_data(b, Gdk::COLORSPACE_RGB, + false, 8, carea.get_width(), carea.get_height(), carea.get_width() * 3); + + Gdk::Cairo::set_source_pixbuf(cr, pb, carea.get_x(), carea.get_y()); + cr->paint(); + } + + } else { + gint c[4], dc[4]; + + /* Render gradient */ + + // part 1: from c0 to cm + if (carea.get_width() > 0) { + for (gint i = 0; i < 4; i++) { + c[i] = _c0[i] << 16; + dc[i] = ((_cm[i] << 16) - c[i]) / (carea.get_width()/2); + } + guint wi = carea.get_width()/2; + const guchar *b = sp_color_slider_render_gradient(0, 0, wi, carea.get_height(), + c, dc, _b0, _b1, _bmask); + + /* Draw pixelstore 1 */ + if (b != NULL && wi > 0) { + Glib::RefPtr pb = Gdk::Pixbuf::create_from_data(b, Gdk::COLORSPACE_RGB, + false, 8, wi, carea.get_height(), carea.get_width() * 3); + + Gdk::Cairo::set_source_pixbuf(cr, pb, carea.get_x(), carea.get_y()); + cr->paint(); + } + } + + // part 2: from cm to c1 + if (carea.get_width() > 0) { + for (gint i = 0; i < 4; i++) { + c[i] = _cm[i] << 16; + dc[i] = ((_c1[i] << 16) - c[i]) / (carea.get_width()/2); + } + guint wi = carea.get_width()/2; + const guchar *b = sp_color_slider_render_gradient(carea.get_width()/2, 0, wi, carea.get_height(), + c, dc, + _b0, _b1, _bmask); + + /* Draw pixelstore 2 */ + if (b != NULL && wi > 0) { + Glib::RefPtr pb = Gdk::Pixbuf::create_from_data(b, Gdk::COLORSPACE_RGB, + false, 8, wi, carea.get_height(), carea.get_width() * 3); + + Gdk::Cairo::set_source_pixbuf(cr, pb, carea.get_width()/2 + carea.get_x(), carea.get_y()); + cr->paint(); + } + } + } + + /* Draw shadow */ + if (!colorsOnTop) { +#if GTK_CHECK_VERSION(3,0,0) + context->render_frame(cr, 0, 0, + allocation.get_width(), allocation.get_height()); +#else + style->paint_shadow(window, get_state(), Gtk::SHADOW_IN, + Gdk::Rectangle(), *this, "colorslider", + 0, 0, + allocation.get_width(), allocation.get_height()); +#endif + } + + /* Draw arrow */ + gint x = (int)(_value * (carea.get_width() - 1) - ARROW_SIZE / 2 + carea.get_x()); + gint y1 = carea.get_y(); + gint y2 = carea.get_y() + carea.get_height() - 1; + cr->set_line_width(1.0); + + // Define top arrow + cr->move_to(x - 0.5, y1 + 0.5); + cr->line_to(x + ARROW_SIZE - 0.5, y1 + 0.5); + cr->line_to(x + (ARROW_SIZE-1)/2.0, y1 + ARROW_SIZE/2.0 + 0.5); + cr->line_to(x - 0.5, y1 + 0.5); + + // Define bottom arrow + cr->move_to(x - 0.5, y2 + 0.5); + cr->line_to(x + ARROW_SIZE - 0.5, y2 + 0.5); + cr->line_to(x + (ARROW_SIZE-1)/2.0, y2 - ARROW_SIZE/2.0 + 0.5); + cr->line_to(x - 0.5, y2 + 0.5); + + // Render both arrows + cr->set_source_rgb(1.0, 1.0, 1.0); + cr->stroke_preserve(); + cr->set_source_rgb(0.0, 0.0, 0.0); + cr->fill(); + return false; } @@ -246,11 +412,6 @@ static gint sp_color_slider_motion_notify (GtkWidget *widget, GdkEventMotion *ev static void sp_color_slider_adjustment_changed (GtkAdjustment *adjustment, SPColorSlider *slider); static void sp_color_slider_adjustment_value_changed (GtkAdjustment *adjustment, SPColorSlider *slider); -static const guchar *sp_color_slider_render_gradient (gint x0, gint y0, gint width, gint height, - gint c[], gint dc[], guint b0, guint b1, guint mask); -static const guchar *sp_color_slider_render_map (gint x0, gint y0, gint width, gint height, - guchar *map, gint start, gint step, guint b0, guint b1, guint mask); - static GtkWidgetClass *parent_class; static guint slider_signals[LAST_SIGNAL] = {0}; -- cgit v1.2.3 From 837f710ed9947b30a77a990ae27beed10449f977 Mon Sep 17 00:00:00 2001 From: Tomasz Boczkowski Date: Sat, 24 May 2014 01:32:04 +0200 Subject: SPColorSlider c++-sification: ported drawing (bzr r13341.6.5) --- src/ui/widget/color-slider.cpp | 79 ++++++++++++++++++++++++++++++++++++++---- src/ui/widget/color-slider.h | 6 ++++ 2 files changed, 78 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/ui/widget/color-slider.cpp b/src/ui/widget/color-slider.cpp index d927a7f67..82eafdcf8 100644 --- a/src/ui/widget/color-slider.cpp +++ b/src/ui/widget/color-slider.cpp @@ -70,8 +70,9 @@ ColorSlider::ColorSlider(Gtk::Adjustment* adjustment) ColorSlider::~ColorSlider() { if (_adjustment) { - //TODO: disconnect all connections - delete _adjustment; + _adjustment_changed_connection.disconnect(); + _adjustment_value_changed_connection.disconnect(); + _adjustment->unreference(); _adjustment = NULL; } } @@ -134,6 +135,8 @@ void ColorSlider::on_size_request(Gtk::Requisition* requisition) { //TODO: GTK3 prefferred width/height void ColorSlider::on_size_allocate(Gtk::Allocation& allocation) { + set_allocation(allocation); + if (get_realized()) { _refGdkWindow->move_resize(allocation.get_x(), allocation.get_y(), allocation.get_width(), allocation.get_height()); @@ -166,8 +169,64 @@ bool ColorSlider::on_motion_notify_event(GdkEventMotion *event) { return false; } -void ColorSlider::set_adjustment(Gtk::Adjustment* /*adjustment*/) { - //TODO: implementation +void ColorSlider::set_adjustment(Gtk::Adjustment *adjustment) { + if (!adjustment) { + _adjustment = Gtk::manage(new Gtk::Adjustment(0.0, 0.0, 1.0, 0.01, 0.0, 0.0)); + } else { + adjustment->set_page_increment(0.0); + adjustment->set_page_size(0.0); + } + + if (_adjustment != adjustment) { + if (_adjustment) { + _adjustment_changed_connection.disconnect(); + _adjustment_value_changed_connection.disconnect(); + //if GTK2 + _adjustment->unreference(); + } + + _adjustment = adjustment; + _adjustment->reference(); + + _adjustment_changed_connection = _adjustment->signal_changed().connect( + sigc::mem_fun(this, &ColorSlider::on_adjustment_changed)); + _adjustment_value_changed_connection = _adjustment->signal_value_changed().connect( + sigc::mem_fun(this, &ColorSlider::on_adjustment_value_changed)); + + _value = ColorScales::getScaled(_adjustment->gobj()); + + on_adjustment_changed(); + } +} + +void ColorSlider::on_adjustment_changed() { + queue_draw(); +} + +void ColorSlider::on_adjustment_value_changed() { + if (_value != ColorScales::getScaled( _adjustment->gobj() )) { + gint cx, cy, cw, ch; + Glib::RefPtr style = get_style(); + Gtk::Allocation allocation = get_allocation(); + cx = style->get_xthickness(); + cy = style->get_ythickness(); + cw = allocation.get_width() - 2 * cx; + ch = allocation.get_height() - 2 * cy; + if ((gint) (ColorScales::getScaled( _adjustment->gobj() ) * cw) != (gint) (_value * cw)) { + gint ax, ay; + gfloat value; + value = _value; + _value = ColorScales::getScaled( _adjustment->gobj() ); + ax = (int)(cx + value * cw - ARROW_SIZE / 2 - 2); + ay = cy; + queue_draw_area(ax, ay, ARROW_SIZE + 4, ch); + ax = (int)(cx + _value * cw - ARROW_SIZE / 2 - 2); + ay = cy; + queue_draw_area(ax, ay, ARROW_SIZE + 4, ch); + } else { + _value = ColorScales::getScaled( _adjustment->gobj() ); + } + } } void ColorSlider::set_colors(guint32 start, guint32 mid, guint32 end) { @@ -193,11 +252,17 @@ void ColorSlider::set_colors(guint32 start, guint32 mid, guint32 end) { } void ColorSlider::set_map(const guchar *map) { + _map = const_cast(map); + queue_draw(); } void ColorSlider::set_background(guint dark, guint light, guint size) { + _b0 = dark; + _b1 = light; + _bmask = size; + queue_draw(); } bool ColorSlider::on_draw(const Cairo::RefPtr& cr) { @@ -278,7 +343,7 @@ bool ColorSlider::on_draw(const Cairo::RefPtr& cr) { /* Draw pixelstore 1 */ if (b != NULL && wi > 0) { Glib::RefPtr pb = Gdk::Pixbuf::create_from_data(b, Gdk::COLORSPACE_RGB, - false, 8, wi, carea.get_height(), carea.get_width() * 3); + false, 8, wi, carea.get_height(), wi * 3); Gdk::Cairo::set_source_pixbuf(cr, pb, carea.get_x(), carea.get_y()); cr->paint(); @@ -299,7 +364,7 @@ bool ColorSlider::on_draw(const Cairo::RefPtr& cr) { /* Draw pixelstore 2 */ if (b != NULL && wi > 0) { Glib::RefPtr pb = Gdk::Pixbuf::create_from_data(b, Gdk::COLORSPACE_RGB, - false, 8, wi, carea.get_height(), carea.get_width() * 3); + false, 8, wi, carea.get_height(), wi * 3); Gdk::Cairo::set_source_pixbuf(cr, pb, carea.get_width()/2 + carea.get_x(), carea.get_y()); cr->paint(); @@ -1012,7 +1077,7 @@ static gboolean sp_color_slider_draw(GtkWidget *widget, cairo_t *cr) cairo_stroke_preserve(cr); cairo_set_source_rgb(cr, 0.0, 0.0, 0.0); cairo_fill(cr); - + return FALSE; } diff --git a/src/ui/widget/color-slider.h b/src/ui/widget/color-slider.h index d8be7d111..7f3088772 100644 --- a/src/ui/widget/color-slider.h +++ b/src/ui/widget/color-slider.h @@ -36,6 +36,7 @@ public: ColorSlider(Gtk::Adjustment *adjustment); ~ColorSlider(); + //if GTK2 void set_adjustment(Gtk::Adjustment *adjustment); void set_colors(guint32 start, guint32 mid, guint32 end); @@ -70,9 +71,14 @@ protected: //TODO: on_adjustment value changed method + connection private: + void on_adjustment_changed(); + void on_adjustment_value_changed(); + bool _dragging; Gtk::Adjustment *_adjustment; + sigc::connection _adjustment_changed_connection; + sigc::connection _adjustment_value_changed_connection; gfloat _value; gfloat _oldvalue; -- cgit v1.2.3 From 84379bcbe7e5008ee24d0b1f465d2c55ff9529b7 Mon Sep 17 00:00:00 2001 From: Tomasz Boczkowski Date: Sat, 24 May 2014 14:42:58 +0200 Subject: SPColorSlider c++-sification: ported mouse events (bzr r13341.6.6) --- src/ui/widget/color-slider.cpp | 53 +++++++++++++++++++++++++++++++++++++++--- 1 file changed, 50 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/ui/widget/color-slider.cpp b/src/ui/widget/color-slider.cpp index 82eafdcf8..2c330e9ca 100644 --- a/src/ui/widget/color-slider.cpp +++ b/src/ui/widget/color-slider.cpp @@ -18,6 +18,7 @@ #include "color-slider.h" #include +#include #include #include #include @@ -155,17 +156,63 @@ bool ColorSlider::on_expose_event(GdkEventExpose* event) { } bool ColorSlider::on_button_press_event(GdkEventButton *event) { - //TODO: implementation + if (event->button == 1) { + Gtk::Allocation allocation = get_allocation(); + gint cx, cw; + cx = get_style()->get_xthickness(); + cw = allocation.get_width() - 2 * cx; + signal_grabbed.emit(); + _dragging = true; + _oldvalue = _value; + ColorScales::setScaled( _adjustment->gobj(), CLAMP ((gfloat) (event->x - cx) / cw, 0.0, 1.0) ); + signal_dragged.emit(); + +#if GTK_CHECK_VERSION(3,0,0) + gdk_device_grab(gdk_event_get_device(reinterpret_cast(event)), + _refGdkWindow->gobj(), + GDK_OWNERSHIP_NONE, + FALSE, + static_cast(GDK_POINTER_MOTION_MASK | GDK_BUTTON_RELEASE_MASK), + NULL, + event->time); +#else + get_window()->pointer_grab(false, Gdk::POINTER_MOTION_MASK | Gdk::BUTTON_RELEASE_MASK, Gdk::Cursor(), event->time); +#endif + } + return false; } bool ColorSlider::on_button_release_event(GdkEventButton *event) { - //TODO: implementation + if (event->button == 1) { + +#if GTK_CHECK_VERSION(3,0,0) + gdk_device_ungrab(gdk_event_get_device(reinterpret_cast(event)), + gdk_event_get_time(reinterpret_cast(event))); +#else + get_window()->pointer_ungrab(event->time); +#endif + + _dragging = false; + signal_released.emit(); + if (_value != _oldvalue) { + signal_value_changed.emit(); + } + } + return false; } bool ColorSlider::on_motion_notify_event(GdkEventMotion *event) { - //TODO: implementation + if (_dragging) { + gint cx, cw; + Gtk::Allocation allocation = get_allocation(); + cx = get_style()->get_xthickness(); + cw = allocation.get_width() - 2 * cx; + ColorScales::setScaled( _adjustment->gobj(), CLAMP ((gfloat) (event->x - cx) / cw, 0.0, 1.0) ); + signal_dragged.emit(); + } + return false; } -- cgit v1.2.3 From a87f50a6174b65b8db1d0a091d30a5de206f03df Mon Sep 17 00:00:00 2001 From: Tomasz Boczkowski Date: Sat, 24 May 2014 15:07:28 +0200 Subject: SPColorSlider c++-sification: fixed drawing border (bzr r13341.6.7) --- src/ui/widget/color-slider.cpp | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/src/ui/widget/color-slider.cpp b/src/ui/widget/color-slider.cpp index 2c330e9ca..31ae5fbdf 100644 --- a/src/ui/widget/color-slider.cpp +++ b/src/ui/widget/color-slider.cpp @@ -330,10 +330,11 @@ bool ColorSlider::on_draw(const Cairo::RefPtr& cr) { context->render_frame(cr, 0, 0, allocation.get_width(), allocation.get_height()); #else - style->paint_shadow(window, get_state(), Gtk::SHADOW_IN, - Gdk::Rectangle(), *this, "colorslider", - 0, 0, - allocation.get_width(), allocation.get_height()); + gtk_paint_shadow( style->gobj(), window->gobj(), + gtk_widget_get_state(gobj()), GTK_SHADOW_IN, + NULL, gobj(), "colorslider", + 0, 0, + allocation.get_width(), allocation.get_height()); #endif } @@ -425,10 +426,11 @@ bool ColorSlider::on_draw(const Cairo::RefPtr& cr) { context->render_frame(cr, 0, 0, allocation.get_width(), allocation.get_height()); #else - style->paint_shadow(window, get_state(), Gtk::SHADOW_IN, - Gdk::Rectangle(), *this, "colorslider", - 0, 0, - allocation.get_width(), allocation.get_height()); + gtk_paint_shadow( style->gobj(), window->gobj(), + gtk_widget_get_state(gobj()), GTK_SHADOW_IN, + NULL, gobj(), "colorslider", + 0, 0, + allocation.get_width(), allocation.get_height()); #endif } -- cgit v1.2.3 From c77abbc4c33e15c742b477a178e90816f4ab3d67 Mon Sep 17 00:00:00 2001 From: Tomasz Boczkowski Date: Sat, 24 May 2014 15:16:37 +0200 Subject: SPColorSlider c++-sification: fixed failed Gtk assertion (bzr r13341.6.8) --- src/ui/widget/color-slider.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/ui/widget/color-slider.cpp b/src/ui/widget/color-slider.cpp index 31ae5fbdf..b28393be0 100644 --- a/src/ui/widget/color-slider.cpp +++ b/src/ui/widget/color-slider.cpp @@ -176,7 +176,9 @@ bool ColorSlider::on_button_press_event(GdkEventButton *event) { NULL, event->time); #else - get_window()->pointer_grab(false, Gdk::POINTER_MOTION_MASK | Gdk::BUTTON_RELEASE_MASK, Gdk::Cursor(), event->time); + gdk_pointer_grab(get_window()->gobj(), FALSE, + static_cast(GDK_POINTER_MOTION_MASK | GDK_BUTTON_RELEASE_MASK), + NULL, NULL, event->time); #endif } -- cgit v1.2.3 From 0d4b01e5ed7dd47bc2f1664845803de87ebb2b01 Mon Sep 17 00:00:00 2001 From: Tomasz Boczkowski Date: Sat, 24 May 2014 16:40:56 +0200 Subject: SPColorSlider c++-sification: compilation with GTK3 (bzr r13341.6.9) --- src/ui/widget/color-slider.cpp | 99 ++++++++++++++++++++++++++++++++++-------- src/ui/widget/color-slider.h | 33 ++++++++------ 2 files changed, 100 insertions(+), 32 deletions(-) (limited to 'src') diff --git a/src/ui/widget/color-slider.cpp b/src/ui/widget/color-slider.cpp index b28393be0..450dcd6f6 100644 --- a/src/ui/widget/color-slider.cpp +++ b/src/ui/widget/color-slider.cpp @@ -22,6 +22,11 @@ #include #include #include +#if GTK_CHECK_VERSION(3,0,0) +#include +#else +#include +#endif #include "widgets/sp-color-scales.h" #include "preferences.h" @@ -39,9 +44,14 @@ namespace Inkscape { namespace UI { namespace Widget { +#if GTK_CHECK_VERSION(3,0,0) +ColorSlider::ColorSlider(Glib::RefPtr adjustment) + : _dragging(false) +#else ColorSlider::ColorSlider(Gtk::Adjustment* adjustment) : _dragging(false) , _adjustment(NULL) +#endif , _value(0.0) , _oldvalue(0.0) , _mapsize(0) @@ -73,8 +83,12 @@ ColorSlider::~ColorSlider() { if (_adjustment) { _adjustment_changed_connection.disconnect(); _adjustment_value_changed_connection.disconnect(); +#if GTK_CHECK_VERSION(3,0,0) + _adjustment.reset(); +#else _adjustment->unreference(); _adjustment = NULL; +#endif } } @@ -117,7 +131,9 @@ void ColorSlider::on_realize() { set_window(_refGdkWindow); _refGdkWindow->set_user_data(gobj()); +#if !GTK_CHECK_VERSION(3,0,0) style_attach(); +#endif } } @@ -127,14 +143,6 @@ void ColorSlider::on_unrealize() { Gtk::Widget::on_unrealize(); } -void ColorSlider::on_size_request(Gtk::Requisition* requisition) { - GtkStyle *style = gtk_widget_get_style(gobj()); - requisition->width = SLIDER_WIDTH + style->xthickness * 2; - requisition->height = SLIDER_HEIGHT + style->ythickness * 2; -} - -//TODO: GTK3 prefferred width/height - void ColorSlider::on_size_allocate(Gtk::Allocation& allocation) { set_allocation(allocation); @@ -144,7 +152,32 @@ void ColorSlider::on_size_allocate(Gtk::Allocation& allocation) { } } -//TODO: if not GTK3 +#if GTK_CHECK_VERSION(3,0,0) + +void ColorSlider::get_preferred_width_vfunc(int& minimum_width, int& natural_width) const +{ + Glib::RefPtrstyle_context = get_style_context(); + Gtk::Border padding = style_context->get_padding(get_state_flags()); + int width = SLIDER_WIDTH + padding.get_left() + padding.get_right(); + minimum_width = natural_width = width; + +} + +void ColorSlider::get_preferred_height_vfunc(int& minimum_height, int& natural_height) const +{ + Glib::RefPtrstyle_context = get_style_context(); + Gtk::Border padding = style_context->get_padding(get_state_flags()); + int height = SLIDER_WIDTH + padding.get_top() + padding.get_bottom(); + minimum_height = natural_height = height; +} +#else + +void ColorSlider::on_size_request(Gtk::Requisition* requisition) { + GtkStyle *style = gtk_widget_get_style(gobj()); + requisition->width = SLIDER_WIDTH + style->xthickness * 2; + requisition->height = SLIDER_HEIGHT + style->ythickness * 2; +} + bool ColorSlider::on_expose_event(GdkEventExpose* event) { bool result = false; @@ -155,11 +188,17 @@ bool ColorSlider::on_expose_event(GdkEventExpose* event) { return result; } +#endif + bool ColorSlider::on_button_press_event(GdkEventButton *event) { if (event->button == 1) { Gtk::Allocation allocation = get_allocation(); gint cx, cw; +#if GTK_CHECK_VERSION(3,0,0) + cx = get_style_context()->get_padding(get_state_flags()).get_left(); +#else cx = get_style()->get_xthickness(); +#endif cw = allocation.get_width() - 2 * cx; signal_grabbed.emit(); _dragging = true; @@ -209,7 +248,11 @@ bool ColorSlider::on_motion_notify_event(GdkEventMotion *event) { if (_dragging) { gint cx, cw; Gtk::Allocation allocation = get_allocation(); +#if GTK_CHECK_VERSION(3,0,0) + cx = get_style_context()->get_padding(get_state_flags()).get_left(); +#else cx = get_style()->get_xthickness(); +#endif cw = allocation.get_width() - 2 * cx; ColorScales::setScaled( _adjustment->gobj(), CLAMP ((gfloat) (event->x - cx) / cw, 0.0, 1.0) ); signal_dragged.emit(); @@ -218,9 +261,17 @@ bool ColorSlider::on_motion_notify_event(GdkEventMotion *event) { return false; } +#if GTK_CHECK_VERSION(3,0,0) +void ColorSlider::set_adjustment(Glib::RefPtr adjustment) { +#else void ColorSlider::set_adjustment(Gtk::Adjustment *adjustment) { +#endif if (!adjustment) { +#if GTK_CHECK_VERSION(3,0,0) + _adjustment = Gtk::Adjustment::create(0.0, 0.0, 1.0, 0.01, 0.0, 0.0); +#else _adjustment = Gtk::manage(new Gtk::Adjustment(0.0, 0.0, 1.0, 0.01, 0.0, 0.0)); +#endif } else { adjustment->set_page_increment(0.0); adjustment->set_page_size(0.0); @@ -230,35 +281,45 @@ void ColorSlider::set_adjustment(Gtk::Adjustment *adjustment) { if (_adjustment) { _adjustment_changed_connection.disconnect(); _adjustment_value_changed_connection.disconnect(); - //if GTK2 +#if !GTK_CHECK_VERSION(3,0,0) _adjustment->unreference(); +#endif } _adjustment = adjustment; +#if !GTK_CHECK_VERSION(3,0,0) _adjustment->reference(); - +#endif _adjustment_changed_connection = _adjustment->signal_changed().connect( - sigc::mem_fun(this, &ColorSlider::on_adjustment_changed)); + sigc::mem_fun(this, &ColorSlider::_on_adjustment_changed)); _adjustment_value_changed_connection = _adjustment->signal_value_changed().connect( - sigc::mem_fun(this, &ColorSlider::on_adjustment_value_changed)); + sigc::mem_fun(this, &ColorSlider::_on_adjustment_value_changed)); _value = ColorScales::getScaled(_adjustment->gobj()); - on_adjustment_changed(); + _on_adjustment_changed(); } } -void ColorSlider::on_adjustment_changed() { +void ColorSlider::_on_adjustment_changed() { queue_draw(); } -void ColorSlider::on_adjustment_value_changed() { +void ColorSlider::_on_adjustment_value_changed() { if (_value != ColorScales::getScaled( _adjustment->gobj() )) { gint cx, cy, cw, ch; +#if GTK_CHECK_VERSION(3,0,0) + Glib::RefPtrstyle_context = get_style_context(); + Gtk::Allocation allocation = get_allocation(); + Gtk::Border padding = style_context->get_padding(get_state_flags()); + cx = padding.get_left(); + cy = padding.get_top(); +#else Glib::RefPtr style = get_style(); Gtk::Allocation allocation = get_allocation(); cx = style->get_xthickness(); cy = style->get_ythickness(); +#endif cw = allocation.get_width() - 2 * cx; ch = allocation.get_height() - 2 * cy; if ((gint) (ColorScales::getScaled( _adjustment->gobj() ) * cw) != (gint) (_value * cw)) { @@ -320,7 +381,7 @@ bool ColorSlider::on_draw(const Cairo::RefPtr& cr) { Gtk::Allocation allocation = get_allocation(); #if GTK_CHECK_VERSION(3,0,0) - Glib::RefPtr context = get_style_context(); + Glib::RefPtr style_context = get_style_context(); #else Glib::RefPtr window = get_window(); Glib::RefPtr style = get_style(); @@ -329,7 +390,7 @@ bool ColorSlider::on_draw(const Cairo::RefPtr& cr) { // Draw shadow if (colorsOnTop) { #if GTK_CHECK_VERSION(3,0,0) - context->render_frame(cr, 0, 0, + style_context->render_frame(cr, 0, 0, allocation.get_width(), allocation.get_height()); #else gtk_paint_shadow( style->gobj(), window->gobj(), @@ -425,7 +486,7 @@ bool ColorSlider::on_draw(const Cairo::RefPtr& cr) { /* Draw shadow */ if (!colorsOnTop) { #if GTK_CHECK_VERSION(3,0,0) - context->render_frame(cr, 0, 0, + style_context->render_frame(cr, 0, 0, allocation.get_width(), allocation.get_height()); #else gtk_paint_shadow( style->gobj(), window->gobj(), diff --git a/src/ui/widget/color-slider.h b/src/ui/widget/color-slider.h index 7f3088772..c6d843fe5 100644 --- a/src/ui/widget/color-slider.h +++ b/src/ui/widget/color-slider.h @@ -32,12 +32,18 @@ namespace Widget */ class ColorSlider: public Gtk::Widget { public: - //if GTK2 +#if GTK_CHECK_VERSION(3,0,0) + ColorSlider(Glib::RefPtr adjustment); +#else ColorSlider(Gtk::Adjustment *adjustment); +#endif ~ColorSlider(); - //if GTK2 +#if GTK_CHECK_VERSION(3,0,0) + void set_adjustment(Glib::RefPtr adjustment); +#else void set_adjustment(Gtk::Adjustment *adjustment); +#endif void set_colors(guint32 start, guint32 mid, guint32 end); @@ -57,26 +63,27 @@ protected: bool on_button_press_event(GdkEventButton *event); bool on_button_release_event(GdkEventButton *event); bool on_motion_notify_event(GdkEventMotion *event); + bool on_draw(const Cairo::RefPtr& cr); - //if GTK2 +#if GTK_CHECK_VERSION(3,0,0) + void get_preferred_width_vfunc(int& minimum_width, int& natural_width) const; + void get_preferred_height_vfunc(int& minimum_height, int& natural_height) const; +#else void on_size_request(Gtk::Requisition* requisition); bool on_expose_event(GdkEventExpose* event); - //if GTK3 - //request mode, get preffered width/height vfunc - //endif - - bool on_draw(const Cairo::RefPtr& cr); - - //TODO: on_adjustment_changed method - //TODO: on_adjustment value changed method + connection +#endif private: - void on_adjustment_changed(); - void on_adjustment_value_changed(); + void _on_adjustment_changed(); + void _on_adjustment_value_changed(); bool _dragging; +#if GTK_CHECK_VERSION(3,0,0) + Glib::RefPtr _adjustment; +#else Gtk::Adjustment *_adjustment; +#endif sigc::connection _adjustment_changed_connection; sigc::connection _adjustment_value_changed_connection; -- cgit v1.2.3 From c28cce00312a421bea39c4d78360e3939c573de3 Mon Sep 17 00:00:00 2001 From: Tomasz Boczkowski Date: Sat, 24 May 2014 19:14:18 +0200 Subject: SPColorSlider c++-sification: fixed size request (bzr r13341.6.10) --- src/ui/widget/color-slider.cpp | 12 +++++++++++- src/ui/widget/color-slider.h | 2 ++ 2 files changed, 13 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/ui/widget/color-slider.cpp b/src/ui/widget/color-slider.cpp index 450dcd6f6..ff69e6ed5 100644 --- a/src/ui/widget/color-slider.cpp +++ b/src/ui/widget/color-slider.cpp @@ -160,16 +160,26 @@ void ColorSlider::get_preferred_width_vfunc(int& minimum_width, int& natural_wid Gtk::Border padding = style_context->get_padding(get_state_flags()); int width = SLIDER_WIDTH + padding.get_left() + padding.get_right(); minimum_width = natural_width = width; +} +void ColorSlider::get_preferred_width_for_height_vfunc(int /*height*/, int& minimum_width, int& natural_width) const +{ + get_preferred_width(minimum_width, natural_width); } void ColorSlider::get_preferred_height_vfunc(int& minimum_height, int& natural_height) const { Glib::RefPtrstyle_context = get_style_context(); Gtk::Border padding = style_context->get_padding(get_state_flags()); - int height = SLIDER_WIDTH + padding.get_top() + padding.get_bottom(); + int height = SLIDER_HEIGHT + padding.get_top() + padding.get_bottom(); minimum_height = natural_height = height; } + +void ColorSlider::get_preferred_height_for_width_vfunc(int /*width*/, int& minimum_height, int& natural_height) const +{ + get_preferred_height(minimum_height, natural_height); +} + #else void ColorSlider::on_size_request(Gtk::Requisition* requisition) { diff --git a/src/ui/widget/color-slider.h b/src/ui/widget/color-slider.h index c6d843fe5..eb4cd99c3 100644 --- a/src/ui/widget/color-slider.h +++ b/src/ui/widget/color-slider.h @@ -67,7 +67,9 @@ protected: #if GTK_CHECK_VERSION(3,0,0) void get_preferred_width_vfunc(int& minimum_width, int& natural_width) const; + void get_preferred_width_for_height_vfunc(int height, int& minimum_width, int& natural_width) const; void get_preferred_height_vfunc(int& minimum_height, int& natural_height) const; + void get_preferred_height_for_width_vfunc(int width, int& minimum_height, int& natural_height) const; #else void on_size_request(Gtk::Requisition* requisition); bool on_expose_event(GdkEventExpose* event); -- cgit v1.2.3 From 15db1bacac6f25cef94f92bb4aa0fc96a02b4113 Mon Sep 17 00:00:00 2001 From: Tomasz Boczkowski Date: Sat, 24 May 2014 19:20:57 +0200 Subject: SPColorSlider c++-sification: fixed crash at exit (bzr r13341.6.11) --- src/widgets/sp-color-wheel-selector.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/widgets/sp-color-wheel-selector.cpp b/src/widgets/sp-color-wheel-selector.cpp index 0ef669aca..2100f555c 100644 --- a/src/widgets/sp-color-wheel-selector.cpp +++ b/src/widgets/sp-color-wheel-selector.cpp @@ -161,7 +161,7 @@ void ColorWheelSelector::init() _adj = GTK_ADJUSTMENT(gtk_adjustment_new(0.0, 0.0, 255.0, 1.0, 10.0, 10.0)); /* Slider */ - _slider = Gtk::manage(new Inkscape::UI::Widget::ColorSlider(Glib::wrap(_adj))); + _slider = Gtk::manage(new Inkscape::UI::Widget::ColorSlider(Glib::wrap(_adj, true))); _slider->set_tooltip_text(_("Alpha (opacity)")); _slider->show(); -- cgit v1.2.3 From 38b4b1f4d34eb3e67c770bd833629e92b336155a Mon Sep 17 00:00:00 2001 From: Tomasz Boczkowski Date: Sat, 24 May 2014 19:59:29 +0200 Subject: SPColorSlider c++-sification: use in sp-color-scales (bzr r13341.6.12) --- src/widgets/sp-color-scales.cpp | 182 ++++++++++++++++++---------------------- src/widgets/sp-color-scales.h | 18 ++-- 2 files changed, 94 insertions(+), 106 deletions(-) (limited to 'src') diff --git a/src/widgets/sp-color-scales.cpp b/src/widgets/sp-color-scales.cpp index 7d5874506..94950e937 100644 --- a/src/widgets/sp-color-scales.cpp +++ b/src/widgets/sp-color-scales.cpp @@ -11,6 +11,8 @@ #include #include #include +#include + #include "../dialogs/dialog-events.h" #include "svg/svg-icc-color.h" #include "ui/widget/color-slider.h" @@ -166,18 +168,18 @@ void ColorScales::init() /* Adjustment */ _a[i] = GTK_ADJUSTMENT(gtk_adjustment_new(0.0, 0.0, _rangeLimit, 1.0, 10.0, 10.0)); /* Slider */ - _s[i] = sp_color_slider_new (_a[i]); - gtk_widget_show (_s[i]); + _s[i] = Gtk::manage(new Inkscape::UI::Widget::ColorSlider(Glib::wrap(_a[i], true))); + _s[i]->show(); #if GTK_CHECK_VERSION(3,0,0) - gtk_widget_set_margin_left(_s[i], XPAD); - gtk_widget_set_margin_right(_s[i], XPAD); - gtk_widget_set_margin_top(_s[i], YPAD); - gtk_widget_set_margin_bottom(_s[i], YPAD); - gtk_widget_set_hexpand(_s[i], TRUE); - gtk_grid_attach(GTK_GRID(t), _s[i], 1, i, 1, 1); + _s[i]->set_margin_left(XPAD); + _s[i]->set_margin_right(XPAD); + _s[i]->set_margin_top(YPAD); + _s[i]->set_margin_bottom(YPAD); + _s[i]->set_hexpand(true); + gtk_grid_attach(GTK_GRID(t), _s[i]->gobj(), 1, i, 1, 1); #else - gtk_table_attach (GTK_TABLE (t), _s[i], 1, 2, i, i + 1, (GtkAttachOptions)(GTK_EXPAND | GTK_FILL), GTK_FILL, XPAD, YPAD); + gtk_table_attach (GTK_TABLE (t), _s[i]->gobj(), 1, 2, i, i + 1, (GtkAttachOptions)(GTK_EXPAND | GTK_FILL), GTK_FILL, XPAD, YPAD); #endif /* Spinbutton */ @@ -203,12 +205,9 @@ void ColorScales::init() /* Signals */ g_signal_connect (G_OBJECT (_a[i]), "value_changed", G_CALLBACK (_adjustmentAnyChanged), _csel); - g_signal_connect (G_OBJECT (_s[i]), "grabbed", - G_CALLBACK (_sliderAnyGrabbed), _csel); - g_signal_connect (G_OBJECT (_s[i]), "released", - G_CALLBACK (_sliderAnyReleased), _csel); - g_signal_connect (G_OBJECT (_s[i]), "changed", - G_CALLBACK (_sliderAnyChanged), _csel); + _s[i]->signal_grabbed.connect(sigc::mem_fun(this, &ColorScales::_sliderAnyGrabbed)); + _s[i]->signal_released.connect(sigc::mem_fun(this, &ColorScales::_sliderAnyReleased)); + _s[i]->signal_value_changed.connect(sigc::mem_fun(this, &ColorScales::_sliderAnyChanged)); } /* Initial mode is none, so it works */ @@ -429,20 +428,20 @@ void ColorScales::setMode(SPColorScalesMode mode) case SP_COLOR_SCALES_MODE_RGB: _setRangeLimit(255.0); gtk_label_set_markup_with_mnemonic (GTK_LABEL (_l[0]), _("_R:")); - gtk_widget_set_tooltip_text (_s[0], _("Red")); + _s[0]->set_tooltip_text(_("Red")); gtk_widget_set_tooltip_text (_b[0], _("Red")); gtk_label_set_markup_with_mnemonic (GTK_LABEL (_l[1]), _("_G:")); - gtk_widget_set_tooltip_text (_s[1], _("Green")); + _s[1]->set_tooltip_text(_("Green")); gtk_widget_set_tooltip_text (_b[1], _("Green")); gtk_label_set_markup_with_mnemonic (GTK_LABEL (_l[2]), _("_B:")); - gtk_widget_set_tooltip_text (_s[2], _("Blue")); + _s[2]->set_tooltip_text(_("Blue")); gtk_widget_set_tooltip_text (_b[2], _("Blue")); gtk_label_set_markup_with_mnemonic (GTK_LABEL (_l[3]), _("_A:")); - gtk_widget_set_tooltip_text (_s[3], _("Alpha (opacity)")); + _s[3]->set_tooltip_text(_("Alpha (opacity)")); gtk_widget_set_tooltip_text (_b[3], _("Alpha (opacity)")); - sp_color_slider_set_map (SP_COLOR_SLIDER (_s[0]), NULL); + _s[0]->set_map(NULL); gtk_widget_hide (_l[4]); - gtk_widget_hide (_s[4]); + _s[4]->hide(); gtk_widget_hide (_b[4]); _updating = TRUE; setScaled( _a[0], rgba[0] ); @@ -455,20 +454,20 @@ void ColorScales::setMode(SPColorScalesMode mode) case SP_COLOR_SCALES_MODE_HSV: _setRangeLimit(255.0); gtk_label_set_markup_with_mnemonic (GTK_LABEL (_l[0]), _("_H:")); - gtk_widget_set_tooltip_text (_s[0], _("Hue")); + _s[0]->set_tooltip_text(_("Hue")); gtk_widget_set_tooltip_text (_b[0], _("Hue")); gtk_label_set_markup_with_mnemonic (GTK_LABEL (_l[1]), _("_S:")); - gtk_widget_set_tooltip_text (_s[1], _("Saturation")); + _s[1]->set_tooltip_text(_("Saturation")); gtk_widget_set_tooltip_text (_b[1], _("Saturation")); gtk_label_set_markup_with_mnemonic (GTK_LABEL (_l[2]), _("_L:")); - gtk_widget_set_tooltip_text (_s[2], _("Lightness")); + _s[2]->set_tooltip_text(_("Lightness")); gtk_widget_set_tooltip_text (_b[2], _("Lightness")); gtk_label_set_markup_with_mnemonic (GTK_LABEL (_l[3]), _("_A:")); - gtk_widget_set_tooltip_text (_s[3], _("Alpha (opacity)")); + _s[3]->set_tooltip_text(_("Alpha (opacity)")); gtk_widget_set_tooltip_text (_b[3], _("Alpha (opacity)")); - sp_color_slider_set_map (SP_COLOR_SLIDER (_s[0]), (guchar *)(sp_color_scales_hue_map())); + _s[0]->set_map((guchar *)(sp_color_scales_hue_map())); gtk_widget_hide (_l[4]); - gtk_widget_hide (_s[4]); + _s[4]->hide(); gtk_widget_hide (_b[4]); _updating = TRUE; c[0] = 0.0; @@ -483,23 +482,23 @@ void ColorScales::setMode(SPColorScalesMode mode) case SP_COLOR_SCALES_MODE_CMYK: _setRangeLimit(100.0); gtk_label_set_markup_with_mnemonic (GTK_LABEL (_l[0]), _("_C:")); - gtk_widget_set_tooltip_text (_s[0], _("Cyan")); + _s[0]->set_tooltip_text(_("Cyan")); gtk_widget_set_tooltip_text (_b[0], _("Cyan")); gtk_label_set_markup_with_mnemonic (GTK_LABEL (_l[1]), _("_M:")); - gtk_widget_set_tooltip_text (_s[1], _("Magenta")); + _s[1]->set_tooltip_text(_("Magenta")); gtk_widget_set_tooltip_text (_b[1], _("Magenta")); gtk_label_set_markup_with_mnemonic (GTK_LABEL (_l[2]), _("_Y:")); - gtk_widget_set_tooltip_text (_s[2], _("Yellow")); + _s[2]->set_tooltip_text(_("Yellow")); gtk_widget_set_tooltip_text (_b[2], _("Yellow")); gtk_label_set_markup_with_mnemonic (GTK_LABEL (_l[3]), _("_K:")); - gtk_widget_set_tooltip_text (_s[3], _("Black")); + _s[3]->set_tooltip_text(_("Black")); gtk_widget_set_tooltip_text (_b[3], _("Black")); gtk_label_set_markup_with_mnemonic (GTK_LABEL (_l[4]), _("_A:")); - gtk_widget_set_tooltip_text (_s[4], _("Alpha (opacity)")); + _s[4]->set_tooltip_text(_("Alpha (opacity)")); gtk_widget_set_tooltip_text (_b[4], _("Alpha (opacity)")); - sp_color_slider_set_map (SP_COLOR_SLIDER (_s[0]), NULL); + _s[0]->set_map(NULL); gtk_widget_show (_l[4]); - gtk_widget_show (_s[4]); + _s[4]->show(); gtk_widget_show (_b[4]); _updating = TRUE; @@ -572,34 +571,27 @@ void ColorScales::_adjustmentAnyChanged( GtkAdjustment *adjustment, SPColorScale _adjustmentChanged(cs, channel); } -void ColorScales::_sliderAnyGrabbed( SPColorSlider *slider, SPColorScales *cs ) +void ColorScales::_sliderAnyGrabbed() { - (void)slider; - ColorScales* scales = static_cast(SP_COLOR_SELECTOR(cs)->base); - if (!scales->_dragging) { - scales->_dragging = TRUE; - scales->_grabbed(); - scales->_recalcColor( FALSE ); + if (!_dragging) { + _dragging = TRUE; + _grabbed(); + _recalcColor( FALSE ); } } -void ColorScales::_sliderAnyReleased( SPColorSlider *slider, SPColorScales *cs ) +void ColorScales::_sliderAnyReleased() { - (void)slider; - ColorScales* scales = static_cast(SP_COLOR_SELECTOR(cs)->base); - if (scales->_dragging) { - scales->_dragging = FALSE; - scales->_released(); - scales->_recalcColor( FALSE ); + if (_dragging) { + _dragging = FALSE; + _released(); + _recalcColor( FALSE ); } } -void ColorScales::_sliderAnyChanged( SPColorSlider *slider, SPColorScales *cs ) +void ColorScales::_sliderAnyChanged() { - (void)slider; - ColorScales* scales = static_cast(SP_COLOR_SELECTOR(cs)->base); - - scales->_recalcColor( TRUE ); + _recalcColor( TRUE ); } void ColorScales::_adjustmentChanged( SPColorScales *cs, guint channel ) @@ -626,31 +618,27 @@ void ColorScales::_updateSliders( guint channels ) case SP_COLOR_SCALES_MODE_RGB: if ((channels != CSC_CHANNEL_R) && (channels != CSC_CHANNEL_A)) { /* Update red */ - sp_color_slider_set_colors (SP_COLOR_SLIDER (_s[0]), - SP_RGBA32_F_COMPOSE (0.0, getScaled(_a[1]), getScaled(_a[2]), 1.0), - SP_RGBA32_F_COMPOSE (0.5, getScaled(_a[1]), getScaled(_a[2]), 1.0), - SP_RGBA32_F_COMPOSE (1.0, getScaled(_a[1]), getScaled(_a[2]), 1.0)); + _s[0]->set_colors(SP_RGBA32_F_COMPOSE (0.0, getScaled(_a[1]), getScaled(_a[2]), 1.0), + SP_RGBA32_F_COMPOSE (0.5, getScaled(_a[1]), getScaled(_a[2]), 1.0), + SP_RGBA32_F_COMPOSE (1.0, getScaled(_a[1]), getScaled(_a[2]), 1.0)); } if ((channels != CSC_CHANNEL_G) && (channels != CSC_CHANNEL_A)) { /* Update green */ - sp_color_slider_set_colors (SP_COLOR_SLIDER (_s[1]), - SP_RGBA32_F_COMPOSE (getScaled(_a[0]), 0.0, getScaled(_a[2]), 1.0), - SP_RGBA32_F_COMPOSE (getScaled(_a[0]), 0.5, getScaled(_a[2]), 1.0), - SP_RGBA32_F_COMPOSE (getScaled(_a[0]), 1.0, getScaled(_a[2]), 1.0)); + _s[1]->set_colors(SP_RGBA32_F_COMPOSE(getScaled(_a[0]), 0.0, getScaled(_a[2]), 1.0), + SP_RGBA32_F_COMPOSE(getScaled(_a[0]), 0.5, getScaled(_a[2]), 1.0), + SP_RGBA32_F_COMPOSE(getScaled(_a[0]), 1.0, getScaled(_a[2]), 1.0)); } if ((channels != CSC_CHANNEL_B) && (channels != CSC_CHANNEL_A)) { /* Update blue */ - sp_color_slider_set_colors (SP_COLOR_SLIDER (_s[2]), - SP_RGBA32_F_COMPOSE (getScaled(_a[0]), getScaled(_a[1]), 0.0, 1.0), - SP_RGBA32_F_COMPOSE (getScaled(_a[0]), getScaled(_a[1]), 0.5, 1.0), - SP_RGBA32_F_COMPOSE (getScaled(_a[0]), getScaled(_a[1]), 1.0, 1.0)); + _s[2]->set_colors(SP_RGBA32_F_COMPOSE (getScaled(_a[0]), getScaled(_a[1]), 0.0, 1.0), + SP_RGBA32_F_COMPOSE (getScaled(_a[0]), getScaled(_a[1]), 0.5, 1.0), + SP_RGBA32_F_COMPOSE (getScaled(_a[0]), getScaled(_a[1]), 1.0, 1.0)); } if (channels != CSC_CHANNEL_A) { /* Update alpha */ - sp_color_slider_set_colors (SP_COLOR_SLIDER (_s[3]), - SP_RGBA32_F_COMPOSE (getScaled(_a[0]), getScaled(_a[1]), getScaled(_a[2]), 0.0), - SP_RGBA32_F_COMPOSE (getScaled(_a[0]), getScaled(_a[1]), getScaled(_a[2]), 0.5), - SP_RGBA32_F_COMPOSE (getScaled(_a[0]), getScaled(_a[1]), getScaled(_a[2]), 1.0)); + _s[3]->set_colors(SP_RGBA32_F_COMPOSE (getScaled(_a[0]), getScaled(_a[1]), getScaled(_a[2]), 0.0), + SP_RGBA32_F_COMPOSE (getScaled(_a[0]), getScaled(_a[1]), getScaled(_a[2]), 0.5), + SP_RGBA32_F_COMPOSE (getScaled(_a[0]), getScaled(_a[1]), getScaled(_a[2]), 1.0)); } break; case SP_COLOR_SCALES_MODE_HSV: @@ -660,28 +648,25 @@ void ColorScales::_updateSliders( guint channels ) sp_color_hsl_to_rgb_floatv (rgb0, getScaled(_a[0]), 0.0, getScaled(_a[2])); sp_color_hsl_to_rgb_floatv (rgbm, getScaled(_a[0]), 0.5, getScaled(_a[2])); sp_color_hsl_to_rgb_floatv (rgb1, getScaled(_a[0]), 1.0, getScaled(_a[2])); - sp_color_slider_set_colors (SP_COLOR_SLIDER (_s[1]), - SP_RGBA32_F_COMPOSE (rgb0[0], rgb0[1], rgb0[2], 1.0), - SP_RGBA32_F_COMPOSE (rgbm[0], rgbm[1], rgbm[2], 1.0), - SP_RGBA32_F_COMPOSE (rgb1[0], rgb1[1], rgb1[2], 1.0)); + _s[1]->set_colors(SP_RGBA32_F_COMPOSE (rgb0[0], rgb0[1], rgb0[2], 1.0), + SP_RGBA32_F_COMPOSE (rgbm[0], rgbm[1], rgbm[2], 1.0), + SP_RGBA32_F_COMPOSE (rgb1[0], rgb1[1], rgb1[2], 1.0)); } if ((channels != CSC_CHANNEL_V) && (channels != CSC_CHANNEL_A)) { /* Update value */ sp_color_hsl_to_rgb_floatv (rgb0, getScaled(_a[0]), getScaled(_a[1]), 0.0); sp_color_hsl_to_rgb_floatv (rgbm, getScaled(_a[0]), getScaled(_a[1]), 0.5); sp_color_hsl_to_rgb_floatv (rgb1, getScaled(_a[0]), getScaled(_a[1]), 1.0); - sp_color_slider_set_colors (SP_COLOR_SLIDER (_s[2]), - SP_RGBA32_F_COMPOSE (rgb0[0], rgb0[1], rgb0[2], 1.0), - SP_RGBA32_F_COMPOSE (rgbm[0], rgbm[1], rgbm[2], 1.0), - SP_RGBA32_F_COMPOSE (rgb1[0], rgb1[1], rgb1[2], 1.0)); + _s[2]->set_colors(SP_RGBA32_F_COMPOSE (rgb0[0], rgb0[1], rgb0[2], 1.0), + SP_RGBA32_F_COMPOSE (rgbm[0], rgbm[1], rgbm[2], 1.0), + SP_RGBA32_F_COMPOSE (rgb1[0], rgb1[1], rgb1[2], 1.0)); } if (channels != CSC_CHANNEL_A) { /* Update alpha */ sp_color_hsl_to_rgb_floatv (rgb0, getScaled(_a[0]), getScaled(_a[1]), getScaled(_a[2])); - sp_color_slider_set_colors (SP_COLOR_SLIDER (_s[3]), - SP_RGBA32_F_COMPOSE (rgb0[0], rgb0[1], rgb0[2], 0.0), - SP_RGBA32_F_COMPOSE (rgb0[0], rgb0[1], rgb0[2], 0.5), - SP_RGBA32_F_COMPOSE (rgb0[0], rgb0[1], rgb0[2], 1.0)); + _s[3]->set_colors(SP_RGBA32_F_COMPOSE (rgb0[0], rgb0[1], rgb0[2], 0.0), + SP_RGBA32_F_COMPOSE (rgb0[0], rgb0[1], rgb0[2], 0.5), + SP_RGBA32_F_COMPOSE (rgb0[0], rgb0[1], rgb0[2], 1.0)); } break; case SP_COLOR_SCALES_MODE_CMYK: @@ -690,48 +675,43 @@ void ColorScales::_updateSliders( guint channels ) sp_color_cmyk_to_rgb_floatv (rgb0, 0.0, getScaled(_a[1]), getScaled(_a[2]), getScaled(_a[3])); sp_color_cmyk_to_rgb_floatv (rgbm, 0.5, getScaled(_a[1]), getScaled(_a[2]), getScaled(_a[3])); sp_color_cmyk_to_rgb_floatv (rgb1, 1.0, getScaled(_a[1]), getScaled(_a[2]), getScaled(_a[3])); - sp_color_slider_set_colors (SP_COLOR_SLIDER (_s[0]), - SP_RGBA32_F_COMPOSE (rgb0[0], rgb0[1], rgb0[2], 1.0), - SP_RGBA32_F_COMPOSE (rgbm[0], rgbm[1], rgbm[2], 1.0), - SP_RGBA32_F_COMPOSE (rgb1[0], rgb1[1], rgb1[2], 1.0)); + _s[0]->set_colors(SP_RGBA32_F_COMPOSE (rgb0[0], rgb0[1], rgb0[2], 1.0), + SP_RGBA32_F_COMPOSE (rgbm[0], rgbm[1], rgbm[2], 1.0), + SP_RGBA32_F_COMPOSE (rgb1[0], rgb1[1], rgb1[2], 1.0)); } if ((channels != CSC_CHANNEL_M) && (channels != CSC_CHANNEL_CMYKA)) { /* Update M */ sp_color_cmyk_to_rgb_floatv (rgb0, getScaled(_a[0]), 0.0, getScaled(_a[2]), getScaled(_a[3])); sp_color_cmyk_to_rgb_floatv (rgbm, getScaled(_a[0]), 0.5, getScaled(_a[2]), getScaled(_a[3])); sp_color_cmyk_to_rgb_floatv (rgb1, getScaled(_a[0]), 1.0, getScaled(_a[2]), getScaled(_a[3])); - sp_color_slider_set_colors (SP_COLOR_SLIDER (_s[1]), - SP_RGBA32_F_COMPOSE (rgb0[0], rgb0[1], rgb0[2], 1.0), - SP_RGBA32_F_COMPOSE (rgbm[0], rgbm[1], rgbm[2], 1.0), - SP_RGBA32_F_COMPOSE (rgb1[0], rgb1[1], rgb1[2], 1.0)); + _s[1]->set_colors(SP_RGBA32_F_COMPOSE (rgb0[0], rgb0[1], rgb0[2], 1.0), + SP_RGBA32_F_COMPOSE (rgbm[0], rgbm[1], rgbm[2], 1.0), + SP_RGBA32_F_COMPOSE (rgb1[0], rgb1[1], rgb1[2], 1.0)); } if ((channels != CSC_CHANNEL_Y) && (channels != CSC_CHANNEL_CMYKA)) { /* Update Y */ sp_color_cmyk_to_rgb_floatv (rgb0, getScaled(_a[0]), getScaled(_a[1]), 0.0, getScaled(_a[3])); sp_color_cmyk_to_rgb_floatv (rgbm, getScaled(_a[0]), getScaled(_a[1]), 0.5, getScaled(_a[3])); sp_color_cmyk_to_rgb_floatv (rgb1, getScaled(_a[0]), getScaled(_a[1]), 1.0, getScaled(_a[3])); - sp_color_slider_set_colors (SP_COLOR_SLIDER (_s[2]), - SP_RGBA32_F_COMPOSE (rgb0[0], rgb0[1], rgb0[2], 1.0), - SP_RGBA32_F_COMPOSE (rgbm[0], rgbm[1], rgbm[2], 1.0), - SP_RGBA32_F_COMPOSE (rgb1[0], rgb1[1], rgb1[2], 1.0)); + _s[2]->set_colors(SP_RGBA32_F_COMPOSE (rgb0[0], rgb0[1], rgb0[2], 1.0), + SP_RGBA32_F_COMPOSE (rgbm[0], rgbm[1], rgbm[2], 1.0), + SP_RGBA32_F_COMPOSE (rgb1[0], rgb1[1], rgb1[2], 1.0)); } if ((channels != CSC_CHANNEL_K) && (channels != CSC_CHANNEL_CMYKA)) { /* Update K */ sp_color_cmyk_to_rgb_floatv (rgb0, getScaled(_a[0]), getScaled(_a[1]), getScaled(_a[2]), 0.0); sp_color_cmyk_to_rgb_floatv (rgbm, getScaled(_a[0]), getScaled(_a[1]), getScaled(_a[2]), 0.5); sp_color_cmyk_to_rgb_floatv (rgb1, getScaled(_a[0]), getScaled(_a[1]), getScaled(_a[2]), 1.0); - sp_color_slider_set_colors (SP_COLOR_SLIDER (_s[3]), - SP_RGBA32_F_COMPOSE (rgb0[0], rgb0[1], rgb0[2], 1.0), - SP_RGBA32_F_COMPOSE (rgbm[0], rgbm[1], rgbm[2], 1.0), - SP_RGBA32_F_COMPOSE (rgb1[0], rgb1[1], rgb1[2], 1.0)); + _s[3]->set_colors(SP_RGBA32_F_COMPOSE (rgb0[0], rgb0[1], rgb0[2], 1.0), + SP_RGBA32_F_COMPOSE (rgbm[0], rgbm[1], rgbm[2], 1.0), + SP_RGBA32_F_COMPOSE (rgb1[0], rgb1[1], rgb1[2], 1.0)); } if (channels != CSC_CHANNEL_CMYKA) { /* Update alpha */ sp_color_cmyk_to_rgb_floatv (rgb0, getScaled(_a[0]), getScaled(_a[1]), getScaled(_a[2]), getScaled(_a[3])); - sp_color_slider_set_colors (SP_COLOR_SLIDER (_s[4]), - SP_RGBA32_F_COMPOSE (rgb0[0], rgb0[1], rgb0[2], 0.0), - SP_RGBA32_F_COMPOSE (rgb0[0], rgb0[1], rgb0[2], 0.5), - SP_RGBA32_F_COMPOSE (rgb0[0], rgb0[1], rgb0[2], 1.0)); + _s[4]->set_colors(SP_RGBA32_F_COMPOSE (rgb0[0], rgb0[1], rgb0[2], 0.0), + SP_RGBA32_F_COMPOSE (rgb0[0], rgb0[1], rgb0[2], 0.5), + SP_RGBA32_F_COMPOSE (rgb0[0], rgb0[1], rgb0[2], 1.0)); } break; default: diff --git a/src/widgets/sp-color-scales.h b/src/widgets/sp-color-scales.h index 65925fecb..06b8f3859 100644 --- a/src/widgets/sp-color-scales.h +++ b/src/widgets/sp-color-scales.h @@ -18,8 +18,16 @@ struct SPColorScales; struct SPColorScalesClass; -struct SPColorSlider; +namespace Inkscape { +namespace UI { +namespace Widget { + +class ColorSlider; + +} +} +} typedef enum { SP_COLOR_SCALES_MODE_NONE = 0, @@ -52,9 +60,9 @@ protected: virtual void _colorChanged(); static void _adjustmentAnyChanged(GtkAdjustment *adjustment, SPColorScales *cs); - static void _sliderAnyGrabbed(SPColorSlider *slider, SPColorScales *cs); - static void _sliderAnyReleased(SPColorSlider *slider, SPColorScales *cs); - static void _sliderAnyChanged(SPColorSlider *slider, SPColorScales *cs); + void _sliderAnyGrabbed(); + void _sliderAnyReleased(); + void _sliderAnyChanged(); static void _adjustmentChanged(SPColorScales *cs, guint channel); void _getRgbaFloatv(gfloat *rgba); @@ -70,7 +78,7 @@ protected: gboolean _updating : 1; gboolean _dragging : 1; GtkAdjustment *_a[5]; /* Channel adjustments */ - GtkWidget *_s[5]; /* Channel sliders */ + Inkscape::UI::Widget::ColorSlider *_s[5]; /* Channel sliders */ GtkWidget *_b[5]; /* Spinbuttons */ GtkWidget *_l[5]; /* Labels */ -- cgit v1.2.3 From f7eca78772e3f94787c3de8d09b5cf92a46e2eab Mon Sep 17 00:00:00 2001 From: Tomasz Boczkowski Date: Sat, 24 May 2014 22:03:06 +0200 Subject: SPColorSlider c++-sification: use in sp-color-icc-selector (bzr r13341.6.13) --- src/widgets/sp-color-icc-selector.cpp | 72 +++++++++++++++++------------------ 1 file changed, 35 insertions(+), 37 deletions(-) (limited to 'src') diff --git a/src/widgets/sp-color-icc-selector.cpp b/src/widgets/sp-color-icc-selector.cpp index baed7e3b6..ca64a915f 100644 --- a/src/widgets/sp-color-icc-selector.cpp +++ b/src/widgets/sp-color-icc-selector.cpp @@ -104,7 +104,7 @@ public: colorspace::Component _component; GtkAdjustment *_adj; // Component adjustment - GtkWidget *_slider; + Inkscape::UI::Widget::ColorSlider *_slider; GtkWidget *_btn; // spinbutton GtkWidget *_label; // Label guchar *_map; @@ -123,9 +123,9 @@ public: static void _adjustmentChanged ( GtkAdjustment *adjustment, SPColorICCSelector *cs ); - static void _sliderGrabbed( SPColorSlider *slider, SPColorICCSelector *cs ); - static void _sliderReleased( SPColorSlider *slider, SPColorICCSelector *cs ); - static void _sliderChanged( SPColorSlider *slider, SPColorICCSelector *cs ); + void _sliderGrabbed(); + void _sliderReleased(); + void _sliderChanged(); static void _profileSelected( GtkWidget* src, gpointer data ); static void _fixupHit( GtkWidget* src, gpointer data ); @@ -149,7 +149,7 @@ public: std::vector _compUI; GtkAdjustment* _adj; // Channel adjustment - GtkWidget* _slider; + Inkscape::UI::Widget::ColorSlider* _slider; GtkWidget* _sbtn; // Spinbutton GtkWidget* _label; // Label @@ -521,15 +521,15 @@ void ColorICCSelector::init() _impl->_compUI[i]._adj = GTK_ADJUSTMENT( gtk_adjustment_new( 0.0, 0.0, scaleValue, step, page, page ) ); // Slider - _impl->_compUI[i]._slider = sp_color_slider_new( _impl->_compUI[i]._adj ); + _impl->_compUI[i]._slider = Gtk::manage(new Inkscape::UI::Widget::ColorSlider(Glib::wrap(_impl->_compUI[i]._adj, true))); #if defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) - gtk_widget_set_tooltip_text( _impl->_compUI[i]._slider, (i < things.size()) ? things[i].tip.c_str() : "" ); + _impl->_compUI[i]._slider->set_tooltip_text((i < things.size()) ? things[i].tip.c_str() : ""); #else - gtk_widget_set_tooltip_text( _impl->_compUI[i]._slider, "." ); + _impl->_compUI[i]._slider->set_tooltip_text("."); #endif // defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) - gtk_widget_show( _impl->_compUI[i]._slider ); + _impl->_compUI[i]._slider->show(); - attachToGridOrTable(t, _impl->_compUI[i]._slider, 1, row, 1, 1, true); + attachToGridOrTable(t, _impl->_compUI[i]._slider->gobj(), 1, row, 1, 1, true); _impl->_compUI[i]._btn = gtk_spin_button_new( _impl->_compUI[i]._adj, step, digits ); #if defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) @@ -550,9 +550,9 @@ void ColorICCSelector::init() // Signals g_signal_connect( G_OBJECT( _impl->_compUI[i]._adj ), "value_changed", G_CALLBACK( ColorICCSelectorImpl::_adjustmentChanged ), _csel ); - g_signal_connect( G_OBJECT( _impl->_compUI[i]._slider ), "grabbed", G_CALLBACK( ColorICCSelectorImpl::_sliderGrabbed ), _csel ); - g_signal_connect( G_OBJECT( _impl->_compUI[i]._slider ), "released", G_CALLBACK( ColorICCSelectorImpl::_sliderReleased ), _csel ); - g_signal_connect( G_OBJECT( _impl->_compUI[i]._slider ), "changed", G_CALLBACK( ColorICCSelectorImpl::_sliderChanged ), _csel ); + _impl->_compUI[i]._slider->signal_grabbed.connect(sigc::mem_fun(_impl, &ColorICCSelectorImpl::_sliderGrabbed)); + _impl->_compUI[i]._slider->signal_released.connect(sigc::mem_fun(_impl, &ColorICCSelectorImpl::_sliderReleased)); + _impl->_compUI[i]._slider->signal_value_changed.connect(sigc::mem_fun(_impl, &ColorICCSelectorImpl::_sliderChanged)); row++; } @@ -568,16 +568,15 @@ void ColorICCSelector::init() _impl->_adj = GTK_ADJUSTMENT(gtk_adjustment_new(0.0, 0.0, 255.0, 1.0, 10.0, 10.0)); // Slider - _impl->_slider = sp_color_slider_new(_impl->_adj); - gtk_widget_set_tooltip_text(_impl->_slider, _("Alpha (opacity)")); - gtk_widget_show(_impl->_slider); + _impl->_slider = Gtk::manage(new Inkscape::UI::Widget::ColorSlider(Glib::wrap(_impl->_adj, true))); + _impl->_slider->set_tooltip_text(_("Alpha (opacity)")); + _impl->_slider->show(); - attachToGridOrTable(t, _impl->_slider, 1, row, 1, 1, true); + attachToGridOrTable(t, _impl->_slider->gobj(), 1, row, 1, 1, true); - sp_color_slider_set_colors( SP_COLOR_SLIDER( _impl->_slider ), - SP_RGBA32_F_COMPOSE( 1.0, 1.0, 1.0, 0.0 ), - SP_RGBA32_F_COMPOSE( 1.0, 1.0, 1.0, 0.5 ), - SP_RGBA32_F_COMPOSE( 1.0, 1.0, 1.0, 1.0 ) ); + _impl->_slider->set_colors(SP_RGBA32_F_COMPOSE( 1.0, 1.0, 1.0, 0.0 ), + SP_RGBA32_F_COMPOSE( 1.0, 1.0, 1.0, 0.5 ), + SP_RGBA32_F_COMPOSE( 1.0, 1.0, 1.0, 1.0 ) ); // Spinbutton @@ -592,9 +591,9 @@ void ColorICCSelector::init() // Signals g_signal_connect(G_OBJECT(_impl->_adj), "value_changed", G_CALLBACK(ColorICCSelectorImpl::_adjustmentChanged), _csel); - g_signal_connect(G_OBJECT(_impl->_slider), "grabbed", G_CALLBACK(ColorICCSelectorImpl::_sliderGrabbed), _csel); - g_signal_connect(G_OBJECT(_impl->_slider), "released", G_CALLBACK(ColorICCSelectorImpl::_sliderReleased), _csel); - g_signal_connect(G_OBJECT(_impl->_slider), "changed", G_CALLBACK(ColorICCSelectorImpl::_sliderChanged), _csel); + _impl->_slider->signal_grabbed.connect(sigc::mem_fun(_impl, &ColorICCSelectorImpl::_sliderGrabbed)); + _impl->_slider->signal_released.connect(sigc::mem_fun(_impl, &ColorICCSelectorImpl::_sliderReleased)); + _impl->_slider->signal_value_changed.connect(sigc::mem_fun(_impl, &ColorICCSelectorImpl::_sliderChanged)); } static void sp_color_icc_selector_dispose(GObject *object) @@ -880,7 +879,7 @@ void ColorICCSelectorImpl::_setProfile( SVGICCColor* profile ) for ( size_t i = 0; i < _compUI.size(); i++ ) { gtk_widget_hide( _compUI[i]._label ); - gtk_widget_hide( _compUI[i]._slider ); + _compUI[i]._slider->hide(); gtk_widget_hide( _compUI[i]._btn ); } @@ -903,13 +902,12 @@ void ColorICCSelectorImpl::_setProfile( SVGICCColor* profile ) for ( guint i = 0; i < _profChannelCount; i++ ) { gtk_label_set_text_with_mnemonic( GTK_LABEL(_compUI[i]._label), (i < things.size()) ? things[i].name.c_str() : ""); - gtk_widget_set_tooltip_text( _compUI[i]._slider, (i < things.size()) ? things[i].tip.c_str() : "" ); + _compUI[i]._slider->set_tooltip_text((i < things.size()) ? things[i].tip.c_str() : ""); gtk_widget_set_tooltip_text( _compUI[i]._btn, (i < things.size()) ? things[i].tip.c_str() : "" ); - sp_color_slider_set_colors( SP_COLOR_SLIDER(_compUI[i]._slider), - SPColor(0.0, 0.0, 0.0).toRGBA32(0xff), - SPColor(0.5, 0.5, 0.5).toRGBA32(0xff), - SPColor(1.0, 1.0, 1.0).toRGBA32(0xff) ); + _compUI[i]._slider->set_colors(SPColor(0.0, 0.0, 0.0).toRGBA32(0xff), + SPColor(0.5, 0.5, 0.5).toRGBA32(0xff), + SPColor(1.0, 1.0, 1.0).toRGBA32(0xff) ); /* _compUI[i]._adj = GTK_ADJUSTMENT( gtk_adjustment_new( val, 0.0, _fooScales[i], step, page, page ) ); g_signal_connect( G_OBJECT( _compUI[i]._adj ), "value_changed", G_CALLBACK( _adjustmentChanged ), _csel ); @@ -919,14 +917,14 @@ void ColorICCSelectorImpl::_setProfile( SVGICCColor* profile ) gtk_spin_button_set_digits( GTK_SPIN_BUTTON(_compUI[i]._btn), digits ); */ gtk_widget_show( _compUI[i]._label ); - gtk_widget_show( _compUI[i]._slider ); + _compUI[i]._slider->show(); gtk_widget_show( _compUI[i]._btn ); //gtk_adjustment_set_value( _compUI[i]._adj, 0.0 ); //gtk_adjustment_set_value( _compUI[i]._adj, val ); } for ( size_t i = _profChannelCount; i < _compUI.size(); i++ ) { gtk_widget_hide( _compUI[i]._label ); - gtk_widget_hide( _compUI[i]._slider ); + _compUI[i]._slider->hide(); gtk_widget_hide( _compUI[i]._btn ); } } @@ -983,7 +981,7 @@ void ColorICCSelectorImpl::_updateSliders( gint ignore ) cmsHTRANSFORM trans = _prof->getTransfToSRGB8(); if ( trans ) { cmsDoTransform( trans, scratch, _compUI[i]._map, 1024 ); - sp_color_slider_set_map( SP_COLOR_SLIDER(_compUI[i]._slider), _compUI[i]._map ); + _compUI[i]._slider->set_map(_compUI[i]._map); } } } @@ -998,7 +996,7 @@ void ColorICCSelectorImpl::_updateSliders( gint ignore ) guint32 mid = _owner->_color.toRGBA32( 0x7f ); guint32 end = _owner->_color.toRGBA32( 0xff ); - sp_color_slider_set_colors( SP_COLOR_SLIDER(_slider), start, mid, end ); + _slider->set_colors(start, mid, end); } @@ -1091,7 +1089,7 @@ void ColorICCSelectorImpl::_adjustmentChanged( GtkAdjustment *adjustment, SPColo #endif // DEBUG_LCMS } -void ColorICCSelectorImpl::_sliderGrabbed( SPColorSlider * /*slider*/, SPColorICCSelector * /*cs*/ ) +void ColorICCSelectorImpl::_sliderGrabbed() { // ColorICCSelector* iccSelector = dynamic_cast(SP_COLOR_SELECTOR(cs)->base); // if (!iccSelector->_dragging) { @@ -1101,7 +1099,7 @@ void ColorICCSelectorImpl::_sliderGrabbed( SPColorSlider * /*slider*/, SPColorIC // } } -void ColorICCSelectorImpl::_sliderReleased( SPColorSlider * /*slider*/, SPColorICCSelector * /*cs*/ ) +void ColorICCSelectorImpl::_sliderReleased() { // ColorICCSelector* iccSelector = dynamic_cast(SP_COLOR_SELECTOR(cs)->base); // if (iccSelector->_dragging) { @@ -1114,7 +1112,7 @@ void ColorICCSelectorImpl::_sliderReleased( SPColorSlider * /*slider*/, SPColorI #ifdef DEBUG_LCMS void ColorICCSelectorImpl::_sliderChanged( SPColorSlider *slider, SPColorICCSelector *cs ) #else -void ColorICCSelectorImpl::_sliderChanged( SPColorSlider * /*slider*/, SPColorICCSelector * /*cs*/ ) +void ColorICCSelectorImpl::_sliderChanged() #endif // DEBUG_LCMS { #ifdef DEBUG_LCMS -- cgit v1.2.3 From 8a251752c5dc2dc686b815f527f4ce20c477b03c Mon Sep 17 00:00:00 2001 From: Tomasz Boczkowski Date: Sat, 24 May 2014 22:09:33 +0200 Subject: SPColorSlider c++-sification: remove gobject based code (bzr r13341.6.14) --- src/ui/widget/color-slider.cpp | 665 ----------------------------------------- src/ui/widget/color-slider.h | 53 ---- 2 files changed, 718 deletions(-) (limited to 'src') diff --git a/src/ui/widget/color-slider.cpp b/src/ui/widget/color-slider.cpp index ff69e6ed5..d501e3724 100644 --- a/src/ui/widget/color-slider.cpp +++ b/src/ui/widget/color-slider.cpp @@ -538,671 +538,6 @@ bool ColorSlider::on_draw(const Cairo::RefPtr& cr) { }//namespace UI }//namespace Inkscape - - - - - - - - - - - - - - - - - - - - - - - -enum { - GRABBED, - DRAGGED, - RELEASED, - CHANGED, - LAST_SIGNAL -}; - -static void sp_color_slider_class_init (SPColorSliderClass *klass); -static void sp_color_slider_init (SPColorSlider *slider); -static void sp_color_slider_dispose(GObject *object); - -static void sp_color_slider_realize (GtkWidget *widget); -static void sp_color_slider_size_request (GtkWidget *widget, GtkRequisition *requisition); - -#if GTK_CHECK_VERSION(3,0,0) -static void sp_color_slider_get_preferred_width(GtkWidget *widget, - gint *minimal_width, - gint *natural_width); - -static void sp_color_slider_get_preferred_height(GtkWidget *widget, - gint *minimal_height, - gint *natural_height); -#else -static gboolean sp_color_slider_expose(GtkWidget *widget, GdkEventExpose *event); -#endif - -static void sp_color_slider_size_allocate (GtkWidget *widget, GtkAllocation *allocation); - -static gboolean sp_color_slider_draw(GtkWidget *widget, cairo_t *cr); - -static gint sp_color_slider_button_press (GtkWidget *widget, GdkEventButton *event); -static gint sp_color_slider_button_release (GtkWidget *widget, GdkEventButton *event); -static gint sp_color_slider_motion_notify (GtkWidget *widget, GdkEventMotion *event); - -static void sp_color_slider_adjustment_changed (GtkAdjustment *adjustment, SPColorSlider *slider); -static void sp_color_slider_adjustment_value_changed (GtkAdjustment *adjustment, SPColorSlider *slider); - -static GtkWidgetClass *parent_class; -static guint slider_signals[LAST_SIGNAL] = {0}; - -GType -sp_color_slider_get_type (void) -{ - static GType type = 0; - if (!type) { - GTypeInfo info = { - sizeof (SPColorSliderClass), - NULL, NULL, - (GClassInitFunc) sp_color_slider_class_init, - NULL, NULL, - sizeof (SPColorSlider), - 0, - (GInstanceInitFunc) sp_color_slider_init, - NULL - }; - type = g_type_register_static (GTK_TYPE_WIDGET, "SPColorSlider", &info, (GTypeFlags)0); - } - return type; -} - -static void sp_color_slider_class_init(SPColorSliderClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS(klass); - GtkWidgetClass *widget_class = GTK_WIDGET_CLASS(klass); - - parent_class = GTK_WIDGET_CLASS(g_type_class_peek_parent(klass)); - - slider_signals[GRABBED] = g_signal_new ("grabbed", - G_TYPE_FROM_CLASS(object_class), - (GSignalFlags)(G_SIGNAL_RUN_FIRST | G_SIGNAL_NO_RECURSE), - G_STRUCT_OFFSET (SPColorSliderClass, grabbed), - NULL, NULL, - g_cclosure_marshal_VOID__VOID, - G_TYPE_NONE, 0); - slider_signals[DRAGGED] = g_signal_new ("dragged", - G_TYPE_FROM_CLASS(object_class), - (GSignalFlags)(G_SIGNAL_RUN_FIRST | G_SIGNAL_NO_RECURSE), - G_STRUCT_OFFSET (SPColorSliderClass, dragged), - NULL, NULL, - g_cclosure_marshal_VOID__VOID, - G_TYPE_NONE, 0); - slider_signals[RELEASED] = g_signal_new ("released", - G_TYPE_FROM_CLASS(object_class), - (GSignalFlags)(G_SIGNAL_RUN_FIRST | G_SIGNAL_NO_RECURSE), - G_STRUCT_OFFSET (SPColorSliderClass, released), - NULL, NULL, - g_cclosure_marshal_VOID__VOID, - G_TYPE_NONE, 0); - slider_signals[CHANGED] = g_signal_new ("changed", - G_TYPE_FROM_CLASS(object_class), - (GSignalFlags)(G_SIGNAL_RUN_FIRST | G_SIGNAL_NO_RECURSE), - G_STRUCT_OFFSET (SPColorSliderClass, changed), - NULL, NULL, - g_cclosure_marshal_VOID__VOID, - G_TYPE_NONE, 0); - - object_class->dispose = sp_color_slider_dispose; - - widget_class->realize = sp_color_slider_realize; -#if GTK_CHECK_VERSION(3,0,0) - widget_class->get_preferred_width = sp_color_slider_get_preferred_width; - widget_class->get_preferred_height = sp_color_slider_get_preferred_height; - widget_class->draw = sp_color_slider_draw; -#else - widget_class->size_request = sp_color_slider_size_request; - widget_class->expose_event = sp_color_slider_expose; -#endif - widget_class->size_allocate = sp_color_slider_size_allocate; -/* widget_class->draw_focus = sp_color_slider_draw_focus; */ -/* widget_class->draw_default = sp_color_slider_draw_default; */ - - widget_class->button_press_event = sp_color_slider_button_press; - widget_class->button_release_event = sp_color_slider_button_release; - widget_class->motion_notify_event = sp_color_slider_motion_notify; -} - -static void -sp_color_slider_init (SPColorSlider *slider) -{ - /* We are widget with window */ - gtk_widget_set_has_window (GTK_WIDGET(slider), TRUE); - - slider->dragging = FALSE; - - slider->adjustment = NULL; - slider->value = 0.0; - - slider->c0[0] = 0x00; - slider->c0[1] = 0x00; - slider->c0[2] = 0x00; - slider->c0[3] = 0xff; - - slider->cm[0] = 0xff; - slider->cm[1] = 0x00; - slider->cm[2] = 0x00; - slider->cm[3] = 0xff; - - slider->c1[0] = 0xff; - slider->c1[1] = 0xff; - slider->c1[2] = 0xff; - slider->c1[3] = 0xff; - - slider->b0 = 0x5f; - slider->b1 = 0xa0; - slider->bmask = 0x08; - - slider->map = NULL; -} - -static void sp_color_slider_dispose(GObject *object) -{ - SPColorSlider *slider = SP_COLOR_SLIDER (object); - - if (slider->adjustment) { - g_signal_handlers_disconnect_matched (G_OBJECT (slider->adjustment), G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, slider); - g_object_unref (slider->adjustment); - slider->adjustment = NULL; - } - - if ((G_OBJECT_CLASS(parent_class))->dispose) - (* (G_OBJECT_CLASS(parent_class))->dispose) (object); -} - -static void -sp_color_slider_realize (GtkWidget *widget) -{ - GdkWindowAttr attributes; - gint attributes_mask; - GtkAllocation allocation; - - gtk_widget_get_allocation(widget, &allocation); - gtk_widget_set_realized (widget, TRUE); - - attributes.window_type = GDK_WINDOW_CHILD; - attributes.x = allocation.x; - attributes.y = allocation.y; - attributes.width = allocation.width; - attributes.height = allocation.height; - attributes.wclass = GDK_INPUT_OUTPUT; - attributes.visual = gdk_screen_get_system_visual(gdk_screen_get_default()); - -#if !GTK_CHECK_VERSION(3,0,0) - attributes.colormap = gdk_screen_get_system_colormap(gdk_screen_get_default()); -#endif - - attributes.event_mask = gtk_widget_get_events (widget); - attributes.event_mask |= (GDK_EXPOSURE_MASK | - GDK_BUTTON_PRESS_MASK | - GDK_BUTTON_RELEASE_MASK | - GDK_POINTER_MOTION_MASK | - GDK_ENTER_NOTIFY_MASK | - GDK_LEAVE_NOTIFY_MASK); -#if GTK_CHECK_VERSION(3,0,0) - attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL; -#else - attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP; -#endif - - gtk_widget_set_window(widget, - gdk_window_new(gtk_widget_get_parent_window(widget), - &attributes, attributes_mask)); - - gdk_window_set_user_data(gtk_widget_get_window(widget), widget); - -#if !GTK_CHECK_VERSION(3,0,0) - // This doesn't do anything in GTK+ 3 - gtk_widget_set_style(widget, - gtk_style_attach(gtk_widget_get_style(widget), - gtk_widget_get_window(widget))); -#endif -} - -static void -sp_color_slider_size_request (GtkWidget *widget, GtkRequisition *requisition) -{ - GtkStyle *style = gtk_widget_get_style(widget); - requisition->width = SLIDER_WIDTH + style->xthickness * 2; - requisition->height = SLIDER_HEIGHT + style->ythickness * 2; -} - -#if GTK_CHECK_VERSION(3,0,0) -static void sp_color_slider_get_preferred_width(GtkWidget *widget, gint *minimal_width, gint *natural_width) -{ - GtkRequisition requisition; - sp_color_slider_size_request(widget, &requisition); - *minimal_width = *natural_width = requisition.width; -} - -static void sp_color_slider_get_preferred_height(GtkWidget *widget, gint *minimal_height, gint *natural_height) -{ - GtkRequisition requisition; - sp_color_slider_size_request(widget, &requisition); - *minimal_height = *natural_height = requisition.height; -} -#endif - -static void -sp_color_slider_size_allocate (GtkWidget *widget, GtkAllocation *allocation) -{ - gtk_widget_set_allocation(widget, allocation); - - if (gtk_widget_get_realized (widget)) { - /* Resize GdkWindow */ - gdk_window_move_resize(gtk_widget_get_window(widget), - allocation->x, allocation->y, - allocation->width, allocation->height); - } -} - -#if !GTK_CHECK_VERSION(3,0,0) -static gboolean sp_color_slider_expose(GtkWidget *widget, GdkEventExpose * /*event*/) -{ - gboolean result = FALSE; - - if (gtk_widget_is_drawable(widget)) { - GdkWindow *window = gtk_widget_get_window(widget); - cairo_t *cr = gdk_cairo_create(window); - result = sp_color_slider_draw(widget, cr); - cairo_destroy(cr); - } - - return result; -} -#endif - -static gint -sp_color_slider_button_press (GtkWidget *widget, GdkEventButton *event) -{ - SPColorSlider *slider; - - slider = SP_COLOR_SLIDER (widget); - - if (event->button == 1) { - GtkAllocation allocation; - gtk_widget_get_allocation(widget, &allocation); - gint cx, cw; - cx = gtk_widget_get_style(widget)->xthickness; - cw = allocation.width - 2 * cx; - g_signal_emit (G_OBJECT (slider), slider_signals[GRABBED], 0); - slider->dragging = TRUE; - slider->oldvalue = slider->value; - ColorScales::setScaled( slider->adjustment, CLAMP ((gfloat) (event->x - cx) / cw, 0.0, 1.0) ); - g_signal_emit (G_OBJECT (slider), slider_signals[DRAGGED], 0); - -#if GTK_CHECK_VERSION(3,0,0) - gdk_device_grab(gdk_event_get_device(reinterpret_cast(event)), - gtk_widget_get_window(widget), - GDK_OWNERSHIP_NONE, - FALSE, - static_cast(GDK_POINTER_MOTION_MASK | GDK_BUTTON_RELEASE_MASK), - NULL, - event->time); -#else - gdk_pointer_grab(gtk_widget_get_window(widget), FALSE, - static_cast(GDK_POINTER_MOTION_MASK | GDK_BUTTON_RELEASE_MASK), - NULL, NULL, event->time); -#endif - } - - return FALSE; -} - -static gint -sp_color_slider_button_release (GtkWidget *widget, GdkEventButton *event) -{ - SPColorSlider *slider; - - slider = SP_COLOR_SLIDER (widget); - - if (event->button == 1) { - -#if GTK_CHECK_VERSION(3,0,0) - gdk_device_ungrab(gdk_event_get_device(reinterpret_cast(event)), - gdk_event_get_time(reinterpret_cast(event))); -#else - gdk_pointer_ungrab (event->time); -#endif - - slider->dragging = FALSE; - g_signal_emit (G_OBJECT (slider), slider_signals[RELEASED], 0); - if (slider->value != slider->oldvalue) g_signal_emit (G_OBJECT (slider), slider_signals[CHANGED], 0); - } - - return FALSE; -} - -static gint -sp_color_slider_motion_notify (GtkWidget *widget, GdkEventMotion *event) -{ - SPColorSlider *slider; - - slider = SP_COLOR_SLIDER (widget); - - if (slider->dragging) { - gint cx, cw; - GtkAllocation allocation; - gtk_widget_get_allocation(widget, &allocation); - cx = gtk_widget_get_style(widget)->xthickness; - cw = allocation.width - 2 * cx; - ColorScales::setScaled( slider->adjustment, CLAMP ((gfloat) (event->x - cx) / cw, 0.0, 1.0) ); - g_signal_emit (G_OBJECT (slider), slider_signals[DRAGGED], 0); - } - - return FALSE; -} - -GtkWidget *sp_color_slider_new(GtkAdjustment *adjustment) -{ - SPColorSlider *slider = SP_COLOR_SLIDER(g_object_new(SP_TYPE_COLOR_SLIDER, NULL)); - - sp_color_slider_set_adjustment (slider, adjustment); - - return GTK_WIDGET (slider); -} - -void sp_color_slider_set_adjustment(SPColorSlider *slider, GtkAdjustment *adjustment) -{ - g_return_if_fail (slider != NULL); - g_return_if_fail (SP_IS_COLOR_SLIDER (slider)); - - if (!adjustment) { - adjustment = GTK_ADJUSTMENT(gtk_adjustment_new(0.0, 0.0, 1.0, 0.01, 0.0, 0.0)); - } else { - gtk_adjustment_set_page_increment(adjustment, 0.0); - gtk_adjustment_set_page_size(adjustment, 0.0); - } - - if (slider->adjustment != adjustment) { - if (slider->adjustment) { - g_signal_handlers_disconnect_matched (G_OBJECT (slider->adjustment), G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, slider); - g_object_unref (slider->adjustment); - } - - slider->adjustment = adjustment; - g_object_ref (adjustment); - g_object_ref_sink (adjustment); - - g_signal_connect (G_OBJECT (adjustment), "changed", - G_CALLBACK (sp_color_slider_adjustment_changed), slider); - g_signal_connect (G_OBJECT (adjustment), "value_changed", - G_CALLBACK (sp_color_slider_adjustment_value_changed), slider); - - slider->value = ColorScales::getScaled( adjustment ); - - sp_color_slider_adjustment_changed (adjustment, slider); - } -} - -void -sp_color_slider_set_colors (SPColorSlider *slider, guint32 start, guint32 mid, guint32 end) -{ - g_return_if_fail (slider != NULL); - g_return_if_fail (SP_IS_COLOR_SLIDER (slider)); - - // Remove any map, if set - slider->map = 0; - - slider->c0[0] = start >> 24; - slider->c0[1] = (start >> 16) & 0xff; - slider->c0[2] = (start >> 8) & 0xff; - slider->c0[3] = start & 0xff; - - slider->cm[0] = mid >> 24; - slider->cm[1] = (mid >> 16) & 0xff; - slider->cm[2] = (mid >> 8) & 0xff; - slider->cm[3] = mid & 0xff; - - slider->c1[0] = end >> 24; - slider->c1[1] = (end >> 16) & 0xff; - slider->c1[2] = (end >> 8) & 0xff; - slider->c1[3] = end & 0xff; - - gtk_widget_queue_draw (GTK_WIDGET (slider)); -} - -void -sp_color_slider_set_map (SPColorSlider *slider, const guchar *map) -{ - g_return_if_fail (slider != NULL); - g_return_if_fail (SP_IS_COLOR_SLIDER (slider)); - - slider->map = const_cast(map); - - gtk_widget_queue_draw (GTK_WIDGET (slider)); -} - -void -sp_color_slider_set_background (SPColorSlider *slider, guint dark, guint light, guint size) -{ - g_return_if_fail (slider != NULL); - g_return_if_fail (SP_IS_COLOR_SLIDER (slider)); - - slider->b0 = dark; - slider->b1 = light; - slider->bmask = size; - - gtk_widget_queue_draw (GTK_WIDGET (slider)); -} - -static void -sp_color_slider_adjustment_changed (GtkAdjustment */*adjustment*/, SPColorSlider *slider) -{ - gtk_widget_queue_draw (GTK_WIDGET (slider)); -} - -static void -sp_color_slider_adjustment_value_changed (GtkAdjustment *adjustment, SPColorSlider *slider) -{ - GtkWidget *widget; - - widget = GTK_WIDGET (slider); - - if (slider->value != ColorScales::getScaled( adjustment )) { - gint cx, cy, cw, ch; - GtkStyle *style = gtk_widget_get_style(widget); - GtkAllocation allocation; - gtk_widget_get_allocation(widget, &allocation); - cx = style->xthickness; - cy = style->ythickness; - cw = allocation.width - 2 * cx; - ch = allocation.height - 2 * cy; - if ((gint) (ColorScales::getScaled( adjustment ) * cw) != (gint) (slider->value * cw)) { - gint ax, ay; - gfloat value; - value = slider->value; - slider->value = ColorScales::getScaled( adjustment ); - ax = (int)(cx + value * cw - ARROW_SIZE / 2 - 2); - ay = cy; - gtk_widget_queue_draw_area (widget, ax, ay, ARROW_SIZE + 4, ch); - ax = (int)(cx + slider->value * cw - ARROW_SIZE / 2 - 2); - ay = cy; - gtk_widget_queue_draw_area (widget, ax, ay, ARROW_SIZE + 4, ch); - } else { - slider->value = ColorScales::getScaled( adjustment ); - } - } -} - -static gboolean sp_color_slider_draw(GtkWidget *widget, cairo_t *cr) -{ - SPColorSlider *slider = SP_COLOR_SLIDER(widget); - - gboolean colorsOnTop = Inkscape::Preferences::get()->getBool("/options/workarounds/colorsontop", false); - - GtkAllocation allocation; - gtk_widget_get_allocation(widget, &allocation); - -#if GTK_CHECK_VERSION(3,0,0) - GtkStyleContext *context = gtk_widget_get_style_context(widget); -#else - GdkWindow *window = gtk_widget_get_window(widget); - GtkStyle *style = gtk_widget_get_style(widget); -#endif - - // Draw shadow - if (colorsOnTop) { -#if GTK_CHECK_VERSION(3,0,0) - gtk_render_frame(context, - cr, - 0, 0, - allocation.width, allocation.height); -#else - gtk_paint_shadow( style, window, - gtk_widget_get_state(widget), GTK_SHADOW_IN, - NULL, widget, "colorslider", - 0, 0, - allocation.width, allocation.height); -#endif - } - - /* Paintable part of color gradient area */ - GdkRectangle carea; - -#if GTK_CHECK_VERSION(3,0,0) - GtkBorder padding; - - gtk_style_context_get_padding(context, - gtk_widget_get_state_flags(widget), - &padding); - - carea.x = padding.left; - carea.y = padding.top; -#else - carea.x = style->xthickness; - carea.y = style->ythickness; -#endif - - carea.width = allocation.width - 2 * carea.x; - carea.height = allocation.height - 2 * carea.y; - - if (slider->map) { - /* Render map pixelstore */ - gint d = (1024 << 16) / carea.width; - gint s = 0; - - const guchar *b = sp_color_slider_render_map(0, 0, carea.width, carea.height, - slider->map, s, d, - slider->b0, slider->b1, slider->bmask); - - if (b != NULL && carea.width > 0) { - GdkPixbuf *pb = gdk_pixbuf_new_from_data (b, GDK_COLORSPACE_RGB, - 0, 8, carea.width, carea.height, carea.width * 3, NULL, NULL); - - gdk_cairo_set_source_pixbuf(cr, pb, carea.x, carea.y); - cairo_paint(cr); - g_object_unref(pb); - } - - } else { - gint c[4], dc[4]; - - /* Render gradient */ - - // part 1: from c0 to cm - if (carea.width > 0) { - for (gint i = 0; i < 4; i++) { - c[i] = slider->c0[i] << 16; - dc[i] = ((slider->cm[i] << 16) - c[i]) / (carea.width/2); - } - guint wi = carea.width/2; - const guchar *b = sp_color_slider_render_gradient(0, 0, wi, carea.height, - c, dc, slider->b0, slider->b1, slider->bmask); - - /* Draw pixelstore 1 */ - if (b != NULL && wi > 0) { - GdkPixbuf *pb = gdk_pixbuf_new_from_data (b, GDK_COLORSPACE_RGB, - 0, 8, wi, carea.height, wi * 3, NULL, NULL); - - gdk_cairo_set_source_pixbuf(cr, pb, carea.x, carea.y); - cairo_paint(cr); - g_object_unref(pb); - } - } - - // part 2: from cm to c1 - if (carea.width > 0) { - for (gint i = 0; i < 4; i++) { - c[i] = slider->cm[i] << 16; - dc[i] = ((slider->c1[i] << 16) - c[i]) / (carea.width/2); - } - guint wi = carea.width/2; - const guchar *b = sp_color_slider_render_gradient(carea.width/2, 0, wi, carea.height, - c, dc, - slider->b0, slider->b1, slider->bmask); - - /* Draw pixelstore 2 */ - if (b != NULL && wi > 0) { - GdkPixbuf *pb = gdk_pixbuf_new_from_data (b, GDK_COLORSPACE_RGB, - 0, 8, wi, carea.height, wi * 3, NULL, NULL); - - gdk_cairo_set_source_pixbuf(cr, pb, carea.width/2 + carea.x, carea.y); - cairo_paint(cr); - - g_object_unref(pb); - } - } - } - - /* Draw shadow */ - if (!colorsOnTop) { -#if GTK_CHECK_VERSION(3,0,0) - gtk_render_frame(context, - cr, - 0, 0, - allocation.width, allocation.height); -#else - gtk_paint_shadow( style, window, - gtk_widget_get_state(widget), GTK_SHADOW_IN, - NULL, widget, "colorslider", - 0, 0, - allocation.width, allocation.height); -#endif - } - - /* Draw arrow */ - gint x = (int)(slider->value * (carea.width - 1) - ARROW_SIZE / 2 + carea.x); - gint y1 = carea.y; - gint y2 = carea.y + carea.height - 1; - cairo_set_line_width(cr, 1.0); - - // Define top arrow - cairo_move_to(cr, x - 0.5, y1 + 0.5); - cairo_line_to(cr, x + ARROW_SIZE - 0.5, y1 + 0.5); - cairo_line_to(cr, x + (ARROW_SIZE-1)/2.0, y1 + ARROW_SIZE/2.0 + 0.5); - cairo_line_to(cr, x - 0.5, y1 + 0.5); - - // Define bottom arrow - cairo_move_to(cr, x - 0.5, y2 + 0.5); - cairo_line_to(cr, x + ARROW_SIZE - 0.5, y2 + 0.5); - cairo_line_to(cr, x + (ARROW_SIZE-1)/2.0, y2 - ARROW_SIZE/2.0 + 0.5); - cairo_line_to(cr, x - 0.5, y2 + 0.5); - - // Render both arrows - cairo_set_source_rgb(cr, 1.0, 1.0, 1.0); - cairo_stroke_preserve(cr); - cairo_set_source_rgb(cr, 0.0, 0.0, 0.0); - cairo_fill(cr); - - return FALSE; -} - /* Colors are << 16 */ static const guchar * diff --git a/src/ui/widget/color-slider.h b/src/ui/widget/color-slider.h index eb4cd99c3..bbc14afc9 100644 --- a/src/ui/widget/color-slider.h +++ b/src/ui/widget/color-slider.h @@ -105,57 +105,4 @@ private: }//namespace UI }//namespace Inkscape - -#include - -#include - - - -struct SPColorSlider; -struct SPColorSliderClass; - -#define SP_TYPE_COLOR_SLIDER (sp_color_slider_get_type ()) -#define SP_COLOR_SLIDER(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), SP_TYPE_COLOR_SLIDER, SPColorSlider)) -#define SP_COLOR_SLIDER_CLASS(k) (G_TYPE_CHECK_CLASS_CAST ((k), SP_TYPE_COLOR_SLIDER, SPColorSliderClass)) -#define SP_IS_COLOR_SLIDER(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), SP_TYPE_COLOR_SLIDER)) -#define SP_IS_COLOR_SLIDER_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), SP_TYPE_COLOR_SLIDER)) - -struct SPColorSlider { - GtkWidget widget; - - guint dragging : 1; - - GtkAdjustment *adjustment; - - gfloat value; - gfloat oldvalue; - guchar c0[4], cm[4], c1[4]; - guchar b0, b1; - guchar bmask; - - gint mapsize; - guchar *map; -}; - -struct SPColorSliderClass { - GtkWidgetClass parent_class; - - void (* grabbed) (SPColorSlider *slider); - void (* dragged) (SPColorSlider *slider); - void (* released) (SPColorSlider *slider); - void (* changed) (SPColorSlider *slider); -}; - -GType sp_color_slider_get_type (void); - -GtkWidget *sp_color_slider_new (GtkAdjustment *adjustment); - -void sp_color_slider_set_adjustment (SPColorSlider *slider, GtkAdjustment *adjustment); -void sp_color_slider_set_colors (SPColorSlider *slider, guint32 start, guint32 mid, guint32 end); -void sp_color_slider_set_map (SPColorSlider *slider, const guchar *map); -void sp_color_slider_set_background (SPColorSlider *slider, guint dark, guint light, guint size); - - - #endif -- cgit v1.2.3 From 0744a31c573dc80d6e8166319e07375e97884f15 Mon Sep 17 00:00:00 2001 From: Tomasz Boczkowski Date: Sun, 25 May 2014 00:02:36 +0200 Subject: SPColorSlider c++-sification: remove unnecessary reference to Gtk::Adjustment (bzr r13341.6.15) --- src/ui/widget/color-slider.cpp | 3 --- 1 file changed, 3 deletions(-) (limited to 'src') diff --git a/src/ui/widget/color-slider.cpp b/src/ui/widget/color-slider.cpp index d501e3724..fc64fad6f 100644 --- a/src/ui/widget/color-slider.cpp +++ b/src/ui/widget/color-slider.cpp @@ -297,9 +297,6 @@ void ColorSlider::set_adjustment(Gtk::Adjustment *adjustment) { } _adjustment = adjustment; -#if !GTK_CHECK_VERSION(3,0,0) - _adjustment->reference(); -#endif _adjustment_changed_connection = _adjustment->signal_changed().connect( sigc::mem_fun(this, &ColorSlider::_on_adjustment_changed)); _adjustment_value_changed_connection = _adjustment->signal_value_changed().connect( -- cgit v1.2.3 From 3b4e451ace16cc3a4c62d2dfdc50587d4a8acf8c Mon Sep 17 00:00:00 2001 From: Tomasz Boczkowski Date: Mon, 26 May 2014 21:02:55 +0200 Subject: SPPattern c++-sification: replaced guint by bool and enum (bzr r13341.6.16) --- src/extension/internal/cairo-render-context.cpp | 4 +-- src/sp-pattern.cpp | 40 ++++++++++++------------- src/sp-pattern.h | 24 +++++++-------- 3 files changed, 34 insertions(+), 34 deletions(-) (limited to 'src') diff --git a/src/extension/internal/cairo-render-context.cpp b/src/extension/internal/cairo-render-context.cpp index c09b8e9c8..2ace19ae5 100644 --- a/src/extension/internal/cairo-render-context.cpp +++ b/src/extension/internal/cairo-render-context.cpp @@ -1015,7 +1015,7 @@ CairoRenderContext::_createPatternPainter(SPPaintServer const *const paintserver TRACE(("%f x %f pattern\n", width, height)); - if (pbox && pattern_patternUnits(pat) == SP_PATTERN_UNITS_OBJECTBOUNDINGBOX) { + if (pbox && pattern_patternUnits(pat) == SPPattern::UNITS_OBJECTBOUNDINGBOX) { //Geom::Affine bbox2user (pbox->x1 - pbox->x0, 0.0, 0.0, pbox->y1 - pbox->y0, pbox->x0, pbox->y0); bbox_width_scaler = pbox->width(); bbox_height_scaler = pbox->height(); @@ -1048,7 +1048,7 @@ CairoRenderContext::_createPatternPainter(SPPaintServer const *const paintserver pcs2dev[3] = h / view_box.height(); pcs2dev[4] = x - view_box.left() * pcs2dev[0]; pcs2dev[5] = y - view_box.top() * pcs2dev[3]; - } else if (pbox && pattern_patternContentUnits(pat) == SP_PATTERN_UNITS_OBJECTBOUNDINGBOX) { + } else if (pbox && pattern_patternContentUnits(pat) == SPPattern::UNITS_OBJECTBOUNDINGBOX) { pcs2dev[0] = pbox->width(); pcs2dev[3] = pbox->height(); } diff --git a/src/sp-pattern.cpp b/src/sp-pattern.cpp index 9b7330a24..c5461d302 100644 --- a/src/sp-pattern.cpp +++ b/src/sp-pattern.cpp @@ -59,14 +59,14 @@ SPPattern::SPPattern() : SPPaintServer(), SPViewBox() { this->ref = new SPPatternReference(this); this->ref->changedSignal().connect(sigc::bind(sigc::ptr_fun(pattern_ref_changed), this)); - this->patternUnits = SP_PATTERN_UNITS_OBJECTBOUNDINGBOX; - this->patternUnits_set = FALSE; + this->patternUnits = UNITS_OBJECTBOUNDINGBOX; + this->patternUnits_set = false; - this->patternContentUnits = SP_PATTERN_UNITS_USERSPACEONUSE; - this->patternContentUnits_set = FALSE; + this->patternContentUnits = UNITS_USERSPACEONUSE; + this->patternContentUnits_set = false; this->patternTransform = Geom::identity(); - this->patternTransform_set = FALSE; + this->patternTransform_set = false; this->x.unset(); this->y.unset(); @@ -116,14 +116,14 @@ void SPPattern::set(unsigned int key, const gchar* value) { case SP_ATTR_PATTERNUNITS: if (value) { if (!strcmp (value, "userSpaceOnUse")) { - this->patternUnits = SP_PATTERN_UNITS_USERSPACEONUSE; + this->patternUnits = UNITS_USERSPACEONUSE; } else { - this->patternUnits = SP_PATTERN_UNITS_OBJECTBOUNDINGBOX; + this->patternUnits = UNITS_OBJECTBOUNDINGBOX; } - this->patternUnits_set = TRUE; + this->patternUnits_set = true; } else { - this->patternUnits_set = FALSE; + this->patternUnits_set = false; } this->requestModified(SP_OBJECT_MODIFIED_FLAG); @@ -132,14 +132,14 @@ void SPPattern::set(unsigned int key, const gchar* value) { case SP_ATTR_PATTERNCONTENTUNITS: if (value) { if (!strcmp (value, "userSpaceOnUse")) { - this->patternContentUnits = SP_PATTERN_UNITS_USERSPACEONUSE; + this->patternContentUnits = UNITS_USERSPACEONUSE; } else { - this->patternContentUnits = SP_PATTERN_UNITS_OBJECTBOUNDINGBOX; + this->patternContentUnits = UNITS_OBJECTBOUNDINGBOX; } - this->patternContentUnits_set = TRUE; + this->patternContentUnits_set = true; } else { - this->patternContentUnits_set = FALSE; + this->patternContentUnits_set = false; } this->requestModified(SP_OBJECT_MODIFIED_FLAG); @@ -150,10 +150,10 @@ void SPPattern::set(unsigned int key, const gchar* value) { if (value && sp_svg_transform_read (value, &t)) { this->patternTransform = t; - this->patternTransform_set = TRUE; + this->patternTransform_set = true; } else { this->patternTransform = Geom::identity(); - this->patternTransform_set = FALSE; + this->patternTransform_set = false; } this->requestModified(SP_OBJECT_MODIFIED_FLAG); @@ -399,7 +399,7 @@ sp_pattern_transform_multiply (SPPattern *pattern, Geom::Affine postmul, bool se } else { pattern->patternTransform = pattern_patternTransform(pattern) * postmul; } - pattern->patternTransform_set = TRUE; + pattern->patternTransform_set = true; gchar *c=sp_svg_transform_write(pattern->patternTransform); pattern->getRepr()->setAttribute("patternTransform", c); @@ -455,7 +455,7 @@ SPPattern *pattern_getroot(SPPattern *pat) // Access functions that look up fields up the chain of referenced patterns and return the first one which is set // FIXME: all of them must use chase_hrefs the same as in SPGradient, to avoid lockup on circular refs -guint pattern_patternUnits (SPPattern const *pat) +SPPattern::PatternUnits pattern_patternUnits (SPPattern const *pat) { for (SPPattern const *pat_i = pat; pat_i != NULL; pat_i = pat_i->ref ? pat_i->ref->getObject() : NULL) { if (pat_i->patternUnits_set) @@ -464,7 +464,7 @@ guint pattern_patternUnits (SPPattern const *pat) return pat->patternUnits; } -guint pattern_patternContentUnits (SPPattern const *pat) +SPPattern::PatternUnits pattern_patternContentUnits (SPPattern const *pat) { for (SPPattern const *pat_i = pat; pat_i != NULL; pat_i = pat_i->ref ? pat_i->ref->getObject() : NULL) { if (pat_i->patternContentUnits_set) @@ -603,7 +603,7 @@ cairo_pattern_t* SPPattern::pattern_new(cairo_t *base_ct, Geom::OptRect const &b double tile_y = pattern_y(this); double tile_width = pattern_width(this); double tile_height = pattern_height(this); - if ( bbox && (pattern_patternUnits(this) == SP_PATTERN_UNITS_OBJECTBOUNDINGBOX) ) { + if ( bbox && (pattern_patternUnits(this) == UNITS_OBJECTBOUNDINGBOX) ) { tile_x *= bbox->width(); tile_y *= bbox->height(); tile_width *= bbox->width(); @@ -625,7 +625,7 @@ cairo_pattern_t* SPPattern::pattern_new(cairo_t *base_ct, Geom::OptRect const &b } else { // Content to bbox - if (bbox && (pattern_patternContentUnits(this) == SP_PATTERN_UNITS_OBJECTBOUNDINGBOX) ) { + if (bbox && (pattern_patternContentUnits(this) == UNITS_OBJECTBOUNDINGBOX) ) { content2ps = Geom::Affine(bbox->width(), 0.0, 0.0, bbox->height(), 0,0); } } diff --git a/src/sp-pattern.h b/src/sp-pattern.h index eb34b6714..d836e7a42 100644 --- a/src/sp-pattern.h +++ b/src/sp-pattern.h @@ -33,6 +33,11 @@ class SPPatternReference; class SPPattern : public SPPaintServer, public SPViewBox { public: + enum PatternUnits { + UNITS_USERSPACEONUSE, + UNITS_OBJECTBOUNDINGBOX + }; + SPPattern(); virtual ~SPPattern(); @@ -41,13 +46,13 @@ public: SPPatternReference *ref; /* patternUnits and patternContentUnits attribute */ - guint patternUnits : 1; - guint patternUnits_set : 1; - guint patternContentUnits : 1; - guint patternContentUnits_set : 1; + PatternUnits patternUnits : 1; + bool patternUnits_set : 1; + PatternUnits patternContentUnits : 1; + bool patternContentUnits_set : 1; /* patternTransform attribute */ Geom::Affine patternTransform; - guint patternTransform_set : 1; + bool patternTransform_set : 1; /* Tile rectangle */ SVGLength x; SVGLength y; @@ -82,11 +87,6 @@ protected: } }; -enum { - SP_PATTERN_UNITS_USERSPACEONUSE, - SP_PATTERN_UNITS_OBJECTBOUNDINGBOX -}; - guint pattern_users (SPPattern *pattern); SPPattern *pattern_chain (SPPattern *pattern); SPPattern *sp_pattern_clone_if_necessary (SPItem *item, SPPattern *pattern, const gchar *property); @@ -96,8 +96,8 @@ const gchar *pattern_tile (GSList *reprs, Geom::Rect bounds, SPDocument *documen SPPattern *pattern_getroot (SPPattern *pat); -guint pattern_patternUnits (SPPattern const *pat); -guint pattern_patternContentUnits (SPPattern const *pat); +SPPattern::PatternUnits pattern_patternUnits (SPPattern const *pat); +SPPattern::PatternUnits pattern_patternContentUnits (SPPattern const *pat); Geom::Affine const &pattern_patternTransform(SPPattern const *pat); gdouble pattern_x (SPPattern const *pat); gdouble pattern_y (SPPattern const *pat); -- cgit v1.2.3 From 258b23eac6fadcd3c02053ac6e890b0be5819194 Mon Sep 17 00:00:00 2001 From: Tomasz Boczkowski Date: Mon, 26 May 2014 22:52:46 +0200 Subject: SPPattern c++-sification: replaced gchar* by Glib::ustring (bzr r13341.6.17) --- src/sp-pattern.cpp | 25 ++++++++++--------------- src/sp-pattern.h | 2 +- 2 files changed, 11 insertions(+), 16 deletions(-) (limited to 'src') diff --git a/src/sp-pattern.cpp b/src/sp-pattern.cpp index c5461d302..59fbca435 100644 --- a/src/sp-pattern.cpp +++ b/src/sp-pattern.cpp @@ -54,8 +54,6 @@ namespace { } SPPattern::SPPattern() : SPPaintServer(), SPViewBox() { - this->href = NULL; - this->ref = new SPPatternReference(this); this->ref->changedSignal().connect(sigc::bind(sigc::ptr_fun(pattern_ref_changed), this)); @@ -190,15 +188,14 @@ void SPPattern::set(unsigned int key, const gchar* value) { break; case SP_ATTR_XLINK_HREF: - if ( value && this->href && ( strcmp(value, this->href) == 0 ) ) { + if ( value && this->href == value ) { /* Href unchanged, do nothing. */ } else { - g_free(this->href); - this->href = NULL; + this->href.clear(); if (value) { // First, set the href field; it's only used in the "unchanged" check above. - this->href = g_strdup(value); + this->href = value; // Now do the attaching, which emits the changed signal. if (value) { try { @@ -360,9 +357,8 @@ SPPattern *pattern_chain(SPPattern *pattern) Inkscape::XML::Node *repr = xml_doc->createElement("svg:pattern"); repr->setAttribute("inkscape:collect", "always"); - gchar *parent_ref = g_strconcat("#", pattern->getRepr()->attribute("id"), NULL); + Glib::ustring parent_ref = Glib::ustring::compose("#%1", pattern->getRepr()->attribute("id")); repr->setAttribute("xlink:href", parent_ref); - g_free (parent_ref); defsrepr->addChild(repr, NULL); const gchar *child_id = repr->attribute("id"); @@ -375,13 +371,14 @@ SPPattern *pattern_chain(SPPattern *pattern) SPPattern * sp_pattern_clone_if_necessary (SPItem *item, SPPattern *pattern, const gchar *property) { - if (!pattern->href || pattern->hrefcount > count_pattern_hrefs(item, pattern)) { + if (pattern->href.empty() || pattern->hrefcount > count_pattern_hrefs(item, pattern)) { pattern = pattern_chain (pattern); - gchar *href = g_strconcat("url(#", pattern->getRepr()->attribute("id"), ")", NULL); + Glib::ustring href = Glib::ustring::compose("url(#%1)", pattern->getRepr()->attribute("id")); SPCSSAttr *css = sp_repr_css_attr_new (); - sp_repr_css_set_property (css, property, href); + sp_repr_css_set_property (css, property, href.c_str()); sp_repr_css_change_recursive(item->getRepr(), css, "style"); + } return pattern; } @@ -401,9 +398,8 @@ sp_pattern_transform_multiply (SPPattern *pattern, Geom::Affine postmul, bool se } pattern->patternTransform_set = true; - gchar *c=sp_svg_transform_write(pattern->patternTransform); + Glib::ustring c=sp_svg_transform_write(pattern->patternTransform); pattern->getRepr()->setAttribute("patternTransform", c); - g_free(c); } const gchar *pattern_tile(GSList *reprs, Geom::Rect bounds, SPDocument *document, Geom::Affine transform, Geom::Affine move) @@ -416,9 +412,8 @@ const gchar *pattern_tile(GSList *reprs, Geom::Rect bounds, SPDocument *document sp_repr_set_svg_double(repr, "width", bounds.dimensions()[Geom::X]); sp_repr_set_svg_double(repr, "height", bounds.dimensions()[Geom::Y]); - gchar *t=sp_svg_transform_write(transform); + Glib::ustring t=sp_svg_transform_write(transform); repr->setAttribute("patternTransform", t); - g_free(t); defsrepr->appendChild(repr); const gchar *pat_id = repr->attribute("id"); diff --git a/src/sp-pattern.h b/src/sp-pattern.h index d836e7a42..422adb169 100644 --- a/src/sp-pattern.h +++ b/src/sp-pattern.h @@ -42,7 +42,7 @@ public: virtual ~SPPattern(); /* Reference (href) */ - gchar *href; + Glib::ustring href; SPPatternReference *ref; /* patternUnits and patternContentUnits attribute */ -- cgit v1.2.3 From 6508c429a4a678541bc51df10a8335bbb45f0128 Mon Sep 17 00:00:00 2001 From: Tomasz Boczkowski Date: Tue, 27 May 2014 19:13:09 +0200 Subject: SPPattern c++-sification: replaced GSList by std::list (bzr r13341.6.18) --- src/selection-chemistry.cpp | 6 ++---- src/sp-pattern.cpp | 41 +++++++++++++++++++++-------------------- src/sp-pattern.h | 21 ++++++++++++++------- 3 files changed, 37 insertions(+), 31 deletions(-) (limited to 'src') diff --git a/src/selection-chemistry.cpp b/src/selection-chemistry.cpp index 868a9d743..19eba8ddd 100644 --- a/src/selection-chemistry.cpp +++ b/src/selection-chemistry.cpp @@ -3242,13 +3242,11 @@ sp_selection_tile(SPDesktop *desktop, bool apply) gint pos = SP_OBJECT(items->data)->getRepr()->position(); // create a list of duplicates - GSList *repr_copies = NULL; + std::list repr_copies; for (GSList *i = items; i != NULL; i = i->next) { Inkscape::XML::Node *dup = SP_OBJECT(i->data)->getRepr()->duplicate(xml_doc); - repr_copies = g_slist_prepend(repr_copies, dup); + repr_copies.push_back(dup); } - // restore the z-order after prepends - repr_copies = g_slist_reverse(repr_copies); Geom::Rect bbox(desktop->dt2doc(r->min()), desktop->dt2doc(r->max())); diff --git a/src/sp-pattern.cpp b/src/sp-pattern.cpp index 59fbca435..a3de09368 100644 --- a/src/sp-pattern.cpp +++ b/src/sp-pattern.cpp @@ -222,37 +222,34 @@ void SPPattern::set(unsigned int key, const gchar* value) { /* fixme: We need ::order_changed handler too (Lauris) */ -static GSList *pattern_getchildren(SPPattern *pat) +void pattern_getchildren(SPPattern *pat, std::list& l) { - GSList *l = NULL; - for (SPPattern *pat_i = pat; pat_i != NULL; pat_i = pat_i->ref ? pat_i->ref->getObject() : NULL) { if (pat_i->firstChild()) { // find the first one with children for (SPObject *child = pat->firstChild() ; child ; child = child->getNext() ) { - l = g_slist_prepend (l, child); + l.push_back(child); } break; // do not go further up the chain if children are found } } - - return l; } void SPPattern::update(SPCtx* ctx, unsigned int flags) { - if (flags & SP_OBJECT_MODIFIED_FLAG) { + typedef std::list::iterator SPObjectIterator; + + if (flags & SP_OBJECT_MODIFIED_FLAG) { flags |= SP_OBJECT_PARENT_MODIFIED_FLAG; } flags &= SP_OBJECT_MODIFIED_CASCADE; - GSList *l = pattern_getchildren (this); - l = g_slist_reverse (l); + std::list l; + pattern_getchildren (this, l); - while (l) { - SPObject *child = SP_OBJECT (l->data); + for (SPObjectIterator it = l.begin(); it != l.end(); it++) { + SPObject *child = *it; sp_object_ref (child, NULL); - l = g_slist_remove (l, child); if (flags || (child->mflags & (SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_CHILD_MODIFIED_FLAG))) { child->updateDisplay(ctx, flags); @@ -263,20 +260,21 @@ void SPPattern::update(SPCtx* ctx, unsigned int flags) { } void SPPattern::modified(unsigned int flags) { + typedef std::list::iterator SPObjectIterator; + if (flags & SP_OBJECT_MODIFIED_FLAG) { flags |= SP_OBJECT_PARENT_MODIFIED_FLAG; } flags &= SP_OBJECT_MODIFIED_CASCADE; - GSList *l = pattern_getchildren (this); - l = g_slist_reverse (l); + std::list l; + pattern_getchildren (this, l); - while (l) { - SPObject *child = SP_OBJECT (l->data); + for (SPObjectIterator it = l.begin(); it != l.end(); it++) { + SPObject *child = *it; sp_object_ref (child, NULL); - l = g_slist_remove (l, child); if (flags || (child->mflags & (SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_CHILD_MODIFIED_FLAG))) { child->emitModified(flags); @@ -402,8 +400,11 @@ sp_pattern_transform_multiply (SPPattern *pattern, Geom::Affine postmul, bool se pattern->getRepr()->setAttribute("patternTransform", c); } -const gchar *pattern_tile(GSList *reprs, Geom::Rect bounds, SPDocument *document, Geom::Affine transform, Geom::Affine move) +const gchar *pattern_tile(const std::list &reprs, Geom::Rect bounds, + SPDocument *document, Geom::Affine transform, Geom::Affine move) { + typedef std::list::const_iterator NodePtrIterator; + Inkscape::XML::Document *xml_doc = document->getReprDoc(); Inkscape::XML::Node *defsrepr = document->getDefs()->getRepr(); @@ -419,8 +420,8 @@ const gchar *pattern_tile(GSList *reprs, Geom::Rect bounds, SPDocument *document const gchar *pat_id = repr->attribute("id"); SPObject *pat_object = document->getObjectById(pat_id); - for (GSList *i = reprs; i != NULL; i = i->next) { - Inkscape::XML::Node *node = (Inkscape::XML::Node *)(i->data); + for (NodePtrIterator i = reprs.begin(); i != reprs.end(); i++) { + Inkscape::XML::Node *node = *i; SPItem *copy = SP_ITEM(pat_object->appendChildRepr(node)); Geom::Affine dup_transform; diff --git a/src/sp-pattern.h b/src/sp-pattern.h index 422adb169..3f7433d62 100644 --- a/src/sp-pattern.h +++ b/src/sp-pattern.h @@ -13,22 +13,29 @@ * Released under GNU GPL, read the file 'COPYING' for more information */ +#include #include +#include +#include #include "sp-item.h" +#include "svg/svg-length.h" +#include "sp-paint-server.h" +#include "uri-references.h" +#include "viewbox.h" #define SP_PATTERN(obj) (dynamic_cast((SPObject*)obj)) #define SP_IS_PATTERN(obj) (dynamic_cast((SPObject*)obj) != NULL) class SPPatternReference; -#include "svg/svg-length.h" -#include "sp-paint-server.h" -#include "uri-references.h" -#include "viewbox.h" +namespace Inkscape { +namespace XML { -#include -#include +class Node; + +} +} class SPPattern : public SPPaintServer, public SPViewBox { @@ -92,7 +99,7 @@ SPPattern *pattern_chain (SPPattern *pattern); SPPattern *sp_pattern_clone_if_necessary (SPItem *item, SPPattern *pattern, const gchar *property); void sp_pattern_transform_multiply (SPPattern *pattern, Geom::Affine postmul, bool set); -const gchar *pattern_tile (GSList *reprs, Geom::Rect bounds, SPDocument *document, Geom::Affine transform, Geom::Affine move); +const gchar *pattern_tile (const std::list &reprs, Geom::Rect bounds, SPDocument *document, Geom::Affine transform, Geom::Affine move); SPPattern *pattern_getroot (SPPattern *pat); -- cgit v1.2.3 From 22db6068f172d060429f17a489bdce59e5836c69 Mon Sep 17 00:00:00 2001 From: Tomasz Boczkowski Date: Tue, 27 May 2014 21:57:33 +0200 Subject: SPPattern c++-sification: replacing pattern_ functions by methods pt1 (bzr r13341.6.19) --- src/extension/internal/cairo-render-context.cpp | 16 +++--- src/extension/internal/emf-print.cpp | 8 +-- src/extension/internal/wmf-print.cpp | 4 +- src/knot-holder-entity.cpp | 10 ++-- src/selection-chemistry.cpp | 7 +-- src/sp-pattern.cpp | 66 ++++++++++++------------- src/sp-pattern.h | 20 +++++--- 7 files changed, 68 insertions(+), 63 deletions(-) (limited to 'src') diff --git a/src/extension/internal/cairo-render-context.cpp b/src/extension/internal/cairo-render-context.cpp index 2ace19ae5..aac2c517a 100644 --- a/src/extension/internal/cairo-render-context.cpp +++ b/src/extension/internal/cairo-render-context.cpp @@ -1006,16 +1006,16 @@ CairoRenderContext::_createPatternPainter(SPPaintServer const *const paintserver ps2user = Geom::identity(); pcs2dev = Geom::identity(); - double x = pattern_x(pat); - double y = pattern_y(pat); - double width = pattern_width(pat); - double height = pattern_height(pat); + double x = pat->get_x(); + double y = pat->get_y(); + double width = pat->get_width(); + double height = pat->get_height(); double bbox_width_scaler; double bbox_height_scaler; TRACE(("%f x %f pattern\n", width, height)); - if (pbox && pattern_patternUnits(pat) == SPPattern::UNITS_OBJECTBOUNDINGBOX) { + if (pbox && pat->get_pattern_units() == SPPattern::UNITS_OBJECTBOUNDINGBOX) { //Geom::Affine bbox2user (pbox->x1 - pbox->x0, 0.0, 0.0, pbox->y1 - pbox->y0, pbox->x0, pbox->y0); bbox_width_scaler = pbox->width(); bbox_height_scaler = pbox->height(); @@ -1029,13 +1029,13 @@ CairoRenderContext::_createPatternPainter(SPPaintServer const *const paintserver } // apply pattern transformation - Geom::Affine pattern_transform(pattern_patternTransform(pat)); + Geom::Affine pattern_transform(pat->get_transform()); ps2user *= pattern_transform; Geom::Point ori (ps2user[4], ps2user[5]); // create pattern contents coordinate system if (pat->viewBox_set) { - Geom::Rect view_box = *pattern_viewBox(pat); + Geom::Rect view_box = *pat->get_viewbox(); double x, y, w, h; x = 0; @@ -1048,7 +1048,7 @@ CairoRenderContext::_createPatternPainter(SPPaintServer const *const paintserver pcs2dev[3] = h / view_box.height(); pcs2dev[4] = x - view_box.left() * pcs2dev[0]; pcs2dev[5] = y - view_box.top() * pcs2dev[3]; - } else if (pbox && pattern_patternContentUnits(pat) == SPPattern::UNITS_OBJECTBOUNDINGBOX) { + } else if (pbox && pat->get_pattern_content_units() == SPPattern::UNITS_OBJECTBOUNDINGBOX) { pcs2dev[0] = pbox->width(); pcs2dev[3] = pbox->height(); } diff --git a/src/extension/internal/emf-print.cpp b/src/extension/internal/emf-print.cpp index 9c68e40a4..2953efd7d 100644 --- a/src/extension/internal/emf-print.cpp +++ b/src/extension/internal/emf-print.cpp @@ -381,8 +381,8 @@ int PrintEmf::create_brush(SPStyle const *style, PU_COLORREF fcolor) } else if (SP_IS_PATTERN(SP_STYLE_FILL_SERVER(style))) { // must be paint-server SPPaintServer *paintserver = style->fill.value.href->getObject(); SPPattern *pat = SP_PATTERN(paintserver); - double dwidth = pattern_width(pat); - double dheight = pattern_height(pat); + double dwidth = pat->get_width(); + double dheight = pat->get_height(); width = dwidth; height = dheight; brush_classify(pat, 0, &pixbuf, &hatchType, &hatchColor, &bkColor); @@ -567,8 +567,8 @@ int PrintEmf::create_pen(SPStyle const *style, const Geom::Affine &transform) if (SP_IS_PATTERN(SP_STYLE_STROKE_SERVER(style))) { // must be paint-server SPPaintServer *paintserver = style->stroke.value.href->getObject(); SPPattern *pat = SP_PATTERN(paintserver); - double dwidth = pattern_width(pat); - double dheight = pattern_height(pat); + double dwidth = pat->get_width(); + double dheight = pat->get_height(); width = dwidth; height = dheight; brush_classify(pat, 0, &pixbuf, &hatchType, &hatchColor, &bkColor); diff --git a/src/extension/internal/wmf-print.cpp b/src/extension/internal/wmf-print.cpp index 55ad5da5f..8f3115693 100644 --- a/src/extension/internal/wmf-print.cpp +++ b/src/extension/internal/wmf-print.cpp @@ -378,8 +378,8 @@ int PrintWmf::create_brush(SPStyle const *style, U_COLORREF *fcolor) } else if (SP_IS_PATTERN(SP_STYLE_FILL_SERVER(style))) { // must be paint-server SPPaintServer *paintserver = style->fill.value.href->getObject(); SPPattern *pat = SP_PATTERN(paintserver); - double dwidth = pattern_width(pat); - double dheight = pattern_height(pat); + double dwidth = pat->get_width(); + double dheight = pat->get_height(); width = dwidth; height = dheight; brush_classify(pat, 0, &pixbuf, &hatchType, &hatchColor, &bkColor); diff --git a/src/knot-holder-entity.cpp b/src/knot-holder-entity.cpp index 6471124ec..7b79d86a8 100644 --- a/src/knot-holder-entity.cpp +++ b/src/knot-holder-entity.cpp @@ -187,7 +187,7 @@ PatternKnotHolderEntityAngle::knot_get() const { SPPattern const *pat = SP_PATTERN(SP_STYLE_FILL_SERVER(SP_OBJECT(item)->style)); - gdouble x = pattern_width(pat); + gdouble x = pat->get_width(); gdouble y = 0; Geom::Point delta = Geom::Point(x,y); Geom::Point scale = sp_pattern_extract_scale(pat); @@ -236,8 +236,8 @@ PatternKnotHolderEntityScale::knot_set(Geom::Point const &p, Geom::Point const & // Get the new scale from the position of the knotholder Geom::Point d = p_snapped - sp_pattern_extract_trans(pat); - gdouble pat_x = pattern_width(pat); - gdouble pat_y = pattern_height(pat); + gdouble pat_x = pat->get_width(); + gdouble pat_y = pat->get_height(); Geom::Scale scl(1); if ( state & GDK_CONTROL_MASK ) { // if ctrl is pressed: use 1:1 scaling @@ -263,8 +263,8 @@ PatternKnotHolderEntityScale::knot_get() const { SPPattern const *pat = SP_PATTERN(SP_STYLE_FILL_SERVER(SP_OBJECT(item)->style)); - gdouble x = pattern_width(pat); - gdouble y = pattern_height(pat); + gdouble x = pat->get_width(); + gdouble y = pat->get_height(); Geom::Point delta = Geom::Point(x,y); Geom::Affine a = pat->patternTransform; a[4] = 0; diff --git a/src/selection-chemistry.cpp b/src/selection-chemistry.cpp index 19eba8ddd..9d07ec046 100644 --- a/src/selection-chemistry.cpp +++ b/src/selection-chemistry.cpp @@ -3344,12 +3344,13 @@ void sp_selection_untile(SPDesktop *desktop) did = true; - SPPattern *pattern = pattern_getroot(SP_PATTERN(server)); + SPPattern *pattern = SP_PATTERN(server); + SPPattern *pattern_root = pattern_getroot(pattern); - Geom::Affine pat_transform = pattern_patternTransform(SP_PATTERN(server)); + Geom::Affine pat_transform = pattern->get_transform(); pat_transform *= item->transform; - for (SPObject *child = pattern->firstChild() ; child != NULL; child = child->next ) { + for (SPObject *child = pattern_root->firstChild() ; child != NULL; child = child->next ) { if (SP_IS_ITEM(child)) { Inkscape::XML::Node *copy = child->getRepr()->duplicate(xml_doc); SPItem *i = SP_ITEM(desktop->currentLayer()->appendChildRepr(copy)); diff --git a/src/sp-pattern.cpp b/src/sp-pattern.cpp index a3de09368..81e11ecb2 100644 --- a/src/sp-pattern.cpp +++ b/src/sp-pattern.cpp @@ -392,7 +392,7 @@ sp_pattern_transform_multiply (SPPattern *pattern, Geom::Affine postmul, bool se if (set) { pattern->patternTransform = postmul; } else { - pattern->patternTransform = pattern_patternTransform(pattern) * postmul; + pattern->patternTransform = pattern->get_transform() * postmul; } pattern->patternTransform_set = true; @@ -451,73 +451,73 @@ SPPattern *pattern_getroot(SPPattern *pat) // Access functions that look up fields up the chain of referenced patterns and return the first one which is set // FIXME: all of them must use chase_hrefs the same as in SPGradient, to avoid lockup on circular refs -SPPattern::PatternUnits pattern_patternUnits (SPPattern const *pat) +SPPattern::PatternUnits SPPattern::get_pattern_units() const { - for (SPPattern const *pat_i = pat; pat_i != NULL; pat_i = pat_i->ref ? pat_i->ref->getObject() : NULL) { + for (SPPattern const *pat_i = this; pat_i != NULL; pat_i = pat_i->ref ? pat_i->ref->getObject() : NULL) { if (pat_i->patternUnits_set) return pat_i->patternUnits; } - return pat->patternUnits; + return patternUnits; } -SPPattern::PatternUnits pattern_patternContentUnits (SPPattern const *pat) +SPPattern::PatternUnits SPPattern::get_pattern_content_units() const { - for (SPPattern const *pat_i = pat; pat_i != NULL; pat_i = pat_i->ref ? pat_i->ref->getObject() : NULL) { + for (SPPattern const *pat_i = this; pat_i != NULL; pat_i = pat_i->ref ? pat_i->ref->getObject() : NULL) { if (pat_i->patternContentUnits_set) return pat_i->patternContentUnits; } - return pat->patternContentUnits; + return patternContentUnits; } -Geom::Affine const &pattern_patternTransform(SPPattern const *pat) +Geom::Affine const &SPPattern::get_transform() const { - for (SPPattern const *pat_i = pat; pat_i != NULL; pat_i = pat_i->ref ? pat_i->ref->getObject() : NULL) { + for (SPPattern const *pat_i = this; pat_i != NULL; pat_i = pat_i->ref ? pat_i->ref->getObject() : NULL) { if (pat_i->patternTransform_set) return pat_i->patternTransform; } - return pat->patternTransform; + return patternTransform; } -gdouble pattern_x (SPPattern const *pat) +gdouble SPPattern::get_x() const { - for (SPPattern const *pat_i = pat; pat_i != NULL; pat_i = pat_i->ref ? pat_i->ref->getObject() : NULL) { + for (SPPattern const *pat_i = this; pat_i != NULL; pat_i = pat_i->ref ? pat_i->ref->getObject() : NULL) { if (pat_i->x._set) return pat_i->x.computed; } return 0; } -gdouble pattern_y (SPPattern const *pat) +gdouble SPPattern::get_y() const { - for (SPPattern const *pat_i = pat; pat_i != NULL; pat_i = pat_i->ref ? pat_i->ref->getObject() : NULL) { + for (SPPattern const *pat_i = this; pat_i != NULL; pat_i = pat_i->ref ? pat_i->ref->getObject() : NULL) { if (pat_i->y._set) return pat_i->y.computed; } return 0; } -gdouble pattern_width (SPPattern const* pat) +gdouble SPPattern::get_width() const { - for (SPPattern const *pat_i = pat; pat_i != NULL; pat_i = pat_i->ref ? pat_i->ref->getObject() : NULL) { + for (SPPattern const *pat_i = this; pat_i != NULL; pat_i = pat_i->ref ? pat_i->ref->getObject() : NULL) { if (pat_i->width._set) return pat_i->width.computed; } return 0; } -gdouble pattern_height (SPPattern const *pat) +gdouble SPPattern::get_height() const { - for (SPPattern const *pat_i = pat; pat_i != NULL; pat_i = pat_i->ref ? pat_i->ref->getObject() : NULL) { + for (SPPattern const *pat_i = this; pat_i != NULL; pat_i = pat_i->ref ? pat_i->ref->getObject() : NULL) { if (pat_i->height._set) return pat_i->height.computed; } return 0; } -Geom::OptRect pattern_viewBox (SPPattern const *pat) +Geom::OptRect SPPattern::get_viewbox() const { Geom::OptRect viewbox; - for (SPPattern const *pat_i = pat; pat_i != NULL; pat_i = pat_i->ref ? pat_i->ref->getObject() : NULL) { + for (SPPattern const *pat_i = this; pat_i != NULL; pat_i = pat_i->ref ? pat_i->ref->getObject() : NULL) { if (pat_i->viewBox_set) { viewbox = pat_i->viewBox; break; @@ -526,10 +526,10 @@ Geom::OptRect pattern_viewBox (SPPattern const *pat) return viewbox; } -static bool pattern_hasItemChildren (SPPattern const *pat) +bool SPPattern::_has_item_children() const { bool hasChildren = false; - for (SPObject const *child = pat->firstChild() ; child && !hasChildren ; child = child->getNext() ) { + for (SPObject const *child = firstChild() ; child && !hasChildren ; child = child->getNext() ) { if (SP_IS_ITEM(child)) { hasChildren = true; } @@ -539,8 +539,8 @@ static bool pattern_hasItemChildren (SPPattern const *pat) bool SPPattern::isValid() const { - double tile_width = pattern_width(this); - double tile_height = pattern_height(this); + double tile_width = get_width(); + double tile_height = get_height(); if (tile_width <= 0 || tile_height <= 0) return false; @@ -561,7 +561,7 @@ cairo_pattern_t* SPPattern::pattern_new(cairo_t *base_ct, Geom::OptRect const &b for (SPPattern *pat_i = this; pat_i != NULL; pat_i = pat_i->ref ? pat_i->ref->getObject() : NULL) { // find the first one with item children - if (pat_i && SP_IS_OBJECT(pat_i) && pattern_hasItemChildren(pat_i)) { + if (pat_i && SP_IS_OBJECT(pat_i) && pat_i->_has_item_children()) { shown = pat_i; break; // do not go further up the chain if children are found } @@ -595,11 +595,11 @@ cairo_pattern_t* SPPattern::pattern_new(cairo_t *base_ct, Geom::OptRect const &b // * "x", "y", and "patternTransform" transform tile to user space after tile is generated. // These functions recursively search up the tree to find the values. - double tile_x = pattern_x(this); - double tile_y = pattern_y(this); - double tile_width = pattern_width(this); - double tile_height = pattern_height(this); - if ( bbox && (pattern_patternUnits(this) == UNITS_OBJECTBOUNDINGBOX) ) { + double tile_x = get_x(); + double tile_y = get_y(); + double tile_width = get_width(); + double tile_height = get_height(); + if ( bbox && (get_pattern_units() == UNITS_OBJECTBOUNDINGBOX) ) { tile_x *= bbox->width(); tile_y *= bbox->height(); tile_width *= bbox->width(); @@ -611,7 +611,7 @@ cairo_pattern_t* SPPattern::pattern_new(cairo_t *base_ct, Geom::OptRect const &b // Content to tile (pattern space) Geom::Affine content2ps; - Geom::OptRect effective_view_box = pattern_viewBox(this); + Geom::OptRect effective_view_box = get_viewbox(); if (effective_view_box) { // viewBox to pattern server (using SPViewBox) viewBox = *effective_view_box; @@ -621,14 +621,14 @@ cairo_pattern_t* SPPattern::pattern_new(cairo_t *base_ct, Geom::OptRect const &b } else { // Content to bbox - if (bbox && (pattern_patternContentUnits(this) == UNITS_OBJECTBOUNDINGBOX) ) { + if (bbox && (get_pattern_content_units() == UNITS_OBJECTBOUNDINGBOX) ) { content2ps = Geom::Affine(bbox->width(), 0.0, 0.0, bbox->height(), 0,0); } } // Tile (pattern space) to user. - Geom::Affine ps2user = Geom::Translate(tile_x,tile_y) * pattern_patternTransform(this); + Geom::Affine ps2user = Geom::Translate(tile_x,tile_y) * get_transform(); // Transform of object with pattern (includes screen scaling) diff --git a/src/sp-pattern.h b/src/sp-pattern.h index 3f7433d62..f1dcc7963 100644 --- a/src/sp-pattern.h +++ b/src/sp-pattern.h @@ -70,6 +70,15 @@ public: bool isValid() const; + gdouble get_x() const; + gdouble get_y() const; + gdouble get_width() const; + gdouble get_height() const; + Geom::OptRect get_viewbox() const; + SPPattern::PatternUnits get_pattern_units() const; + SPPattern::PatternUnits get_pattern_content_units() const; + Geom::Affine const &get_transform() const; + virtual cairo_pattern_t* pattern_new(cairo_t *ct, Geom::OptRect const &bbox, double opacity); protected: @@ -78,6 +87,9 @@ protected: virtual void set(unsigned int key, const gchar* value); virtual void update(SPCtx* ctx, unsigned int flags); virtual void modified(unsigned int flags); + +private: + bool _has_item_children() const; }; @@ -103,14 +115,6 @@ const gchar *pattern_tile (const std::list &reprs, Geom::R SPPattern *pattern_getroot (SPPattern *pat); -SPPattern::PatternUnits pattern_patternUnits (SPPattern const *pat); -SPPattern::PatternUnits pattern_patternContentUnits (SPPattern const *pat); -Geom::Affine const &pattern_patternTransform(SPPattern const *pat); -gdouble pattern_x (SPPattern const *pat); -gdouble pattern_y (SPPattern const *pat); -gdouble pattern_width (SPPattern const *pat); -gdouble pattern_height (SPPattern const *pat); -Geom::OptRect pattern_viewBox (SPPattern const *pat); #endif // SEEN_SP_PATTERN_H -- cgit v1.2.3 From 9f92d7370e6e3f456259f5774d3443ae763160d3 Mon Sep 17 00:00:00 2001 From: Tomasz Boczkowski Date: Tue, 27 May 2014 22:21:15 +0200 Subject: SPPattern c++-sification: removed unused declatations and includes (bzr r13341.6.20) --- src/sp-pattern.h | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) (limited to 'src') diff --git a/src/sp-pattern.h b/src/sp-pattern.h index f1dcc7963..f2a1e1c6c 100644 --- a/src/sp-pattern.h +++ b/src/sp-pattern.h @@ -1,9 +1,6 @@ -#ifndef SEEN_SP_PATTERN_H -#define SEEN_SP_PATTERN_H - -/* +/** @file * SVG implementation - * + *//* * Author: * Lauris Kaplinski * Abhishek Sharma @@ -13,21 +10,21 @@ * Released under GNU GPL, read the file 'COPYING' for more information */ +#ifndef SEEN_SP_PATTERN_H +#define SEEN_SP_PATTERN_H + #include -#include #include +#include #include -#include "sp-item.h" #include "svg/svg-length.h" #include "sp-paint-server.h" #include "uri-references.h" #include "viewbox.h" -#define SP_PATTERN(obj) (dynamic_cast((SPObject*)obj)) -#define SP_IS_PATTERN(obj) (dynamic_cast((SPObject*)obj) != NULL) - class SPPatternReference; +class SPItem; namespace Inkscape { namespace XML { @@ -37,6 +34,8 @@ class Node; } } +#define SP_PATTERN(obj) (dynamic_cast((SPObject*)obj)) +#define SP_IS_PATTERN(obj) (dynamic_cast((SPObject*)obj) != NULL) class SPPattern : public SPPaintServer, public SPViewBox { public: @@ -106,7 +105,6 @@ protected: } }; -guint pattern_users (SPPattern *pattern); SPPattern *pattern_chain (SPPattern *pattern); SPPattern *sp_pattern_clone_if_necessary (SPItem *item, SPPattern *pattern, const gchar *property); void sp_pattern_transform_multiply (SPPattern *pattern, Geom::Affine postmul, bool set); -- cgit v1.2.3 From 4d75f1ecca2fcab4cbfec9fb84c5b1f3647dbc17 Mon Sep 17 00:00:00 2001 From: Tomasz Boczkowski Date: Wed, 28 May 2014 23:28:17 +0200 Subject: SPPattern c++-sification: replaced function by methods (bzr r13341.6.21) --- src/desktop-style.cpp | 4 ++-- src/selection-chemistry.cpp | 6 ++--- src/sp-item.cpp | 8 +++---- src/sp-pattern.cpp | 50 +++++++++++++++++------------------------- src/sp-pattern.h | 15 ++++++++----- src/widgets/fill-style.cpp | 4 ++-- src/widgets/paint-selector.cpp | 4 ++-- 7 files changed, 43 insertions(+), 48 deletions(-) (limited to 'src') diff --git a/src/desktop-style.cpp b/src/desktop-style.cpp index 37f537cc5..8c3dac382 100644 --- a/src/desktop-style.cpp +++ b/src/desktop-style.cpp @@ -538,8 +538,8 @@ objects_query_fillstroke (GSList *objects, SPStyle *style_res, bool const isfill if (!SP_IS_PATTERN(server)) return QUERY_STYLE_MULTIPLE_DIFFERENT; // different kind of server - SPPattern *pat = pattern_getroot (SP_PATTERN (server)); - SPPattern *pat_res = pattern_getroot (SP_PATTERN (server_res)); + SPPattern *pat = SP_PATTERN (server)->get_root(); + SPPattern *pat_res = SP_PATTERN (server_res)->get_root(); if (pat_res != pat) return QUERY_STYLE_MULTIPLE_DIFFERENT; // different pattern roots } diff --git a/src/selection-chemistry.cpp b/src/selection-chemistry.cpp index 9d07ec046..069aa57bb 100644 --- a/src/selection-chemistry.cpp +++ b/src/selection-chemistry.cpp @@ -1945,8 +1945,8 @@ GSList *sp_get_same_fill_or_stroke_color(SPItem *sel, GSList *src, SPSelectStrok } } else if (SP_IS_PATTERN(sel_server) && SP_IS_PATTERN(iter_server)) { - SPPattern *sel_pat = pattern_getroot(SP_PATTERN(sel_server)); - SPPattern *iter_pat = pattern_getroot(SP_PATTERN(iter_server)); + SPPattern *sel_pat = SP_PATTERN(sel_server)->get_root(); + SPPattern *iter_pat = SP_PATTERN(iter_server)->get_root(); if (sel_pat == iter_pat) { match = true; } @@ -3345,7 +3345,7 @@ void sp_selection_untile(SPDesktop *desktop) did = true; SPPattern *pattern = SP_PATTERN(server); - SPPattern *pattern_root = pattern_getroot(pattern); + SPPattern *pattern_root = pattern->get_root(); Geom::Affine pat_transform = pattern->get_transform(); pat_transform *= item->transform; diff --git a/src/sp-item.cpp b/src/sp-item.cpp index b10aae1c6..b6a6e66ef 100644 --- a/src/sp-item.cpp +++ b/src/sp-item.cpp @@ -1113,16 +1113,16 @@ void SPItem::adjust_pattern (Geom::Affine const &postmul, bool set) if (style && (style->fill.isPaintserver())) { SPObject *server = style->getFillPaintServer(); if ( SP_IS_PATTERN(server) ) { - SPPattern *pattern = sp_pattern_clone_if_necessary(this, SP_PATTERN(server), "fill"); - sp_pattern_transform_multiply(pattern, postmul, set); + SPPattern *pattern = SP_PATTERN(server)->clone_if_necessary(this, "fill"); + pattern->transform_multiply(postmul, set); } } if (style && (style->stroke.isPaintserver())) { SPObject *server = style->getStrokePaintServer(); if ( SP_IS_PATTERN(server) ) { - SPPattern *pattern = sp_pattern_clone_if_necessary(this, SP_PATTERN(server), "stroke"); - sp_pattern_transform_multiply(pattern, postmul, set); + SPPattern *pattern = SP_PATTERN(server)->clone_if_necessary(this, "stroke"); + pattern->transform_multiply(postmul, set); } } } diff --git a/src/sp-pattern.cpp b/src/sp-pattern.cpp index 81e11ecb2..bd24ab1bb 100644 --- a/src/sp-pattern.cpp +++ b/src/sp-pattern.cpp @@ -312,12 +312,7 @@ static void pattern_ref_modified (SPObject */*ref*/, guint /*flags*/, SPPattern // Conditional to avoid causing infinite loop if there's a cycle in the href chain. } - -/** -Count how many times pat is used by the styles of o and its descendants -*/ -static guint -count_pattern_hrefs(SPObject *o, SPPattern *pat) +guint SPPattern::_count_hrefs(SPObject *o) const { if (!o) return 1; @@ -328,34 +323,32 @@ count_pattern_hrefs(SPObject *o, SPPattern *pat) if (style && style->fill.isPaintserver() && SP_IS_PATTERN(SP_STYLE_FILL_SERVER(style)) - && SP_PATTERN(SP_STYLE_FILL_SERVER(style)) == pat) + && SP_PATTERN(SP_STYLE_FILL_SERVER(style)) == this) { i ++; } if (style && style->stroke.isPaintserver() && SP_IS_PATTERN(SP_STYLE_STROKE_SERVER(style)) - && SP_PATTERN(SP_STYLE_STROKE_SERVER(style)) == pat) + && SP_PATTERN(SP_STYLE_STROKE_SERVER(style)) == this) { i ++; } for ( SPObject *child = o->firstChild(); child != NULL; child = child->next ) { - i += count_pattern_hrefs(child, pat); + i += _count_hrefs(child); } return i; } -SPPattern *pattern_chain(SPPattern *pattern) -{ - SPDocument *document = pattern->document; - Inkscape::XML::Document *xml_doc = document->getReprDoc(); +SPPattern *SPPattern::_chain() const { + Inkscape::XML::Document *xml_doc = document->getReprDoc(); Inkscape::XML::Node *defsrepr = document->getDefs()->getRepr(); Inkscape::XML::Node *repr = xml_doc->createElement("svg:pattern"); repr->setAttribute("inkscape:collect", "always"); - Glib::ustring parent_ref = Glib::ustring::compose("#%1", pattern->getRepr()->attribute("id")); + Glib::ustring parent_ref = Glib::ustring::compose("#%1", getRepr()->attribute("id")); repr->setAttribute("xlink:href", parent_ref); defsrepr->addChild(repr, NULL); @@ -366,11 +359,10 @@ SPPattern *pattern_chain(SPPattern *pattern) return SP_PATTERN (child); } -SPPattern * -sp_pattern_clone_if_necessary (SPItem *item, SPPattern *pattern, const gchar *property) -{ - if (pattern->href.empty() || pattern->hrefcount > count_pattern_hrefs(item, pattern)) { - pattern = pattern_chain (pattern); +SPPattern *SPPattern::clone_if_necessary(SPItem *item, const gchar *property) { + SPPattern *pattern = this; + if (pattern->href.empty() || pattern->hrefcount > _count_hrefs(item)) { + pattern = _chain(); Glib::ustring href = Glib::ustring::compose("url(#%1)", pattern->getRepr()->attribute("id")); SPCSSAttr *css = sp_repr_css_attr_new (); @@ -381,23 +373,21 @@ sp_pattern_clone_if_necessary (SPItem *item, SPPattern *pattern, const gchar *pr return pattern; } -void -sp_pattern_transform_multiply (SPPattern *pattern, Geom::Affine postmul, bool set) -{ +void SPPattern::transform_multiply(Geom::Affine postmul, bool set) { // this formula is for a different interpretation of pattern transforms as described in (*) in sp-pattern.cpp // for it to work, we also need sp_object_read_attr( item, "transform"); //pattern->patternTransform = premul * item->transform * pattern->patternTransform * item->transform.inverse() * postmul; // otherwise the formula is much simpler if (set) { - pattern->patternTransform = postmul; + patternTransform = postmul; } else { - pattern->patternTransform = pattern->get_transform() * postmul; + patternTransform = get_transform() * postmul; } - pattern->patternTransform_set = true; + patternTransform_set = true; - Glib::ustring c=sp_svg_transform_write(pattern->patternTransform); - pattern->getRepr()->setAttribute("patternTransform", c); + Glib::ustring c=sp_svg_transform_write(patternTransform); + getRepr()->setAttribute("patternTransform", c); } const gchar *pattern_tile(const std::list &reprs, Geom::Rect bounds, @@ -436,14 +426,14 @@ const gchar *pattern_tile(const std::list &reprs, Geom::Re return pat_id; } -SPPattern *pattern_getroot(SPPattern *pat) +SPPattern *SPPattern::get_root() { - for (SPPattern *pat_i = pat; pat_i != NULL; pat_i = pat_i->ref ? pat_i->ref->getObject() : NULL) { + for (SPPattern *pat_i = this; pat_i != NULL; pat_i = pat_i->ref ? pat_i->ref->getObject() : NULL) { if ( pat_i->firstChild() ) { // find the first one with children return pat_i; } } - return pat; // document is broken, we can't get to root; but at least we can return pat which is supposedly a valid pattern + return this; // document is broken, we can't get to root; but at least we can return pat which is supposedly a valid pattern } diff --git a/src/sp-pattern.h b/src/sp-pattern.h index f2a1e1c6c..0c468d8f7 100644 --- a/src/sp-pattern.h +++ b/src/sp-pattern.h @@ -77,6 +77,10 @@ public: SPPattern::PatternUnits get_pattern_units() const; SPPattern::PatternUnits get_pattern_content_units() const; Geom::Affine const &get_transform() const; + SPPattern *get_root(); //TODO: const + + SPPattern *clone_if_necessary(SPItem *item, const gchar *property); + void transform_multiply(Geom::Affine postmul, bool set); virtual cairo_pattern_t* pattern_new(cairo_t *ct, Geom::OptRect const &bbox, double opacity); @@ -89,6 +93,12 @@ protected: private: bool _has_item_children() const; + SPPattern *_chain() const; + + /** + Count how many times pat is used by the styles of o and its descendants + */ + guint _count_hrefs(SPObject* o) const; }; @@ -105,14 +115,9 @@ protected: } }; -SPPattern *pattern_chain (SPPattern *pattern); -SPPattern *sp_pattern_clone_if_necessary (SPItem *item, SPPattern *pattern, const gchar *property); -void sp_pattern_transform_multiply (SPPattern *pattern, Geom::Affine postmul, bool set); const gchar *pattern_tile (const std::list &reprs, Geom::Rect bounds, SPDocument *document, Geom::Affine transform, Geom::Affine move); -SPPattern *pattern_getroot (SPPattern *pat); - #endif // SEEN_SP_PATTERN_H diff --git a/src/widgets/fill-style.cpp b/src/widgets/fill-style.cpp index d1d318abe..27ab7156c 100644 --- a/src/widgets/fill-style.cpp +++ b/src/widgets/fill-style.cpp @@ -304,7 +304,7 @@ void FillNStroke::performUpdate() psel->setGradientProperties( rg->getUnits(), rg->getSpread() ); } else if (SP_IS_PATTERN(server)) { - SPPattern *pat = pattern_getroot(SP_PATTERN(server)); + SPPattern *pat = SP_PATTERN(server)->get_root(); psel->updatePatternList( pat ); } } @@ -663,7 +663,7 @@ void FillNStroke::updateFromPaint() SPPaintServer *server = (kind == FILL) ? selobj->style->getFillPaintServer() : selobj->style->getStrokePaintServer(); - if (SP_IS_PATTERN(server) && pattern_getroot(SP_PATTERN(server)) == pattern) + if (SP_IS_PATTERN(server) && SP_PATTERN(server)->get_root() == pattern) // only if this object's pattern is not rooted in our selected pattern, apply continue; } diff --git a/src/widgets/paint-selector.cpp b/src/widgets/paint-selector.cpp index 9466c875e..39336267b 100644 --- a/src/widgets/paint-selector.cpp +++ b/src/widgets/paint-selector.cpp @@ -803,7 +803,7 @@ ink_pattern_list_get (SPDocument *source) GSList *pl = NULL; GSList const *patterns = source->getResourceList("pattern"); for (GSList *l = const_cast(patterns); l != NULL; l = l->next) { - if (SP_PATTERN(l->data) == pattern_getroot(SP_PATTERN(l->data))) { // only if this is a root pattern + if (SP_PATTERN(l->data) == SP_PATTERN(l->data)->get_root()) { // only if this is a root pattern pl = g_slist_prepend(pl, l->data); } } @@ -1123,7 +1123,7 @@ SPPattern *SPPaintSelector::getPattern() } g_free(paturn); } else { - pat = pattern_getroot(SP_PATTERN(patid)); + pat = SP_PATTERN(patid)->get_root(); } if (pat && !SP_IS_PATTERN(pat)) { -- cgit v1.2.3 From 85840ae655411c47248cd794a19dedd9ea3a591f Mon Sep 17 00:00:00 2001 From: Tomasz Boczkowski Date: Thu, 29 May 2014 12:04:56 +0200 Subject: SPPattern c++-sification: replaced function by methods pt3 (bzr r13341.6.22) --- src/selection-chemistry.cpp | 2 +- src/sp-pattern.cpp | 39 ++++++++++----------------------------- src/sp-pattern.h | 24 +++++++++++++++++++----- 3 files changed, 30 insertions(+), 35 deletions(-) (limited to 'src') diff --git a/src/selection-chemistry.cpp b/src/selection-chemistry.cpp index 069aa57bb..fa4589129 100644 --- a/src/selection-chemistry.cpp +++ b/src/selection-chemistry.cpp @@ -3265,7 +3265,7 @@ sp_selection_tile(SPDesktop *desktop, bool apply) int saved_compensation = prefs->getInt("/options/clonecompensation/value", SP_CLONE_COMPENSATION_UNMOVED); prefs->setInt("/options/clonecompensation/value", SP_CLONE_COMPENSATION_UNMOVED); - gchar const *pat_id = pattern_tile(repr_copies, bbox, doc, + gchar const *pat_id = SPPattern::produce(repr_copies, bbox, doc, ( Geom::Affine(Geom::Translate(desktop->dt2doc(Geom::Point(r->min()[Geom::X], r->max()[Geom::Y])))) * parent_transform.inverse() ), diff --git a/src/sp-pattern.cpp b/src/sp-pattern.cpp index bd24ab1bb..82e3cdacf 100644 --- a/src/sp-pattern.cpp +++ b/src/sp-pattern.cpp @@ -19,7 +19,8 @@ #include #include #include <2geom/transforms.h> -#include "macros.h" +#include + #include "svg/svg.h" #include "display/cairo-utils.h" #include "display/drawing-context.h" @@ -32,16 +33,6 @@ #include "style.h" #include "sp-pattern.h" #include "xml/repr.h" -#include "display/grayscale.h" - -#include -#include - -/* - * Pattern - */ -static void pattern_ref_changed(SPObject *old_ref, SPObject *ref, SPPattern *pat); -static void pattern_ref_modified (SPObject *ref, guint flags, SPPattern *pattern); #include "sp-factory.h" @@ -55,7 +46,7 @@ namespace { SPPattern::SPPattern() : SPPaintServer(), SPViewBox() { this->ref = new SPPatternReference(this); - this->ref->changedSignal().connect(sigc::bind(sigc::ptr_fun(pattern_ref_changed), this)); + this->ref->changedSignal().connect(sigc::mem_fun(this, &SPPattern::_on_ref_changed)); this->patternUnits = UNITS_OBJECTBOUNDINGBOX; this->patternUnits_set = false; @@ -284,31 +275,21 @@ void SPPattern::modified(unsigned int flags) { } } -/** -Gets called when the pattern is reattached to another -*/ -static void -pattern_ref_changed(SPObject *old_ref, SPObject *ref, SPPattern *pat) -{ +void SPPattern::_on_ref_changed(SPObject *old_ref, SPObject *ref) { if (old_ref) { - pat->modified_connection.disconnect(); + modified_connection.disconnect(); } if (SP_IS_PATTERN (ref)) { - pat->modified_connection = ref->connectModified(sigc::bind<2>(sigc::ptr_fun(&pattern_ref_modified), pat)); + modified_connection = ref->connectModified(sigc::mem_fun(this, &SPPattern::_on_ref_modified)); } - pattern_ref_modified (ref, 0, pat); + _on_ref_modified(ref, 0); } -/** -Gets called when the referenced is changed -*/ -static void pattern_ref_modified (SPObject */*ref*/, guint /*flags*/, SPPattern *pattern) +void SPPattern::_on_ref_modified(SPObject */*ref*/, guint /*flags*/) { - if ( SP_IS_OBJECT(pattern) ) { - pattern->requestModified(SP_OBJECT_MODIFIED_FLAG); - } + requestModified(SP_OBJECT_MODIFIED_FLAG); // Conditional to avoid causing infinite loop if there's a cycle in the href chain. } @@ -390,7 +371,7 @@ void SPPattern::transform_multiply(Geom::Affine postmul, bool set) { getRepr()->setAttribute("patternTransform", c); } -const gchar *pattern_tile(const std::list &reprs, Geom::Rect bounds, +const gchar *SPPattern::produce(const std::list &reprs, Geom::Rect bounds, SPDocument *document, Geom::Affine transform, Geom::Affine move) { typedef std::list::const_iterator NodePtrIterator; diff --git a/src/sp-pattern.h b/src/sp-pattern.h index 0c468d8f7..1eec0da7f 100644 --- a/src/sp-pattern.h +++ b/src/sp-pattern.h @@ -82,6 +82,14 @@ public: SPPattern *clone_if_necessary(SPItem *item, const gchar *property); void transform_multiply(Geom::Affine postmul, bool set); + /** + * @brief create a new pattern in XML tree + * @return created pattern id + */ + static const gchar *produce(const std::list &reprs, + Geom::Rect bounds, SPDocument *document, Geom::Affine transform, Geom::Affine move); + + virtual cairo_pattern_t* pattern_new(cairo_t *ct, Geom::OptRect const &bbox, double opacity); protected: @@ -96,9 +104,19 @@ private: SPPattern *_chain() const; /** - Count how many times pat is used by the styles of o and its descendants + Count how many times pattern is used by the styles of o and its descendants */ guint _count_hrefs(SPObject* o) const; + + /** + Gets called when the pattern is reattached to another + */ + void _on_ref_changed(SPObject *old_ref, SPObject *ref); + + /** + Gets called when the referenced is changed + */ + void _on_ref_modified(SPObject *ref, guint flags); }; @@ -115,10 +133,6 @@ protected: } }; - -const gchar *pattern_tile (const std::list &reprs, Geom::Rect bounds, SPDocument *document, Geom::Affine transform, Geom::Affine move); - - #endif // SEEN_SP_PATTERN_H /* -- cgit v1.2.3 From 35100d54d146fd0fcf702abca02311b0ef95152f Mon Sep 17 00:00:00 2001 From: Tomasz Boczkowski Date: Thu, 29 May 2014 12:35:19 +0200 Subject: SPPattern c++-sification: class fields are private (bzr r13341.6.23) --- src/knot-holder-entity.cpp | 8 ++++---- src/sp-pattern.cpp | 8 ++++---- src/sp-pattern.h | 37 ++++++++++++++++++------------------- 3 files changed, 26 insertions(+), 27 deletions(-) (limited to 'src') diff --git a/src/knot-holder-entity.cpp b/src/knot-holder-entity.cpp index 7b79d86a8..c3e48cf49 100644 --- a/src/knot-holder-entity.cpp +++ b/src/knot-holder-entity.cpp @@ -136,19 +136,19 @@ KnotHolderEntity::snap_knot_position_constrained(Geom::Point const &p, Inkscape: static gdouble sp_pattern_extract_theta(SPPattern const *pat) { - Geom::Affine transf = pat->patternTransform; + Geom::Affine transf = pat->get_transform(); return Geom::atan2(transf.xAxis()); } static Geom::Point sp_pattern_extract_scale(SPPattern const *pat) { - Geom::Affine transf = pat->patternTransform; + Geom::Affine transf = pat->get_transform(); return Geom::Point( transf.expansionX(), transf.expansionY() ); } static Geom::Point sp_pattern_extract_trans(SPPattern const *pat) { - return Geom::Point(pat->patternTransform[4], pat->patternTransform[5]); + return Geom::Point(pat->get_transform()[4], pat->get_transform()[5]); } void @@ -266,7 +266,7 @@ PatternKnotHolderEntityScale::knot_get() const gdouble x = pat->get_width(); gdouble y = pat->get_height(); Geom::Point delta = Geom::Point(x,y); - Geom::Affine a = pat->patternTransform; + Geom::Affine a = pat->get_transform(); a[4] = 0; a[5] = 0; delta = delta * a; diff --git a/src/sp-pattern.cpp b/src/sp-pattern.cpp index 82e3cdacf..c2835eadd 100644 --- a/src/sp-pattern.cpp +++ b/src/sp-pattern.cpp @@ -213,8 +213,8 @@ void SPPattern::set(unsigned int key, const gchar* value) { /* fixme: We need ::order_changed handler too (Lauris) */ -void pattern_getchildren(SPPattern *pat, std::list& l) -{ +void SPPattern::_get_children(std::list& l) { + SPPattern *pat = this; for (SPPattern *pat_i = pat; pat_i != NULL; pat_i = pat_i->ref ? pat_i->ref->getObject() : NULL) { if (pat_i->firstChild()) { // find the first one with children for (SPObject *child = pat->firstChild() ; child ; child = child->getNext() ) { @@ -235,7 +235,7 @@ void SPPattern::update(SPCtx* ctx, unsigned int flags) { flags &= SP_OBJECT_MODIFIED_CASCADE; std::list l; - pattern_getchildren (this, l); + _get_children(l); for (SPObjectIterator it = l.begin(); it != l.end(); it++) { SPObject *child = *it; @@ -260,7 +260,7 @@ void SPPattern::modified(unsigned int flags) { flags &= SP_OBJECT_MODIFIED_CASCADE; std::list l; - pattern_getchildren (this, l); + _get_children(l); for (SPObjectIterator it = l.begin(); it != l.end(); it++) { SPObject *child = *it; diff --git a/src/sp-pattern.h b/src/sp-pattern.h index 1eec0da7f..3fe0f53d8 100644 --- a/src/sp-pattern.h +++ b/src/sp-pattern.h @@ -51,24 +51,6 @@ public: Glib::ustring href; SPPatternReference *ref; - /* patternUnits and patternContentUnits attribute */ - PatternUnits patternUnits : 1; - bool patternUnits_set : 1; - PatternUnits patternContentUnits : 1; - bool patternContentUnits_set : 1; - /* patternTransform attribute */ - Geom::Affine patternTransform; - bool patternTransform_set : 1; - /* Tile rectangle */ - SVGLength x; - SVGLength y; - SVGLength width; - SVGLength height; - - sigc::connection modified_connection; - - bool isValid() const; - gdouble get_x() const; gdouble get_y() const; gdouble get_width() const; @@ -89,7 +71,7 @@ public: static const gchar *produce(const std::list &reprs, Geom::Rect bounds, SPDocument *document, Geom::Affine transform, Geom::Affine move); - + bool isValid() const; virtual cairo_pattern_t* pattern_new(cairo_t *ct, Geom::OptRect const &bbox, double opacity); protected: @@ -101,6 +83,7 @@ protected: private: bool _has_item_children() const; + void _get_children(std::list& l); SPPattern *_chain() const; /** @@ -117,6 +100,22 @@ private: Gets called when the referenced is changed */ void _on_ref_modified(SPObject *ref, guint flags); + + /* patternUnits and patternContentUnits attribute */ + PatternUnits patternUnits : 1; + bool patternUnits_set : 1; + PatternUnits patternContentUnits : 1; + bool patternContentUnits_set : 1; + /* patternTransform attribute */ + Geom::Affine patternTransform; + bool patternTransform_set : 1; + /* Tile rectangle */ + SVGLength x; + SVGLength y; + SVGLength width; + SVGLength height; + + sigc::connection modified_connection; }; -- cgit v1.2.3 From f92d08e05a6e8af396e9afda669e3f25d06ee7bf Mon Sep 17 00:00:00 2001 From: Tomasz Boczkowski Date: Thu, 29 May 2014 12:38:20 +0200 Subject: fixed possible bug SPPattern::_get_children (bzr r13341.6.24) --- src/sp-pattern.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/sp-pattern.cpp b/src/sp-pattern.cpp index c2835eadd..18eb78a27 100644 --- a/src/sp-pattern.cpp +++ b/src/sp-pattern.cpp @@ -214,10 +214,9 @@ void SPPattern::set(unsigned int key, const gchar* value) { /* fixme: We need ::order_changed handler too (Lauris) */ void SPPattern::_get_children(std::list& l) { - SPPattern *pat = this; - for (SPPattern *pat_i = pat; pat_i != NULL; pat_i = pat_i->ref ? pat_i->ref->getObject() : NULL) { + for (SPPattern *pat_i = this; pat_i != NULL; pat_i = pat_i->ref ? pat_i->ref->getObject() : NULL) { if (pat_i->firstChild()) { // find the first one with children - for (SPObject *child = pat->firstChild() ; child ; child = child->getNext() ) { + for (SPObject *child = pat_i->firstChild() ; child ; child = child->getNext() ) { l.push_back(child); } break; // do not go further up the chain if children are found -- cgit v1.2.3 From 1cf0f193c7848428a1cce2dfa40716608163fa33 Mon Sep 17 00:00:00 2001 From: Tomasz Boczkowski Date: Thu, 29 May 2014 13:59:08 +0200 Subject: SPColorSelector c++-sification: added SelectedColor class (bzr r13341.6.25) --- src/ui/Makefile_insert | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src') diff --git a/src/ui/Makefile_insert b/src/ui/Makefile_insert index 4081f86f8..75801886e 100644 --- a/src/ui/Makefile_insert +++ b/src/ui/Makefile_insert @@ -11,5 +11,7 @@ ink_common_sources += \ ui/previewfillable.h \ ui/previewholder.cpp \ ui/previewholder.h \ + ui/selected-color.h \ + ui/selected-color.cpp \ ui/uxmanager.cpp \ ui/uxmanager.h -- cgit v1.2.3 From 51eab9e9fdc5a520f91cb90ba101cedd62fd3eb4 Mon Sep 17 00:00:00 2001 From: Tomasz Boczkowski Date: Thu, 29 May 2014 18:21:29 +0200 Subject: SPColorSelector c++-sification: added SelectedColor class (bzr r13341.6.26) --- src/ui/selected-color.cpp | 92 +++++++++++++++++++++++++++++++++++++++++++++++ src/ui/selected-color.h | 55 ++++++++++++++++++++++++++++ 2 files changed, 147 insertions(+) create mode 100644 src/ui/selected-color.cpp create mode 100644 src/ui/selected-color.h (limited to 'src') diff --git a/src/ui/selected-color.cpp b/src/ui/selected-color.cpp new file mode 100644 index 000000000..246c51ebd --- /dev/null +++ b/src/ui/selected-color.cpp @@ -0,0 +1,92 @@ +/** @file + * Color selected in color selector widget. + * This file was created during the refactoring of SPColorSelector + *//* + * Authors: + * bulia byak + * Jon A. Cruz + * Tomasz Boczkowski + * + * Copyright (C) 2014 Authors + * Released under GNU GPL, read the file 'COPYING' for more information + */ +#include +#include + +#include "selected-color.h" + +double SelectedColor::_epsilon = 1e-4; + +SelectedColor::SelectedColor() + : _color(0) + , _alpha(1.0) + , _virgin(true) +{ + +} + +SelectedColor::~SelectedColor() { + +} + +void SelectedColor::set_color(const SPColor& color) +{ + set_color_alpha( color, _alpha ); +} + +SPColor SelectedColor::get_color() const +{ + return _color; +} + +void SelectedColor::set_alpha(gfloat alpha) +{ + g_return_if_fail( ( 0.0 <= alpha ) && ( alpha <= 1.0 ) ); + set_color_alpha( _color, alpha ); +} + +gfloat SelectedColor::get_alpha() const +{ + return _alpha; +} + +void SelectedColor::set_color_alpha(const SPColor& color, gfloat alpha, bool emit) +{ +#ifdef DUMP_CHANGE_INFO + g_message("SelectedColor::setColorAlpha( this=%p, %f, %f, %f, %s, %f, %s) in %s", this, color.v.c[0], color.v.c[1], color.v.c[2], (color.icc?color.icc->colorProfile.c_str():""), alpha, (emit?"YES":"no"), FOO_NAME(_csel)); +#endif + g_return_if_fail( ( 0.0 <= alpha ) && ( alpha <= 1.0 ) ); + +#ifdef DUMP_CHANGE_INFO + g_message("---- SelectedColor::setColorAlpha virgin:%s !close:%s alpha is:%s in %s", + (_virgin?"YES":"no"), + (!color.isClose( _color, _epsilon )?"YES":"no"), + ((fabs((_alpha) - (alpha)) >= _epsilon )?"YES":"no"), + FOO_NAME(_csel) + ); +#endif + + if ( _virgin || !color.isClose( _color, _epsilon ) || + (fabs((_alpha) - (alpha)) >= _epsilon )) { + + _virgin = false; + + _color = color; + _alpha = alpha; + + if (emit) { + signal_changed.emit(); + } +#ifdef DUMP_CHANGE_INFO + } else { + g_message("++++ SelectedColor::setColorAlpha color:%08x ==> _color:%08X isClose:%s in %s", color.toRGBA32(alpha), _color.toRGBA32(_alpha), + (color.isClose( _color, _epsilon )?"YES":"no"), FOO_NAME(_csel)); +#endif + } +} + +void SelectedColor::get_color_alpha(SPColor &color, gfloat &alpha) const { + color = _color; + alpha = _alpha; +} + diff --git a/src/ui/selected-color.h b/src/ui/selected-color.h new file mode 100644 index 000000000..f7f0d6ad0 --- /dev/null +++ b/src/ui/selected-color.h @@ -0,0 +1,55 @@ +/** @file + * Color selected in color selector widget. + * This file was created during the refactoring of SPColorSelector + *//* + * Authors: + * bulia byak + * Jon A. Cruz + * Tomasz Boczkowski + * + * Copyright (C) 2014 Authors + * Released under GNU GPL, read the file 'COPYING' for more information + */ +#ifndef SEEN_SELECTED_COLOR +#define SEEN_SELECTED_COLOR + +#include +#include "color.h" + +class SelectedColor +{ +public: + SelectedColor(); + virtual ~SelectedColor(); + + void set_color( const SPColor& color ); + SPColor get_color() const; + + void set_alpha( gfloat alpha ); + gfloat get_alpha() const; + + void set_color_alpha( const SPColor& color, gfloat alpha, bool emit = false ); + void get_color_alpha( SPColor &color, gfloat &alpha ) const; + + sigc::signal signal_changed; +private: + // By default, disallow copy constructor and assignment operator + SelectedColor( const SelectedColor& obj ); + SelectedColor& operator=( const SelectedColor& obj ); + + SPColor _color; + /** + * Color alpha value guaranteed to be in [0, 1]. + */ + gfloat _alpha; + + /** + * This flag is true if no color is set yet + */ + bool _virgin; + + static double _epsilon; +}; + +#endif + -- cgit v1.2.3 From e373a552e457bb9aec3a31cf7d3fd01ded3f330d Mon Sep 17 00:00:00 2001 From: Tomasz Boczkowski Date: Fri, 30 May 2014 13:28:00 +0200 Subject: SPColorSelector c++-sification: added ColorSelectorFactory (bzr r13341.6.27) --- src/ui/selected-color.cpp | 6 ++++++ src/ui/selected-color.h | 20 ++++++++++++++++++-- src/widgets/sp-color-icc-selector.cpp | 11 +++++++++++ src/widgets/sp-color-icc-selector.h | 9 ++++++++- src/widgets/sp-color-notebook.cpp | 2 +- src/widgets/sp-color-scales.cpp | 22 ++++++++++++++++++++++ src/widgets/sp-color-scales.h | 17 +++++++++++++++++ src/widgets/sp-color-wheel-selector.cpp | 14 ++++++++++++++ src/widgets/sp-color-wheel-selector.h | 9 +++++++++ 9 files changed, 106 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/ui/selected-color.cpp b/src/ui/selected-color.cpp index 246c51ebd..927c421b8 100644 --- a/src/ui/selected-color.cpp +++ b/src/ui/selected-color.cpp @@ -15,6 +15,9 @@ #include "selected-color.h" +namespace Inkscape { +namespace UI { + double SelectedColor::_epsilon = 1e-4; SelectedColor::SelectedColor() @@ -90,3 +93,6 @@ void SelectedColor::get_color_alpha(SPColor &color, gfloat &alpha) const { alpha = _alpha; } +} +} + diff --git a/src/ui/selected-color.h b/src/ui/selected-color.h index f7f0d6ad0..db2f2f68c 100644 --- a/src/ui/selected-color.h +++ b/src/ui/selected-color.h @@ -14,10 +14,13 @@ #define SEEN_SELECTED_COLOR #include +#include #include "color.h" -class SelectedColor -{ +namespace Inkscape { +namespace UI { + +class SelectedColor { public: SelectedColor(); virtual ~SelectedColor(); @@ -51,5 +54,18 @@ private: static double _epsilon; }; + +class ColorSelectorFactory { +public: + virtual ~ColorSelectorFactory() {} + + virtual Gtk::Widget* createWidget(SelectedColor& color) const = 0; + virtual Glib::ustring modeName() const = 0; +}; + + +} +} + #endif diff --git a/src/widgets/sp-color-icc-selector.cpp b/src/widgets/sp-color-icc-selector.cpp index ca64a915f..806ddba8d 100644 --- a/src/widgets/sp-color-icc-selector.cpp +++ b/src/widgets/sp-color-icc-selector.cpp @@ -270,6 +270,7 @@ static void sp_color_icc_selector_class_init(SPColorICCSelectorClass *klass) widget_class->hide = sp_color_icc_selector_hide; } +const gchar* ColorICCSelector::MODE_NAME = N_("CMS"); ColorICCSelector::ColorICCSelector( SPColorSelector* csel ) : ColorSelector( csel ), @@ -1123,6 +1124,16 @@ void ColorICCSelectorImpl::_sliderChanged() // iccSelector->_updateInternals( iccSelector->_color, ColorScales::getScaled( iccSelector->_adj ), iccSelector->_dragging ); } +Gtk::Widget *ColorICCSelectorFactory::createWidget(Inkscape::UI::SelectedColor &color) const { + GtkWidget *w = sp_color_selector_new(SP_TYPE_COLOR_ICC_SELECTOR); + Gtk::Widget *wrapped = Glib::wrap(w); + return wrapped; +} + +Glib::ustring ColorICCSelectorFactory::modeName() const { + return gettext(ColorICCSelector::MODE_NAME); +} + /* Local Variables: diff --git a/src/widgets/sp-color-icc-selector.h b/src/widgets/sp-color-icc-selector.h index f63ab0853..a59d3fe7e 100644 --- a/src/widgets/sp-color-icc-selector.h +++ b/src/widgets/sp-color-icc-selector.h @@ -5,6 +5,7 @@ #include #include "sp-color-selector.h" +#include "ui/selected-color.h" namespace Inkscape { class ColorProfile; @@ -18,6 +19,8 @@ class ColorICCSelectorImpl; class ColorICCSelector: public ColorSelector { public: + static const gchar* MODE_NAME; + ColorICCSelector( SPColorSelector* csel ); virtual ~ColorICCSelector(); @@ -58,7 +61,11 @@ GType sp_color_icc_selector_get_type(void); GtkWidget *sp_color_icc_selector_new(void); - +class ColorICCSelectorFactory: public Inkscape::UI::ColorSelectorFactory { +public: + Gtk::Widget* createWidget(Inkscape::UI::SelectedColor &color) const; + Glib::ustring modeName() const; +}; #endif // SEEN_SP_COLOR_ICC_SELECTOR_H diff --git a/src/widgets/sp-color-notebook.cpp b/src/widgets/sp-color-notebook.cpp index e081f98e0..367063790 100644 --- a/src/widgets/sp-color-notebook.cpp +++ b/src/widgets/sp-color-notebook.cpp @@ -360,7 +360,7 @@ void ColorNotebook::init() // uncomment to reenable the "show/hide modes" menu, // but first fix it so it remembers its settings in prefs and does not take that much space (entire vertical column!) - //gtk_table_attach (GTK_TABLE (table), align, 2, 3, row, row + 1, GTK_FILL, GTK_FILL, XPAD, YPAD); + gtk_table_attach (GTK_TABLE (table), align, 2, 3, row, row + 1, GTK_FILL, GTK_FILL, XPAD, YPAD); g_signal_connect_swapped(G_OBJECT(_btn), "event", G_CALLBACK (sp_color_notebook_menu_handler), G_OBJECT(_csel)); if ( !found ) diff --git a/src/widgets/sp-color-scales.cpp b/src/widgets/sp-color-scales.cpp index 94950e937..97933d949 100644 --- a/src/widgets/sp-color-scales.cpp +++ b/src/widgets/sp-color-scales.cpp @@ -53,6 +53,12 @@ static SPColorSelectorClass *parent_class; #define noDUMP_CHANGE_INFO 1 +const gchar* ColorScales::SUBMODE_NAMES[] = { + N_("RGB"), + N_("HSL"), + N_("CMYK") +}; + GType sp_color_scales_get_type (void) { @@ -754,4 +760,20 @@ sp_color_scales_hue_map (void) return map; } +ColorScalesFactory::ColorScalesFactory(SPColorScalesMode submode) + : _submode(submode) +{ +} + +ColorScalesFactory::~ColorScalesFactory() { +} + +Gtk::Widget *ColorScalesFactory::createWidget(Inkscape::UI::SelectedColor &color) const { + GtkWidget *w = sp_color_selector_new(SP_TYPE_COLOR_SCALES); + Gtk::Widget *wrapped = Glib::wrap(w); + return wrapped; +} +Glib::ustring ColorScalesFactory::modeName() const { + return gettext(ColorScales::SUBMODE_NAMES[_submode]); +} diff --git a/src/widgets/sp-color-scales.h b/src/widgets/sp-color-scales.h index 06b8f3859..946f0935e 100644 --- a/src/widgets/sp-color-scales.h +++ b/src/widgets/sp-color-scales.h @@ -15,6 +15,7 @@ #include #include +#include "ui/selected-color.h" struct SPColorScales; struct SPColorScalesClass; @@ -41,6 +42,8 @@ typedef enum { class ColorScales: public ColorSelector { public: + static const gchar* SUBMODE_NAMES[]; + static gfloat getScaled( const GtkAdjustment *a ); static void setScaled( GtkAdjustment *a, gfloat v); @@ -108,6 +111,20 @@ GType sp_color_scales_get_type(); GtkWidget *sp_color_scales_new(); + +class ColorScalesFactory: public Inkscape::UI::ColorSelectorFactory { +public: + ColorScalesFactory(SPColorScalesMode submode); + ~ColorScalesFactory(); + + Gtk::Widget *createWidget(Inkscape::UI::SelectedColor &color) const; + Glib::ustring modeName() const; + +private: + SPColorScalesMode _submode; +}; + + #endif /* !SEEN_SP_COLOR_SCALES_H */ /* diff --git a/src/widgets/sp-color-wheel-selector.cpp b/src/widgets/sp-color-wheel-selector.cpp index 2100f555c..e41a312a1 100644 --- a/src/widgets/sp-color-wheel-selector.cpp +++ b/src/widgets/sp-color-wheel-selector.cpp @@ -32,6 +32,9 @@ static SPColorSelectorClass *parent_class; #define XPAD 4 #define YPAD 1 + +const gchar* ColorWheelSelector::MODE_NAME = N_("Wheel"); + GType sp_color_wheel_selector_get_type (void) { @@ -341,6 +344,17 @@ void ColorWheelSelector::_wheelChanged( GimpColorWheel *wheel, SPColorWheelSelec } +Gtk::Widget *ColorWheelSelectorFactory::createWidget(Inkscape::UI::SelectedColor &color) const { + GtkWidget *w = sp_color_selector_new(SP_TYPE_COLOR_WHEEL_SELECTOR); + Gtk::Widget *wrapped = Glib::wrap(w); + return wrapped; +} + +Glib::ustring ColorWheelSelectorFactory::modeName() const { + return gettext(ColorWheelSelector::MODE_NAME); +} + + /* Local Variables: mode:c++ diff --git a/src/widgets/sp-color-wheel-selector.h b/src/widgets/sp-color-wheel-selector.h index bb6078906..ad0d11bad 100644 --- a/src/widgets/sp-color-wheel-selector.h +++ b/src/widgets/sp-color-wheel-selector.h @@ -13,6 +13,7 @@ #include #include "sp-color-selector.h" +#include "ui/selected-color.h" typedef struct _GimpColorWheel GimpColorWheel; struct SPColorWheelSelector; @@ -31,6 +32,8 @@ class ColorSlider; class ColorWheelSelector: public ColorSelector { public: + static const gchar* MODE_NAME; + ColorWheelSelector( SPColorSelector* csel ); virtual ~ColorWheelSelector(); @@ -87,6 +90,12 @@ GType sp_color_wheel_selector_get_type (void); GtkWidget *sp_color_wheel_selector_new (void); +class ColorWheelSelectorFactory: public Inkscape::UI::ColorSelectorFactory { +public: + Gtk::Widget *createWidget(Inkscape::UI::SelectedColor &color) const; + Glib::ustring modeName() const; +}; + #endif // SEEN_SP_COLOR_WHEEL_SELECTOR_H -- cgit v1.2.3 From 17055d029cc8732d1b2636b9e98338c8e7056558 Mon Sep 17 00:00:00 2001 From: Tomasz Boczkowski Date: Fri, 30 May 2014 15:55:34 +0200 Subject: SPColorNotebok c++-sification - available pages list (bzr r13341.6.28) --- src/extension/param/parameter.cpp | 4 ++ src/ui/selected-color.cpp | 5 ++- src/ui/selected-color.h | 8 ++++ src/widgets/sp-color-icc-selector.cpp | 2 +- src/widgets/sp-color-notebook.cpp | 65 +++++++++++++++++++++++++++++---- src/widgets/sp-color-notebook.h | 28 ++++++++++++-- src/widgets/sp-color-scales.cpp | 11 +++++- src/widgets/sp-color-selector.cpp | 5 ++- src/widgets/sp-color-selector.h | 8 ++++ src/widgets/sp-color-wheel-selector.cpp | 2 +- 10 files changed, 121 insertions(+), 17 deletions(-) (limited to 'src') diff --git a/src/extension/param/parameter.cpp b/src/extension/param/parameter.cpp index 202b8110f..b18525215 100644 --- a/src/extension/param/parameter.cpp +++ b/src/extension/param/parameter.cpp @@ -15,6 +15,10 @@ # include "config.h" #endif +#if GLIBMM_DISABLE_DEPRECATED && HAVE_GLIBMM_THREADS_H +#include +#endif + #ifdef linux // does the dollar sign need escaping when passed as string parameter? # define ESCAPE_DOLLAR_COMMANDLINE #endif diff --git a/src/ui/selected-color.cpp b/src/ui/selected-color.cpp index 927c421b8..f61c3b7f8 100644 --- a/src/ui/selected-color.cpp +++ b/src/ui/selected-color.cpp @@ -10,11 +10,12 @@ * Copyright (C) 2014 Authors * Released under GNU GPL, read the file 'COPYING' for more information */ -#include -#include #include "selected-color.h" +#include +#include + namespace Inkscape { namespace UI { diff --git a/src/ui/selected-color.h b/src/ui/selected-color.h index db2f2f68c..a56ee6afb 100644 --- a/src/ui/selected-color.h +++ b/src/ui/selected-color.h @@ -13,6 +13,14 @@ #ifndef SEEN_SELECTED_COLOR #define SEEN_SELECTED_COLOR +#ifdef HAVE_CONFIG_H +# include +#endif + +#if GLIBMM_DISABLE_DEPRECATED && HAVE_GLIBMM_THREADS_H +#include +#endif + #include #include #include "color.h" diff --git a/src/widgets/sp-color-icc-selector.cpp b/src/widgets/sp-color-icc-selector.cpp index 806ddba8d..69818ba99 100644 --- a/src/widgets/sp-color-icc-selector.cpp +++ b/src/widgets/sp-color-icc-selector.cpp @@ -1126,7 +1126,7 @@ void ColorICCSelectorImpl::_sliderChanged() Gtk::Widget *ColorICCSelectorFactory::createWidget(Inkscape::UI::SelectedColor &color) const { GtkWidget *w = sp_color_selector_new(SP_TYPE_COLOR_ICC_SELECTOR); - Gtk::Widget *wrapped = Glib::wrap(w); + Gtk::Widget *wrapped = Gtk::manage(Glib::wrap(w)); return wrapped; } diff --git a/src/widgets/sp-color-notebook.cpp b/src/widgets/sp-color-notebook.cpp index 367063790..923a4480f 100644 --- a/src/widgets/sp-color-notebook.cpp +++ b/src/widgets/sp-color-notebook.cpp @@ -24,6 +24,7 @@ #include #include #include +#include #include "../dialogs/dialog-events.h" #include "../preferences.h" @@ -53,6 +54,7 @@ struct SPColorNotebookTracker { SPColorNotebook *backPointer; }; + static void sp_color_notebook_class_init (SPColorNotebookClass *klass); static void sp_color_notebook_init (SPColorNotebook *colorbook); static void sp_color_notebook_dispose(GObject *object); @@ -264,16 +266,11 @@ void ColorNotebook::init() #endif gtk_widget_show (_buttonbox); - _buttons = new GtkWidget *[_trackerList->len]; + _buttons = new GtkWidget *[_available_pages.size()]; - for ( i = 0; i < _trackerList->len; i++ ) + for ( i = 0; i < _available_pages.size(); i++ ) { - SPColorNotebookTracker *entry = - reinterpret_cast< SPColorNotebookTracker* > (g_ptr_array_index (_trackerList, i)); - if ( entry ) - { - addPage(entry->type, entry->submode); - } + _addPage(_available_pages[i]); } #if GTK_CHECK_VERSION(3,0,0) @@ -507,6 +504,20 @@ GtkWidget *sp_color_notebook_new() ColorNotebook::ColorNotebook( SPColorSelector* csel ) : ColorSelector( csel ) { + Page *page; + + page = new Page(new ColorScalesFactory(SP_COLOR_SCALES_MODE_RGB), true); + _available_pages.push_back(page); + page = new Page(new ColorScalesFactory(SP_COLOR_SCALES_MODE_HSV), true); + _available_pages.push_back(page); + page = new Page(new ColorScalesFactory(SP_COLOR_SCALES_MODE_CMYK), true); + _available_pages.push_back(page); + page = new Page(new ColorWheelSelectorFactory, true); + _available_pages.push_back(page); +#if defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) + page = new Page(new ColorICCSelectorFactory, true); + _available_pages.push_back(page); +#endif } SPColorSelector* ColorNotebook::getCurrentSelector() @@ -526,6 +537,12 @@ SPColorSelector* ColorNotebook::getCurrentSelector() return csel; } +ColorNotebook::Page::Page(Inkscape::UI::ColorSelectorFactory *selector_factory, bool enabled_full) + : selector_factory(selector_factory) + , enabled_full(enabled_full) +{ +} + void ColorNotebook::_colorChanged() { SPColorSelector* cselPage = getCurrentSelector(); @@ -769,6 +786,38 @@ GtkWidget* ColorNotebook::addPage(GType page_type, guint submode) return page; } +GtkWidget* ColorNotebook::_addPage(Page& page) { + Gtk::Widget *selector_widget; + + selector_widget = page.selector_factory->createWidget(_selected_color); + if (selector_widget) { + selector_widget->show(); + + Glib::ustring mode_name = page.selector_factory->modeName(); + Gtk::Widget* tab_label = Gtk::manage(new Gtk::Label(mode_name)); + gint page_num = gtk_notebook_append_page( GTK_NOTEBOOK(_book), selector_widget->gobj(), tab_label->gobj()); + + _buttons[page_num] = gtk_radio_button_new_with_label(NULL, mode_name.c_str()); + gtk_toggle_button_set_mode(GTK_TOGGLE_BUTTON(_buttons[page_num]), FALSE); + if (page_num > 0) { + GSList *group = gtk_radio_button_get_group (GTK_RADIO_BUTTON(_buttons[0])); + gtk_radio_button_set_group (GTK_RADIO_BUTTON(_buttons[page_num]), group); + } + gtk_widget_show (_buttons[page_num]); + gtk_box_pack_start (GTK_BOX (_buttonbox), _buttons[page_num], TRUE, TRUE, 0); + + g_signal_connect (G_OBJECT (_buttons[page_num]), "clicked", G_CALLBACK (_buttonClicked), _csel); + + //Connect glib signals of non-refactored widgets + g_signal_connect (selector_widget->gobj(), "grabbed", G_CALLBACK (_entryGrabbed), _csel); + g_signal_connect (selector_widget->gobj(), "dragged", G_CALLBACK (_entryDragged), _csel); + g_signal_connect (selector_widget->gobj(), "released", G_CALLBACK (_entryReleased), _csel); + g_signal_connect (selector_widget->gobj(), "changed", G_CALLBACK (_entryChanged), _csel); + } + + return selector_widget->gobj(); +} + GtkWidget* ColorNotebook::getPage(GType page_type, guint submode) { gint count = 0; diff --git a/src/widgets/sp-color-notebook.h b/src/widgets/sp-color-notebook.h index 6e5111132..5db278e3f 100644 --- a/src/widgets/sp-color-notebook.h +++ b/src/widgets/sp-color-notebook.h @@ -12,12 +12,21 @@ * This code is in public domain */ -#include -#include "../color.h" -#include "sp-color-selector.h" +#ifdef HAVE_CONFIG_H +# include +#endif +#if GLIBMM_DISABLE_DEPRECATED && HAVE_GLIBMM_THREADS_H +#include +#endif + +#include +#include #include +#include "../color.h" +#include "sp-color-selector.h" +#include "ui/selected-color.h" struct SPColorNotebook; @@ -40,6 +49,13 @@ public: gint menuHandler( GdkEvent* event ); protected: + struct Page { + Page(Inkscape::UI::ColorSelectorFactory *selector_factory, bool enabled_full); + + Inkscape::UI::ColorSelectorFactory *selector_factory; + bool enabled_full; + }; + static void _rgbaEntryChangedHook( GtkEntry* entry, SPColorNotebook *colorbook ); static void _entryGrabbed( SPColorSelector *csel, SPColorNotebook *colorbook ); static void _entryDragged( SPColorSelector *csel, SPColorNotebook *colorbook ); @@ -55,6 +71,9 @@ protected: void _updateRgbaEntry( const SPColor& color, gfloat alpha ); void _setCurrentPage(int i); + GtkWidget* _addPage(Page& page); + + Inkscape::UI::SelectedColor _selected_color; gboolean _updating : 1; gboolean _updatingrgba : 1; gboolean _dragging : 1; @@ -72,6 +91,7 @@ protected: GtkWidget *_btn; GtkWidget *_popup; GPtrArray *_trackerList; + boost::ptr_vector _available_pages; private: // By default, disallow copy constructor and assignment operator @@ -81,6 +101,8 @@ private: + + #define SP_TYPE_COLOR_NOTEBOOK (sp_color_notebook_get_type ()) #define SP_COLOR_NOTEBOOK(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), SP_TYPE_COLOR_NOTEBOOK, SPColorNotebook)) #define SP_COLOR_NOTEBOOK_CLASS(k) (G_TYPE_CHECK_CLASS_CAST ((k), SP_TYPE_COLOR_NOTEBOOK, SPColorNotebookClass)) diff --git a/src/widgets/sp-color-scales.cpp b/src/widgets/sp-color-scales.cpp index 97933d949..d7466be98 100644 --- a/src/widgets/sp-color-scales.cpp +++ b/src/widgets/sp-color-scales.cpp @@ -54,6 +54,7 @@ static SPColorSelectorClass *parent_class; #define noDUMP_CHANGE_INFO 1 const gchar* ColorScales::SUBMODE_NAMES[] = { + N_("None"), N_("RGB"), N_("HSL"), N_("CMYK") @@ -770,7 +771,15 @@ ColorScalesFactory::~ColorScalesFactory() { Gtk::Widget *ColorScalesFactory::createWidget(Inkscape::UI::SelectedColor &color) const { GtkWidget *w = sp_color_selector_new(SP_TYPE_COLOR_SCALES); - Gtk::Widget *wrapped = Glib::wrap(w); + SPColorSelector* csel; + + csel = SP_COLOR_SELECTOR (w); + if ( _submode > 0 ) + { + csel->base->setSubmode( _submode - 1 ); + } + + Gtk::Widget *wrapped = Gtk::manage(Glib::wrap(w)); return wrapped; } diff --git a/src/widgets/sp-color-selector.cpp b/src/widgets/sp-color-selector.cpp index 6d62acecd..05af162ef 100644 --- a/src/widgets/sp-color-selector.cpp +++ b/src/widgets/sp-color-selector.cpp @@ -6,10 +6,13 @@ #ifdef HAVE_CONFIG_H # include "config.h" #endif + +#include "sp-color-selector.h" + #include #include #include -#include "sp-color-selector.h" + enum { GRABBED, diff --git a/src/widgets/sp-color-selector.h b/src/widgets/sp-color-selector.h index 616d5a9e7..560b4c59d 100644 --- a/src/widgets/sp-color-selector.h +++ b/src/widgets/sp-color-selector.h @@ -1,6 +1,14 @@ #ifndef SEEN_SP_COLOR_SELECTOR_H #define SEEN_SP_COLOR_SELECTOR_H +#ifdef HAVE_CONFIG_H +# include +#endif + +#if GLIBMM_DISABLE_DEPRECATED && HAVE_GLIBMM_THREADS_H +#include +#endif + #include #include "../color.h" diff --git a/src/widgets/sp-color-wheel-selector.cpp b/src/widgets/sp-color-wheel-selector.cpp index e41a312a1..15177377d 100644 --- a/src/widgets/sp-color-wheel-selector.cpp +++ b/src/widgets/sp-color-wheel-selector.cpp @@ -346,7 +346,7 @@ void ColorWheelSelector::_wheelChanged( GimpColorWheel *wheel, SPColorWheelSelec Gtk::Widget *ColorWheelSelectorFactory::createWidget(Inkscape::UI::SelectedColor &color) const { GtkWidget *w = sp_color_selector_new(SP_TYPE_COLOR_WHEEL_SELECTOR); - Gtk::Widget *wrapped = Glib::wrap(w); + Gtk::Widget *wrapped = Gtk::manage(Glib::wrap(w)); return wrapped; } -- cgit v1.2.3 From cee4e3c55c0d455f10da9bd30fc18f8d1f1e531c Mon Sep 17 00:00:00 2001 From: Tomasz Boczkowski Date: Fri, 30 May 2014 16:37:08 +0200 Subject: SPColorNotebok c++-sification - removed trackerList, commented out unused pop-up menu (bzr r13341.6.29) --- src/widgets/sp-color-notebook.cpp | 196 ++++++++++---------------------------- src/widgets/sp-color-notebook.h | 24 +++-- 2 files changed, 67 insertions(+), 153 deletions(-) (limited to 'src') diff --git a/src/widgets/sp-color-notebook.cpp b/src/widgets/sp-color-notebook.cpp index 923a4480f..364e81ae5 100644 --- a/src/widgets/sp-color-notebook.cpp +++ b/src/widgets/sp-color-notebook.cpp @@ -141,47 +141,6 @@ void ColorNotebook::switchPage(GtkNotebook*, } } -static gint sp_color_notebook_menu_handler( GtkWidget *widget, GdkEvent *event ) -{ - if (event->type == GDK_BUTTON_PRESS) - { - SPColorSelector* csel = SP_COLOR_SELECTOR(widget); - (dynamic_cast(csel->base))->menuHandler( event ); - - /* Tell calling code that we have handled this event; the buck - * stops here. */ - return TRUE; - } - - /* Tell calling code that we have not handled this event; pass it on. */ - return FALSE; -} - -gint ColorNotebook::menuHandler( GdkEvent* event ) -{ - GdkEventButton *bevent = (GdkEventButton *) event; - gtk_menu_popup (GTK_MENU( _popup ), NULL, NULL, NULL, NULL, - bevent->button, bevent->time); - return TRUE; -} - -static void sp_color_notebook_menuitem_response (GtkMenuItem *menuitem, gpointer user_data) -{ - gboolean active = gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (menuitem)); - SPColorNotebookTracker *entry = reinterpret_cast< SPColorNotebookTracker* > (user_data); - if ( entry ) - { - if ( active ) - { - (dynamic_cast(SP_COLOR_SELECTOR(entry->backPointer)->base))->addPage(entry->type, entry->submode); - } - else - { - (dynamic_cast(SP_COLOR_SELECTOR(entry->backPointer)->base))->removePage(entry->type, entry->submode); - } - } -} - static void sp_color_notebook_init (SPColorNotebook *colorbook) { @@ -196,28 +155,9 @@ sp_color_notebook_init (SPColorNotebook *colorbook) void ColorNotebook::init() { guint row = 0; - guint i = 0; - guint j = 0; - GType *selector_types = 0; - guint selector_type_count = 0; - - /* tempory hardcoding to get types loaded */ - SP_TYPE_COLOR_SCALES; - SP_TYPE_COLOR_WHEEL_SELECTOR; -#if defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) - SP_TYPE_COLOR_ICC_SELECTOR; -#endif // defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) - - /* REJON: Comment out the next line to not use the normal GTK Color - wheel. */ - -// SP_TYPE_COLOR_GTKSELECTOR; _updating = FALSE; _updatingrgba = FALSE; - _btn = 0; - _popup = 0; - _trackerList = g_ptr_array_new (); _book = gtk_notebook_new (); gtk_widget_show (_book); @@ -226,38 +166,6 @@ void ColorNotebook::init() gtk_notebook_set_show_border (GTK_NOTEBOOK (_book), false); gtk_notebook_set_show_tabs (GTK_NOTEBOOK (_book), false); - selector_types = g_type_children (SP_TYPE_COLOR_SELECTOR, &selector_type_count); - - for ( i = 0; i < selector_type_count; i++ ) - { - if (!g_type_is_a (selector_types[i], SP_TYPE_COLOR_NOTEBOOK)) - { - guint howmany = 1; - gpointer klass = g_type_class_ref (selector_types[i]); - if ( klass && SP_IS_COLOR_SELECTOR_CLASS(klass) ) - { - SPColorSelectorClass *ck = SP_COLOR_SELECTOR_CLASS (klass); - howmany = MAX (1, ck->submode_count); - for ( j = 0; j < howmany; j++ ) - { - SPColorNotebookTracker *entry = reinterpret_cast< SPColorNotebookTracker* > (malloc(sizeof(SPColorNotebookTracker))); - if ( entry ) - { - memset( entry, 0, sizeof(SPColorNotebookTracker) ); - entry->name = ck->name[j]; - entry->type = selector_types[i]; - entry->submode = j; - entry->enabledFull = TRUE; - entry->enabledBrief = TRUE; - entry->backPointer = SP_COLOR_NOTEBOOK(_csel); - - g_ptr_array_add (_trackerList, entry); - } - } - } - } - } - #if GTK_CHECK_VERSION(3,0,0) _buttonbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 2); gtk_box_set_homogeneous(GTK_BOX(_buttonbox), TRUE); @@ -268,7 +176,7 @@ void ColorNotebook::init() gtk_widget_show (_buttonbox); _buttons = new GtkWidget *[_available_pages.size()]; - for ( i = 0; i < _available_pages.size(); i++ ) + for (int i = 0; static_cast(i) < _available_pages.size(); i++ ) { _addPage(_available_pages[i]); } @@ -321,13 +229,15 @@ void ColorNotebook::init() Inkscape::Preferences *prefs = Inkscape::Preferences::get(); _setCurrentPage(prefs->getInt("/colorselector/page", 0)); + + /* Commented out: see comment at the bottom of the header file { gboolean found = FALSE; _popup = gtk_menu_new(); GtkMenu *menu = GTK_MENU (_popup); - for ( i = 0; i < _trackerList->len; i++ ) + for (int i = 0; i < _trackerList->len; i++ ) { SPColorNotebookTracker *entry = reinterpret_cast< SPColorNotebookTracker* > (g_ptr_array_index (_trackerList, i)); if ( entry ) @@ -365,6 +275,7 @@ void ColorNotebook::init() gtk_widget_set_sensitive (_btn, FALSE); } } + */ row++; @@ -403,7 +314,6 @@ void ColorNotebook::init() GtkWidget *picker = gtk_image_new_from_icon_name ("color-picker", GTK_ICON_SIZE_SMALL_TOOLBAR); _btn_picker = gtk_button_new (); gtk_button_set_relief(GTK_BUTTON(_btn_picker), GTK_RELIEF_NONE); - gtk_widget_show (_btn); gtk_container_add (GTK_CONTAINER (_btn_picker), picker); gtk_widget_set_tooltip_text (_btn_picker, _("Pick colors from image")); gtk_box_pack_start(GTK_BOX(rgbabox), _btn_picker, FALSE, FALSE, 2); @@ -460,12 +370,6 @@ static void sp_color_notebook_dispose(GObject *object) ColorNotebook::~ColorNotebook() { - if ( _trackerList ) - { - g_ptr_array_free (_trackerList, TRUE); - _trackerList = 0; - } - if ( _switchId ) { if ( _book ) @@ -670,7 +574,7 @@ void ColorNotebook::_setCurrentPage(int i) { gtk_notebook_set_current_page(GTK_NOTEBOOK(_book), i); - if (_buttons && _trackerList && (static_cast(i) < _trackerList->len) ) { + if (_buttons && (static_cast(i) < _available_pages.size())) { gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(_buttons[i]), TRUE); } } @@ -744,48 +648,6 @@ void ColorNotebook::_entryModified (SPColorSelector *csel, SPColorNotebook *colo nb->_updateInternals( color, alpha, nb->_dragging ); } -GtkWidget* ColorNotebook::addPage(GType page_type, guint submode) -{ - GtkWidget *page; - - page = sp_color_selector_new( page_type ); - if ( page ) - { - GtkWidget* tab_label = 0; - SPColorSelector* csel; - - csel = SP_COLOR_SELECTOR (page); - if ( submode > 0 ) - { - csel->base->setSubmode( submode ); - } - gtk_widget_show (page); - int index = csel->base ? csel->base->getSubmode() : 0; - const gchar* str = _(SP_COLOR_SELECTOR_GET_CLASS (csel)->name[index]); -// g_message( "Hitting up for tab for '%s'", str ); - tab_label = gtk_label_new(_(str)); - gint pageNum = gtk_notebook_append_page( GTK_NOTEBOOK (_book), page, tab_label ); - - // Add a button for each page - _buttons[pageNum] = gtk_radio_button_new_with_label(NULL, _(str)); - gtk_toggle_button_set_mode(GTK_TOGGLE_BUTTON(_buttons[pageNum]), FALSE); - if (pageNum > 0) { - GSList *group = gtk_radio_button_get_group (GTK_RADIO_BUTTON(_buttons[0])); - gtk_radio_button_set_group (GTK_RADIO_BUTTON(_buttons[pageNum]), group); - } - gtk_widget_show (_buttons[pageNum]); - gtk_box_pack_start (GTK_BOX (_buttonbox), _buttons[pageNum], TRUE, TRUE, 0); - - g_signal_connect (G_OBJECT (_buttons[pageNum]), "clicked", G_CALLBACK (_buttonClicked), _csel); - g_signal_connect (G_OBJECT (page), "grabbed", G_CALLBACK (_entryGrabbed), _csel); - g_signal_connect (G_OBJECT (page), "dragged", G_CALLBACK (_entryDragged), _csel); - g_signal_connect (G_OBJECT (page), "released", G_CALLBACK (_entryReleased), _csel); - g_signal_connect (G_OBJECT (page), "changed", G_CALLBACK (_entryChanged), _csel); - } - - return page; -} - GtkWidget* ColorNotebook::_addPage(Page& page) { Gtk::Widget *selector_widget; @@ -818,6 +680,9 @@ GtkWidget* ColorNotebook::_addPage(Page& page) { return selector_widget->gobj(); } + +/* Commented out: see comment at the bottom of the header file + GtkWidget* ColorNotebook::getPage(GType page_type, guint submode) { gint count = 0; @@ -873,6 +738,49 @@ void ColorNotebook::removePage( GType page_type, guint submode ) } } + +static gint sp_color_notebook_menu_handler( GtkWidget *widget, GdkEvent *event ) +{ + if (event->type == GDK_BUTTON_PRESS) + { + SPColorSelector* csel = SP_COLOR_SELECTOR(widget); + (dynamic_cast(csel->base))->menuHandler( event ); + + // Tell calling code that we have handled this event; the buck + // stops here. + return TRUE; + } + + //Tell calling code that we have not handled this event; pass it on. + return FALSE; +} + +gint ColorNotebook::menuHandler( GdkEvent* event ) +{ + GdkEventButton *bevent = (GdkEventButton *) event; + gtk_menu_popup (GTK_MENU( _popup ), NULL, NULL, NULL, NULL, + bevent->button, bevent->time); + return TRUE; +} + +static void sp_color_notebook_menuitem_response (GtkMenuItem *menuitem, gpointer user_data) +{ + gboolean active = gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (menuitem)); + SPColorNotebookTracker *entry = reinterpret_cast< SPColorNotebookTracker* > (user_data); + if ( entry ) + { + if ( active ) + { + (dynamic_cast(SP_COLOR_SELECTOR(entry->backPointer)->base))->addPage(entry->type, entry->submode); + } + else + { + (dynamic_cast(SP_COLOR_SELECTOR(entry->backPointer)->base))->removePage(entry->type, entry->submode); + } + } +} +*/ + /* Local Variables: mode:c++ diff --git a/src/widgets/sp-color-notebook.h b/src/widgets/sp-color-notebook.h index 5db278e3f..f688d9210 100644 --- a/src/widgets/sp-color-notebook.h +++ b/src/widgets/sp-color-notebook.h @@ -42,12 +42,6 @@ public: SPColorSelector* getCurrentSelector(); void switchPage( GtkNotebook *notebook, GtkWidget *page, guint page_num ); - GtkWidget* addPage( GType page_type, guint submode ); - void removePage( GType page_type, guint submode ); - GtkWidget* getPage( GType page_type, guint submode ); - - gint menuHandler( GdkEvent* event ); - protected: struct Page { Page(Inkscape::UI::ColorSelectorFactory *selector_factory, bool enabled_full); @@ -88,15 +82,27 @@ protected: #endif //defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) GtkWidget *_btn_picker; GtkWidget *_p; /* Color preview */ - GtkWidget *_btn; - GtkWidget *_popup; - GPtrArray *_trackerList; boost::ptr_vector _available_pages; private: // By default, disallow copy constructor and assignment operator ColorNotebook( const ColorNotebook& obj ); ColorNotebook& operator=( const ColorNotebook& obj ); + + /* Following methods support the pop-up menu to choose + * active color selectors (notebook tabs). This function + * is not used in Inkscape. If you want to re-enable it you have to + * * port the code to c++ + * * fix it so it remembers its settings in prefs + * * fix it so it does not take that much space (entire vertical column!) + * Current class design supports dynamic addtion and removal of color selectors + * + GtkWidget* addPage( GType page_type, guint submode ); + void removePage( GType page_type, guint submode ); + GtkWidget* getPage( GType page_type, guint submode ); + gint menuHandler( GdkEvent* event ); + + */ }; -- cgit v1.2.3 From 7a205911659013dea26f1554158cc050fdff20bc Mon Sep 17 00:00:00 2001 From: Tomasz Boczkowski Date: Fri, 30 May 2014 18:47:23 +0200 Subject: changed coding style of SelectedColor (bzr r13341.6.30) --- src/ui/selected-color.cpp | 32 +++++++++++++++++++++----------- src/ui/selected-color.h | 46 +++++++++++++++++++++++++++------------------- 2 files changed, 48 insertions(+), 30 deletions(-) (limited to 'src') diff --git a/src/ui/selected-color.cpp b/src/ui/selected-color.cpp index f61c3b7f8..296b15796 100644 --- a/src/ui/selected-color.cpp +++ b/src/ui/selected-color.cpp @@ -19,7 +19,7 @@ namespace Inkscape { namespace UI { -double SelectedColor::_epsilon = 1e-4; +double const SelectedColor::_EPSILON = 1e-4; SelectedColor::SelectedColor() : _color(0) @@ -33,28 +33,28 @@ SelectedColor::~SelectedColor() { } -void SelectedColor::set_color(const SPColor& color) +void SelectedColor::setColor(SPColor const &color) { - set_color_alpha( color, _alpha ); + setColorAlpha( color, _alpha ); } -SPColor SelectedColor::get_color() const +SPColor SelectedColor::color() const { return _color; } -void SelectedColor::set_alpha(gfloat alpha) +void SelectedColor::setAlpha(gfloat alpha) { g_return_if_fail( ( 0.0 <= alpha ) && ( alpha <= 1.0 ) ); - set_color_alpha( _color, alpha ); + setColorAlpha( _color, alpha ); } -gfloat SelectedColor::get_alpha() const +gfloat SelectedColor::alpha() const { return _alpha; } -void SelectedColor::set_color_alpha(const SPColor& color, gfloat alpha, bool emit) +void SelectedColor::setColorAlpha(SPColor const &color, gfloat alpha, bool emit) { #ifdef DUMP_CHANGE_INFO g_message("SelectedColor::setColorAlpha( this=%p, %f, %f, %f, %s, %f, %s) in %s", this, color.v.c[0], color.v.c[1], color.v.c[2], (color.icc?color.icc->colorProfile.c_str():""), alpha, (emit?"YES":"no"), FOO_NAME(_csel)); @@ -70,8 +70,8 @@ void SelectedColor::set_color_alpha(const SPColor& color, gfloat alpha, bool emi ); #endif - if ( _virgin || !color.isClose( _color, _epsilon ) || - (fabs((_alpha) - (alpha)) >= _epsilon )) { + if ( _virgin || !color.isClose( _color, _EPSILON ) || + (fabs((_alpha) - (alpha)) >= _EPSILON )) { _virgin = false; @@ -89,7 +89,7 @@ void SelectedColor::set_color_alpha(const SPColor& color, gfloat alpha, bool emi } } -void SelectedColor::get_color_alpha(SPColor &color, gfloat &alpha) const { +void SelectedColor::colorAlpha(SPColor &color, gfloat &alpha) const { color = _color; alpha = _alpha; } @@ -97,3 +97,13 @@ void SelectedColor::get_color_alpha(SPColor &color, gfloat &alpha) const { } } +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 : diff --git a/src/ui/selected-color.h b/src/ui/selected-color.h index a56ee6afb..08b84b66c 100644 --- a/src/ui/selected-color.h +++ b/src/ui/selected-color.h @@ -33,47 +33,55 @@ public: SelectedColor(); virtual ~SelectedColor(); - void set_color( const SPColor& color ); - SPColor get_color() const; + void setColor(SPColor const &color); + SPColor color() const; - void set_alpha( gfloat alpha ); - gfloat get_alpha() const; + void setAlpha(gfloat alpha); + gfloat alpha() const; - void set_color_alpha( const SPColor& color, gfloat alpha, bool emit = false ); - void get_color_alpha( SPColor &color, gfloat &alpha ) const; + void setColorAlpha(SPColor const &color, gfloat alpha, bool emit = false); + void colorAlpha(SPColor &color, gfloat &alpha) const; sigc::signal signal_changed; private: // By default, disallow copy constructor and assignment operator - SelectedColor( const SelectedColor& obj ); - SelectedColor& operator=( const SelectedColor& obj ); + SelectedColor(SelectedColor const &obj); + SelectedColor& operator=(SelectedColor const &obj); - SPColor _color; - /** - * Color alpha value guaranteed to be in [0, 1]. - */ - gfloat _alpha; + SPColor _color; + /** + * Color alpha value guaranteed to be in [0, 1]. + */ + gfloat _alpha; /** * This flag is true if no color is set yet */ bool _virgin; - static double _epsilon; + static double const _EPSILON; }; - class ColorSelectorFactory { public: - virtual ~ColorSelectorFactory() {} + virtual ~ColorSelectorFactory() { + } - virtual Gtk::Widget* createWidget(SelectedColor& color) const = 0; + virtual Gtk::Widget* createWidget(SelectedColor &color) const = 0; virtual Glib::ustring modeName() const = 0; }; - } } #endif - +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 : -- cgit v1.2.3 From b0e9181bacdad19055532a2620f5390815b91727 Mon Sep 17 00:00:00 2001 From: Tomasz Boczkowski Date: Fri, 30 May 2014 22:53:40 +0200 Subject: added ColorEntry class, refactored SPColorNotebook to use it (bzr r13341.6.31) --- src/ui/widget/Makefile_insert | 2 + src/ui/widget/color-entry.cpp | 115 ++++++++++++++++++++++++++++++++++++++ src/ui/widget/color-entry.h | 59 +++++++++++++++++++ src/widgets/sp-color-notebook.cpp | 104 +++++++++------------------------- src/widgets/sp-color-notebook.h | 6 +- 5 files changed, 206 insertions(+), 80 deletions(-) create mode 100644 src/ui/widget/color-entry.cpp create mode 100644 src/ui/widget/color-entry.h (limited to 'src') diff --git a/src/ui/widget/Makefile_insert b/src/ui/widget/Makefile_insert index 6deaf6671..bad3342b1 100644 --- a/src/ui/widget/Makefile_insert +++ b/src/ui/widget/Makefile_insert @@ -6,6 +6,8 @@ ink_common_sources += \ ui/widget/attr-widget.h \ ui/widget/button.h \ ui/widget/button.cpp \ + ui/widget/color-entry.cpp \ + ui/widget/color-entry.h \ ui/widget/color-picker.cpp \ ui/widget/color-picker.h \ ui/widget/color-preview.cpp \ diff --git a/src/ui/widget/color-entry.cpp b/src/ui/widget/color-entry.cpp new file mode 100644 index 000000000..223c86fd3 --- /dev/null +++ b/src/ui/widget/color-entry.cpp @@ -0,0 +1,115 @@ +/** @file + * Entry widget for typing color value in css form + *//* + * Authors: + * Tomasz Boczkowski + * + * Copyright (C) 2014 Authors + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#if GLIBMM_DISABLE_DEPRECATED && HAVE_GLIBMM_THREADS_H +#include +#endif + +#include +#include + +#include "color-entry.h" + +namespace Inkscape { +namespace UI { +namespace Widget { + +ColorEntry::ColorEntry(SelectedColor &color) + : _color(color) + , _updating(false) +{ + _color_changed_connection = color.signal_changed.connect(sigc::mem_fun(this, &ColorEntry::_onColorChanged)); + _onColorChanged(); + + set_max_length(8); + set_width_chars(8); + set_tooltip_text(_("Hexadecimal RGBA value of the color")); +} + +ColorEntry::~ColorEntry() { + _color_changed_connection.disconnect(); +} + +void ColorEntry::on_changed() { + if (_updating) { + return; + } + + Glib::ustring text = get_text(); + bool changed = false; + + //Coerce the value format to eight hex digits + if (!text.empty() && text[0] == '#') { + changed = true; + text.erase(0, 1); + if (text.size() == 6) { + // it was a standard RGB hex + unsigned int alph = SP_COLOR_F_TO_U(_color.alpha()); + Glib::ustring tmp = Glib::ustring::format(std::hex, std::setw(2), std::setfill(L'0'), alph); + text += tmp; + } + } + + gchar* str = g_strdup(text.c_str()); + gchar* end = 0; + guint64 rgba = g_ascii_strtoull(str, &end, 16); + if (end != str) { + ptrdiff_t len = end - str; + if (len < 8) { + rgba = rgba << (4 * (8 - len)); + } + _updating = true; + if (changed) { + set_text(str); + } + SPColor color(rgba); + _color.setColorAlpha(color, SP_RGBA32_A_F(rgba), true); + _updating = false; + } + g_free(str); +} + + +void ColorEntry::_onColorChanged() { + if (_updating) { + return; + } + + SPColor color = _color.color(); + gdouble alpha = _color.alpha(); + + guint32 rgba = color.toRGBA32( alpha ); + Glib::ustring text = Glib::ustring::format(std::hex, std::setw(8), std::setfill(L'0'), rgba); + + Glib::ustring old_text = get_text(); + if (old_text != text) { + _updating = true; + set_text(text); + _updating = false; + } +} + +} +} +} +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 : diff --git a/src/ui/widget/color-entry.h b/src/ui/widget/color-entry.h new file mode 100644 index 000000000..742324337 --- /dev/null +++ b/src/ui/widget/color-entry.h @@ -0,0 +1,59 @@ +/** @file + * Entry widget for typing color value in css form + *//* + * Authors: + * Tomasz Boczkowski + * + * Copyright (C) 2014 Authors + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +#ifndef SEEN_COLOR_ENTRY_H +#define SEEN_COLOR_ENTRY_H_ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#if GLIBMM_DISABLE_DEPRECATED && HAVE_GLIBMM_THREADS_H +#include +#endif + +#include +#include "ui/selected-color.h" + +namespace Inkscape { +namespace UI { +namespace Widget { + +class ColorEntry: public Gtk::Entry { +public: + ColorEntry(SelectedColor &color); + virtual ~ColorEntry(); + +protected: + void on_changed(); + +private: + void _onColorChanged(); + + SelectedColor &_color; + sigc::connection _color_changed_connection; + bool _updating; +}; + +} +} +} + +#endif +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 : diff --git a/src/widgets/sp-color-notebook.cpp b/src/widgets/sp-color-notebook.cpp index 364e81ae5..ac110b86c 100644 --- a/src/widgets/sp-color-notebook.cpp +++ b/src/widgets/sp-color-notebook.cpp @@ -41,9 +41,12 @@ #include "cms-system.h" #include "tools-switch.h" #include "ui/tools/tool-base.h" +#include "ui/widget/color-entry.h" using Inkscape::CMSSystem; +using namespace Inkscape::UI::Widget; + struct SPColorNotebookTracker { const gchar* name; const gchar* className; @@ -156,8 +159,7 @@ void ColorNotebook::init() { guint row = 0; - _updating = FALSE; - _updatingrgba = FALSE; + _updating = false; _book = gtk_notebook_new (); gtk_widget_show (_book); @@ -324,13 +326,10 @@ void ColorNotebook::init() gtk_misc_set_alignment (GTK_MISC (_rgbal), 1.0, 0.5); gtk_box_pack_start(GTK_BOX(rgbabox), _rgbal, TRUE, TRUE, 2); - _rgbae = gtk_entry_new (); - sp_dialog_defocus_on_enter (_rgbae); - gtk_entry_set_max_length (GTK_ENTRY (_rgbae), 8); - gtk_entry_set_width_chars (GTK_ENTRY (_rgbae), 8); - gtk_widget_set_tooltip_text (_rgbae, _("Hexadecimal RGBA value of the color")); - gtk_box_pack_start(GTK_BOX(rgbabox), _rgbae, FALSE, FALSE, 0); - gtk_label_set_mnemonic_widget (GTK_LABEL(_rgbal), _rgbae); + ColorEntry* rgba_entry = Gtk::manage(new ColorEntry(_selected_color)); + sp_dialog_defocus_on_enter (GTK_WIDGET(rgba_entry->gobj())); + gtk_box_pack_start(GTK_BOX(rgbabox), GTK_WIDGET(rgba_entry->gobj()), FALSE, FALSE, 0); + gtk_label_set_mnemonic_widget (GTK_LABEL(_rgbal), GTK_WIDGET(rgba_entry->gobj())); sp_set_font_size_smaller (rgbabox); gtk_widget_show_all (rgbabox); @@ -359,7 +358,7 @@ void ColorNotebook::init() _switchId = g_signal_connect(G_OBJECT (_book), "switch-page", G_CALLBACK (sp_color_notebook_switch_page), SP_COLOR_NOTEBOOK(_csel)); - _entryId = g_signal_connect (G_OBJECT (_rgbae), "changed", G_CALLBACK (ColorNotebook::_rgbaEntryChangedHook), _csel); + _selected_color.signal_changed.connect(sigc::mem_fun(this, &ColorNotebook::_onSelectedColorChanged)); } static void sp_color_notebook_dispose(GObject *object) @@ -449,13 +448,13 @@ ColorNotebook::Page::Page(Inkscape::UI::ColorSelectorFactory *selector_factory, void ColorNotebook::_colorChanged() { + _selected_color.setColorAlpha(_color, _alpha, true); + SPColorSelector* cselPage = getCurrentSelector(); if ( cselPage ) { cselPage->base->setColorAlpha( _color, _alpha ); } - - _updateRgbaEntry( _color, _alpha ); } void ColorNotebook::_picker_clicked(GtkWidget * /*widget*/, SPColorNotebook * /*colorbook*/) @@ -466,52 +465,6 @@ void ColorNotebook::_picker_clicked(GtkWidget * /*widget*/, SPColorNotebook * /* Inkscape::UI::Tools::sp_toggle_dropper(SP_ACTIVE_DESKTOP); } -void ColorNotebook::_rgbaEntryChangedHook(GtkEntry *entry, SPColorNotebook *colorbook) -{ - (dynamic_cast(SP_COLOR_SELECTOR(colorbook)->base))->_rgbaEntryChanged( entry ); -} - -void ColorNotebook::_rgbaEntryChanged(GtkEntry* entry) -{ - if (_updating) return; - if (_updatingrgba) return; - - const gchar *t = gtk_entry_get_text( entry ); - - if (t) { - Glib::ustring text = t; - bool changed = false; - if (!text.empty() && text[0] == '#') { - changed = true; - text.erase(0,1); - if (text.size() == 6) { - // it was a standard RGB hex - unsigned int alph = SP_COLOR_F_TO_U(_alpha); - gchar* tmp = g_strdup_printf("%02x", alph); - text += tmp; - g_free(tmp); - } - } - gchar* str = g_strdup(text.c_str()); - gchar* end = 0; - guint64 rgba = g_ascii_strtoull( str, &end, 16 ); - if ( end != str ) { - ptrdiff_t len = end - str; - if ( len < 8 ) { - rgba = rgba << ( 4 * ( 8 - len ) ); - } - _updatingrgba = TRUE; - if ( changed ) { - gtk_entry_set_text( entry, str ); - } - SPColor color( rgba ); - setColorAlpha( color, SP_RGBA32_A_F(rgba), true ); - _updatingrgba = FALSE; - } - g_free(str); - } -} - // TODO pass in param so as to avoid the need for SP_ACTIVE_DOCUMENT void ColorNotebook::_updateRgbaEntry( const SPColor& color, gfloat alpha ) { @@ -550,24 +503,6 @@ void ColorNotebook::_updateRgbaEntry( const SPColor& color, gfloat alpha ) } } #endif //defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) - - if ( !_updatingrgba ) - { - gchar s[32]; - guint32 rgba; - - /* Update RGBA entry */ - rgba = color.toRGBA32( alpha ); - - g_snprintf (s, 32, "%08x", rgba); - const gchar* oldText = gtk_entry_get_text( GTK_ENTRY( _rgbae ) ); - if ( strcmp( oldText, s ) != 0 ) - { - g_signal_handler_block( _rgbae, _entryId ); - gtk_entry_set_text( GTK_ENTRY(_rgbae), s ); - g_signal_handler_unblock( _rgbae, _entryId ); - } - } } void ColorNotebook::_setCurrentPage(int i) @@ -644,10 +579,25 @@ void ColorNotebook::_entryModified (SPColorSelector *csel, SPColorNotebook *colo gfloat alpha = 1.0; csel->base->getColorAlpha( color, alpha ); - nb->_updateRgbaEntry( color, alpha ); + + nb->_updating = true; + nb->_selected_color.setColorAlpha(color, alpha, true); + nb->_updating = false; nb->_updateInternals( color, alpha, nb->_dragging ); } +void ColorNotebook::_onSelectedColorChanged() { + if (_updating) { + return; + } + + SPColor color; + gfloat alpha = 1.0; + + _selected_color.colorAlpha(color, alpha); + _updateInternals(color, alpha, _dragging); +} + GtkWidget* ColorNotebook::_addPage(Page& page) { Gtk::Widget *selector_widget; diff --git a/src/widgets/sp-color-notebook.h b/src/widgets/sp-color-notebook.h index f688d9210..9ab98f1e9 100644 --- a/src/widgets/sp-color-notebook.h +++ b/src/widgets/sp-color-notebook.h @@ -50,7 +50,6 @@ protected: bool enabled_full; }; - static void _rgbaEntryChangedHook( GtkEntry* entry, SPColorNotebook *colorbook ); static void _entryGrabbed( SPColorSelector *csel, SPColorNotebook *colorbook ); static void _entryDragged( SPColorSelector *csel, SPColorNotebook *colorbook ); static void _entryReleased( SPColorSelector *csel, SPColorNotebook *colorbook ); @@ -61,7 +60,8 @@ protected: virtual void _colorChanged(); - void _rgbaEntryChanged( GtkEntry* entry ); + virtual void _onSelectedColorChanged(); + void _updateRgbaEntry( const SPColor& color, gfloat alpha ); void _setCurrentPage(int i); @@ -76,7 +76,7 @@ protected: GtkWidget *_book; GtkWidget *_buttonbox; GtkWidget **_buttons; - GtkWidget *_rgbal, *_rgbae; /* RGBA entry */ + GtkWidget *_rgbal; /* RGBA entry */ #if defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) GtkWidget *_box_outofgamut, *_box_colormanaged, *_box_toomuchink; #endif //defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) -- cgit v1.2.3 From 746ade6352656a8db136039a1dd9cff9645ed9f4 Mon Sep 17 00:00:00 2001 From: Tomasz Boczkowski Date: Sat, 31 May 2014 09:14:19 +0200 Subject: ColorSlider coding style (bzr r13341.6.32) --- src/ui/widget/color-slider.cpp | 38 ++++++++++++++++----------------- src/ui/widget/color-slider.h | 32 +++++++++++++++++---------- src/widgets/sp-color-icc-selector.cpp | 8 +++---- src/widgets/sp-color-scales.cpp | 30 +++++++++++++------------- src/widgets/sp-color-wheel-selector.cpp | 6 +++--- 5 files changed, 62 insertions(+), 52 deletions(-) (limited to 'src') diff --git a/src/ui/widget/color-slider.cpp b/src/ui/widget/color-slider.cpp index fc64fad6f..711942e28 100644 --- a/src/ui/widget/color-slider.cpp +++ b/src/ui/widget/color-slider.cpp @@ -76,7 +76,7 @@ ColorSlider::ColorSlider(Gtk::Adjustment* adjustment) _b1 = 0xa0; _bmask = 0x08; - set_adjustment(adjustment); + setAdjustment(adjustment); } ColorSlider::~ColorSlider() { @@ -95,7 +95,7 @@ ColorSlider::~ColorSlider() { void ColorSlider::on_realize() { set_realized(); - if(!_refGdkWindow) + if(!_gdk_window) { GdkWindowAttr attributes; gint attributes_mask; @@ -126,10 +126,10 @@ void ColorSlider::on_realize() { attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP; #endif - _refGdkWindow = Gdk::Window::create(get_parent_window(), &attributes, + _gdk_window = Gdk::Window::create(get_parent_window(), &attributes, attributes_mask); - set_window(_refGdkWindow); - _refGdkWindow->set_user_data(gobj()); + set_window(_gdk_window); + _gdk_window->set_user_data(gobj()); #if !GTK_CHECK_VERSION(3,0,0) style_attach(); @@ -138,7 +138,7 @@ void ColorSlider::on_realize() { } void ColorSlider::on_unrealize() { - _refGdkWindow.reset(); + _gdk_window.reset(); Gtk::Widget::on_unrealize(); } @@ -147,7 +147,7 @@ void ColorSlider::on_size_allocate(Gtk::Allocation& allocation) { set_allocation(allocation); if (get_realized()) { - _refGdkWindow->move_resize(allocation.get_x(), allocation.get_y(), + _gdk_window->move_resize(allocation.get_x(), allocation.get_y(), allocation.get_width(), allocation.get_height()); } } @@ -192,7 +192,7 @@ bool ColorSlider::on_expose_event(GdkEventExpose* event) { bool result = false; if (get_is_drawable()) { - Cairo::RefPtr cr = _refGdkWindow->create_cairo_context(); + Cairo::RefPtr cr = _gdk_window->create_cairo_context(); result = on_draw(cr); } return result; @@ -218,7 +218,7 @@ bool ColorSlider::on_button_press_event(GdkEventButton *event) { #if GTK_CHECK_VERSION(3,0,0) gdk_device_grab(gdk_event_get_device(reinterpret_cast(event)), - _refGdkWindow->gobj(), + _gdk_window->gobj(), GDK_OWNERSHIP_NONE, FALSE, static_cast(GDK_POINTER_MOTION_MASK | GDK_BUTTON_RELEASE_MASK), @@ -272,9 +272,9 @@ bool ColorSlider::on_motion_notify_event(GdkEventMotion *event) { } #if GTK_CHECK_VERSION(3,0,0) -void ColorSlider::set_adjustment(Glib::RefPtr adjustment) { +void ColorSlider::setAdjustment(Glib::RefPtr adjustment) { #else -void ColorSlider::set_adjustment(Gtk::Adjustment *adjustment) { +void ColorSlider::setAdjustment(Gtk::Adjustment *adjustment) { #endif if (!adjustment) { #if GTK_CHECK_VERSION(3,0,0) @@ -298,21 +298,21 @@ void ColorSlider::set_adjustment(Gtk::Adjustment *adjustment) { _adjustment = adjustment; _adjustment_changed_connection = _adjustment->signal_changed().connect( - sigc::mem_fun(this, &ColorSlider::_on_adjustment_changed)); + sigc::mem_fun(this, &ColorSlider::_onAdjustmentChanged)); _adjustment_value_changed_connection = _adjustment->signal_value_changed().connect( - sigc::mem_fun(this, &ColorSlider::_on_adjustment_value_changed)); + sigc::mem_fun(this, &ColorSlider::_onAdjustmentValueChanged)); _value = ColorScales::getScaled(_adjustment->gobj()); - _on_adjustment_changed(); + _onAdjustmentChanged(); } } -void ColorSlider::_on_adjustment_changed() { +void ColorSlider::_onAdjustmentChanged() { queue_draw(); } -void ColorSlider::_on_adjustment_value_changed() { +void ColorSlider::_onAdjustmentValueChanged() { if (_value != ColorScales::getScaled( _adjustment->gobj() )) { gint cx, cy, cw, ch; #if GTK_CHECK_VERSION(3,0,0) @@ -346,7 +346,7 @@ void ColorSlider::_on_adjustment_value_changed() { } } -void ColorSlider::set_colors(guint32 start, guint32 mid, guint32 end) { +void ColorSlider::setColors(guint32 start, guint32 mid, guint32 end) { // Remove any map, if set _map = 0; @@ -368,13 +368,13 @@ void ColorSlider::set_colors(guint32 start, guint32 mid, guint32 end) { queue_draw(); } -void ColorSlider::set_map(const guchar *map) { +void ColorSlider::setMap(const guchar *map) { _map = const_cast(map); queue_draw(); } -void ColorSlider::set_background(guint dark, guint light, guint size) { +void ColorSlider::setBackground(guint dark, guint light, guint size) { _b0 = dark; _b1 = light; _bmask = size; diff --git a/src/ui/widget/color-slider.h b/src/ui/widget/color-slider.h index bbc14afc9..ef54c84e6 100644 --- a/src/ui/widget/color-slider.h +++ b/src/ui/widget/color-slider.h @@ -1,6 +1,3 @@ -#ifndef __SP_COLOR_SLIDER_H__ -#define __SP_COLOR_SLIDER_H__ - /* Author: * Lauris Kaplinski * @@ -9,6 +6,9 @@ * This code is in public domain */ +#ifndef SEEN_COLOR_SLIDER_H +#define SEEN_COLOR_SLIDER_H + #ifdef HAVE_CONFIG_H # include #endif @@ -40,16 +40,16 @@ public: ~ColorSlider(); #if GTK_CHECK_VERSION(3,0,0) - void set_adjustment(Glib::RefPtr adjustment); + void setAdjustment(Glib::RefPtr adjustment); #else - void set_adjustment(Gtk::Adjustment *adjustment); + void setAdjustment(Gtk::Adjustment *adjustment); #endif - void set_colors(guint32 start, guint32 mid, guint32 end); + void setColors(guint32 start, guint32 mid, guint32 end); - void set_map(const guchar* map); + void setMap(const guchar* map); - void set_background(guint dark, guint light, guint size); + void setBackground(guint dark, guint light, guint size); sigc::signal signal_grabbed; sigc::signal signal_dragged; @@ -76,8 +76,8 @@ protected: #endif private: - void _on_adjustment_changed(); - void _on_adjustment_value_changed(); + void _onAdjustmentChanged(); + void _onAdjustmentValueChanged(); bool _dragging; @@ -98,7 +98,7 @@ private: gint _mapsize; guchar *_map; - Glib::RefPtr _refGdkWindow; + Glib::RefPtr _gdk_window; }; }//namespace Widget @@ -106,3 +106,13 @@ private: }//namespace Inkscape #endif +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 : diff --git a/src/widgets/sp-color-icc-selector.cpp b/src/widgets/sp-color-icc-selector.cpp index 69818ba99..cd1586661 100644 --- a/src/widgets/sp-color-icc-selector.cpp +++ b/src/widgets/sp-color-icc-selector.cpp @@ -575,7 +575,7 @@ void ColorICCSelector::init() attachToGridOrTable(t, _impl->_slider->gobj(), 1, row, 1, 1, true); - _impl->_slider->set_colors(SP_RGBA32_F_COMPOSE( 1.0, 1.0, 1.0, 0.0 ), + _impl->_slider->setColors(SP_RGBA32_F_COMPOSE( 1.0, 1.0, 1.0, 0.0 ), SP_RGBA32_F_COMPOSE( 1.0, 1.0, 1.0, 0.5 ), SP_RGBA32_F_COMPOSE( 1.0, 1.0, 1.0, 1.0 ) ); @@ -906,7 +906,7 @@ void ColorICCSelectorImpl::_setProfile( SVGICCColor* profile ) _compUI[i]._slider->set_tooltip_text((i < things.size()) ? things[i].tip.c_str() : ""); gtk_widget_set_tooltip_text( _compUI[i]._btn, (i < things.size()) ? things[i].tip.c_str() : "" ); - _compUI[i]._slider->set_colors(SPColor(0.0, 0.0, 0.0).toRGBA32(0xff), + _compUI[i]._slider->setColors(SPColor(0.0, 0.0, 0.0).toRGBA32(0xff), SPColor(0.5, 0.5, 0.5).toRGBA32(0xff), SPColor(1.0, 1.0, 1.0).toRGBA32(0xff) ); /* @@ -982,7 +982,7 @@ void ColorICCSelectorImpl::_updateSliders( gint ignore ) cmsHTRANSFORM trans = _prof->getTransfToSRGB8(); if ( trans ) { cmsDoTransform( trans, scratch, _compUI[i]._map, 1024 ); - _compUI[i]._slider->set_map(_compUI[i]._map); + _compUI[i]._slider->setMap(_compUI[i]._map); } } } @@ -997,7 +997,7 @@ void ColorICCSelectorImpl::_updateSliders( gint ignore ) guint32 mid = _owner->_color.toRGBA32( 0x7f ); guint32 end = _owner->_color.toRGBA32( 0xff ); - _slider->set_colors(start, mid, end); + _slider->setColors(start, mid, end); } diff --git a/src/widgets/sp-color-scales.cpp b/src/widgets/sp-color-scales.cpp index d7466be98..3d9de650c 100644 --- a/src/widgets/sp-color-scales.cpp +++ b/src/widgets/sp-color-scales.cpp @@ -446,7 +446,7 @@ void ColorScales::setMode(SPColorScalesMode mode) gtk_label_set_markup_with_mnemonic (GTK_LABEL (_l[3]), _("_A:")); _s[3]->set_tooltip_text(_("Alpha (opacity)")); gtk_widget_set_tooltip_text (_b[3], _("Alpha (opacity)")); - _s[0]->set_map(NULL); + _s[0]->setMap(NULL); gtk_widget_hide (_l[4]); _s[4]->hide(); gtk_widget_hide (_b[4]); @@ -472,7 +472,7 @@ void ColorScales::setMode(SPColorScalesMode mode) gtk_label_set_markup_with_mnemonic (GTK_LABEL (_l[3]), _("_A:")); _s[3]->set_tooltip_text(_("Alpha (opacity)")); gtk_widget_set_tooltip_text (_b[3], _("Alpha (opacity)")); - _s[0]->set_map((guchar *)(sp_color_scales_hue_map())); + _s[0]->setMap((guchar *)(sp_color_scales_hue_map())); gtk_widget_hide (_l[4]); _s[4]->hide(); gtk_widget_hide (_b[4]); @@ -503,7 +503,7 @@ void ColorScales::setMode(SPColorScalesMode mode) gtk_label_set_markup_with_mnemonic (GTK_LABEL (_l[4]), _("_A:")); _s[4]->set_tooltip_text(_("Alpha (opacity)")); gtk_widget_set_tooltip_text (_b[4], _("Alpha (opacity)")); - _s[0]->set_map(NULL); + _s[0]->setMap(NULL); gtk_widget_show (_l[4]); _s[4]->show(); gtk_widget_show (_b[4]); @@ -625,25 +625,25 @@ void ColorScales::_updateSliders( guint channels ) case SP_COLOR_SCALES_MODE_RGB: if ((channels != CSC_CHANNEL_R) && (channels != CSC_CHANNEL_A)) { /* Update red */ - _s[0]->set_colors(SP_RGBA32_F_COMPOSE (0.0, getScaled(_a[1]), getScaled(_a[2]), 1.0), + _s[0]->setColors(SP_RGBA32_F_COMPOSE (0.0, getScaled(_a[1]), getScaled(_a[2]), 1.0), SP_RGBA32_F_COMPOSE (0.5, getScaled(_a[1]), getScaled(_a[2]), 1.0), SP_RGBA32_F_COMPOSE (1.0, getScaled(_a[1]), getScaled(_a[2]), 1.0)); } if ((channels != CSC_CHANNEL_G) && (channels != CSC_CHANNEL_A)) { /* Update green */ - _s[1]->set_colors(SP_RGBA32_F_COMPOSE(getScaled(_a[0]), 0.0, getScaled(_a[2]), 1.0), + _s[1]->setColors(SP_RGBA32_F_COMPOSE(getScaled(_a[0]), 0.0, getScaled(_a[2]), 1.0), SP_RGBA32_F_COMPOSE(getScaled(_a[0]), 0.5, getScaled(_a[2]), 1.0), SP_RGBA32_F_COMPOSE(getScaled(_a[0]), 1.0, getScaled(_a[2]), 1.0)); } if ((channels != CSC_CHANNEL_B) && (channels != CSC_CHANNEL_A)) { /* Update blue */ - _s[2]->set_colors(SP_RGBA32_F_COMPOSE (getScaled(_a[0]), getScaled(_a[1]), 0.0, 1.0), + _s[2]->setColors(SP_RGBA32_F_COMPOSE (getScaled(_a[0]), getScaled(_a[1]), 0.0, 1.0), SP_RGBA32_F_COMPOSE (getScaled(_a[0]), getScaled(_a[1]), 0.5, 1.0), SP_RGBA32_F_COMPOSE (getScaled(_a[0]), getScaled(_a[1]), 1.0, 1.0)); } if (channels != CSC_CHANNEL_A) { /* Update alpha */ - _s[3]->set_colors(SP_RGBA32_F_COMPOSE (getScaled(_a[0]), getScaled(_a[1]), getScaled(_a[2]), 0.0), + _s[3]->setColors(SP_RGBA32_F_COMPOSE (getScaled(_a[0]), getScaled(_a[1]), getScaled(_a[2]), 0.0), SP_RGBA32_F_COMPOSE (getScaled(_a[0]), getScaled(_a[1]), getScaled(_a[2]), 0.5), SP_RGBA32_F_COMPOSE (getScaled(_a[0]), getScaled(_a[1]), getScaled(_a[2]), 1.0)); } @@ -655,7 +655,7 @@ void ColorScales::_updateSliders( guint channels ) sp_color_hsl_to_rgb_floatv (rgb0, getScaled(_a[0]), 0.0, getScaled(_a[2])); sp_color_hsl_to_rgb_floatv (rgbm, getScaled(_a[0]), 0.5, getScaled(_a[2])); sp_color_hsl_to_rgb_floatv (rgb1, getScaled(_a[0]), 1.0, getScaled(_a[2])); - _s[1]->set_colors(SP_RGBA32_F_COMPOSE (rgb0[0], rgb0[1], rgb0[2], 1.0), + _s[1]->setColors(SP_RGBA32_F_COMPOSE (rgb0[0], rgb0[1], rgb0[2], 1.0), SP_RGBA32_F_COMPOSE (rgbm[0], rgbm[1], rgbm[2], 1.0), SP_RGBA32_F_COMPOSE (rgb1[0], rgb1[1], rgb1[2], 1.0)); } @@ -664,14 +664,14 @@ void ColorScales::_updateSliders( guint channels ) sp_color_hsl_to_rgb_floatv (rgb0, getScaled(_a[0]), getScaled(_a[1]), 0.0); sp_color_hsl_to_rgb_floatv (rgbm, getScaled(_a[0]), getScaled(_a[1]), 0.5); sp_color_hsl_to_rgb_floatv (rgb1, getScaled(_a[0]), getScaled(_a[1]), 1.0); - _s[2]->set_colors(SP_RGBA32_F_COMPOSE (rgb0[0], rgb0[1], rgb0[2], 1.0), + _s[2]->setColors(SP_RGBA32_F_COMPOSE (rgb0[0], rgb0[1], rgb0[2], 1.0), SP_RGBA32_F_COMPOSE (rgbm[0], rgbm[1], rgbm[2], 1.0), SP_RGBA32_F_COMPOSE (rgb1[0], rgb1[1], rgb1[2], 1.0)); } if (channels != CSC_CHANNEL_A) { /* Update alpha */ sp_color_hsl_to_rgb_floatv (rgb0, getScaled(_a[0]), getScaled(_a[1]), getScaled(_a[2])); - _s[3]->set_colors(SP_RGBA32_F_COMPOSE (rgb0[0], rgb0[1], rgb0[2], 0.0), + _s[3]->setColors(SP_RGBA32_F_COMPOSE (rgb0[0], rgb0[1], rgb0[2], 0.0), SP_RGBA32_F_COMPOSE (rgb0[0], rgb0[1], rgb0[2], 0.5), SP_RGBA32_F_COMPOSE (rgb0[0], rgb0[1], rgb0[2], 1.0)); } @@ -682,7 +682,7 @@ void ColorScales::_updateSliders( guint channels ) sp_color_cmyk_to_rgb_floatv (rgb0, 0.0, getScaled(_a[1]), getScaled(_a[2]), getScaled(_a[3])); sp_color_cmyk_to_rgb_floatv (rgbm, 0.5, getScaled(_a[1]), getScaled(_a[2]), getScaled(_a[3])); sp_color_cmyk_to_rgb_floatv (rgb1, 1.0, getScaled(_a[1]), getScaled(_a[2]), getScaled(_a[3])); - _s[0]->set_colors(SP_RGBA32_F_COMPOSE (rgb0[0], rgb0[1], rgb0[2], 1.0), + _s[0]->setColors(SP_RGBA32_F_COMPOSE (rgb0[0], rgb0[1], rgb0[2], 1.0), SP_RGBA32_F_COMPOSE (rgbm[0], rgbm[1], rgbm[2], 1.0), SP_RGBA32_F_COMPOSE (rgb1[0], rgb1[1], rgb1[2], 1.0)); } @@ -691,7 +691,7 @@ void ColorScales::_updateSliders( guint channels ) sp_color_cmyk_to_rgb_floatv (rgb0, getScaled(_a[0]), 0.0, getScaled(_a[2]), getScaled(_a[3])); sp_color_cmyk_to_rgb_floatv (rgbm, getScaled(_a[0]), 0.5, getScaled(_a[2]), getScaled(_a[3])); sp_color_cmyk_to_rgb_floatv (rgb1, getScaled(_a[0]), 1.0, getScaled(_a[2]), getScaled(_a[3])); - _s[1]->set_colors(SP_RGBA32_F_COMPOSE (rgb0[0], rgb0[1], rgb0[2], 1.0), + _s[1]->setColors(SP_RGBA32_F_COMPOSE (rgb0[0], rgb0[1], rgb0[2], 1.0), SP_RGBA32_F_COMPOSE (rgbm[0], rgbm[1], rgbm[2], 1.0), SP_RGBA32_F_COMPOSE (rgb1[0], rgb1[1], rgb1[2], 1.0)); } @@ -700,7 +700,7 @@ void ColorScales::_updateSliders( guint channels ) sp_color_cmyk_to_rgb_floatv (rgb0, getScaled(_a[0]), getScaled(_a[1]), 0.0, getScaled(_a[3])); sp_color_cmyk_to_rgb_floatv (rgbm, getScaled(_a[0]), getScaled(_a[1]), 0.5, getScaled(_a[3])); sp_color_cmyk_to_rgb_floatv (rgb1, getScaled(_a[0]), getScaled(_a[1]), 1.0, getScaled(_a[3])); - _s[2]->set_colors(SP_RGBA32_F_COMPOSE (rgb0[0], rgb0[1], rgb0[2], 1.0), + _s[2]->setColors(SP_RGBA32_F_COMPOSE (rgb0[0], rgb0[1], rgb0[2], 1.0), SP_RGBA32_F_COMPOSE (rgbm[0], rgbm[1], rgbm[2], 1.0), SP_RGBA32_F_COMPOSE (rgb1[0], rgb1[1], rgb1[2], 1.0)); } @@ -709,14 +709,14 @@ void ColorScales::_updateSliders( guint channels ) sp_color_cmyk_to_rgb_floatv (rgb0, getScaled(_a[0]), getScaled(_a[1]), getScaled(_a[2]), 0.0); sp_color_cmyk_to_rgb_floatv (rgbm, getScaled(_a[0]), getScaled(_a[1]), getScaled(_a[2]), 0.5); sp_color_cmyk_to_rgb_floatv (rgb1, getScaled(_a[0]), getScaled(_a[1]), getScaled(_a[2]), 1.0); - _s[3]->set_colors(SP_RGBA32_F_COMPOSE (rgb0[0], rgb0[1], rgb0[2], 1.0), + _s[3]->setColors(SP_RGBA32_F_COMPOSE (rgb0[0], rgb0[1], rgb0[2], 1.0), SP_RGBA32_F_COMPOSE (rgbm[0], rgbm[1], rgbm[2], 1.0), SP_RGBA32_F_COMPOSE (rgb1[0], rgb1[1], rgb1[2], 1.0)); } if (channels != CSC_CHANNEL_CMYKA) { /* Update alpha */ sp_color_cmyk_to_rgb_floatv (rgb0, getScaled(_a[0]), getScaled(_a[1]), getScaled(_a[2]), getScaled(_a[3])); - _s[4]->set_colors(SP_RGBA32_F_COMPOSE (rgb0[0], rgb0[1], rgb0[2], 0.0), + _s[4]->setColors(SP_RGBA32_F_COMPOSE (rgb0[0], rgb0[1], rgb0[2], 0.0), SP_RGBA32_F_COMPOSE (rgb0[0], rgb0[1], rgb0[2], 0.5), SP_RGBA32_F_COMPOSE (rgb0[0], rgb0[1], rgb0[2], 1.0)); } diff --git a/src/widgets/sp-color-wheel-selector.cpp b/src/widgets/sp-color-wheel-selector.cpp index 15177377d..2b448e075 100644 --- a/src/widgets/sp-color-wheel-selector.cpp +++ b/src/widgets/sp-color-wheel-selector.cpp @@ -181,7 +181,7 @@ void ColorWheelSelector::init() gtk_table_attach(GTK_TABLE (t), _slider->gobj(), 1, 2, row, row + 1, (GtkAttachOptions)(GTK_EXPAND | GTK_FILL), GTK_FILL, XPAD, YPAD); #endif - _slider->set_colors(SP_RGBA32_F_COMPOSE (1.0, 1.0, 1.0, 0.0), + _slider->setColors(SP_RGBA32_F_COMPOSE (1.0, 1.0, 1.0, 0.0), SP_RGBA32_F_COMPOSE (1.0, 1.0, 1.0, 0.5), SP_RGBA32_F_COMPOSE (1.0, 1.0, 1.0, 1.0)); @@ -262,7 +262,7 @@ void ColorWheelSelector::_colorChanged() guint32 mid = _color.toRGBA32( 0x7f ); guint32 end = _color.toRGBA32( 0xff ); - _slider->set_colors(start, mid, end); + _slider->setColors(start, mid, end); ColorScales::setScaled(_adj, _alpha); @@ -337,7 +337,7 @@ void ColorWheelSelector::_wheelChanged( GimpColorWheel *wheel, SPColorWheelSelec guint32 mid = color.toRGBA32( 0x7f ); guint32 end = color.toRGBA32( 0xff ); - wheelSelector->_slider->set_colors(start, mid, end); + wheelSelector->_slider->setColors(start, mid, end); wheelSelector->_preserve_icc(&color); wheelSelector->_updateInternals( color, wheelSelector->_alpha, gimp_color_wheel_is_adjusting(wheel) ); -- cgit v1.2.3 From e8f6b534a6db5c64b5d3a1fc9e4f1f691cb04ecc Mon Sep 17 00:00:00 2001 From: Tomasz Boczkowski Date: Sat, 31 May 2014 10:35:07 +0200 Subject: added dragged, released, grabbed signals to SelectedColor (bzr r13341.6.33) --- src/ui/selected-color.cpp | 22 +++++++++++++++++++++- src/ui/selected-color.h | 6 ++++++ src/ui/widget/color-entry.cpp | 2 ++ src/ui/widget/color-entry.h | 1 + 4 files changed, 30 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/ui/selected-color.cpp b/src/ui/selected-color.cpp index 296b15796..1be171a6b 100644 --- a/src/ui/selected-color.cpp +++ b/src/ui/selected-color.cpp @@ -25,6 +25,7 @@ SelectedColor::SelectedColor() : _color(0) , _alpha(1.0) , _virgin(true) + , _held(false) { } @@ -79,7 +80,11 @@ void SelectedColor::setColorAlpha(SPColor const &color, gfloat alpha, bool emit) _alpha = alpha; if (emit) { - signal_changed.emit(); + if (_held) { + signal_dragged.emit(); + } else { + signal_changed.emit(); + } } #ifdef DUMP_CHANGE_INFO } else { @@ -94,6 +99,21 @@ void SelectedColor::colorAlpha(SPColor &color, gfloat &alpha) const { alpha = _alpha; } +void SelectedColor::setHeld(bool held) { + bool grabbed = held && !_held; + bool released = !held && _held; + + _held = held; + + if (grabbed) { + signal_grabbed.emit(); + } + + if (released) { + signal_released.emit(); + } +} + } } diff --git a/src/ui/selected-color.h b/src/ui/selected-color.h index 08b84b66c..ec0cc55e3 100644 --- a/src/ui/selected-color.h +++ b/src/ui/selected-color.h @@ -42,6 +42,11 @@ public: void setColorAlpha(SPColor const &color, gfloat alpha, bool emit = false); void colorAlpha(SPColor &color, gfloat &alpha) const; + void setHeld(bool held); + + sigc::signal signal_grabbed; + sigc::signal signal_dragged; + sigc::signal signal_released; sigc::signal signal_changed; private: // By default, disallow copy constructor and assignment operator @@ -54,6 +59,7 @@ private: */ gfloat _alpha; + bool _held; /** * This flag is true if no color is set yet */ diff --git a/src/ui/widget/color-entry.cpp b/src/ui/widget/color-entry.cpp index 223c86fd3..56fd6080e 100644 --- a/src/ui/widget/color-entry.cpp +++ b/src/ui/widget/color-entry.cpp @@ -30,6 +30,7 @@ ColorEntry::ColorEntry(SelectedColor &color) , _updating(false) { _color_changed_connection = color.signal_changed.connect(sigc::mem_fun(this, &ColorEntry::_onColorChanged)); + _color_dragged_connection = color.signal_dragged.connect(sigc::mem_fun(this, &ColorEntry::_onColorChanged)); _onColorChanged(); set_max_length(8); @@ -39,6 +40,7 @@ ColorEntry::ColorEntry(SelectedColor &color) ColorEntry::~ColorEntry() { _color_changed_connection.disconnect(); + _color_dragged_connection.disconnect(); } void ColorEntry::on_changed() { diff --git a/src/ui/widget/color-entry.h b/src/ui/widget/color-entry.h index 742324337..148b5dfe9 100644 --- a/src/ui/widget/color-entry.h +++ b/src/ui/widget/color-entry.h @@ -39,6 +39,7 @@ private: SelectedColor &_color; sigc::connection _color_changed_connection; + sigc::connection _color_dragged_connection; bool _updating; }; -- cgit v1.2.3 From ba8232e27fbff22f2af10c39a66c2a084bacbfb4 Mon Sep 17 00:00:00 2001 From: Tomasz Boczkowski Date: Sat, 31 May 2014 10:48:29 +0200 Subject: SPColorWheelSelector c++-sification: moved to ui/widgets (bzr r13341.6.34) --- src/ui/widget/Makefile_insert | 2 + src/ui/widget/color-wheel-selector.cpp | 366 +++++++++++++++++++++++++++++++ src/ui/widget/color-wheel-selector.h | 111 ++++++++++ src/widgets/Makefile_insert | 2 - src/widgets/sp-color-notebook.cpp | 2 +- src/widgets/sp-color-wheel-selector.cpp | 367 -------------------------------- src/widgets/sp-color-wheel-selector.h | 111 ---------- 7 files changed, 480 insertions(+), 481 deletions(-) create mode 100644 src/ui/widget/color-wheel-selector.cpp create mode 100644 src/ui/widget/color-wheel-selector.h delete mode 100644 src/widgets/sp-color-wheel-selector.cpp delete mode 100644 src/widgets/sp-color-wheel-selector.h (limited to 'src') diff --git a/src/ui/widget/Makefile_insert b/src/ui/widget/Makefile_insert index bad3342b1..97625f04e 100644 --- a/src/ui/widget/Makefile_insert +++ b/src/ui/widget/Makefile_insert @@ -8,6 +8,8 @@ ink_common_sources += \ ui/widget/button.cpp \ ui/widget/color-entry.cpp \ ui/widget/color-entry.h \ + ui/widget/color-wheel-selector.cpp \ + ui/widget/color-wheel-selector.h \ ui/widget/color-picker.cpp \ ui/widget/color-picker.h \ ui/widget/color-preview.cpp \ diff --git a/src/ui/widget/color-wheel-selector.cpp b/src/ui/widget/color-wheel-selector.cpp new file mode 100644 index 000000000..134232813 --- /dev/null +++ b/src/ui/widget/color-wheel-selector.cpp @@ -0,0 +1,366 @@ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include "color-wheel-selector.h" + +#include +#include +#include +#include +#include "dialogs/dialog-events.h" +#include "widgets/sp-color-scales.h" +#include "svg/svg-icc-color.h" +#include "ui/widget/color-slider.h" +#include "ui/widget/gimpcolorwheel.h" + +G_BEGIN_DECLS + +static void sp_color_wheel_selector_class_init (SPColorWheelSelectorClass *klass); +static void sp_color_wheel_selector_init (SPColorWheelSelector *cs); +static void sp_color_wheel_selector_dispose(GObject *object); + +static void sp_color_wheel_selector_show_all (GtkWidget *widget); +static void sp_color_wheel_selector_hide(GtkWidget *widget); + + +G_END_DECLS + +static SPColorSelectorClass *parent_class; + +#define XPAD 4 +#define YPAD 1 + + +const gchar* ColorWheelSelector::MODE_NAME = N_("Wheel"); + +GType +sp_color_wheel_selector_get_type (void) +{ + static GType type = 0; + if (!type) { + static const GTypeInfo info = { + sizeof (SPColorWheelSelectorClass), + NULL, /* base_init */ + NULL, /* base_finalize */ + (GClassInitFunc) sp_color_wheel_selector_class_init, + NULL, /* class_finalize */ + NULL, /* class_data */ + sizeof (SPColorWheelSelector), + 0, /* n_preallocs */ + (GInstanceInitFunc) sp_color_wheel_selector_init, + 0, /* value_table */ + }; + + type = g_type_register_static (SP_TYPE_COLOR_SELECTOR, + "SPColorWheelSelector", + &info, + static_cast< GTypeFlags > (0) ); + } + return type; +} + +static void sp_color_wheel_selector_class_init(SPColorWheelSelectorClass *klass) +{ + static const gchar* nameset[] = {N_("Wheel"), 0}; + GObjectClass *object_class = G_OBJECT_CLASS(klass); + GtkWidgetClass *widget_class = GTK_WIDGET_CLASS(klass); + SPColorSelectorClass *selector_class = SP_COLOR_SELECTOR_CLASS (klass); + + parent_class = SP_COLOR_SELECTOR_CLASS (g_type_class_peek_parent (klass)); + + selector_class->name = nameset; + selector_class->submode_count = 1; + + object_class->dispose = sp_color_wheel_selector_dispose; + + widget_class->show_all = sp_color_wheel_selector_show_all; + widget_class->hide = sp_color_wheel_selector_hide; +} + +ColorWheelSelector::ColorWheelSelector( SPColorSelector* csel ) + : ColorSelector( csel ), + _updating( FALSE ), + _dragging( FALSE ), + _adj(0), + _wheel(0), + _slider(0), + _sbtn(0), + _label(0) +{ +} + +ColorWheelSelector::~ColorWheelSelector() +{ + _adj = 0; + _wheel = 0; + _sbtn = 0; + _label = 0; +} + +void sp_color_wheel_selector_init (SPColorWheelSelector *cs) +{ + SP_COLOR_SELECTOR(cs)->base = new ColorWheelSelector( SP_COLOR_SELECTOR(cs) ); + + if ( SP_COLOR_SELECTOR(cs)->base ) + { + SP_COLOR_SELECTOR(cs)->base->init(); + } +} + +void ColorWheelSelector::init() +{ + gint row = 0; + + _updating = FALSE; + _dragging = FALSE; + +#if GTK_CHECK_VERSION(3,0,0) + GtkWidget *t = gtk_grid_new(); +#else + GtkWidget *t = gtk_table_new (5, 3, FALSE); +#endif + + gtk_widget_show (t); + gtk_box_pack_start (GTK_BOX (_csel), t, TRUE, TRUE, 0); + + /* Create components */ + row = 0; + + _wheel = gimp_color_wheel_new(); + gtk_widget_show( _wheel ); + +#if GTK_CHECK_VERSION(3,0,0) + gtk_widget_set_halign(_wheel, GTK_ALIGN_FILL); + gtk_widget_set_valign(_wheel, GTK_ALIGN_FILL); + gtk_widget_set_hexpand(_wheel, TRUE); + gtk_widget_set_vexpand(_wheel, TRUE); + gtk_grid_attach(GTK_GRID(t), _wheel, 0, row, 3, 1); +#else + gtk_table_attach(GTK_TABLE(t), _wheel, 0, 3, row, row + 1, (GtkAttachOptions)(GTK_EXPAND | GTK_FILL), (GtkAttachOptions)(GTK_EXPAND | GTK_FILL), 0, 0); +#endif + + row++; + + /* Label */ + _label = gtk_label_new_with_mnemonic (_("_A:")); + gtk_misc_set_alignment (GTK_MISC (_label), 1.0, 0.5); + gtk_widget_show (_label); + +#if GTK_CHECK_VERSION(3,0,0) + gtk_widget_set_margin_left(_label, XPAD); + gtk_widget_set_margin_right(_label, XPAD); + gtk_widget_set_margin_top(_label, YPAD); + gtk_widget_set_margin_bottom(_label, YPAD); + gtk_widget_set_halign(_label, GTK_ALIGN_FILL); + gtk_widget_set_valign(_label, GTK_ALIGN_FILL); + gtk_grid_attach(GTK_GRID(t), _label, 0, row, 1, 1); +#else + gtk_table_attach (GTK_TABLE (t), _label, 0, 1, row, row + 1, GTK_FILL, GTK_FILL, XPAD, YPAD); +#endif + + /* Adjustment */ + _adj = GTK_ADJUSTMENT(gtk_adjustment_new(0.0, 0.0, 255.0, 1.0, 10.0, 10.0)); + + /* Slider */ + _slider = Gtk::manage(new Inkscape::UI::Widget::ColorSlider(Glib::wrap(_adj, true))); + _slider->set_tooltip_text(_("Alpha (opacity)")); + _slider->show(); + +#if GTK_CHECK_VERSION(3,0,0) + _slider->set_margin_left(XPAD); + _slider->set_margin_right(XPAD); + _slider->set_margin_top(YPAD); + _slider->set_margin_bottom(YPAD); + _slider->set_hexpand(true); + _slider->set_halign(Gtk::ALIGN_FILL); + _slider->set_valign(Gtk::ALIGN_FILL); + gtk_grid_attach(GTK_GRID(t), _slider->gobj(), 1, row, 1, 1); +#else + gtk_table_attach(GTK_TABLE (t), _slider->gobj(), 1, 2, row, row + 1, (GtkAttachOptions)(GTK_EXPAND | GTK_FILL), GTK_FILL, XPAD, YPAD); +#endif + + _slider->setColors(SP_RGBA32_F_COMPOSE (1.0, 1.0, 1.0, 0.0), + SP_RGBA32_F_COMPOSE (1.0, 1.0, 1.0, 0.5), + SP_RGBA32_F_COMPOSE (1.0, 1.0, 1.0, 1.0)); + + /* Spinbutton */ + _sbtn = gtk_spin_button_new (GTK_ADJUSTMENT (_adj), 1.0, 0); + gtk_widget_set_tooltip_text (_sbtn, _("Alpha (opacity)")); + sp_dialog_defocus_on_enter (_sbtn); + gtk_label_set_mnemonic_widget (GTK_LABEL(_label), _sbtn); + gtk_widget_show (_sbtn); + +#if GTK_CHECK_VERSION(3,0,0) + gtk_widget_set_margin_left(_sbtn, XPAD); + gtk_widget_set_margin_right(_sbtn, XPAD); + gtk_widget_set_margin_top(_sbtn, YPAD); + gtk_widget_set_margin_bottom(_sbtn, YPAD); + gtk_widget_set_halign(_sbtn, GTK_ALIGN_CENTER); + gtk_widget_set_valign(_sbtn, GTK_ALIGN_CENTER); + gtk_grid_attach(GTK_GRID(t), _sbtn, 2, row, 1, 1); +#else + gtk_table_attach (GTK_TABLE (t), _sbtn, 2, 3, row, row + 1, (GtkAttachOptions)0, (GtkAttachOptions)0, XPAD, YPAD); +#endif + + /* Signals */ + g_signal_connect (G_OBJECT (_adj), "value_changed", + G_CALLBACK (_adjustmentChanged), _csel); + + _slider->signal_grabbed.connect(sigc::mem_fun(*this, &ColorWheelSelector::_sliderGrabbed)); + _slider->signal_released.connect(sigc::mem_fun(*this, &ColorWheelSelector::_sliderReleased)); + _slider->signal_value_changed.connect(sigc::mem_fun(*this, &ColorWheelSelector::_sliderChanged)); + + g_signal_connect( G_OBJECT(_wheel), "changed", + G_CALLBACK (_wheelChanged), _csel ); +} + +static void sp_color_wheel_selector_dispose(GObject *object) +{ + if ((G_OBJECT_CLASS(parent_class))->dispose) + (* (G_OBJECT_CLASS(parent_class))->dispose) (object); +} + +static void +sp_color_wheel_selector_show_all (GtkWidget *widget) +{ + gtk_widget_show (widget); +} + +static void sp_color_wheel_selector_hide(GtkWidget *widget) +{ + gtk_widget_hide(widget); +} + +GtkWidget *sp_color_wheel_selector_new() +{ + SPColorWheelSelector *csel = SP_COLOR_WHEEL_SELECTOR(g_object_new (SP_TYPE_COLOR_WHEEL_SELECTOR, NULL)); + + return GTK_WIDGET (csel); +} + +/* Helpers for setting color value */ + +void ColorWheelSelector::_preserve_icc(SPColor *color) const { + color->icc = getColor().icc ? new SVGICCColor(*getColor().icc) : 0; +} + +void ColorWheelSelector::_colorChanged() +{ +#ifdef DUMP_CHANGE_INFO + g_message("ColorWheelSelector::_colorChanged( this=%p, %f, %f, %f, %f)", this, color.v.c[0], color.v.c[1], color.v.c[2], alpha ); +#endif + _updating = TRUE; + { + float hsv[3] = {0,0,0}; + sp_color_rgb_to_hsv_floatv(hsv, _color.v.c[0], _color.v.c[1], _color.v.c[2]); + gimp_color_wheel_set_color( GIMP_COLOR_WHEEL(_wheel), hsv[0], hsv[1], hsv[2] ); + } + + guint32 start = _color.toRGBA32( 0x00 ); + guint32 mid = _color.toRGBA32( 0x7f ); + guint32 end = _color.toRGBA32( 0xff ); + + _slider->setColors(start, mid, end); + + ColorScales::setScaled(_adj, _alpha); + + _updating = FALSE; +} + +void ColorWheelSelector::_adjustmentChanged( GtkAdjustment *adjustment, SPColorWheelSelector *cs ) +{ +// TODO check this. It looks questionable: + // if a value is entered between 0 and 1 exclusive, normalize it to (int) 0..255 or 0..100 + gdouble value = gtk_adjustment_get_value (adjustment); + gdouble upper = gtk_adjustment_get_upper (adjustment); + + if (value > 0.0 && value < 1.0) { + gtk_adjustment_set_value( adjustment, floor (value * upper + 0.5) ); + } + + ColorWheelSelector* wheelSelector = static_cast(SP_COLOR_SELECTOR(cs)->base); + if (wheelSelector->_updating) return; + + wheelSelector->_updating = TRUE; + + wheelSelector->_preserve_icc(&wheelSelector->_color); + wheelSelector->_updateInternals( wheelSelector->_color, ColorScales::getScaled( wheelSelector->_adj ), wheelSelector->_dragging ); + + wheelSelector->_updating = FALSE; +} + +void ColorWheelSelector::_sliderGrabbed() +{ + if (!_dragging) { + _dragging = TRUE; + _grabbed(); + + _preserve_icc(&_color); + _updateInternals( _color, ColorScales::getScaled( _adj ), _dragging ); + } +} + +void ColorWheelSelector::_sliderReleased() +{ + if (_dragging) { + _dragging = FALSE; + _released(); + + _preserve_icc(&_color); + _updateInternals( _color, ColorScales::getScaled( _adj ), _dragging ); + } +} + +void ColorWheelSelector::_sliderChanged() +{ + _preserve_icc(&_color); + _updateInternals( _color, ColorScales::getScaled( _adj ), _dragging ); +} + +void ColorWheelSelector::_wheelChanged( GimpColorWheel *wheel, SPColorWheelSelector *cs ) +{ + ColorWheelSelector* wheelSelector = static_cast(SP_COLOR_SELECTOR(cs)->base); + + gdouble h = 0; + gdouble s = 0; + gdouble v = 0; + gimp_color_wheel_get_color( wheel, &h, &s, &v ); + + float rgb[3] = {0,0,0}; + sp_color_hsv_to_rgb_floatv (rgb, h, s, v); + + SPColor color(rgb[0], rgb[1], rgb[2]); + + guint32 start = color.toRGBA32( 0x00 ); + guint32 mid = color.toRGBA32( 0x7f ); + guint32 end = color.toRGBA32( 0xff ); + + wheelSelector->_slider->setColors(start, mid, end); + + wheelSelector->_preserve_icc(&color); + wheelSelector->_updateInternals( color, wheelSelector->_alpha, gimp_color_wheel_is_adjusting(wheel) ); +} + + +Gtk::Widget *ColorWheelSelectorFactory::createWidget(Inkscape::UI::SelectedColor &color) const { + GtkWidget *w = sp_color_selector_new(SP_TYPE_COLOR_WHEEL_SELECTOR); + Gtk::Widget *wrapped = Gtk::manage(Glib::wrap(w)); + return wrapped; +} + +Glib::ustring ColorWheelSelectorFactory::modeName() const { + return gettext(ColorWheelSelector::MODE_NAME); +} + + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 : diff --git a/src/ui/widget/color-wheel-selector.h b/src/ui/widget/color-wheel-selector.h new file mode 100644 index 000000000..7a9cb5093 --- /dev/null +++ b/src/ui/widget/color-wheel-selector.h @@ -0,0 +1,111 @@ +#ifndef SEEN_SP_COLOR_WHEEL_SELECTOR_H +#define SEEN_SP_COLOR_WHEEL_SELECTOR_H + +#ifdef HAVE_CONFIG_H +# include +#endif + +#if GLIBMM_DISABLE_DEPRECATED && HAVE_GLIBMM_THREADS_H +#include +#endif + +#include +#include + +#include "widgets/sp-color-selector.h" +#include "ui/selected-color.h" + +typedef struct _GimpColorWheel GimpColorWheel; +struct SPColorWheelSelector; +struct SPColorWheelSelectorClass; + +namespace Inkscape { +namespace UI { +namespace Widget { + +class ColorSlider; + +} +} +} + +class ColorWheelSelector: public ColorSelector +{ +public: + static const gchar* MODE_NAME; + + ColorWheelSelector( SPColorSelector* csel ); + virtual ~ColorWheelSelector(); + + virtual void init(); + +protected: + virtual void _colorChanged(); + + static void _adjustmentChanged ( GtkAdjustment *adjustment, SPColorWheelSelector *cs ); + + void _sliderGrabbed(); + void _sliderReleased(); + void _sliderChanged(); + static void _wheelChanged( GimpColorWheel *wheel, SPColorWheelSelector *cs ); + + static void _fooChanged( GtkWidget foo, SPColorWheelSelector *cs ); + + void _recalcColor( gboolean changing ); + + gboolean _updating : 1; + gboolean _dragging : 1; + GtkAdjustment* _adj; // Channel adjustment + GtkWidget* _wheel; + Inkscape::UI::Widget::ColorSlider* _slider; + GtkWidget* _sbtn; // Spinbutton + GtkWidget* _label; // Label + +private: + // By default, disallow copy constructor and assignment operator + ColorWheelSelector( const ColorWheelSelector& obj ); + ColorWheelSelector& operator=( const ColorWheelSelector& obj ); + + void _preserve_icc(SPColor *color) const; +}; + + + +#define SP_TYPE_COLOR_WHEEL_SELECTOR (sp_color_wheel_selector_get_type ()) +#define SP_COLOR_WHEEL_SELECTOR(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), SP_TYPE_COLOR_WHEEL_SELECTOR, SPColorWheelSelector)) +#define SP_COLOR_WHEEL_SELECTOR_CLASS(k) (G_TYPE_CHECK_CLASS_CAST ((k), SP_TYPE_COLOR_WHEEL_SELECTOR, SPColorWheelSelectorClass)) +#define SP_IS_COLOR_WHEEL_SELECTOR(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), SP_TYPE_COLOR_WHEEL_SELECTOR)) +#define SP_IS_COLOR_WHEEL_SELECTOR_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), SP_TYPE_COLOR_WHEEL_SELECTOR)) + +struct SPColorWheelSelector { + SPColorSelector parent; +}; + +struct SPColorWheelSelectorClass { + SPColorSelectorClass parent_class; +}; + +GType sp_color_wheel_selector_get_type (void); + +GtkWidget *sp_color_wheel_selector_new (void); + + +class ColorWheelSelectorFactory: public Inkscape::UI::ColorSelectorFactory { +public: + Gtk::Widget *createWidget(Inkscape::UI::SelectedColor &color) const; + Glib::ustring modeName() const; +}; + + +#endif // SEEN_SP_COLOR_WHEEL_SELECTOR_H + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 : diff --git a/src/widgets/Makefile_insert b/src/widgets/Makefile_insert index a4a3bb61b..7a1a7a4ef 100644 --- a/src/widgets/Makefile_insert +++ b/src/widgets/Makefile_insert @@ -74,8 +74,6 @@ ink_common_sources += \ widgets/sp-color-scales.h \ widgets/sp-color-selector.cpp \ widgets/sp-color-selector.h \ - widgets/sp-color-wheel-selector.cpp \ - widgets/sp-color-wheel-selector.h \ widgets/spinbutton-events.cpp \ widgets/spinbutton-events.h \ widgets/sp-widget.cpp \ diff --git a/src/widgets/sp-color-notebook.cpp b/src/widgets/sp-color-notebook.cpp index ac110b86c..ca189e086 100644 --- a/src/widgets/sp-color-notebook.cpp +++ b/src/widgets/sp-color-notebook.cpp @@ -32,7 +32,6 @@ #include "spw-utilities.h" #include "sp-color-scales.h" #include "sp-color-icc-selector.h" -#include "sp-color-wheel-selector.h" #include "svg/svg-icc-color.h" #include "../inkscape.h" #include "../document.h" @@ -42,6 +41,7 @@ #include "tools-switch.h" #include "ui/tools/tool-base.h" #include "ui/widget/color-entry.h" +#include "ui/widget/color-wheel-selector.h" using Inkscape::CMSSystem; diff --git a/src/widgets/sp-color-wheel-selector.cpp b/src/widgets/sp-color-wheel-selector.cpp deleted file mode 100644 index 2b448e075..000000000 --- a/src/widgets/sp-color-wheel-selector.cpp +++ /dev/null @@ -1,367 +0,0 @@ -#ifdef HAVE_CONFIG_H -# include "config.h" -#endif - -#include "sp-color-wheel-selector.h" - -#include -#include -#include -#include -#include "../dialogs/dialog-events.h" -#include "sp-color-scales.h" -#include "sp-color-icc-selector.h" -#include "../svg/svg-icc-color.h" -#include "ui/widget/color-slider.h" -#include "ui/widget/gimpcolorwheel.h" - -G_BEGIN_DECLS - -static void sp_color_wheel_selector_class_init (SPColorWheelSelectorClass *klass); -static void sp_color_wheel_selector_init (SPColorWheelSelector *cs); -static void sp_color_wheel_selector_dispose(GObject *object); - -static void sp_color_wheel_selector_show_all (GtkWidget *widget); -static void sp_color_wheel_selector_hide(GtkWidget *widget); - - -G_END_DECLS - -static SPColorSelectorClass *parent_class; - -#define XPAD 4 -#define YPAD 1 - - -const gchar* ColorWheelSelector::MODE_NAME = N_("Wheel"); - -GType -sp_color_wheel_selector_get_type (void) -{ - static GType type = 0; - if (!type) { - static const GTypeInfo info = { - sizeof (SPColorWheelSelectorClass), - NULL, /* base_init */ - NULL, /* base_finalize */ - (GClassInitFunc) sp_color_wheel_selector_class_init, - NULL, /* class_finalize */ - NULL, /* class_data */ - sizeof (SPColorWheelSelector), - 0, /* n_preallocs */ - (GInstanceInitFunc) sp_color_wheel_selector_init, - 0, /* value_table */ - }; - - type = g_type_register_static (SP_TYPE_COLOR_SELECTOR, - "SPColorWheelSelector", - &info, - static_cast< GTypeFlags > (0) ); - } - return type; -} - -static void sp_color_wheel_selector_class_init(SPColorWheelSelectorClass *klass) -{ - static const gchar* nameset[] = {N_("Wheel"), 0}; - GObjectClass *object_class = G_OBJECT_CLASS(klass); - GtkWidgetClass *widget_class = GTK_WIDGET_CLASS(klass); - SPColorSelectorClass *selector_class = SP_COLOR_SELECTOR_CLASS (klass); - - parent_class = SP_COLOR_SELECTOR_CLASS (g_type_class_peek_parent (klass)); - - selector_class->name = nameset; - selector_class->submode_count = 1; - - object_class->dispose = sp_color_wheel_selector_dispose; - - widget_class->show_all = sp_color_wheel_selector_show_all; - widget_class->hide = sp_color_wheel_selector_hide; -} - -ColorWheelSelector::ColorWheelSelector( SPColorSelector* csel ) - : ColorSelector( csel ), - _updating( FALSE ), - _dragging( FALSE ), - _adj(0), - _wheel(0), - _slider(0), - _sbtn(0), - _label(0) -{ -} - -ColorWheelSelector::~ColorWheelSelector() -{ - _adj = 0; - _wheel = 0; - _sbtn = 0; - _label = 0; -} - -void sp_color_wheel_selector_init (SPColorWheelSelector *cs) -{ - SP_COLOR_SELECTOR(cs)->base = new ColorWheelSelector( SP_COLOR_SELECTOR(cs) ); - - if ( SP_COLOR_SELECTOR(cs)->base ) - { - SP_COLOR_SELECTOR(cs)->base->init(); - } -} - -void ColorWheelSelector::init() -{ - gint row = 0; - - _updating = FALSE; - _dragging = FALSE; - -#if GTK_CHECK_VERSION(3,0,0) - GtkWidget *t = gtk_grid_new(); -#else - GtkWidget *t = gtk_table_new (5, 3, FALSE); -#endif - - gtk_widget_show (t); - gtk_box_pack_start (GTK_BOX (_csel), t, TRUE, TRUE, 0); - - /* Create components */ - row = 0; - - _wheel = gimp_color_wheel_new(); - gtk_widget_show( _wheel ); - -#if GTK_CHECK_VERSION(3,0,0) - gtk_widget_set_halign(_wheel, GTK_ALIGN_FILL); - gtk_widget_set_valign(_wheel, GTK_ALIGN_FILL); - gtk_widget_set_hexpand(_wheel, TRUE); - gtk_widget_set_vexpand(_wheel, TRUE); - gtk_grid_attach(GTK_GRID(t), _wheel, 0, row, 3, 1); -#else - gtk_table_attach(GTK_TABLE(t), _wheel, 0, 3, row, row + 1, (GtkAttachOptions)(GTK_EXPAND | GTK_FILL), (GtkAttachOptions)(GTK_EXPAND | GTK_FILL), 0, 0); -#endif - - row++; - - /* Label */ - _label = gtk_label_new_with_mnemonic (_("_A:")); - gtk_misc_set_alignment (GTK_MISC (_label), 1.0, 0.5); - gtk_widget_show (_label); - -#if GTK_CHECK_VERSION(3,0,0) - gtk_widget_set_margin_left(_label, XPAD); - gtk_widget_set_margin_right(_label, XPAD); - gtk_widget_set_margin_top(_label, YPAD); - gtk_widget_set_margin_bottom(_label, YPAD); - gtk_widget_set_halign(_label, GTK_ALIGN_FILL); - gtk_widget_set_valign(_label, GTK_ALIGN_FILL); - gtk_grid_attach(GTK_GRID(t), _label, 0, row, 1, 1); -#else - gtk_table_attach (GTK_TABLE (t), _label, 0, 1, row, row + 1, GTK_FILL, GTK_FILL, XPAD, YPAD); -#endif - - /* Adjustment */ - _adj = GTK_ADJUSTMENT(gtk_adjustment_new(0.0, 0.0, 255.0, 1.0, 10.0, 10.0)); - - /* Slider */ - _slider = Gtk::manage(new Inkscape::UI::Widget::ColorSlider(Glib::wrap(_adj, true))); - _slider->set_tooltip_text(_("Alpha (opacity)")); - _slider->show(); - -#if GTK_CHECK_VERSION(3,0,0) - _slider->set_margin_left(XPAD); - _slider->set_margin_right(XPAD); - _slider->set_margin_top(YPAD); - _slider->set_margin_bottom(YPAD); - _slider->set_hexpand(true); - _slider->set_halign(Gtk::ALIGN_FILL); - _slider->set_valign(Gtk::ALIGN_FILL); - gtk_grid_attach(GTK_GRID(t), _slider->gobj(), 1, row, 1, 1); -#else - gtk_table_attach(GTK_TABLE (t), _slider->gobj(), 1, 2, row, row + 1, (GtkAttachOptions)(GTK_EXPAND | GTK_FILL), GTK_FILL, XPAD, YPAD); -#endif - - _slider->setColors(SP_RGBA32_F_COMPOSE (1.0, 1.0, 1.0, 0.0), - SP_RGBA32_F_COMPOSE (1.0, 1.0, 1.0, 0.5), - SP_RGBA32_F_COMPOSE (1.0, 1.0, 1.0, 1.0)); - - /* Spinbutton */ - _sbtn = gtk_spin_button_new (GTK_ADJUSTMENT (_adj), 1.0, 0); - gtk_widget_set_tooltip_text (_sbtn, _("Alpha (opacity)")); - sp_dialog_defocus_on_enter (_sbtn); - gtk_label_set_mnemonic_widget (GTK_LABEL(_label), _sbtn); - gtk_widget_show (_sbtn); - -#if GTK_CHECK_VERSION(3,0,0) - gtk_widget_set_margin_left(_sbtn, XPAD); - gtk_widget_set_margin_right(_sbtn, XPAD); - gtk_widget_set_margin_top(_sbtn, YPAD); - gtk_widget_set_margin_bottom(_sbtn, YPAD); - gtk_widget_set_halign(_sbtn, GTK_ALIGN_CENTER); - gtk_widget_set_valign(_sbtn, GTK_ALIGN_CENTER); - gtk_grid_attach(GTK_GRID(t), _sbtn, 2, row, 1, 1); -#else - gtk_table_attach (GTK_TABLE (t), _sbtn, 2, 3, row, row + 1, (GtkAttachOptions)0, (GtkAttachOptions)0, XPAD, YPAD); -#endif - - /* Signals */ - g_signal_connect (G_OBJECT (_adj), "value_changed", - G_CALLBACK (_adjustmentChanged), _csel); - - _slider->signal_grabbed.connect(sigc::mem_fun(*this, &ColorWheelSelector::_sliderGrabbed)); - _slider->signal_released.connect(sigc::mem_fun(*this, &ColorWheelSelector::_sliderReleased)); - _slider->signal_value_changed.connect(sigc::mem_fun(*this, &ColorWheelSelector::_sliderChanged)); - - g_signal_connect( G_OBJECT(_wheel), "changed", - G_CALLBACK (_wheelChanged), _csel ); -} - -static void sp_color_wheel_selector_dispose(GObject *object) -{ - if ((G_OBJECT_CLASS(parent_class))->dispose) - (* (G_OBJECT_CLASS(parent_class))->dispose) (object); -} - -static void -sp_color_wheel_selector_show_all (GtkWidget *widget) -{ - gtk_widget_show (widget); -} - -static void sp_color_wheel_selector_hide(GtkWidget *widget) -{ - gtk_widget_hide(widget); -} - -GtkWidget *sp_color_wheel_selector_new() -{ - SPColorWheelSelector *csel = SP_COLOR_WHEEL_SELECTOR(g_object_new (SP_TYPE_COLOR_WHEEL_SELECTOR, NULL)); - - return GTK_WIDGET (csel); -} - -/* Helpers for setting color value */ - -void ColorWheelSelector::_preserve_icc(SPColor *color) const { - color->icc = getColor().icc ? new SVGICCColor(*getColor().icc) : 0; -} - -void ColorWheelSelector::_colorChanged() -{ -#ifdef DUMP_CHANGE_INFO - g_message("ColorWheelSelector::_colorChanged( this=%p, %f, %f, %f, %f)", this, color.v.c[0], color.v.c[1], color.v.c[2], alpha ); -#endif - _updating = TRUE; - { - float hsv[3] = {0,0,0}; - sp_color_rgb_to_hsv_floatv(hsv, _color.v.c[0], _color.v.c[1], _color.v.c[2]); - gimp_color_wheel_set_color( GIMP_COLOR_WHEEL(_wheel), hsv[0], hsv[1], hsv[2] ); - } - - guint32 start = _color.toRGBA32( 0x00 ); - guint32 mid = _color.toRGBA32( 0x7f ); - guint32 end = _color.toRGBA32( 0xff ); - - _slider->setColors(start, mid, end); - - ColorScales::setScaled(_adj, _alpha); - - _updating = FALSE; -} - -void ColorWheelSelector::_adjustmentChanged( GtkAdjustment *adjustment, SPColorWheelSelector *cs ) -{ -// TODO check this. It looks questionable: - // if a value is entered between 0 and 1 exclusive, normalize it to (int) 0..255 or 0..100 - gdouble value = gtk_adjustment_get_value (adjustment); - gdouble upper = gtk_adjustment_get_upper (adjustment); - - if (value > 0.0 && value < 1.0) { - gtk_adjustment_set_value( adjustment, floor (value * upper + 0.5) ); - } - - ColorWheelSelector* wheelSelector = static_cast(SP_COLOR_SELECTOR(cs)->base); - if (wheelSelector->_updating) return; - - wheelSelector->_updating = TRUE; - - wheelSelector->_preserve_icc(&wheelSelector->_color); - wheelSelector->_updateInternals( wheelSelector->_color, ColorScales::getScaled( wheelSelector->_adj ), wheelSelector->_dragging ); - - wheelSelector->_updating = FALSE; -} - -void ColorWheelSelector::_sliderGrabbed() -{ - if (!_dragging) { - _dragging = TRUE; - _grabbed(); - - _preserve_icc(&_color); - _updateInternals( _color, ColorScales::getScaled( _adj ), _dragging ); - } -} - -void ColorWheelSelector::_sliderReleased() -{ - if (_dragging) { - _dragging = FALSE; - _released(); - - _preserve_icc(&_color); - _updateInternals( _color, ColorScales::getScaled( _adj ), _dragging ); - } -} - -void ColorWheelSelector::_sliderChanged() -{ - _preserve_icc(&_color); - _updateInternals( _color, ColorScales::getScaled( _adj ), _dragging ); -} - -void ColorWheelSelector::_wheelChanged( GimpColorWheel *wheel, SPColorWheelSelector *cs ) -{ - ColorWheelSelector* wheelSelector = static_cast(SP_COLOR_SELECTOR(cs)->base); - - gdouble h = 0; - gdouble s = 0; - gdouble v = 0; - gimp_color_wheel_get_color( wheel, &h, &s, &v ); - - float rgb[3] = {0,0,0}; - sp_color_hsv_to_rgb_floatv (rgb, h, s, v); - - SPColor color(rgb[0], rgb[1], rgb[2]); - - guint32 start = color.toRGBA32( 0x00 ); - guint32 mid = color.toRGBA32( 0x7f ); - guint32 end = color.toRGBA32( 0xff ); - - wheelSelector->_slider->setColors(start, mid, end); - - wheelSelector->_preserve_icc(&color); - wheelSelector->_updateInternals( color, wheelSelector->_alpha, gimp_color_wheel_is_adjusting(wheel) ); -} - - -Gtk::Widget *ColorWheelSelectorFactory::createWidget(Inkscape::UI::SelectedColor &color) const { - GtkWidget *w = sp_color_selector_new(SP_TYPE_COLOR_WHEEL_SELECTOR); - Gtk::Widget *wrapped = Gtk::manage(Glib::wrap(w)); - return wrapped; -} - -Glib::ustring ColorWheelSelectorFactory::modeName() const { - return gettext(ColorWheelSelector::MODE_NAME); -} - - -/* - Local Variables: - mode:c++ - c-file-style:"stroustrup" - c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) - indent-tabs-mode:nil - fill-column:99 - End: -*/ -// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 : diff --git a/src/widgets/sp-color-wheel-selector.h b/src/widgets/sp-color-wheel-selector.h deleted file mode 100644 index ad0d11bad..000000000 --- a/src/widgets/sp-color-wheel-selector.h +++ /dev/null @@ -1,111 +0,0 @@ -#ifndef SEEN_SP_COLOR_WHEEL_SELECTOR_H -#define SEEN_SP_COLOR_WHEEL_SELECTOR_H - -#ifdef HAVE_CONFIG_H -# include -#endif - -#if GLIBMM_DISABLE_DEPRECATED && HAVE_GLIBMM_THREADS_H -#include -#endif - -#include -#include - -#include "sp-color-selector.h" -#include "ui/selected-color.h" - -typedef struct _GimpColorWheel GimpColorWheel; -struct SPColorWheelSelector; -struct SPColorWheelSelectorClass; - -namespace Inkscape { -namespace UI { -namespace Widget { - -class ColorSlider; - -} -} -} - -class ColorWheelSelector: public ColorSelector -{ -public: - static const gchar* MODE_NAME; - - ColorWheelSelector( SPColorSelector* csel ); - virtual ~ColorWheelSelector(); - - virtual void init(); - -protected: - virtual void _colorChanged(); - - static void _adjustmentChanged ( GtkAdjustment *adjustment, SPColorWheelSelector *cs ); - - void _sliderGrabbed(); - void _sliderReleased(); - void _sliderChanged(); - static void _wheelChanged( GimpColorWheel *wheel, SPColorWheelSelector *cs ); - - static void _fooChanged( GtkWidget foo, SPColorWheelSelector *cs ); - - void _recalcColor( gboolean changing ); - - gboolean _updating : 1; - gboolean _dragging : 1; - GtkAdjustment* _adj; // Channel adjustment - GtkWidget* _wheel; - Inkscape::UI::Widget::ColorSlider* _slider; - GtkWidget* _sbtn; // Spinbutton - GtkWidget* _label; // Label - -private: - // By default, disallow copy constructor and assignment operator - ColorWheelSelector( const ColorWheelSelector& obj ); - ColorWheelSelector& operator=( const ColorWheelSelector& obj ); - - void _preserve_icc(SPColor *color) const; -}; - - - -#define SP_TYPE_COLOR_WHEEL_SELECTOR (sp_color_wheel_selector_get_type ()) -#define SP_COLOR_WHEEL_SELECTOR(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), SP_TYPE_COLOR_WHEEL_SELECTOR, SPColorWheelSelector)) -#define SP_COLOR_WHEEL_SELECTOR_CLASS(k) (G_TYPE_CHECK_CLASS_CAST ((k), SP_TYPE_COLOR_WHEEL_SELECTOR, SPColorWheelSelectorClass)) -#define SP_IS_COLOR_WHEEL_SELECTOR(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), SP_TYPE_COLOR_WHEEL_SELECTOR)) -#define SP_IS_COLOR_WHEEL_SELECTOR_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), SP_TYPE_COLOR_WHEEL_SELECTOR)) - -struct SPColorWheelSelector { - SPColorSelector parent; -}; - -struct SPColorWheelSelectorClass { - SPColorSelectorClass parent_class; -}; - -GType sp_color_wheel_selector_get_type (void); - -GtkWidget *sp_color_wheel_selector_new (void); - - -class ColorWheelSelectorFactory: public Inkscape::UI::ColorSelectorFactory { -public: - Gtk::Widget *createWidget(Inkscape::UI::SelectedColor &color) const; - Glib::ustring modeName() const; -}; - - -#endif // SEEN_SP_COLOR_WHEEL_SELECTOR_H - -/* - Local Variables: - mode:c++ - c-file-style:"stroustrup" - c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) - indent-tabs-mode:nil - fill-column:99 - End: -*/ -// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 : -- cgit v1.2.3 From c2b99414ee441654e641552f372ebf1165f94ffc Mon Sep 17 00:00:00 2001 From: Tomasz Boczkowski Date: Sat, 31 May 2014 12:34:20 +0200 Subject: SPColorWheelSelector c++-sification: inherit Gtk::Table/Grid (bzr r13341.6.35) --- src/ui/selected-color.cpp | 13 +- src/ui/selected-color.h | 2 + src/ui/widget/color-wheel-selector.cpp | 220 +++++++++++---------------------- src/ui/widget/color-wheel-selector.h | 70 +++++------ src/widgets/sp-color-notebook.cpp | 20 +-- 5 files changed, 125 insertions(+), 200 deletions(-) (limited to 'src') diff --git a/src/ui/selected-color.cpp b/src/ui/selected-color.cpp index 1be171a6b..10ca68b21 100644 --- a/src/ui/selected-color.cpp +++ b/src/ui/selected-color.cpp @@ -16,6 +16,8 @@ #include #include +#include "svg/svg-icc-color.h" + namespace Inkscape { namespace UI { @@ -24,8 +26,8 @@ double const SelectedColor::_EPSILON = 1e-4; SelectedColor::SelectedColor() : _color(0) , _alpha(1.0) - , _virgin(true) , _held(false) + , _virgin(true) { } @@ -36,7 +38,7 @@ SelectedColor::~SelectedColor() { void SelectedColor::setColor(SPColor const &color) { - setColorAlpha( color, _alpha ); + setColorAlpha( color, _alpha, true); } SPColor SelectedColor::color() const @@ -47,7 +49,7 @@ SPColor SelectedColor::color() const void SelectedColor::setAlpha(gfloat alpha) { g_return_if_fail( ( 0.0 <= alpha ) && ( alpha <= 1.0 ) ); - setColorAlpha( _color, alpha ); + setColorAlpha( _color, alpha, true); } gfloat SelectedColor::alpha() const @@ -111,9 +113,14 @@ void SelectedColor::setHeld(bool held) { if (released) { signal_released.emit(); + signal_changed.emit(); } } +void SelectedColor::preserveICC() { + _color.icc = _color.icc ? new SVGICCColor(*_color.icc) : 0; +} + } } diff --git a/src/ui/selected-color.h b/src/ui/selected-color.h index ec0cc55e3..5d3d89672 100644 --- a/src/ui/selected-color.h +++ b/src/ui/selected-color.h @@ -44,6 +44,8 @@ public: void setHeld(bool held); + void preserveICC(); + sigc::signal signal_grabbed; sigc::signal signal_dragged; sigc::signal signal_released; diff --git a/src/ui/widget/color-wheel-selector.cpp b/src/ui/widget/color-wheel-selector.cpp index 134232813..e14c70728 100644 --- a/src/ui/widget/color-wheel-selector.cpp +++ b/src/ui/widget/color-wheel-selector.cpp @@ -11,22 +11,14 @@ #include "dialogs/dialog-events.h" #include "widgets/sp-color-scales.h" #include "svg/svg-icc-color.h" +#include "ui/selected-color.h" #include "ui/widget/color-slider.h" #include "ui/widget/gimpcolorwheel.h" -G_BEGIN_DECLS +namespace Inkscape { +namespace UI { +namespace Widget { -static void sp_color_wheel_selector_class_init (SPColorWheelSelectorClass *klass); -static void sp_color_wheel_selector_init (SPColorWheelSelector *cs); -static void sp_color_wheel_selector_dispose(GObject *object); - -static void sp_color_wheel_selector_show_all (GtkWidget *widget); -static void sp_color_wheel_selector_hide(GtkWidget *widget); - - -G_END_DECLS - -static SPColorSelectorClass *parent_class; #define XPAD 4 #define YPAD 1 @@ -34,60 +26,24 @@ static SPColorSelectorClass *parent_class; const gchar* ColorWheelSelector::MODE_NAME = N_("Wheel"); -GType -sp_color_wheel_selector_get_type (void) -{ - static GType type = 0; - if (!type) { - static const GTypeInfo info = { - sizeof (SPColorWheelSelectorClass), - NULL, /* base_init */ - NULL, /* base_finalize */ - (GClassInitFunc) sp_color_wheel_selector_class_init, - NULL, /* class_finalize */ - NULL, /* class_data */ - sizeof (SPColorWheelSelector), - 0, /* n_preallocs */ - (GInstanceInitFunc) sp_color_wheel_selector_init, - 0, /* value_table */ - }; - - type = g_type_register_static (SP_TYPE_COLOR_SELECTOR, - "SPColorWheelSelector", - &info, - static_cast< GTypeFlags > (0) ); - } - return type; -} - -static void sp_color_wheel_selector_class_init(SPColorWheelSelectorClass *klass) -{ - static const gchar* nameset[] = {N_("Wheel"), 0}; - GObjectClass *object_class = G_OBJECT_CLASS(klass); - GtkWidgetClass *widget_class = GTK_WIDGET_CLASS(klass); - SPColorSelectorClass *selector_class = SP_COLOR_SELECTOR_CLASS (klass); - - parent_class = SP_COLOR_SELECTOR_CLASS (g_type_class_peek_parent (klass)); - - selector_class->name = nameset; - selector_class->submode_count = 1; - - object_class->dispose = sp_color_wheel_selector_dispose; - - widget_class->show_all = sp_color_wheel_selector_show_all; - widget_class->hide = sp_color_wheel_selector_hide; -} - -ColorWheelSelector::ColorWheelSelector( SPColorSelector* csel ) - : ColorSelector( csel ), - _updating( FALSE ), - _dragging( FALSE ), +ColorWheelSelector::ColorWheelSelector(SelectedColor &color) +#if GTK_CHECK_VERSION(3,0,0) + : Gtk::Grid() +#else + : Gtk::Table(5, 3, false) +#endif + , _color(color) + , _updating(false), _adj(0), _wheel(0), _slider(0), _sbtn(0), _label(0) { + _initUI(); + _color_changed_connection = color.signal_changed.connect(sigc::mem_fun(this, &ColorWheelSelector::_colorChanged)); + _color_dragged_connection = color.signal_dragged.connect(sigc::mem_fun(this, &ColorWheelSelector::_colorChanged)); + } ColorWheelSelector::~ColorWheelSelector() @@ -96,33 +52,17 @@ ColorWheelSelector::~ColorWheelSelector() _wheel = 0; _sbtn = 0; _label = 0; -} - -void sp_color_wheel_selector_init (SPColorWheelSelector *cs) -{ - SP_COLOR_SELECTOR(cs)->base = new ColorWheelSelector( SP_COLOR_SELECTOR(cs) ); - if ( SP_COLOR_SELECTOR(cs)->base ) - { - SP_COLOR_SELECTOR(cs)->base->init(); - } + _color_changed_connection.disconnect(); + _color_dragged_connection.disconnect(); } -void ColorWheelSelector::init() -{ +void ColorWheelSelector::_initUI() { gint row = 0; - _updating = FALSE; - _dragging = FALSE; - -#if GTK_CHECK_VERSION(3,0,0) - GtkWidget *t = gtk_grid_new(); -#else - GtkWidget *t = gtk_table_new (5, 3, FALSE); -#endif + GtkWidget *t = GTK_WIDGET(gobj()); - gtk_widget_show (t); - gtk_box_pack_start (GTK_BOX (_csel), t, TRUE, TRUE, 0); + //gtk_widget_show (t); /* Create components */ row = 0; @@ -205,44 +145,14 @@ void ColorWheelSelector::init() /* Signals */ g_signal_connect (G_OBJECT (_adj), "value_changed", - G_CALLBACK (_adjustmentChanged), _csel); + G_CALLBACK (_adjustmentChanged), this); _slider->signal_grabbed.connect(sigc::mem_fun(*this, &ColorWheelSelector::_sliderGrabbed)); _slider->signal_released.connect(sigc::mem_fun(*this, &ColorWheelSelector::_sliderReleased)); _slider->signal_value_changed.connect(sigc::mem_fun(*this, &ColorWheelSelector::_sliderChanged)); g_signal_connect( G_OBJECT(_wheel), "changed", - G_CALLBACK (_wheelChanged), _csel ); -} - -static void sp_color_wheel_selector_dispose(GObject *object) -{ - if ((G_OBJECT_CLASS(parent_class))->dispose) - (* (G_OBJECT_CLASS(parent_class))->dispose) (object); -} - -static void -sp_color_wheel_selector_show_all (GtkWidget *widget) -{ - gtk_widget_show (widget); -} - -static void sp_color_wheel_selector_hide(GtkWidget *widget) -{ - gtk_widget_hide(widget); -} - -GtkWidget *sp_color_wheel_selector_new() -{ - SPColorWheelSelector *csel = SP_COLOR_WHEEL_SELECTOR(g_object_new (SP_TYPE_COLOR_WHEEL_SELECTOR, NULL)); - - return GTK_WIDGET (csel); -} - -/* Helpers for setting color value */ - -void ColorWheelSelector::_preserve_icc(SPColor *color) const { - color->icc = getColor().icc ? new SVGICCColor(*getColor().icc) : 0; + G_CALLBACK (_wheelChanged), this ); } void ColorWheelSelector::_colorChanged() @@ -250,26 +160,34 @@ void ColorWheelSelector::_colorChanged() #ifdef DUMP_CHANGE_INFO g_message("ColorWheelSelector::_colorChanged( this=%p, %f, %f, %f, %f)", this, color.v.c[0], color.v.c[1], color.v.c[2], alpha ); #endif - _updating = TRUE; + if (_updating) { + return; + } + + _updating = true; { float hsv[3] = {0,0,0}; - sp_color_rgb_to_hsv_floatv(hsv, _color.v.c[0], _color.v.c[1], _color.v.c[2]); + sp_color_rgb_to_hsv_floatv(hsv, _color.color().v.c[0], _color.color().v.c[1], _color.color().v.c[2]); gimp_color_wheel_set_color( GIMP_COLOR_WHEEL(_wheel), hsv[0], hsv[1], hsv[2] ); } - guint32 start = _color.toRGBA32( 0x00 ); - guint32 mid = _color.toRGBA32( 0x7f ); - guint32 end = _color.toRGBA32( 0xff ); + guint32 start = _color.color().toRGBA32( 0x00 ); + guint32 mid = _color.color().toRGBA32( 0x7f ); + guint32 end = _color.color().toRGBA32( 0xff ); _slider->setColors(start, mid, end); - ColorScales::setScaled(_adj, _alpha); + ColorScales::setScaled(_adj, _color.alpha()); _updating = FALSE; } -void ColorWheelSelector::_adjustmentChanged( GtkAdjustment *adjustment, SPColorWheelSelector *cs ) +void ColorWheelSelector::_adjustmentChanged( GtkAdjustment *adjustment, ColorWheelSelector *cs ) { + if (cs->_updating) { + return; + } + // TODO check this. It looks questionable: // if a value is entered between 0 and 1 exclusive, normalize it to (int) 0..255 or 0..100 gdouble value = gtk_adjustment_get_value (adjustment); @@ -279,48 +197,42 @@ void ColorWheelSelector::_adjustmentChanged( GtkAdjustment *adjustment, SPColorW gtk_adjustment_set_value( adjustment, floor (value * upper + 0.5) ); } - ColorWheelSelector* wheelSelector = static_cast(SP_COLOR_SELECTOR(cs)->base); - if (wheelSelector->_updating) return; + cs->_updating = true; - wheelSelector->_updating = TRUE; + cs->_color.preserveICC(); - wheelSelector->_preserve_icc(&wheelSelector->_color); - wheelSelector->_updateInternals( wheelSelector->_color, ColorScales::getScaled( wheelSelector->_adj ), wheelSelector->_dragging ); + cs->_color.setAlpha(ColorScales::getScaled( cs->_adj )); - wheelSelector->_updating = FALSE; + cs->_updating = false; } void ColorWheelSelector::_sliderGrabbed() { - if (!_dragging) { - _dragging = TRUE; - _grabbed(); - - _preserve_icc(&_color); - _updateInternals( _color, ColorScales::getScaled( _adj ), _dragging ); - } + _color.preserveICC(); + _color.setHeld(true); } void ColorWheelSelector::_sliderReleased() { - if (_dragging) { - _dragging = FALSE; - _released(); - - _preserve_icc(&_color); - _updateInternals( _color, ColorScales::getScaled( _adj ), _dragging ); - } + _color.preserveICC(); + _color.setHeld(false); } void ColorWheelSelector::_sliderChanged() { - _preserve_icc(&_color); - _updateInternals( _color, ColorScales::getScaled( _adj ), _dragging ); + if (_updating) { + return; + } + + _updating = true; + _color.preserveICC(); + _color.setAlpha(ColorScales::getScaled(_adj)); + _updating = false; } -void ColorWheelSelector::_wheelChanged( GimpColorWheel *wheel, SPColorWheelSelector *cs ) +void ColorWheelSelector::_wheelChanged( GimpColorWheel *wheel, ColorWheelSelector *wheelSelector ) { - ColorWheelSelector* wheelSelector = static_cast(SP_COLOR_SELECTOR(cs)->base); + if (wheelSelector->_updating) return; gdouble h = 0; gdouble s = 0; @@ -338,21 +250,31 @@ void ColorWheelSelector::_wheelChanged( GimpColorWheel *wheel, SPColorWheelSelec wheelSelector->_slider->setColors(start, mid, end); - wheelSelector->_preserve_icc(&color); - wheelSelector->_updateInternals( color, wheelSelector->_alpha, gimp_color_wheel_is_adjusting(wheel) ); + wheelSelector->_updating = true; + + wheelSelector->_color.preserveICC(); + + wheelSelector->_color.setHeld(gimp_color_wheel_is_adjusting(wheel)); + wheelSelector->_color.setColor(color); + + wheelSelector->_updating = false; } Gtk::Widget *ColorWheelSelectorFactory::createWidget(Inkscape::UI::SelectedColor &color) const { - GtkWidget *w = sp_color_selector_new(SP_TYPE_COLOR_WHEEL_SELECTOR); - Gtk::Widget *wrapped = Gtk::manage(Glib::wrap(w)); - return wrapped; + Gtk::Widget *w = Gtk::manage(new ColorWheelSelector(color)); + return w; } Glib::ustring ColorWheelSelectorFactory::modeName() const { return gettext(ColorWheelSelector::MODE_NAME); } +} +} +} + + /* Local Variables: diff --git a/src/ui/widget/color-wheel-selector.h b/src/ui/widget/color-wheel-selector.h index 7a9cb5093..e289a8df6 100644 --- a/src/ui/widget/color-wheel-selector.h +++ b/src/ui/widget/color-wheel-selector.h @@ -1,3 +1,14 @@ +/** + * @file + * Color selector widget containing GIMP color wheel and slider + */ +/* Authors: + * Tomasz Boczkowski (c++-sification) + * + * Copyright (C) 2014 Authors + * + * This code is in public domain + */ #ifndef SEEN_SP_COLOR_WHEEL_SELECTOR_H #define SEEN_SP_COLOR_WHEEL_SELECTOR_H @@ -11,13 +22,11 @@ #include #include +#include -#include "widgets/sp-color-selector.h" #include "ui/selected-color.h" typedef struct _GimpColorWheel GimpColorWheel; -struct SPColorWheelSelector; -struct SPColorWheelSelectorClass; namespace Inkscape { namespace UI { @@ -25,36 +34,31 @@ namespace Widget { class ColorSlider; -} -} -} - -class ColorWheelSelector: public ColorSelector +class ColorWheelSelector + : public Gtk::Table //if GTK2 { public: static const gchar* MODE_NAME; - ColorWheelSelector( SPColorSelector* csel ); + ColorWheelSelector(SelectedColor &color); virtual ~ColorWheelSelector(); - virtual void init(); - protected: + void _initUI(); virtual void _colorChanged(); - static void _adjustmentChanged ( GtkAdjustment *adjustment, SPColorWheelSelector *cs ); + static void _adjustmentChanged ( GtkAdjustment *adjustment, ColorWheelSelector *cs ); void _sliderGrabbed(); void _sliderReleased(); void _sliderChanged(); - static void _wheelChanged( GimpColorWheel *wheel, SPColorWheelSelector *cs ); - - static void _fooChanged( GtkWidget foo, SPColorWheelSelector *cs ); + static void _wheelChanged( GimpColorWheel *wheel, ColorWheelSelector *cs ); void _recalcColor( gboolean changing ); - gboolean _updating : 1; - gboolean _dragging : 1; + SelectedColor &_color; + bool _updating; + GtkAdjustment* _adj; // Channel adjustment GtkWidget* _wheel; Inkscape::UI::Widget::ColorSlider* _slider; @@ -66,36 +70,20 @@ private: ColorWheelSelector( const ColorWheelSelector& obj ); ColorWheelSelector& operator=( const ColorWheelSelector& obj ); - void _preserve_icc(SPColor *color) const; + sigc::connection _color_changed_connection; + sigc::connection _color_dragged_connection; }; - - -#define SP_TYPE_COLOR_WHEEL_SELECTOR (sp_color_wheel_selector_get_type ()) -#define SP_COLOR_WHEEL_SELECTOR(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), SP_TYPE_COLOR_WHEEL_SELECTOR, SPColorWheelSelector)) -#define SP_COLOR_WHEEL_SELECTOR_CLASS(k) (G_TYPE_CHECK_CLASS_CAST ((k), SP_TYPE_COLOR_WHEEL_SELECTOR, SPColorWheelSelectorClass)) -#define SP_IS_COLOR_WHEEL_SELECTOR(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), SP_TYPE_COLOR_WHEEL_SELECTOR)) -#define SP_IS_COLOR_WHEEL_SELECTOR_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), SP_TYPE_COLOR_WHEEL_SELECTOR)) - -struct SPColorWheelSelector { - SPColorSelector parent; -}; - -struct SPColorWheelSelectorClass { - SPColorSelectorClass parent_class; -}; - -GType sp_color_wheel_selector_get_type (void); - -GtkWidget *sp_color_wheel_selector_new (void); - - -class ColorWheelSelectorFactory: public Inkscape::UI::ColorSelectorFactory { +class ColorWheelSelectorFactory: public ColorSelectorFactory { public: - Gtk::Widget *createWidget(Inkscape::UI::SelectedColor &color) const; + Gtk::Widget *createWidget(SelectedColor &color) const; Glib::ustring modeName() const; }; +} +} +} + #endif // SEEN_SP_COLOR_WHEEL_SELECTOR_H diff --git a/src/widgets/sp-color-notebook.cpp b/src/widgets/sp-color-notebook.cpp index ca189e086..58c26b8b0 100644 --- a/src/widgets/sp-color-notebook.cpp +++ b/src/widgets/sp-color-notebook.cpp @@ -131,13 +131,17 @@ void ColorNotebook::switchPage(GtkNotebook*, if ( gtk_notebook_get_current_page (GTK_NOTEBOOK (_book)) >= 0 ) { csel = getCurrentSelector(); - csel->base->getColorAlpha(_color, _alpha); + if (csel) { + csel->base->getColorAlpha(_color, _alpha); + } } widget = gtk_notebook_get_nth_page (GTK_NOTEBOOK (_book), page_num); if ( widget && SP_IS_COLOR_SELECTOR(widget) ) { csel = SP_COLOR_SELECTOR (widget); - csel->base->setColorAlpha( _color, _alpha ); + if (csel) { + csel->base->setColorAlpha( _color, _alpha ); + } // Temporary workaround to undo a spurious GRABBED _released(); @@ -620,11 +624,13 @@ GtkWidget* ColorNotebook::_addPage(Page& page) { g_signal_connect (G_OBJECT (_buttons[page_num]), "clicked", G_CALLBACK (_buttonClicked), _csel); - //Connect glib signals of non-refactored widgets - g_signal_connect (selector_widget->gobj(), "grabbed", G_CALLBACK (_entryGrabbed), _csel); - g_signal_connect (selector_widget->gobj(), "dragged", G_CALLBACK (_entryDragged), _csel); - g_signal_connect (selector_widget->gobj(), "released", G_CALLBACK (_entryReleased), _csel); - g_signal_connect (selector_widget->gobj(), "changed", G_CALLBACK (_entryChanged), _csel); + if (SP_IS_COLOR_SELECTOR(selector_widget)) { + //Connect glib signals of non-refactored widgets + g_signal_connect (selector_widget->gobj(), "grabbed", G_CALLBACK (_entryGrabbed), _csel); + g_signal_connect (selector_widget->gobj(), "dragged", G_CALLBACK (_entryDragged), _csel); + g_signal_connect (selector_widget->gobj(), "released", G_CALLBACK (_entryReleased), _csel); + g_signal_connect (selector_widget->gobj(), "changed", G_CALLBACK (_entryChanged), _csel); + } } return selector_widget->gobj(); -- cgit v1.2.3 From efd28a1d2bae756f53ad9b689fb6079be9d92605 Mon Sep 17 00:00:00 2001 From: Tomasz Boczkowski Date: Sat, 31 May 2014 13:13:31 +0200 Subject: fixed updating selected color using wheel (bzr r13341.6.36) --- src/widgets/sp-color-notebook.cpp | 33 ++++++++++++++++++++++++++++++++- src/widgets/sp-color-notebook.h | 3 +++ 2 files changed, 35 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/widgets/sp-color-notebook.cpp b/src/widgets/sp-color-notebook.cpp index 58c26b8b0..7495d1deb 100644 --- a/src/widgets/sp-color-notebook.cpp +++ b/src/widgets/sp-color-notebook.cpp @@ -363,6 +363,9 @@ void ColorNotebook::init() G_CALLBACK (sp_color_notebook_switch_page), SP_COLOR_NOTEBOOK(_csel)); _selected_color.signal_changed.connect(sigc::mem_fun(this, &ColorNotebook::_onSelectedColorChanged)); + _selected_color.signal_dragged.connect(sigc::mem_fun(this, &ColorNotebook::_onSelectedColorDragged)); + _selected_color.signal_grabbed.connect(sigc::mem_fun(this, &ColorNotebook::_onSelectedColorGrabbed)); + _selected_color.signal_released.connect(sigc::mem_fun(this, &ColorNotebook::_onSelectedColorReleased)); } static void sp_color_notebook_dispose(GObject *object) @@ -598,8 +601,36 @@ void ColorNotebook::_onSelectedColorChanged() { SPColor color; gfloat alpha = 1.0; + _updating = true; _selected_color.colorAlpha(color, alpha); _updateInternals(color, alpha, _dragging); + _updating = false; +} + +void ColorNotebook::_onSelectedColorDragged() { + if (_updating) { + return; + } + bool oldState = _dragging; + + _dragging = TRUE; + SPColor color; + gfloat alpha = 1.0; + + _updating = true; + _selected_color.colorAlpha(color, alpha); + _updateInternals(color, alpha, _dragging); + _updating = false; + + _dragging = oldState; +} + +void ColorNotebook::_onSelectedColorGrabbed() { + _grabbed(); +} + +void ColorNotebook::_onSelectedColorReleased() { + _released(); } GtkWidget* ColorNotebook::_addPage(Page& page) { @@ -624,7 +655,7 @@ GtkWidget* ColorNotebook::_addPage(Page& page) { g_signal_connect (G_OBJECT (_buttons[page_num]), "clicked", G_CALLBACK (_buttonClicked), _csel); - if (SP_IS_COLOR_SELECTOR(selector_widget)) { + if (SP_IS_COLOR_SELECTOR(selector_widget->gobj())) { //Connect glib signals of non-refactored widgets g_signal_connect (selector_widget->gobj(), "grabbed", G_CALLBACK (_entryGrabbed), _csel); g_signal_connect (selector_widget->gobj(), "dragged", G_CALLBACK (_entryDragged), _csel); diff --git a/src/widgets/sp-color-notebook.h b/src/widgets/sp-color-notebook.h index 9ab98f1e9..7c6dbc770 100644 --- a/src/widgets/sp-color-notebook.h +++ b/src/widgets/sp-color-notebook.h @@ -61,6 +61,9 @@ protected: virtual void _colorChanged(); virtual void _onSelectedColorChanged(); + virtual void _onSelectedColorDragged(); + virtual void _onSelectedColorGrabbed(); + virtual void _onSelectedColorReleased(); void _updateRgbaEntry( const SPColor& color, gfloat alpha ); void _setCurrentPage(int i); -- cgit v1.2.3 From acb2a6bf56c0c932e89114e00cef10fdb5c2f9b5 Mon Sep 17 00:00:00 2001 From: Tomasz Boczkowski Date: Sat, 31 May 2014 14:59:50 +0200 Subject: SPColorWheelSelector c++-sification: replaced gtk calls by gtkmm versions (bzr r13341.6.37) --- src/ui/widget/color-wheel-selector.cpp | 146 ++++++++++++++++----------------- src/ui/widget/color-wheel-selector.h | 30 ++++--- 2 files changed, 90 insertions(+), 86 deletions(-) (limited to 'src') diff --git a/src/ui/widget/color-wheel-selector.cpp b/src/ui/widget/color-wheel-selector.cpp index e14c70728..e49e4ba16 100644 --- a/src/ui/widget/color-wheel-selector.cpp +++ b/src/ui/widget/color-wheel-selector.cpp @@ -8,6 +8,8 @@ #include #include #include +#include +#include #include "dialogs/dialog-events.h" #include "widgets/sp-color-scales.h" #include "svg/svg-icc-color.h" @@ -33,12 +35,12 @@ ColorWheelSelector::ColorWheelSelector(SelectedColor &color) : Gtk::Table(5, 3, false) #endif , _color(color) - , _updating(false), - _adj(0), - _wheel(0), - _slider(0), - _sbtn(0), - _label(0) + , _updating(false) +#if !GTK_CHECK_VERSION(3,0,0) + , _alpha_adjustment(NULL) +#endif + , _wheel(0) + , _slider(0) { _initUI(); _color_changed_connection = color.signal_changed.connect(sigc::mem_fun(this, &ColorWheelSelector::_colorChanged)); @@ -48,24 +50,18 @@ ColorWheelSelector::ColorWheelSelector(SelectedColor &color) ColorWheelSelector::~ColorWheelSelector() { - _adj = 0; _wheel = 0; - _sbtn = 0; - _label = 0; +#if !GTK_CHECK_VERSION(3,0,0) + delete _alpha_adjustment; +#endif _color_changed_connection.disconnect(); _color_dragged_connection.disconnect(); } void ColorWheelSelector::_initUI() { - gint row = 0; - - GtkWidget *t = GTK_WIDGET(gobj()); - - //gtk_widget_show (t); - /* Create components */ - row = 0; + gint row = 0; _wheel = gimp_color_wheel_new(); gtk_widget_show( _wheel ); @@ -75,35 +71,38 @@ void ColorWheelSelector::_initUI() { gtk_widget_set_valign(_wheel, GTK_ALIGN_FILL); gtk_widget_set_hexpand(_wheel, TRUE); gtk_widget_set_vexpand(_wheel, TRUE); - gtk_grid_attach(GTK_GRID(t), _wheel, 0, row, 3, 1); + gtk_grid_attach(GTK_GRID(gobj()), _wheel, 0, row, 3, 1); #else - gtk_table_attach(GTK_TABLE(t), _wheel, 0, 3, row, row + 1, (GtkAttachOptions)(GTK_EXPAND | GTK_FILL), (GtkAttachOptions)(GTK_EXPAND | GTK_FILL), 0, 0); + gtk_table_attach(GTK_TABLE(gobj()), _wheel, 0, 3, row, row + 1, (GtkAttachOptions)(GTK_EXPAND | GTK_FILL), (GtkAttachOptions)(GTK_EXPAND | GTK_FILL), 0, 0); #endif row++; /* Label */ - _label = gtk_label_new_with_mnemonic (_("_A:")); - gtk_misc_set_alignment (GTK_MISC (_label), 1.0, 0.5); - gtk_widget_show (_label); + Gtk::Label* label = Gtk::manage(new Gtk::Label(_("_A:"), true)); + label->set_alignment(1.0, 0.5); + label->show(); #if GTK_CHECK_VERSION(3,0,0) - gtk_widget_set_margin_left(_label, XPAD); - gtk_widget_set_margin_right(_label, XPAD); - gtk_widget_set_margin_top(_label, YPAD); - gtk_widget_set_margin_bottom(_label, YPAD); - gtk_widget_set_halign(_label, GTK_ALIGN_FILL); - gtk_widget_set_valign(_label, GTK_ALIGN_FILL); - gtk_grid_attach(GTK_GRID(t), _label, 0, row, 1, 1); + label->set_margin_left(XPAD); + label->set_margin_right(XPAD); + label->set_margin_top(YPAD); + label->set_margin_bottom(YPAD); + label->set_halign(Gtk::ALIGN_FILL); + label->set_valign(Gtk::ALIGN_FILL); + attach(*label, 0, row, 1, 1); #else - gtk_table_attach (GTK_TABLE (t), _label, 0, 1, row, row + 1, GTK_FILL, GTK_FILL, XPAD, YPAD); + attach(*label, 0, 1, row, row + 1, Gtk::FILL, Gtk::FILL, XPAD, YPAD); #endif /* Adjustment */ - _adj = GTK_ADJUSTMENT(gtk_adjustment_new(0.0, 0.0, 255.0, 1.0, 10.0, 10.0)); - +#if GTK_CHECK_VERSION(3,0,0) + _alpha_adjustment = Gtk::Adjustment::create(0.0, 0.0, 255.0, 1.0, 10.0, 10.0); +#else + _alpha_adjustment = new Gtk::Adjustment(0.0, 0.0, 255.0, 1.0, 10.0, 10.0); +#endif /* Slider */ - _slider = Gtk::manage(new Inkscape::UI::Widget::ColorSlider(Glib::wrap(_adj, true))); + _slider = Gtk::manage(new Inkscape::UI::Widget::ColorSlider(_alpha_adjustment)); _slider->set_tooltip_text(_("Alpha (opacity)")); _slider->show(); @@ -115,9 +114,9 @@ void ColorWheelSelector::_initUI() { _slider->set_hexpand(true); _slider->set_halign(Gtk::ALIGN_FILL); _slider->set_valign(Gtk::ALIGN_FILL); - gtk_grid_attach(GTK_GRID(t), _slider->gobj(), 1, row, 1, 1); + attach(*_slider, 1, row, 1, 1); #else - gtk_table_attach(GTK_TABLE (t), _slider->gobj(), 1, 2, row, row + 1, (GtkAttachOptions)(GTK_EXPAND | GTK_FILL), GTK_FILL, XPAD, YPAD); + attach(*_slider, 1, 2, row, row+1, Gtk::EXPAND | Gtk::FILL, Gtk::FILL, XPAD, YPAD); #endif _slider->setColors(SP_RGBA32_F_COMPOSE (1.0, 1.0, 1.0, 0.0), @@ -125,32 +124,34 @@ void ColorWheelSelector::_initUI() { SP_RGBA32_F_COMPOSE (1.0, 1.0, 1.0, 1.0)); /* Spinbutton */ - _sbtn = gtk_spin_button_new (GTK_ADJUSTMENT (_adj), 1.0, 0); - gtk_widget_set_tooltip_text (_sbtn, _("Alpha (opacity)")); - sp_dialog_defocus_on_enter (_sbtn); - gtk_label_set_mnemonic_widget (GTK_LABEL(_label), _sbtn); - gtk_widget_show (_sbtn); +#if GTK_CHECK_VERSION(3,0,0) + Gtk::SpinButton* spin_button = Gtk::manage(new Gtk::SpinButton(_alpha_adjustment, 1.0, 0)); + #else + Gtk::SpinButton* spin_button = Gtk::manage(new Gtk::SpinButton(*_alpha_adjustment, 1.0, 0)); +#endif + spin_button->set_tooltip_text(_("Alpha (opacity)")); + sp_dialog_defocus_on_enter(GTK_WIDGET(spin_button->gobj())); + label->set_mnemonic_widget(*spin_button); + spin_button->show(); #if GTK_CHECK_VERSION(3,0,0) - gtk_widget_set_margin_left(_sbtn, XPAD); - gtk_widget_set_margin_right(_sbtn, XPAD); - gtk_widget_set_margin_top(_sbtn, YPAD); - gtk_widget_set_margin_bottom(_sbtn, YPAD); - gtk_widget_set_halign(_sbtn, GTK_ALIGN_CENTER); - gtk_widget_set_valign(_sbtn, GTK_ALIGN_CENTER); - gtk_grid_attach(GTK_GRID(t), _sbtn, 2, row, 1, 1); + + spin_button->set_margin_left(XPAD); + spin_button->set_margin_right(XPAD); + spin_button->set_margin_top(YPAD); + spin_button->set_margin_bottom(YPAD); + spin_button->set_halign(Gtk::ALIGN_CENTER); + spin_button->set_valign(Gtk::ALIGN_CENTER); + attach(*spin_button, 2, row, 1, 1); #else - gtk_table_attach (GTK_TABLE (t), _sbtn, 2, 3, row, row + 1, (GtkAttachOptions)0, (GtkAttachOptions)0, XPAD, YPAD); + attach(*spin_button, 2, 3, row, row + 1, (Gtk::AttachOptions)0, (Gtk::AttachOptions)0, XPAD, YPAD); #endif /* Signals */ - g_signal_connect (G_OBJECT (_adj), "value_changed", - G_CALLBACK (_adjustmentChanged), this); - + _alpha_adjustment->signal_value_changed().connect(sigc::mem_fun(this, &ColorWheelSelector::_adjustmentChanged)); _slider->signal_grabbed.connect(sigc::mem_fun(*this, &ColorWheelSelector::_sliderGrabbed)); _slider->signal_released.connect(sigc::mem_fun(*this, &ColorWheelSelector::_sliderReleased)); _slider->signal_value_changed.connect(sigc::mem_fun(*this, &ColorWheelSelector::_sliderChanged)); - g_signal_connect( G_OBJECT(_wheel), "changed", G_CALLBACK (_wheelChanged), this ); } @@ -158,7 +159,7 @@ void ColorWheelSelector::_initUI() { void ColorWheelSelector::_colorChanged() { #ifdef DUMP_CHANGE_INFO - g_message("ColorWheelSelector::_colorChanged( this=%p, %f, %f, %f, %f)", this, color.v.c[0], color.v.c[1], color.v.c[2], alpha ); + g_message("ColorWheelSelector::_colorChanged( this=%p, %f, %f, %f, %f)", this, _color.color().v.c[0], _color.color().v.c[1], _color.color().v.c[2], alpha ); #endif if (_updating) { return; @@ -177,33 +178,30 @@ void ColorWheelSelector::_colorChanged() _slider->setColors(start, mid, end); - ColorScales::setScaled(_adj, _color.alpha()); + ColorScales::setScaled(_alpha_adjustment->gobj(), _color.alpha()); - _updating = FALSE; + _updating = false; } -void ColorWheelSelector::_adjustmentChanged( GtkAdjustment *adjustment, ColorWheelSelector *cs ) +void ColorWheelSelector::_adjustmentChanged() { - if (cs->_updating) { + if (_updating) { return; } + _updating = true; -// TODO check this. It looks questionable: + // TODO check this. It looks questionable: // if a value is entered between 0 and 1 exclusive, normalize it to (int) 0..255 or 0..100 - gdouble value = gtk_adjustment_get_value (adjustment); - gdouble upper = gtk_adjustment_get_upper (adjustment); - + gdouble value = _alpha_adjustment->get_value(); + gdouble upper = _alpha_adjustment->get_upper(); if (value > 0.0 && value < 1.0) { - gtk_adjustment_set_value( adjustment, floor (value * upper + 0.5) ); + _alpha_adjustment->set_value(floor(value * upper + 0.5)); } - cs->_updating = true; - - cs->_color.preserveICC(); - - cs->_color.setAlpha(ColorScales::getScaled( cs->_adj )); + _color.preserveICC(); + _color.setAlpha(ColorScales::getScaled(_alpha_adjustment->gobj())); - cs->_updating = false; + _updating = false; } void ColorWheelSelector::_sliderGrabbed() @@ -226,13 +224,16 @@ void ColorWheelSelector::_sliderChanged() _updating = true; _color.preserveICC(); - _color.setAlpha(ColorScales::getScaled(_adj)); + _color.setAlpha(ColorScales::getScaled(_alpha_adjustment->gobj())); _updating = false; } -void ColorWheelSelector::_wheelChanged( GimpColorWheel *wheel, ColorWheelSelector *wheelSelector ) +void ColorWheelSelector::_wheelChanged(GimpColorWheel *wheel, ColorWheelSelector *wheelSelector) { - if (wheelSelector->_updating) return; + if (wheelSelector->_updating){ + return; + } + wheelSelector->_updating = true; gdouble h = 0; gdouble s = 0; @@ -250,8 +251,6 @@ void ColorWheelSelector::_wheelChanged( GimpColorWheel *wheel, ColorWheelSelecto wheelSelector->_slider->setColors(start, mid, end); - wheelSelector->_updating = true; - wheelSelector->_color.preserveICC(); wheelSelector->_color.setHeld(gimp_color_wheel_is_adjusting(wheel)); @@ -273,9 +272,6 @@ Glib::ustring ColorWheelSelectorFactory::modeName() const { } } } - - - /* Local Variables: mode:c++ diff --git a/src/ui/widget/color-wheel-selector.h b/src/ui/widget/color-wheel-selector.h index e289a8df6..f5213fad7 100644 --- a/src/ui/widget/color-wheel-selector.h +++ b/src/ui/widget/color-wheel-selector.h @@ -22,7 +22,11 @@ #include #include +#if GTK_CHECK_VERSION(3,0,0) +#include +#else #include +#endif #include "ui/selected-color.h" @@ -35,7 +39,11 @@ namespace Widget { class ColorSlider; class ColorWheelSelector - : public Gtk::Table //if GTK2 +#if GTK_CHECK_VERSION(3,0,0) + : public Gtk::Grid +#else + : public Gtk::Table +#endif { public: static const gchar* MODE_NAME; @@ -45,25 +53,25 @@ public: protected: void _initUI(); - virtual void _colorChanged(); - - static void _adjustmentChanged ( GtkAdjustment *adjustment, ColorWheelSelector *cs ); + void _colorChanged(); + void _adjustmentChanged(); void _sliderGrabbed(); void _sliderReleased(); void _sliderChanged(); - static void _wheelChanged( GimpColorWheel *wheel, ColorWheelSelector *cs ); + static void _wheelChanged(GimpColorWheel *wheel, ColorWheelSelector *cs); - void _recalcColor( gboolean changing ); + void _recalcColor(gboolean changing); SelectedColor &_color; bool _updating; - - GtkAdjustment* _adj; // Channel adjustment +#if GTK_CHECK_VERSION(3,0,0) + Glib::RefPtr _alpha_adjustment; +#else + Gtk::Adjustment* _alpha_adjustment; +#endif GtkWidget* _wheel; Inkscape::UI::Widget::ColorSlider* _slider; - GtkWidget* _sbtn; // Spinbutton - GtkWidget* _label; // Label private: // By default, disallow copy constructor and assignment operator @@ -74,6 +82,7 @@ private: sigc::connection _color_dragged_connection; }; + class ColorWheelSelectorFactory: public ColorSelectorFactory { public: Gtk::Widget *createWidget(SelectedColor &color) const; @@ -84,7 +93,6 @@ public: } } - #endif // SEEN_SP_COLOR_WHEEL_SELECTOR_H /* -- cgit v1.2.3 From 9325918fd04118cda566f15120b975467b2e6e9f Mon Sep 17 00:00:00 2001 From: Tomasz Boczkowski Date: Sat, 31 May 2014 15:09:21 +0200 Subject: SPColorScales c++-sification - move to ui/widget (bzr r13341.6.38) --- src/ui/widget/Makefile_insert | 2 + src/ui/widget/color-scales.cpp | 788 +++++++++++++++++++++++++++++++++ src/ui/widget/color-scales.h | 139 ++++++ src/ui/widget/color-slider.cpp | 2 +- src/ui/widget/color-wheel-selector.cpp | 2 +- src/widgets/Makefile_insert | 2 - src/widgets/sp-color-icc-selector.cpp | 2 +- src/widgets/sp-color-notebook.cpp | 2 +- src/widgets/sp-color-scales.cpp | 788 --------------------------------- src/widgets/sp-color-scales.h | 139 ------ 10 files changed, 933 insertions(+), 933 deletions(-) create mode 100644 src/ui/widget/color-scales.cpp create mode 100644 src/ui/widget/color-scales.h delete mode 100644 src/widgets/sp-color-scales.cpp delete mode 100644 src/widgets/sp-color-scales.h (limited to 'src') diff --git a/src/ui/widget/Makefile_insert b/src/ui/widget/Makefile_insert index 97625f04e..039e2a8d9 100644 --- a/src/ui/widget/Makefile_insert +++ b/src/ui/widget/Makefile_insert @@ -16,6 +16,8 @@ ink_common_sources += \ ui/widget/color-preview.h \ ui/widget/color-slider.cpp \ ui/widget/color-slider.h \ + ui/widget/color-scales.cpp \ + ui/widget/color-scales.h \ ui/widget/combo-enums.h \ ui/widget/dock.h \ ui/widget/dock.cpp \ diff --git a/src/ui/widget/color-scales.cpp b/src/ui/widget/color-scales.cpp new file mode 100644 index 000000000..bba44034a --- /dev/null +++ b/src/ui/widget/color-scales.cpp @@ -0,0 +1,788 @@ +/* + * bulia byak + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include "ui/widget/color-scales.h" + +#include +#include +#include +#include + +#include "dialogs/dialog-events.h" +#include "svg/svg-icc-color.h" +#include "ui/widget/color-slider.h" + +#define CSC_CHANNEL_R (1 << 0) +#define CSC_CHANNEL_G (1 << 1) +#define CSC_CHANNEL_B (1 << 2) +#define CSC_CHANNEL_A (1 << 3) +#define CSC_CHANNEL_H (1 << 0) +#define CSC_CHANNEL_S (1 << 1) +#define CSC_CHANNEL_V (1 << 2) +#define CSC_CHANNEL_C (1 << 0) +#define CSC_CHANNEL_M (1 << 1) +#define CSC_CHANNEL_Y (1 << 2) +#define CSC_CHANNEL_K (1 << 3) +#define CSC_CHANNEL_CMYKA (1 << 4) + +#define CSC_CHANNELS_ALL 0 + + +G_BEGIN_DECLS + +static void sp_color_scales_class_init (SPColorScalesClass *klass); +static void sp_color_scales_init (SPColorScales *cs); +static void sp_color_scales_dispose(GObject *object); + +static void sp_color_scales_show_all (GtkWidget *widget); +static void sp_color_scales_hide(GtkWidget *widget); + +static const gchar *sp_color_scales_hue_map (void); + +G_END_DECLS + +static SPColorSelectorClass *parent_class; + +#define XPAD 4 +#define YPAD 1 + +#define noDUMP_CHANGE_INFO 1 + +const gchar* ColorScales::SUBMODE_NAMES[] = { + N_("None"), + N_("RGB"), + N_("HSL"), + N_("CMYK") +}; + +GType +sp_color_scales_get_type (void) +{ + static GType type = 0; + if (!type) { + static const GTypeInfo info = { + sizeof (SPColorScalesClass), + NULL, /* base_init */ + NULL, /* base_finalize */ + (GClassInitFunc) sp_color_scales_class_init, + NULL, /* class_finalize */ + NULL, /* class_data */ + sizeof (SPColorScales), + 0, /* n_preallocs */ + (GInstanceInitFunc) sp_color_scales_init, + NULL + }; + + type = g_type_register_static (SP_TYPE_COLOR_SELECTOR, + "SPColorScales", + &info, + static_cast< GTypeFlags > (0) ); + } + return type; +} + +static void +sp_color_scales_class_init (SPColorScalesClass *klass) +{ + static const gchar* nameset[] = {N_("RGB"), N_("HSL"), N_("CMYK"), 0}; + GObjectClass *object_class = G_OBJECT_CLASS(klass); + GtkWidgetClass *widget_class = GTK_WIDGET_CLASS(klass); + SPColorSelectorClass *selector_class = SP_COLOR_SELECTOR_CLASS (klass); + + parent_class = SP_COLOR_SELECTOR_CLASS (g_type_class_peek_parent (klass)); + + selector_class->name = nameset; + selector_class->submode_count = 3; + + object_class->dispose = sp_color_scales_dispose; + + widget_class->show_all = sp_color_scales_show_all; + widget_class->hide = sp_color_scales_hide; +} + +ColorScales::ColorScales( SPColorSelector* csel ) + : ColorSelector( csel ), + _mode( SP_COLOR_SCALES_MODE_NONE ), + _rangeLimit( 255.0 ), + _updating( FALSE ), + _dragging( FALSE ) +{ + for (gint i = 0; i < 5; i++) { + _l[i] = 0; + _a[i] = 0; + _s[i] = 0; + _b[i] = 0; + } +} + +ColorScales::~ColorScales() +{ + for (gint i = 0; i < 5; i++) { + _l[i] = 0; + _a[i] = 0; + _s[i] = 0; + _b[i] = 0; + } +} + +void sp_color_scales_init (SPColorScales *cs) +{ + SP_COLOR_SELECTOR(cs)->base = new ColorScales( SP_COLOR_SELECTOR(cs) ); + + if ( SP_COLOR_SELECTOR(cs)->base ) + { + SP_COLOR_SELECTOR(cs)->base->init(); + } +} + +void ColorScales::init() +{ + gint i; + + _updating = FALSE; + _dragging = FALSE; + +#if GTK_CHECK_VERSION(3,0,0) + GtkWidget *t = gtk_grid_new(); +#else + GtkWidget *t = gtk_table_new (5, 3, FALSE); +#endif + gtk_widget_show (t); + gtk_box_pack_start (GTK_BOX (_csel), t, TRUE, TRUE, 4); + + /* Create components */ + for (i = 0; i < static_cast< gint > (G_N_ELEMENTS(_a)) ; i++) { + /* Label */ + _l[i] = gtk_label_new(""); + gtk_misc_set_alignment (GTK_MISC (_l[i]), 1.0, 0.5); + gtk_widget_show (_l[i]); + +#if GTK_CHECK_VERSION(3,0,0) + gtk_widget_set_margin_left(_l[i], XPAD); + gtk_widget_set_margin_right(_l[i], XPAD); + gtk_widget_set_margin_top(_l[i], YPAD); + gtk_widget_set_margin_bottom(_l[i], YPAD); + gtk_grid_attach(GTK_GRID(t), _l[i], 0, i, 1, 1); +#else + gtk_table_attach (GTK_TABLE (t), _l[i], 0, 1, i, i + 1, GTK_FILL, GTK_FILL, XPAD, YPAD); +#endif + + /* Adjustment */ + _a[i] = GTK_ADJUSTMENT(gtk_adjustment_new(0.0, 0.0, _rangeLimit, 1.0, 10.0, 10.0)); + /* Slider */ + _s[i] = Gtk::manage(new Inkscape::UI::Widget::ColorSlider(Glib::wrap(_a[i], true))); + _s[i]->show(); + +#if GTK_CHECK_VERSION(3,0,0) + _s[i]->set_margin_left(XPAD); + _s[i]->set_margin_right(XPAD); + _s[i]->set_margin_top(YPAD); + _s[i]->set_margin_bottom(YPAD); + _s[i]->set_hexpand(true); + gtk_grid_attach(GTK_GRID(t), _s[i]->gobj(), 1, i, 1, 1); +#else + gtk_table_attach (GTK_TABLE (t), _s[i]->gobj(), 1, 2, i, i + 1, (GtkAttachOptions)(GTK_EXPAND | GTK_FILL), GTK_FILL, XPAD, YPAD); +#endif + + /* Spinbutton */ + _b[i] = gtk_spin_button_new (GTK_ADJUSTMENT (_a[i]), 1.0, 0); + sp_dialog_defocus_on_enter (_b[i]); + gtk_label_set_mnemonic_widget (GTK_LABEL(_l[i]), _b[i]); + gtk_widget_show (_b[i]); + +#if GTK_CHECK_VERSION(3,0,0) + gtk_widget_set_margin_left(_b[i], XPAD); + gtk_widget_set_margin_right(_b[i], XPAD); + gtk_widget_set_margin_top(_b[i], YPAD); + gtk_widget_set_margin_bottom(_b[i], YPAD); + gtk_widget_set_halign(_b[i], GTK_ALIGN_CENTER); + gtk_widget_set_valign(_b[i], GTK_ALIGN_CENTER); + gtk_grid_attach(GTK_GRID(t), _b[i], 2, i, 1, 1); +#else + gtk_table_attach (GTK_TABLE (t), _b[i], 2, 3, i, i + 1, (GtkAttachOptions)0, (GtkAttachOptions)0, XPAD, YPAD); +#endif + + /* Attach channel value to adjustment */ + g_object_set_data (G_OBJECT (_a[i]), "channel", GINT_TO_POINTER (i)); + /* Signals */ + g_signal_connect (G_OBJECT (_a[i]), "value_changed", + G_CALLBACK (_adjustmentAnyChanged), _csel); + _s[i]->signal_grabbed.connect(sigc::mem_fun(this, &ColorScales::_sliderAnyGrabbed)); + _s[i]->signal_released.connect(sigc::mem_fun(this, &ColorScales::_sliderAnyReleased)); + _s[i]->signal_value_changed.connect(sigc::mem_fun(this, &ColorScales::_sliderAnyChanged)); + } + + /* Initial mode is none, so it works */ + setMode(SP_COLOR_SCALES_MODE_RGB); +} + +static void sp_color_scales_dispose(GObject *object) +{ + if ((G_OBJECT_CLASS(parent_class))->dispose) + (* (G_OBJECT_CLASS(parent_class))->dispose) (object); +} + +static void +sp_color_scales_show_all (GtkWidget *widget) +{ + gtk_widget_show (widget); +} + +static void sp_color_scales_hide(GtkWidget *widget) +{ + gtk_widget_hide(widget); +} + +GtkWidget *sp_color_scales_new() +{ + SPColorScales *csel = SP_COLOR_SCALES(g_object_new (SP_TYPE_COLOR_SCALES, NULL)); + + return GTK_WIDGET (csel); +} + +void ColorScales::_recalcColor( gboolean changing ) +{ + if ( changing ) + { + SPColor color; + gfloat alpha = 1.0; + gfloat c[5]; + + switch (_mode) { + case SP_COLOR_SCALES_MODE_RGB: + case SP_COLOR_SCALES_MODE_HSV: + _getRgbaFloatv(c); + color.set( c[0], c[1], c[2] ); + alpha = c[3]; + break; + case SP_COLOR_SCALES_MODE_CMYK: + { + _getCmykaFloatv( c ); + + float rgb[3]; + sp_color_cmyk_to_rgb_floatv( rgb, c[0], c[1], c[2], c[3] ); + color.set( rgb[0], rgb[1], rgb[2] ); + alpha = c[4]; + break; + } + default: + g_warning ("file %s: line %d: Illegal color selector mode %d", __FILE__, __LINE__, _mode); + break; + } + + /* Preserve ICC */ + color.icc = _color.icc ? new SVGICCColor(*_color.icc) : 0; + + _updateInternals( color, alpha, _dragging ); + } + else + { + _updateInternals( _color, _alpha, _dragging ); + } +} + +/* Helpers for setting color value */ +gfloat ColorScales::getScaled( const GtkAdjustment *a ) +{ + gfloat val = gtk_adjustment_get_value (const_cast(a)) + / gtk_adjustment_get_upper (const_cast(a)); + return val; +} + +void ColorScales::setScaled( GtkAdjustment *a, gfloat v ) +{ + gfloat val = v * gtk_adjustment_get_upper (a); + gtk_adjustment_set_value( a, val ); +} + +void ColorScales::_setRangeLimit( gdouble upper ) +{ + _rangeLimit = upper; + for ( gint i = 0; i < static_cast(G_N_ELEMENTS(_a)); i++ ) { + gtk_adjustment_set_upper (_a[i], upper); + gtk_adjustment_changed( _a[i] ); + } +} + +void ColorScales::_colorChanged() +{ +#ifdef DUMP_CHANGE_INFO + g_message("ColorScales::_colorChanged( this=%p, %f, %f, %f, %f)", this, _color.v.c[0], _color.v.c[1], _color.v.c[2], _alpha ); +#endif + gfloat tmp[3]; + gfloat c[5] = {0.0, 0.0, 0.0, 0.0}; + + switch (_mode) { + case SP_COLOR_SCALES_MODE_RGB: + sp_color_get_rgb_floatv( &_color, c ); + c[3] = _alpha; + c[4] = 0.0; + break; + case SP_COLOR_SCALES_MODE_HSV: + sp_color_get_rgb_floatv( &_color, tmp ); + sp_color_rgb_to_hsl_floatv (c, tmp[0], tmp[1], tmp[2]); + c[3] = _alpha; + c[4] = 0.0; + break; + case SP_COLOR_SCALES_MODE_CMYK: + sp_color_get_cmyk_floatv( &_color, c ); + c[4] = _alpha; + break; + default: + g_warning ("file %s: line %d: Illegal color selector mode %d", __FILE__, __LINE__, _mode); + break; + } + + _updating = TRUE; + setScaled( _a[0], c[0] ); + setScaled( _a[1], c[1] ); + setScaled( _a[2], c[2] ); + setScaled( _a[3], c[3] ); + setScaled( _a[4], c[4] ); + _updateSliders( CSC_CHANNELS_ALL ); + _updating = FALSE; +} + +void ColorScales::_getRgbaFloatv( gfloat *rgba ) +{ + g_return_if_fail (rgba != NULL); + + switch (_mode) { + case SP_COLOR_SCALES_MODE_RGB: + rgba[0] = getScaled(_a[0]); + rgba[1] = getScaled(_a[1]); + rgba[2] = getScaled(_a[2]); + rgba[3] = getScaled(_a[3]); + break; + case SP_COLOR_SCALES_MODE_HSV: + sp_color_hsl_to_rgb_floatv (rgba, getScaled(_a[0]), getScaled(_a[1]), getScaled(_a[2])); + rgba[3] = getScaled(_a[3]); + break; + case SP_COLOR_SCALES_MODE_CMYK: + sp_color_cmyk_to_rgb_floatv (rgba, getScaled(_a[0]), getScaled(_a[1]), getScaled(_a[2]), getScaled(_a[3])); + rgba[3] = getScaled(_a[4]); + break; + default: + g_warning ("file %s: line %d: Illegal color selector mode", __FILE__, __LINE__); + break; + } +} + +void ColorScales::_getCmykaFloatv( gfloat *cmyka ) +{ + gfloat rgb[3]; + + g_return_if_fail (cmyka != NULL); + + switch (_mode) { + case SP_COLOR_SCALES_MODE_RGB: + sp_color_rgb_to_cmyk_floatv (cmyka, getScaled(_a[0]), getScaled(_a[1]), getScaled(_a[2])); + cmyka[4] = getScaled(_a[3]); + break; + case SP_COLOR_SCALES_MODE_HSV: + sp_color_hsl_to_rgb_floatv (rgb, getScaled(_a[0]), getScaled(_a[1]), getScaled(_a[2])); + sp_color_rgb_to_cmyk_floatv (cmyka, rgb[0], rgb[1], rgb[2]); + cmyka[4] = getScaled(_a[3]); + break; + case SP_COLOR_SCALES_MODE_CMYK: + cmyka[0] = getScaled(_a[0]); + cmyka[1] = getScaled(_a[1]); + cmyka[2] = getScaled(_a[2]); + cmyka[3] = getScaled(_a[3]); + cmyka[4] = getScaled(_a[4]); + break; + default: + g_warning ("file %s: line %d: Illegal color selector mode", __FILE__, __LINE__); + break; + } +} + +guint32 ColorScales::_getRgba32() +{ + gfloat c[4]; + guint32 rgba; + + _getRgbaFloatv(c); + + rgba = SP_RGBA32_F_COMPOSE (c[0], c[1], c[2], c[3]); + + return rgba; +} + +void ColorScales::setMode(SPColorScalesMode mode) +{ + gfloat rgba[4]; + gfloat c[4]; + + if (_mode == mode) return; + + if ((_mode == SP_COLOR_SCALES_MODE_RGB) || + (_mode == SP_COLOR_SCALES_MODE_HSV) || + (_mode == SP_COLOR_SCALES_MODE_CMYK)) { + _getRgbaFloatv(rgba); + } else { + rgba[0] = rgba[1] = rgba[2] = rgba[3] = 1.0; + } + + _mode = mode; + + switch (mode) { + case SP_COLOR_SCALES_MODE_RGB: + _setRangeLimit(255.0); + gtk_label_set_markup_with_mnemonic (GTK_LABEL (_l[0]), _("_R:")); + _s[0]->set_tooltip_text(_("Red")); + gtk_widget_set_tooltip_text (_b[0], _("Red")); + gtk_label_set_markup_with_mnemonic (GTK_LABEL (_l[1]), _("_G:")); + _s[1]->set_tooltip_text(_("Green")); + gtk_widget_set_tooltip_text (_b[1], _("Green")); + gtk_label_set_markup_with_mnemonic (GTK_LABEL (_l[2]), _("_B:")); + _s[2]->set_tooltip_text(_("Blue")); + gtk_widget_set_tooltip_text (_b[2], _("Blue")); + gtk_label_set_markup_with_mnemonic (GTK_LABEL (_l[3]), _("_A:")); + _s[3]->set_tooltip_text(_("Alpha (opacity)")); + gtk_widget_set_tooltip_text (_b[3], _("Alpha (opacity)")); + _s[0]->setMap(NULL); + gtk_widget_hide (_l[4]); + _s[4]->hide(); + gtk_widget_hide (_b[4]); + _updating = TRUE; + setScaled( _a[0], rgba[0] ); + setScaled( _a[1], rgba[1] ); + setScaled( _a[2], rgba[2] ); + setScaled( _a[3], rgba[3] ); + _updating = FALSE; + _updateSliders( CSC_CHANNELS_ALL ); + break; + case SP_COLOR_SCALES_MODE_HSV: + _setRangeLimit(255.0); + gtk_label_set_markup_with_mnemonic (GTK_LABEL (_l[0]), _("_H:")); + _s[0]->set_tooltip_text(_("Hue")); + gtk_widget_set_tooltip_text (_b[0], _("Hue")); + gtk_label_set_markup_with_mnemonic (GTK_LABEL (_l[1]), _("_S:")); + _s[1]->set_tooltip_text(_("Saturation")); + gtk_widget_set_tooltip_text (_b[1], _("Saturation")); + gtk_label_set_markup_with_mnemonic (GTK_LABEL (_l[2]), _("_L:")); + _s[2]->set_tooltip_text(_("Lightness")); + gtk_widget_set_tooltip_text (_b[2], _("Lightness")); + gtk_label_set_markup_with_mnemonic (GTK_LABEL (_l[3]), _("_A:")); + _s[3]->set_tooltip_text(_("Alpha (opacity)")); + gtk_widget_set_tooltip_text (_b[3], _("Alpha (opacity)")); + _s[0]->setMap((guchar *)(sp_color_scales_hue_map())); + gtk_widget_hide (_l[4]); + _s[4]->hide(); + gtk_widget_hide (_b[4]); + _updating = TRUE; + c[0] = 0.0; + sp_color_rgb_to_hsl_floatv (c, rgba[0], rgba[1], rgba[2]); + setScaled( _a[0], c[0] ); + setScaled( _a[1], c[1] ); + setScaled( _a[2], c[2] ); + setScaled( _a[3], rgba[3] ); + _updating = FALSE; + _updateSliders( CSC_CHANNELS_ALL ); + break; + case SP_COLOR_SCALES_MODE_CMYK: + _setRangeLimit(100.0); + gtk_label_set_markup_with_mnemonic (GTK_LABEL (_l[0]), _("_C:")); + _s[0]->set_tooltip_text(_("Cyan")); + gtk_widget_set_tooltip_text (_b[0], _("Cyan")); + gtk_label_set_markup_with_mnemonic (GTK_LABEL (_l[1]), _("_M:")); + _s[1]->set_tooltip_text(_("Magenta")); + gtk_widget_set_tooltip_text (_b[1], _("Magenta")); + gtk_label_set_markup_with_mnemonic (GTK_LABEL (_l[2]), _("_Y:")); + _s[2]->set_tooltip_text(_("Yellow")); + gtk_widget_set_tooltip_text (_b[2], _("Yellow")); + gtk_label_set_markup_with_mnemonic (GTK_LABEL (_l[3]), _("_K:")); + _s[3]->set_tooltip_text(_("Black")); + gtk_widget_set_tooltip_text (_b[3], _("Black")); + gtk_label_set_markup_with_mnemonic (GTK_LABEL (_l[4]), _("_A:")); + _s[4]->set_tooltip_text(_("Alpha (opacity)")); + gtk_widget_set_tooltip_text (_b[4], _("Alpha (opacity)")); + _s[0]->setMap(NULL); + gtk_widget_show (_l[4]); + _s[4]->show(); + gtk_widget_show (_b[4]); + _updating = TRUE; + + sp_color_rgb_to_cmyk_floatv (c, rgba[0], rgba[1], rgba[2]); + setScaled( _a[0], c[0] ); + setScaled( _a[1], c[1] ); + setScaled( _a[2], c[2] ); + setScaled( _a[3], c[3] ); + + setScaled( _a[4], rgba[3] ); + _updating = FALSE; + _updateSliders( CSC_CHANNELS_ALL ); + break; + default: + g_warning ("file %s: line %d: Illegal color selector mode", __FILE__, __LINE__); + break; + } +} + +SPColorScalesMode ColorScales::getMode() const +{ + return _mode; +} + +void ColorScales::setSubmode( guint submode ) +{ + g_return_if_fail (_csel != NULL); + g_return_if_fail (SP_IS_COLOR_SCALES (_csel)); + g_return_if_fail (submode < 3); + + switch ( submode ) + { + default: + case 0: + setMode(SP_COLOR_SCALES_MODE_RGB); + break; + case 1: + setMode(SP_COLOR_SCALES_MODE_HSV); + break; + case 2: + setMode(SP_COLOR_SCALES_MODE_CMYK); + break; + } +} + +guint ColorScales::getSubmode() const +{ + guint submode = 0; + + switch ( _mode ) + { + case SP_COLOR_SCALES_MODE_HSV: + submode = 1; + break; + case SP_COLOR_SCALES_MODE_CMYK: + submode = 2; + break; + case SP_COLOR_SCALES_MODE_RGB: + default: + submode = 0; + } + + return submode; +} + +void ColorScales::_adjustmentAnyChanged( GtkAdjustment *adjustment, SPColorScales *cs ) +{ + gint channel = GPOINTER_TO_INT (g_object_get_data(G_OBJECT (adjustment), "channel")); + + _adjustmentChanged(cs, channel); +} + +void ColorScales::_sliderAnyGrabbed() +{ + if (!_dragging) { + _dragging = TRUE; + _grabbed(); + _recalcColor( FALSE ); + } +} + +void ColorScales::_sliderAnyReleased() +{ + if (_dragging) { + _dragging = FALSE; + _released(); + _recalcColor( FALSE ); + } +} + +void ColorScales::_sliderAnyChanged() +{ + _recalcColor( TRUE ); +} + +void ColorScales::_adjustmentChanged( SPColorScales *cs, guint channel ) +{ + ColorScales* scales = static_cast(SP_COLOR_SELECTOR(cs)->base); + if (scales->_updating) return; + + scales->_updating = TRUE; + + scales->_updateSliders( (1 << channel) ); + + scales->_recalcColor (TRUE); + + scales->_updating = FALSE; +} + +void ColorScales::_updateSliders( guint channels ) +{ + gfloat rgb0[3], rgbm[3], rgb1[3]; +#ifdef SPCS_PREVIEW + guint32 rgba; +#endif + switch (_mode) { + case SP_COLOR_SCALES_MODE_RGB: + if ((channels != CSC_CHANNEL_R) && (channels != CSC_CHANNEL_A)) { + /* Update red */ + _s[0]->setColors(SP_RGBA32_F_COMPOSE (0.0, getScaled(_a[1]), getScaled(_a[2]), 1.0), + SP_RGBA32_F_COMPOSE (0.5, getScaled(_a[1]), getScaled(_a[2]), 1.0), + SP_RGBA32_F_COMPOSE (1.0, getScaled(_a[1]), getScaled(_a[2]), 1.0)); + } + if ((channels != CSC_CHANNEL_G) && (channels != CSC_CHANNEL_A)) { + /* Update green */ + _s[1]->setColors(SP_RGBA32_F_COMPOSE(getScaled(_a[0]), 0.0, getScaled(_a[2]), 1.0), + SP_RGBA32_F_COMPOSE(getScaled(_a[0]), 0.5, getScaled(_a[2]), 1.0), + SP_RGBA32_F_COMPOSE(getScaled(_a[0]), 1.0, getScaled(_a[2]), 1.0)); + } + if ((channels != CSC_CHANNEL_B) && (channels != CSC_CHANNEL_A)) { + /* Update blue */ + _s[2]->setColors(SP_RGBA32_F_COMPOSE (getScaled(_a[0]), getScaled(_a[1]), 0.0, 1.0), + SP_RGBA32_F_COMPOSE (getScaled(_a[0]), getScaled(_a[1]), 0.5, 1.0), + SP_RGBA32_F_COMPOSE (getScaled(_a[0]), getScaled(_a[1]), 1.0, 1.0)); + } + if (channels != CSC_CHANNEL_A) { + /* Update alpha */ + _s[3]->setColors(SP_RGBA32_F_COMPOSE (getScaled(_a[0]), getScaled(_a[1]), getScaled(_a[2]), 0.0), + SP_RGBA32_F_COMPOSE (getScaled(_a[0]), getScaled(_a[1]), getScaled(_a[2]), 0.5), + SP_RGBA32_F_COMPOSE (getScaled(_a[0]), getScaled(_a[1]), getScaled(_a[2]), 1.0)); + } + break; + case SP_COLOR_SCALES_MODE_HSV: + /* Hue is never updated */ + if ((channels != CSC_CHANNEL_S) && (channels != CSC_CHANNEL_A)) { + /* Update saturation */ + sp_color_hsl_to_rgb_floatv (rgb0, getScaled(_a[0]), 0.0, getScaled(_a[2])); + sp_color_hsl_to_rgb_floatv (rgbm, getScaled(_a[0]), 0.5, getScaled(_a[2])); + sp_color_hsl_to_rgb_floatv (rgb1, getScaled(_a[0]), 1.0, getScaled(_a[2])); + _s[1]->setColors(SP_RGBA32_F_COMPOSE (rgb0[0], rgb0[1], rgb0[2], 1.0), + SP_RGBA32_F_COMPOSE (rgbm[0], rgbm[1], rgbm[2], 1.0), + SP_RGBA32_F_COMPOSE (rgb1[0], rgb1[1], rgb1[2], 1.0)); + } + if ((channels != CSC_CHANNEL_V) && (channels != CSC_CHANNEL_A)) { + /* Update value */ + sp_color_hsl_to_rgb_floatv (rgb0, getScaled(_a[0]), getScaled(_a[1]), 0.0); + sp_color_hsl_to_rgb_floatv (rgbm, getScaled(_a[0]), getScaled(_a[1]), 0.5); + sp_color_hsl_to_rgb_floatv (rgb1, getScaled(_a[0]), getScaled(_a[1]), 1.0); + _s[2]->setColors(SP_RGBA32_F_COMPOSE (rgb0[0], rgb0[1], rgb0[2], 1.0), + SP_RGBA32_F_COMPOSE (rgbm[0], rgbm[1], rgbm[2], 1.0), + SP_RGBA32_F_COMPOSE (rgb1[0], rgb1[1], rgb1[2], 1.0)); + } + if (channels != CSC_CHANNEL_A) { + /* Update alpha */ + sp_color_hsl_to_rgb_floatv (rgb0, getScaled(_a[0]), getScaled(_a[1]), getScaled(_a[2])); + _s[3]->setColors(SP_RGBA32_F_COMPOSE (rgb0[0], rgb0[1], rgb0[2], 0.0), + SP_RGBA32_F_COMPOSE (rgb0[0], rgb0[1], rgb0[2], 0.5), + SP_RGBA32_F_COMPOSE (rgb0[0], rgb0[1], rgb0[2], 1.0)); + } + break; + case SP_COLOR_SCALES_MODE_CMYK: + if ((channels != CSC_CHANNEL_C) && (channels != CSC_CHANNEL_CMYKA)) { + /* Update C */ + sp_color_cmyk_to_rgb_floatv (rgb0, 0.0, getScaled(_a[1]), getScaled(_a[2]), getScaled(_a[3])); + sp_color_cmyk_to_rgb_floatv (rgbm, 0.5, getScaled(_a[1]), getScaled(_a[2]), getScaled(_a[3])); + sp_color_cmyk_to_rgb_floatv (rgb1, 1.0, getScaled(_a[1]), getScaled(_a[2]), getScaled(_a[3])); + _s[0]->setColors(SP_RGBA32_F_COMPOSE (rgb0[0], rgb0[1], rgb0[2], 1.0), + SP_RGBA32_F_COMPOSE (rgbm[0], rgbm[1], rgbm[2], 1.0), + SP_RGBA32_F_COMPOSE (rgb1[0], rgb1[1], rgb1[2], 1.0)); + } + if ((channels != CSC_CHANNEL_M) && (channels != CSC_CHANNEL_CMYKA)) { + /* Update M */ + sp_color_cmyk_to_rgb_floatv (rgb0, getScaled(_a[0]), 0.0, getScaled(_a[2]), getScaled(_a[3])); + sp_color_cmyk_to_rgb_floatv (rgbm, getScaled(_a[0]), 0.5, getScaled(_a[2]), getScaled(_a[3])); + sp_color_cmyk_to_rgb_floatv (rgb1, getScaled(_a[0]), 1.0, getScaled(_a[2]), getScaled(_a[3])); + _s[1]->setColors(SP_RGBA32_F_COMPOSE (rgb0[0], rgb0[1], rgb0[2], 1.0), + SP_RGBA32_F_COMPOSE (rgbm[0], rgbm[1], rgbm[2], 1.0), + SP_RGBA32_F_COMPOSE (rgb1[0], rgb1[1], rgb1[2], 1.0)); + } + if ((channels != CSC_CHANNEL_Y) && (channels != CSC_CHANNEL_CMYKA)) { + /* Update Y */ + sp_color_cmyk_to_rgb_floatv (rgb0, getScaled(_a[0]), getScaled(_a[1]), 0.0, getScaled(_a[3])); + sp_color_cmyk_to_rgb_floatv (rgbm, getScaled(_a[0]), getScaled(_a[1]), 0.5, getScaled(_a[3])); + sp_color_cmyk_to_rgb_floatv (rgb1, getScaled(_a[0]), getScaled(_a[1]), 1.0, getScaled(_a[3])); + _s[2]->setColors(SP_RGBA32_F_COMPOSE (rgb0[0], rgb0[1], rgb0[2], 1.0), + SP_RGBA32_F_COMPOSE (rgbm[0], rgbm[1], rgbm[2], 1.0), + SP_RGBA32_F_COMPOSE (rgb1[0], rgb1[1], rgb1[2], 1.0)); + } + if ((channels != CSC_CHANNEL_K) && (channels != CSC_CHANNEL_CMYKA)) { + /* Update K */ + sp_color_cmyk_to_rgb_floatv (rgb0, getScaled(_a[0]), getScaled(_a[1]), getScaled(_a[2]), 0.0); + sp_color_cmyk_to_rgb_floatv (rgbm, getScaled(_a[0]), getScaled(_a[1]), getScaled(_a[2]), 0.5); + sp_color_cmyk_to_rgb_floatv (rgb1, getScaled(_a[0]), getScaled(_a[1]), getScaled(_a[2]), 1.0); + _s[3]->setColors(SP_RGBA32_F_COMPOSE (rgb0[0], rgb0[1], rgb0[2], 1.0), + SP_RGBA32_F_COMPOSE (rgbm[0], rgbm[1], rgbm[2], 1.0), + SP_RGBA32_F_COMPOSE (rgb1[0], rgb1[1], rgb1[2], 1.0)); + } + if (channels != CSC_CHANNEL_CMYKA) { + /* Update alpha */ + sp_color_cmyk_to_rgb_floatv (rgb0, getScaled(_a[0]), getScaled(_a[1]), getScaled(_a[2]), getScaled(_a[3])); + _s[4]->setColors(SP_RGBA32_F_COMPOSE (rgb0[0], rgb0[1], rgb0[2], 0.0), + SP_RGBA32_F_COMPOSE (rgb0[0], rgb0[1], rgb0[2], 0.5), + SP_RGBA32_F_COMPOSE (rgb0[0], rgb0[1], rgb0[2], 1.0)); + } + break; + default: + g_warning ("file %s: line %d: Illegal color selector mode", __FILE__, __LINE__); + break; + } + + // Force the internal color to be updated + if ( !_updating ) + { + _recalcColor( TRUE ); + } + +#ifdef SPCS_PREVIEW + rgba = sp_color_scales_get_rgba32 (cs); + sp_color_preview_set_rgba32 (SP_COLOR_PREVIEW (_p), rgba); +#endif +} + +static const gchar * +sp_color_scales_hue_map (void) +{ + static gchar *map = NULL; + + if (!map) { + gchar *p; + gint h; + map = g_new (gchar, 4 * 1024); + p = map; + for (h = 0; h < 1024; h++) { + gfloat rgb[3]; + sp_color_hsl_to_rgb_floatv (rgb, h / 1024.0, 1.0, 0.5); + *p++ = SP_COLOR_F_TO_U (rgb[0]); + *p++ = SP_COLOR_F_TO_U (rgb[1]); + *p++ = SP_COLOR_F_TO_U (rgb[2]); + *p++ = 255; + } + } + + return map; +} + +ColorScalesFactory::ColorScalesFactory(SPColorScalesMode submode) + : _submode(submode) +{ +} + +ColorScalesFactory::~ColorScalesFactory() { +} + +Gtk::Widget *ColorScalesFactory::createWidget(Inkscape::UI::SelectedColor &color) const { + GtkWidget *w = sp_color_selector_new(SP_TYPE_COLOR_SCALES); + SPColorSelector* csel; + + csel = SP_COLOR_SELECTOR (w); + if ( _submode > 0 ) + { + csel->base->setSubmode( _submode - 1 ); + } + + Gtk::Widget *wrapped = Gtk::manage(Glib::wrap(w)); + return wrapped; +} + +Glib::ustring ColorScalesFactory::modeName() const { + return gettext(ColorScales::SUBMODE_NAMES[_submode]); +} diff --git a/src/ui/widget/color-scales.h b/src/ui/widget/color-scales.h new file mode 100644 index 000000000..946f0935e --- /dev/null +++ b/src/ui/widget/color-scales.h @@ -0,0 +1,139 @@ +#ifndef SEEN_SP_COLOR_SCALES_H +#define SEEN_SP_COLOR_SCALES_H + +#ifdef HAVE_CONFIG_H +# include +#endif + +#if GLIBMM_DISABLE_DEPRECATED && HAVE_GLIBMM_THREADS_H +#include +#endif + +#include +#include + +#include +#include + +#include "ui/selected-color.h" + +struct SPColorScales; +struct SPColorScalesClass; + +namespace Inkscape { +namespace UI { +namespace Widget { + +class ColorSlider; + +} +} +} + +typedef enum { + SP_COLOR_SCALES_MODE_NONE = 0, + SP_COLOR_SCALES_MODE_RGB = 1, + SP_COLOR_SCALES_MODE_HSV = 2, + SP_COLOR_SCALES_MODE_CMYK = 3 +} SPColorScalesMode; + + + +class ColorScales: public ColorSelector +{ +public: + static const gchar* SUBMODE_NAMES[]; + + static gfloat getScaled( const GtkAdjustment *a ); + static void setScaled( GtkAdjustment *a, gfloat v); + + ColorScales(SPColorSelector *csel); + virtual ~ColorScales(); + + virtual void init(); + + virtual void setSubmode(guint submode); + virtual guint getSubmode() const; + + void setMode(SPColorScalesMode mode); + SPColorScalesMode getMode() const; + + +protected: + virtual void _colorChanged(); + + static void _adjustmentAnyChanged(GtkAdjustment *adjustment, SPColorScales *cs); + void _sliderAnyGrabbed(); + void _sliderAnyReleased(); + void _sliderAnyChanged(); + static void _adjustmentChanged(SPColorScales *cs, guint channel); + + void _getRgbaFloatv(gfloat *rgba); + void _getCmykaFloatv(gfloat *cmyka); + guint32 _getRgba32(); + void _updateSliders(guint channels); + void _recalcColor(gboolean changing); + + void _setRangeLimit( gdouble upper ); + + SPColorScalesMode _mode; + gdouble _rangeLimit; + gboolean _updating : 1; + gboolean _dragging : 1; + GtkAdjustment *_a[5]; /* Channel adjustments */ + Inkscape::UI::Widget::ColorSlider *_s[5]; /* Channel sliders */ + GtkWidget *_b[5]; /* Spinbuttons */ + GtkWidget *_l[5]; /* Labels */ + +private: + // By default, disallow copy constructor and assignment operator + ColorScales(ColorScales const &obj); + ColorScales &operator=(ColorScales const &obj ); +}; + + + +#define SP_TYPE_COLOR_SCALES (sp_color_scales_get_type()) +#define SP_COLOR_SCALES(o) (G_TYPE_CHECK_INSTANCE_CAST((o), SP_TYPE_COLOR_SCALES, SPColorScales)) +#define SP_COLOR_SCALES_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), SP_TYPE_COLOR_SCALES, SPColorScalesClass)) +#define SP_IS_COLOR_SCALES(o) (G_TYPE_CHECK_INSTANCE_TYPE((o), SP_TYPE_COLOR_SCALES)) +#define SP_IS_COLOR_SCALES_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE((k), SP_TYPE_COLOR_SCALES)) + +struct SPColorScales { + SPColorSelector parent; +}; + +struct SPColorScalesClass { + SPColorSelectorClass parent_class; +}; + +GType sp_color_scales_get_type(); + +GtkWidget *sp_color_scales_new(); + + +class ColorScalesFactory: public Inkscape::UI::ColorSelectorFactory { +public: + ColorScalesFactory(SPColorScalesMode submode); + ~ColorScalesFactory(); + + Gtk::Widget *createWidget(Inkscape::UI::SelectedColor &color) const; + Glib::ustring modeName() const; + +private: + SPColorScalesMode _submode; +}; + + +#endif /* !SEEN_SP_COLOR_SCALES_H */ + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 : diff --git a/src/ui/widget/color-slider.cpp b/src/ui/widget/color-slider.cpp index 711942e28..ad9662c6c 100644 --- a/src/ui/widget/color-slider.cpp +++ b/src/ui/widget/color-slider.cpp @@ -28,7 +28,7 @@ #include #endif -#include "widgets/sp-color-scales.h" +#include "ui/widget/color-scales.h" #include "preferences.h" static const gint SLIDER_WIDTH = 96; diff --git a/src/ui/widget/color-wheel-selector.cpp b/src/ui/widget/color-wheel-selector.cpp index e49e4ba16..4bf40dbb6 100644 --- a/src/ui/widget/color-wheel-selector.cpp +++ b/src/ui/widget/color-wheel-selector.cpp @@ -11,9 +11,9 @@ #include #include #include "dialogs/dialog-events.h" -#include "widgets/sp-color-scales.h" #include "svg/svg-icc-color.h" #include "ui/selected-color.h" +#include "ui/widget/color-scales.h" #include "ui/widget/color-slider.h" #include "ui/widget/gimpcolorwheel.h" diff --git a/src/widgets/Makefile_insert b/src/widgets/Makefile_insert index 7a1a7a4ef..6d860996a 100644 --- a/src/widgets/Makefile_insert +++ b/src/widgets/Makefile_insert @@ -70,8 +70,6 @@ ink_common_sources += \ widgets/sp-color-icc-selector.h \ widgets/sp-color-notebook.cpp \ widgets/sp-color-notebook.h \ - widgets/sp-color-scales.cpp \ - widgets/sp-color-scales.h \ widgets/sp-color-selector.cpp \ widgets/sp-color-selector.h \ widgets/spinbutton-events.cpp \ diff --git a/src/widgets/sp-color-icc-selector.cpp b/src/widgets/sp-color-icc-selector.cpp index cd1586661..808dfc925 100644 --- a/src/widgets/sp-color-icc-selector.cpp +++ b/src/widgets/sp-color-icc-selector.cpp @@ -12,7 +12,7 @@ #include "../dialogs/dialog-events.h" #include "sp-color-icc-selector.h" -#include "sp-color-scales.h" +#include "ui/widget/color-scales.h" #include "ui/widget/color-slider.h" #include "svg/svg-icc-color.h" #include "colorspace.h" diff --git a/src/widgets/sp-color-notebook.cpp b/src/widgets/sp-color-notebook.cpp index 7495d1deb..0e1634314 100644 --- a/src/widgets/sp-color-notebook.cpp +++ b/src/widgets/sp-color-notebook.cpp @@ -30,7 +30,6 @@ #include "../preferences.h" #include "sp-color-notebook.h" #include "spw-utilities.h" -#include "sp-color-scales.h" #include "sp-color-icc-selector.h" #include "svg/svg-icc-color.h" #include "../inkscape.h" @@ -41,6 +40,7 @@ #include "tools-switch.h" #include "ui/tools/tool-base.h" #include "ui/widget/color-entry.h" +#include "ui/widget/color-scales.h" #include "ui/widget/color-wheel-selector.h" using Inkscape::CMSSystem; diff --git a/src/widgets/sp-color-scales.cpp b/src/widgets/sp-color-scales.cpp deleted file mode 100644 index 3d9de650c..000000000 --- a/src/widgets/sp-color-scales.cpp +++ /dev/null @@ -1,788 +0,0 @@ -/* - * bulia byak - */ - -#ifdef HAVE_CONFIG_H -# include "config.h" -#endif - -#include "sp-color-scales.h" - -#include -#include -#include -#include - -#include "../dialogs/dialog-events.h" -#include "svg/svg-icc-color.h" -#include "ui/widget/color-slider.h" - -#define CSC_CHANNEL_R (1 << 0) -#define CSC_CHANNEL_G (1 << 1) -#define CSC_CHANNEL_B (1 << 2) -#define CSC_CHANNEL_A (1 << 3) -#define CSC_CHANNEL_H (1 << 0) -#define CSC_CHANNEL_S (1 << 1) -#define CSC_CHANNEL_V (1 << 2) -#define CSC_CHANNEL_C (1 << 0) -#define CSC_CHANNEL_M (1 << 1) -#define CSC_CHANNEL_Y (1 << 2) -#define CSC_CHANNEL_K (1 << 3) -#define CSC_CHANNEL_CMYKA (1 << 4) - -#define CSC_CHANNELS_ALL 0 - - -G_BEGIN_DECLS - -static void sp_color_scales_class_init (SPColorScalesClass *klass); -static void sp_color_scales_init (SPColorScales *cs); -static void sp_color_scales_dispose(GObject *object); - -static void sp_color_scales_show_all (GtkWidget *widget); -static void sp_color_scales_hide(GtkWidget *widget); - -static const gchar *sp_color_scales_hue_map (void); - -G_END_DECLS - -static SPColorSelectorClass *parent_class; - -#define XPAD 4 -#define YPAD 1 - -#define noDUMP_CHANGE_INFO 1 - -const gchar* ColorScales::SUBMODE_NAMES[] = { - N_("None"), - N_("RGB"), - N_("HSL"), - N_("CMYK") -}; - -GType -sp_color_scales_get_type (void) -{ - static GType type = 0; - if (!type) { - static const GTypeInfo info = { - sizeof (SPColorScalesClass), - NULL, /* base_init */ - NULL, /* base_finalize */ - (GClassInitFunc) sp_color_scales_class_init, - NULL, /* class_finalize */ - NULL, /* class_data */ - sizeof (SPColorScales), - 0, /* n_preallocs */ - (GInstanceInitFunc) sp_color_scales_init, - NULL - }; - - type = g_type_register_static (SP_TYPE_COLOR_SELECTOR, - "SPColorScales", - &info, - static_cast< GTypeFlags > (0) ); - } - return type; -} - -static void -sp_color_scales_class_init (SPColorScalesClass *klass) -{ - static const gchar* nameset[] = {N_("RGB"), N_("HSL"), N_("CMYK"), 0}; - GObjectClass *object_class = G_OBJECT_CLASS(klass); - GtkWidgetClass *widget_class = GTK_WIDGET_CLASS(klass); - SPColorSelectorClass *selector_class = SP_COLOR_SELECTOR_CLASS (klass); - - parent_class = SP_COLOR_SELECTOR_CLASS (g_type_class_peek_parent (klass)); - - selector_class->name = nameset; - selector_class->submode_count = 3; - - object_class->dispose = sp_color_scales_dispose; - - widget_class->show_all = sp_color_scales_show_all; - widget_class->hide = sp_color_scales_hide; -} - -ColorScales::ColorScales( SPColorSelector* csel ) - : ColorSelector( csel ), - _mode( SP_COLOR_SCALES_MODE_NONE ), - _rangeLimit( 255.0 ), - _updating( FALSE ), - _dragging( FALSE ) -{ - for (gint i = 0; i < 5; i++) { - _l[i] = 0; - _a[i] = 0; - _s[i] = 0; - _b[i] = 0; - } -} - -ColorScales::~ColorScales() -{ - for (gint i = 0; i < 5; i++) { - _l[i] = 0; - _a[i] = 0; - _s[i] = 0; - _b[i] = 0; - } -} - -void sp_color_scales_init (SPColorScales *cs) -{ - SP_COLOR_SELECTOR(cs)->base = new ColorScales( SP_COLOR_SELECTOR(cs) ); - - if ( SP_COLOR_SELECTOR(cs)->base ) - { - SP_COLOR_SELECTOR(cs)->base->init(); - } -} - -void ColorScales::init() -{ - gint i; - - _updating = FALSE; - _dragging = FALSE; - -#if GTK_CHECK_VERSION(3,0,0) - GtkWidget *t = gtk_grid_new(); -#else - GtkWidget *t = gtk_table_new (5, 3, FALSE); -#endif - gtk_widget_show (t); - gtk_box_pack_start (GTK_BOX (_csel), t, TRUE, TRUE, 4); - - /* Create components */ - for (i = 0; i < static_cast< gint > (G_N_ELEMENTS(_a)) ; i++) { - /* Label */ - _l[i] = gtk_label_new(""); - gtk_misc_set_alignment (GTK_MISC (_l[i]), 1.0, 0.5); - gtk_widget_show (_l[i]); - -#if GTK_CHECK_VERSION(3,0,0) - gtk_widget_set_margin_left(_l[i], XPAD); - gtk_widget_set_margin_right(_l[i], XPAD); - gtk_widget_set_margin_top(_l[i], YPAD); - gtk_widget_set_margin_bottom(_l[i], YPAD); - gtk_grid_attach(GTK_GRID(t), _l[i], 0, i, 1, 1); -#else - gtk_table_attach (GTK_TABLE (t), _l[i], 0, 1, i, i + 1, GTK_FILL, GTK_FILL, XPAD, YPAD); -#endif - - /* Adjustment */ - _a[i] = GTK_ADJUSTMENT(gtk_adjustment_new(0.0, 0.0, _rangeLimit, 1.0, 10.0, 10.0)); - /* Slider */ - _s[i] = Gtk::manage(new Inkscape::UI::Widget::ColorSlider(Glib::wrap(_a[i], true))); - _s[i]->show(); - -#if GTK_CHECK_VERSION(3,0,0) - _s[i]->set_margin_left(XPAD); - _s[i]->set_margin_right(XPAD); - _s[i]->set_margin_top(YPAD); - _s[i]->set_margin_bottom(YPAD); - _s[i]->set_hexpand(true); - gtk_grid_attach(GTK_GRID(t), _s[i]->gobj(), 1, i, 1, 1); -#else - gtk_table_attach (GTK_TABLE (t), _s[i]->gobj(), 1, 2, i, i + 1, (GtkAttachOptions)(GTK_EXPAND | GTK_FILL), GTK_FILL, XPAD, YPAD); -#endif - - /* Spinbutton */ - _b[i] = gtk_spin_button_new (GTK_ADJUSTMENT (_a[i]), 1.0, 0); - sp_dialog_defocus_on_enter (_b[i]); - gtk_label_set_mnemonic_widget (GTK_LABEL(_l[i]), _b[i]); - gtk_widget_show (_b[i]); - -#if GTK_CHECK_VERSION(3,0,0) - gtk_widget_set_margin_left(_b[i], XPAD); - gtk_widget_set_margin_right(_b[i], XPAD); - gtk_widget_set_margin_top(_b[i], YPAD); - gtk_widget_set_margin_bottom(_b[i], YPAD); - gtk_widget_set_halign(_b[i], GTK_ALIGN_CENTER); - gtk_widget_set_valign(_b[i], GTK_ALIGN_CENTER); - gtk_grid_attach(GTK_GRID(t), _b[i], 2, i, 1, 1); -#else - gtk_table_attach (GTK_TABLE (t), _b[i], 2, 3, i, i + 1, (GtkAttachOptions)0, (GtkAttachOptions)0, XPAD, YPAD); -#endif - - /* Attach channel value to adjustment */ - g_object_set_data (G_OBJECT (_a[i]), "channel", GINT_TO_POINTER (i)); - /* Signals */ - g_signal_connect (G_OBJECT (_a[i]), "value_changed", - G_CALLBACK (_adjustmentAnyChanged), _csel); - _s[i]->signal_grabbed.connect(sigc::mem_fun(this, &ColorScales::_sliderAnyGrabbed)); - _s[i]->signal_released.connect(sigc::mem_fun(this, &ColorScales::_sliderAnyReleased)); - _s[i]->signal_value_changed.connect(sigc::mem_fun(this, &ColorScales::_sliderAnyChanged)); - } - - /* Initial mode is none, so it works */ - setMode(SP_COLOR_SCALES_MODE_RGB); -} - -static void sp_color_scales_dispose(GObject *object) -{ - if ((G_OBJECT_CLASS(parent_class))->dispose) - (* (G_OBJECT_CLASS(parent_class))->dispose) (object); -} - -static void -sp_color_scales_show_all (GtkWidget *widget) -{ - gtk_widget_show (widget); -} - -static void sp_color_scales_hide(GtkWidget *widget) -{ - gtk_widget_hide(widget); -} - -GtkWidget *sp_color_scales_new() -{ - SPColorScales *csel = SP_COLOR_SCALES(g_object_new (SP_TYPE_COLOR_SCALES, NULL)); - - return GTK_WIDGET (csel); -} - -void ColorScales::_recalcColor( gboolean changing ) -{ - if ( changing ) - { - SPColor color; - gfloat alpha = 1.0; - gfloat c[5]; - - switch (_mode) { - case SP_COLOR_SCALES_MODE_RGB: - case SP_COLOR_SCALES_MODE_HSV: - _getRgbaFloatv(c); - color.set( c[0], c[1], c[2] ); - alpha = c[3]; - break; - case SP_COLOR_SCALES_MODE_CMYK: - { - _getCmykaFloatv( c ); - - float rgb[3]; - sp_color_cmyk_to_rgb_floatv( rgb, c[0], c[1], c[2], c[3] ); - color.set( rgb[0], rgb[1], rgb[2] ); - alpha = c[4]; - break; - } - default: - g_warning ("file %s: line %d: Illegal color selector mode %d", __FILE__, __LINE__, _mode); - break; - } - - /* Preserve ICC */ - color.icc = _color.icc ? new SVGICCColor(*_color.icc) : 0; - - _updateInternals( color, alpha, _dragging ); - } - else - { - _updateInternals( _color, _alpha, _dragging ); - } -} - -/* Helpers for setting color value */ -gfloat ColorScales::getScaled( const GtkAdjustment *a ) -{ - gfloat val = gtk_adjustment_get_value (const_cast(a)) - / gtk_adjustment_get_upper (const_cast(a)); - return val; -} - -void ColorScales::setScaled( GtkAdjustment *a, gfloat v ) -{ - gfloat val = v * gtk_adjustment_get_upper (a); - gtk_adjustment_set_value( a, val ); -} - -void ColorScales::_setRangeLimit( gdouble upper ) -{ - _rangeLimit = upper; - for ( gint i = 0; i < static_cast(G_N_ELEMENTS(_a)); i++ ) { - gtk_adjustment_set_upper (_a[i], upper); - gtk_adjustment_changed( _a[i] ); - } -} - -void ColorScales::_colorChanged() -{ -#ifdef DUMP_CHANGE_INFO - g_message("ColorScales::_colorChanged( this=%p, %f, %f, %f, %f)", this, _color.v.c[0], _color.v.c[1], _color.v.c[2], _alpha ); -#endif - gfloat tmp[3]; - gfloat c[5] = {0.0, 0.0, 0.0, 0.0}; - - switch (_mode) { - case SP_COLOR_SCALES_MODE_RGB: - sp_color_get_rgb_floatv( &_color, c ); - c[3] = _alpha; - c[4] = 0.0; - break; - case SP_COLOR_SCALES_MODE_HSV: - sp_color_get_rgb_floatv( &_color, tmp ); - sp_color_rgb_to_hsl_floatv (c, tmp[0], tmp[1], tmp[2]); - c[3] = _alpha; - c[4] = 0.0; - break; - case SP_COLOR_SCALES_MODE_CMYK: - sp_color_get_cmyk_floatv( &_color, c ); - c[4] = _alpha; - break; - default: - g_warning ("file %s: line %d: Illegal color selector mode %d", __FILE__, __LINE__, _mode); - break; - } - - _updating = TRUE; - setScaled( _a[0], c[0] ); - setScaled( _a[1], c[1] ); - setScaled( _a[2], c[2] ); - setScaled( _a[3], c[3] ); - setScaled( _a[4], c[4] ); - _updateSliders( CSC_CHANNELS_ALL ); - _updating = FALSE; -} - -void ColorScales::_getRgbaFloatv( gfloat *rgba ) -{ - g_return_if_fail (rgba != NULL); - - switch (_mode) { - case SP_COLOR_SCALES_MODE_RGB: - rgba[0] = getScaled(_a[0]); - rgba[1] = getScaled(_a[1]); - rgba[2] = getScaled(_a[2]); - rgba[3] = getScaled(_a[3]); - break; - case SP_COLOR_SCALES_MODE_HSV: - sp_color_hsl_to_rgb_floatv (rgba, getScaled(_a[0]), getScaled(_a[1]), getScaled(_a[2])); - rgba[3] = getScaled(_a[3]); - break; - case SP_COLOR_SCALES_MODE_CMYK: - sp_color_cmyk_to_rgb_floatv (rgba, getScaled(_a[0]), getScaled(_a[1]), getScaled(_a[2]), getScaled(_a[3])); - rgba[3] = getScaled(_a[4]); - break; - default: - g_warning ("file %s: line %d: Illegal color selector mode", __FILE__, __LINE__); - break; - } -} - -void ColorScales::_getCmykaFloatv( gfloat *cmyka ) -{ - gfloat rgb[3]; - - g_return_if_fail (cmyka != NULL); - - switch (_mode) { - case SP_COLOR_SCALES_MODE_RGB: - sp_color_rgb_to_cmyk_floatv (cmyka, getScaled(_a[0]), getScaled(_a[1]), getScaled(_a[2])); - cmyka[4] = getScaled(_a[3]); - break; - case SP_COLOR_SCALES_MODE_HSV: - sp_color_hsl_to_rgb_floatv (rgb, getScaled(_a[0]), getScaled(_a[1]), getScaled(_a[2])); - sp_color_rgb_to_cmyk_floatv (cmyka, rgb[0], rgb[1], rgb[2]); - cmyka[4] = getScaled(_a[3]); - break; - case SP_COLOR_SCALES_MODE_CMYK: - cmyka[0] = getScaled(_a[0]); - cmyka[1] = getScaled(_a[1]); - cmyka[2] = getScaled(_a[2]); - cmyka[3] = getScaled(_a[3]); - cmyka[4] = getScaled(_a[4]); - break; - default: - g_warning ("file %s: line %d: Illegal color selector mode", __FILE__, __LINE__); - break; - } -} - -guint32 ColorScales::_getRgba32() -{ - gfloat c[4]; - guint32 rgba; - - _getRgbaFloatv(c); - - rgba = SP_RGBA32_F_COMPOSE (c[0], c[1], c[2], c[3]); - - return rgba; -} - -void ColorScales::setMode(SPColorScalesMode mode) -{ - gfloat rgba[4]; - gfloat c[4]; - - if (_mode == mode) return; - - if ((_mode == SP_COLOR_SCALES_MODE_RGB) || - (_mode == SP_COLOR_SCALES_MODE_HSV) || - (_mode == SP_COLOR_SCALES_MODE_CMYK)) { - _getRgbaFloatv(rgba); - } else { - rgba[0] = rgba[1] = rgba[2] = rgba[3] = 1.0; - } - - _mode = mode; - - switch (mode) { - case SP_COLOR_SCALES_MODE_RGB: - _setRangeLimit(255.0); - gtk_label_set_markup_with_mnemonic (GTK_LABEL (_l[0]), _("_R:")); - _s[0]->set_tooltip_text(_("Red")); - gtk_widget_set_tooltip_text (_b[0], _("Red")); - gtk_label_set_markup_with_mnemonic (GTK_LABEL (_l[1]), _("_G:")); - _s[1]->set_tooltip_text(_("Green")); - gtk_widget_set_tooltip_text (_b[1], _("Green")); - gtk_label_set_markup_with_mnemonic (GTK_LABEL (_l[2]), _("_B:")); - _s[2]->set_tooltip_text(_("Blue")); - gtk_widget_set_tooltip_text (_b[2], _("Blue")); - gtk_label_set_markup_with_mnemonic (GTK_LABEL (_l[3]), _("_A:")); - _s[3]->set_tooltip_text(_("Alpha (opacity)")); - gtk_widget_set_tooltip_text (_b[3], _("Alpha (opacity)")); - _s[0]->setMap(NULL); - gtk_widget_hide (_l[4]); - _s[4]->hide(); - gtk_widget_hide (_b[4]); - _updating = TRUE; - setScaled( _a[0], rgba[0] ); - setScaled( _a[1], rgba[1] ); - setScaled( _a[2], rgba[2] ); - setScaled( _a[3], rgba[3] ); - _updating = FALSE; - _updateSliders( CSC_CHANNELS_ALL ); - break; - case SP_COLOR_SCALES_MODE_HSV: - _setRangeLimit(255.0); - gtk_label_set_markup_with_mnemonic (GTK_LABEL (_l[0]), _("_H:")); - _s[0]->set_tooltip_text(_("Hue")); - gtk_widget_set_tooltip_text (_b[0], _("Hue")); - gtk_label_set_markup_with_mnemonic (GTK_LABEL (_l[1]), _("_S:")); - _s[1]->set_tooltip_text(_("Saturation")); - gtk_widget_set_tooltip_text (_b[1], _("Saturation")); - gtk_label_set_markup_with_mnemonic (GTK_LABEL (_l[2]), _("_L:")); - _s[2]->set_tooltip_text(_("Lightness")); - gtk_widget_set_tooltip_text (_b[2], _("Lightness")); - gtk_label_set_markup_with_mnemonic (GTK_LABEL (_l[3]), _("_A:")); - _s[3]->set_tooltip_text(_("Alpha (opacity)")); - gtk_widget_set_tooltip_text (_b[3], _("Alpha (opacity)")); - _s[0]->setMap((guchar *)(sp_color_scales_hue_map())); - gtk_widget_hide (_l[4]); - _s[4]->hide(); - gtk_widget_hide (_b[4]); - _updating = TRUE; - c[0] = 0.0; - sp_color_rgb_to_hsl_floatv (c, rgba[0], rgba[1], rgba[2]); - setScaled( _a[0], c[0] ); - setScaled( _a[1], c[1] ); - setScaled( _a[2], c[2] ); - setScaled( _a[3], rgba[3] ); - _updating = FALSE; - _updateSliders( CSC_CHANNELS_ALL ); - break; - case SP_COLOR_SCALES_MODE_CMYK: - _setRangeLimit(100.0); - gtk_label_set_markup_with_mnemonic (GTK_LABEL (_l[0]), _("_C:")); - _s[0]->set_tooltip_text(_("Cyan")); - gtk_widget_set_tooltip_text (_b[0], _("Cyan")); - gtk_label_set_markup_with_mnemonic (GTK_LABEL (_l[1]), _("_M:")); - _s[1]->set_tooltip_text(_("Magenta")); - gtk_widget_set_tooltip_text (_b[1], _("Magenta")); - gtk_label_set_markup_with_mnemonic (GTK_LABEL (_l[2]), _("_Y:")); - _s[2]->set_tooltip_text(_("Yellow")); - gtk_widget_set_tooltip_text (_b[2], _("Yellow")); - gtk_label_set_markup_with_mnemonic (GTK_LABEL (_l[3]), _("_K:")); - _s[3]->set_tooltip_text(_("Black")); - gtk_widget_set_tooltip_text (_b[3], _("Black")); - gtk_label_set_markup_with_mnemonic (GTK_LABEL (_l[4]), _("_A:")); - _s[4]->set_tooltip_text(_("Alpha (opacity)")); - gtk_widget_set_tooltip_text (_b[4], _("Alpha (opacity)")); - _s[0]->setMap(NULL); - gtk_widget_show (_l[4]); - _s[4]->show(); - gtk_widget_show (_b[4]); - _updating = TRUE; - - sp_color_rgb_to_cmyk_floatv (c, rgba[0], rgba[1], rgba[2]); - setScaled( _a[0], c[0] ); - setScaled( _a[1], c[1] ); - setScaled( _a[2], c[2] ); - setScaled( _a[3], c[3] ); - - setScaled( _a[4], rgba[3] ); - _updating = FALSE; - _updateSliders( CSC_CHANNELS_ALL ); - break; - default: - g_warning ("file %s: line %d: Illegal color selector mode", __FILE__, __LINE__); - break; - } -} - -SPColorScalesMode ColorScales::getMode() const -{ - return _mode; -} - -void ColorScales::setSubmode( guint submode ) -{ - g_return_if_fail (_csel != NULL); - g_return_if_fail (SP_IS_COLOR_SCALES (_csel)); - g_return_if_fail (submode < 3); - - switch ( submode ) - { - default: - case 0: - setMode(SP_COLOR_SCALES_MODE_RGB); - break; - case 1: - setMode(SP_COLOR_SCALES_MODE_HSV); - break; - case 2: - setMode(SP_COLOR_SCALES_MODE_CMYK); - break; - } -} - -guint ColorScales::getSubmode() const -{ - guint submode = 0; - - switch ( _mode ) - { - case SP_COLOR_SCALES_MODE_HSV: - submode = 1; - break; - case SP_COLOR_SCALES_MODE_CMYK: - submode = 2; - break; - case SP_COLOR_SCALES_MODE_RGB: - default: - submode = 0; - } - - return submode; -} - -void ColorScales::_adjustmentAnyChanged( GtkAdjustment *adjustment, SPColorScales *cs ) -{ - gint channel = GPOINTER_TO_INT (g_object_get_data(G_OBJECT (adjustment), "channel")); - - _adjustmentChanged(cs, channel); -} - -void ColorScales::_sliderAnyGrabbed() -{ - if (!_dragging) { - _dragging = TRUE; - _grabbed(); - _recalcColor( FALSE ); - } -} - -void ColorScales::_sliderAnyReleased() -{ - if (_dragging) { - _dragging = FALSE; - _released(); - _recalcColor( FALSE ); - } -} - -void ColorScales::_sliderAnyChanged() -{ - _recalcColor( TRUE ); -} - -void ColorScales::_adjustmentChanged( SPColorScales *cs, guint channel ) -{ - ColorScales* scales = static_cast(SP_COLOR_SELECTOR(cs)->base); - if (scales->_updating) return; - - scales->_updating = TRUE; - - scales->_updateSliders( (1 << channel) ); - - scales->_recalcColor (TRUE); - - scales->_updating = FALSE; -} - -void ColorScales::_updateSliders( guint channels ) -{ - gfloat rgb0[3], rgbm[3], rgb1[3]; -#ifdef SPCS_PREVIEW - guint32 rgba; -#endif - switch (_mode) { - case SP_COLOR_SCALES_MODE_RGB: - if ((channels != CSC_CHANNEL_R) && (channels != CSC_CHANNEL_A)) { - /* Update red */ - _s[0]->setColors(SP_RGBA32_F_COMPOSE (0.0, getScaled(_a[1]), getScaled(_a[2]), 1.0), - SP_RGBA32_F_COMPOSE (0.5, getScaled(_a[1]), getScaled(_a[2]), 1.0), - SP_RGBA32_F_COMPOSE (1.0, getScaled(_a[1]), getScaled(_a[2]), 1.0)); - } - if ((channels != CSC_CHANNEL_G) && (channels != CSC_CHANNEL_A)) { - /* Update green */ - _s[1]->setColors(SP_RGBA32_F_COMPOSE(getScaled(_a[0]), 0.0, getScaled(_a[2]), 1.0), - SP_RGBA32_F_COMPOSE(getScaled(_a[0]), 0.5, getScaled(_a[2]), 1.0), - SP_RGBA32_F_COMPOSE(getScaled(_a[0]), 1.0, getScaled(_a[2]), 1.0)); - } - if ((channels != CSC_CHANNEL_B) && (channels != CSC_CHANNEL_A)) { - /* Update blue */ - _s[2]->setColors(SP_RGBA32_F_COMPOSE (getScaled(_a[0]), getScaled(_a[1]), 0.0, 1.0), - SP_RGBA32_F_COMPOSE (getScaled(_a[0]), getScaled(_a[1]), 0.5, 1.0), - SP_RGBA32_F_COMPOSE (getScaled(_a[0]), getScaled(_a[1]), 1.0, 1.0)); - } - if (channels != CSC_CHANNEL_A) { - /* Update alpha */ - _s[3]->setColors(SP_RGBA32_F_COMPOSE (getScaled(_a[0]), getScaled(_a[1]), getScaled(_a[2]), 0.0), - SP_RGBA32_F_COMPOSE (getScaled(_a[0]), getScaled(_a[1]), getScaled(_a[2]), 0.5), - SP_RGBA32_F_COMPOSE (getScaled(_a[0]), getScaled(_a[1]), getScaled(_a[2]), 1.0)); - } - break; - case SP_COLOR_SCALES_MODE_HSV: - /* Hue is never updated */ - if ((channels != CSC_CHANNEL_S) && (channels != CSC_CHANNEL_A)) { - /* Update saturation */ - sp_color_hsl_to_rgb_floatv (rgb0, getScaled(_a[0]), 0.0, getScaled(_a[2])); - sp_color_hsl_to_rgb_floatv (rgbm, getScaled(_a[0]), 0.5, getScaled(_a[2])); - sp_color_hsl_to_rgb_floatv (rgb1, getScaled(_a[0]), 1.0, getScaled(_a[2])); - _s[1]->setColors(SP_RGBA32_F_COMPOSE (rgb0[0], rgb0[1], rgb0[2], 1.0), - SP_RGBA32_F_COMPOSE (rgbm[0], rgbm[1], rgbm[2], 1.0), - SP_RGBA32_F_COMPOSE (rgb1[0], rgb1[1], rgb1[2], 1.0)); - } - if ((channels != CSC_CHANNEL_V) && (channels != CSC_CHANNEL_A)) { - /* Update value */ - sp_color_hsl_to_rgb_floatv (rgb0, getScaled(_a[0]), getScaled(_a[1]), 0.0); - sp_color_hsl_to_rgb_floatv (rgbm, getScaled(_a[0]), getScaled(_a[1]), 0.5); - sp_color_hsl_to_rgb_floatv (rgb1, getScaled(_a[0]), getScaled(_a[1]), 1.0); - _s[2]->setColors(SP_RGBA32_F_COMPOSE (rgb0[0], rgb0[1], rgb0[2], 1.0), - SP_RGBA32_F_COMPOSE (rgbm[0], rgbm[1], rgbm[2], 1.0), - SP_RGBA32_F_COMPOSE (rgb1[0], rgb1[1], rgb1[2], 1.0)); - } - if (channels != CSC_CHANNEL_A) { - /* Update alpha */ - sp_color_hsl_to_rgb_floatv (rgb0, getScaled(_a[0]), getScaled(_a[1]), getScaled(_a[2])); - _s[3]->setColors(SP_RGBA32_F_COMPOSE (rgb0[0], rgb0[1], rgb0[2], 0.0), - SP_RGBA32_F_COMPOSE (rgb0[0], rgb0[1], rgb0[2], 0.5), - SP_RGBA32_F_COMPOSE (rgb0[0], rgb0[1], rgb0[2], 1.0)); - } - break; - case SP_COLOR_SCALES_MODE_CMYK: - if ((channels != CSC_CHANNEL_C) && (channels != CSC_CHANNEL_CMYKA)) { - /* Update C */ - sp_color_cmyk_to_rgb_floatv (rgb0, 0.0, getScaled(_a[1]), getScaled(_a[2]), getScaled(_a[3])); - sp_color_cmyk_to_rgb_floatv (rgbm, 0.5, getScaled(_a[1]), getScaled(_a[2]), getScaled(_a[3])); - sp_color_cmyk_to_rgb_floatv (rgb1, 1.0, getScaled(_a[1]), getScaled(_a[2]), getScaled(_a[3])); - _s[0]->setColors(SP_RGBA32_F_COMPOSE (rgb0[0], rgb0[1], rgb0[2], 1.0), - SP_RGBA32_F_COMPOSE (rgbm[0], rgbm[1], rgbm[2], 1.0), - SP_RGBA32_F_COMPOSE (rgb1[0], rgb1[1], rgb1[2], 1.0)); - } - if ((channels != CSC_CHANNEL_M) && (channels != CSC_CHANNEL_CMYKA)) { - /* Update M */ - sp_color_cmyk_to_rgb_floatv (rgb0, getScaled(_a[0]), 0.0, getScaled(_a[2]), getScaled(_a[3])); - sp_color_cmyk_to_rgb_floatv (rgbm, getScaled(_a[0]), 0.5, getScaled(_a[2]), getScaled(_a[3])); - sp_color_cmyk_to_rgb_floatv (rgb1, getScaled(_a[0]), 1.0, getScaled(_a[2]), getScaled(_a[3])); - _s[1]->setColors(SP_RGBA32_F_COMPOSE (rgb0[0], rgb0[1], rgb0[2], 1.0), - SP_RGBA32_F_COMPOSE (rgbm[0], rgbm[1], rgbm[2], 1.0), - SP_RGBA32_F_COMPOSE (rgb1[0], rgb1[1], rgb1[2], 1.0)); - } - if ((channels != CSC_CHANNEL_Y) && (channels != CSC_CHANNEL_CMYKA)) { - /* Update Y */ - sp_color_cmyk_to_rgb_floatv (rgb0, getScaled(_a[0]), getScaled(_a[1]), 0.0, getScaled(_a[3])); - sp_color_cmyk_to_rgb_floatv (rgbm, getScaled(_a[0]), getScaled(_a[1]), 0.5, getScaled(_a[3])); - sp_color_cmyk_to_rgb_floatv (rgb1, getScaled(_a[0]), getScaled(_a[1]), 1.0, getScaled(_a[3])); - _s[2]->setColors(SP_RGBA32_F_COMPOSE (rgb0[0], rgb0[1], rgb0[2], 1.0), - SP_RGBA32_F_COMPOSE (rgbm[0], rgbm[1], rgbm[2], 1.0), - SP_RGBA32_F_COMPOSE (rgb1[0], rgb1[1], rgb1[2], 1.0)); - } - if ((channels != CSC_CHANNEL_K) && (channels != CSC_CHANNEL_CMYKA)) { - /* Update K */ - sp_color_cmyk_to_rgb_floatv (rgb0, getScaled(_a[0]), getScaled(_a[1]), getScaled(_a[2]), 0.0); - sp_color_cmyk_to_rgb_floatv (rgbm, getScaled(_a[0]), getScaled(_a[1]), getScaled(_a[2]), 0.5); - sp_color_cmyk_to_rgb_floatv (rgb1, getScaled(_a[0]), getScaled(_a[1]), getScaled(_a[2]), 1.0); - _s[3]->setColors(SP_RGBA32_F_COMPOSE (rgb0[0], rgb0[1], rgb0[2], 1.0), - SP_RGBA32_F_COMPOSE (rgbm[0], rgbm[1], rgbm[2], 1.0), - SP_RGBA32_F_COMPOSE (rgb1[0], rgb1[1], rgb1[2], 1.0)); - } - if (channels != CSC_CHANNEL_CMYKA) { - /* Update alpha */ - sp_color_cmyk_to_rgb_floatv (rgb0, getScaled(_a[0]), getScaled(_a[1]), getScaled(_a[2]), getScaled(_a[3])); - _s[4]->setColors(SP_RGBA32_F_COMPOSE (rgb0[0], rgb0[1], rgb0[2], 0.0), - SP_RGBA32_F_COMPOSE (rgb0[0], rgb0[1], rgb0[2], 0.5), - SP_RGBA32_F_COMPOSE (rgb0[0], rgb0[1], rgb0[2], 1.0)); - } - break; - default: - g_warning ("file %s: line %d: Illegal color selector mode", __FILE__, __LINE__); - break; - } - - // Force the internal color to be updated - if ( !_updating ) - { - _recalcColor( TRUE ); - } - -#ifdef SPCS_PREVIEW - rgba = sp_color_scales_get_rgba32 (cs); - sp_color_preview_set_rgba32 (SP_COLOR_PREVIEW (_p), rgba); -#endif -} - -static const gchar * -sp_color_scales_hue_map (void) -{ - static gchar *map = NULL; - - if (!map) { - gchar *p; - gint h; - map = g_new (gchar, 4 * 1024); - p = map; - for (h = 0; h < 1024; h++) { - gfloat rgb[3]; - sp_color_hsl_to_rgb_floatv (rgb, h / 1024.0, 1.0, 0.5); - *p++ = SP_COLOR_F_TO_U (rgb[0]); - *p++ = SP_COLOR_F_TO_U (rgb[1]); - *p++ = SP_COLOR_F_TO_U (rgb[2]); - *p++ = 255; - } - } - - return map; -} - -ColorScalesFactory::ColorScalesFactory(SPColorScalesMode submode) - : _submode(submode) -{ -} - -ColorScalesFactory::~ColorScalesFactory() { -} - -Gtk::Widget *ColorScalesFactory::createWidget(Inkscape::UI::SelectedColor &color) const { - GtkWidget *w = sp_color_selector_new(SP_TYPE_COLOR_SCALES); - SPColorSelector* csel; - - csel = SP_COLOR_SELECTOR (w); - if ( _submode > 0 ) - { - csel->base->setSubmode( _submode - 1 ); - } - - Gtk::Widget *wrapped = Gtk::manage(Glib::wrap(w)); - return wrapped; -} - -Glib::ustring ColorScalesFactory::modeName() const { - return gettext(ColorScales::SUBMODE_NAMES[_submode]); -} diff --git a/src/widgets/sp-color-scales.h b/src/widgets/sp-color-scales.h deleted file mode 100644 index 946f0935e..000000000 --- a/src/widgets/sp-color-scales.h +++ /dev/null @@ -1,139 +0,0 @@ -#ifndef SEEN_SP_COLOR_SCALES_H -#define SEEN_SP_COLOR_SCALES_H - -#ifdef HAVE_CONFIG_H -# include -#endif - -#if GLIBMM_DISABLE_DEPRECATED && HAVE_GLIBMM_THREADS_H -#include -#endif - -#include -#include - -#include -#include - -#include "ui/selected-color.h" - -struct SPColorScales; -struct SPColorScalesClass; - -namespace Inkscape { -namespace UI { -namespace Widget { - -class ColorSlider; - -} -} -} - -typedef enum { - SP_COLOR_SCALES_MODE_NONE = 0, - SP_COLOR_SCALES_MODE_RGB = 1, - SP_COLOR_SCALES_MODE_HSV = 2, - SP_COLOR_SCALES_MODE_CMYK = 3 -} SPColorScalesMode; - - - -class ColorScales: public ColorSelector -{ -public: - static const gchar* SUBMODE_NAMES[]; - - static gfloat getScaled( const GtkAdjustment *a ); - static void setScaled( GtkAdjustment *a, gfloat v); - - ColorScales(SPColorSelector *csel); - virtual ~ColorScales(); - - virtual void init(); - - virtual void setSubmode(guint submode); - virtual guint getSubmode() const; - - void setMode(SPColorScalesMode mode); - SPColorScalesMode getMode() const; - - -protected: - virtual void _colorChanged(); - - static void _adjustmentAnyChanged(GtkAdjustment *adjustment, SPColorScales *cs); - void _sliderAnyGrabbed(); - void _sliderAnyReleased(); - void _sliderAnyChanged(); - static void _adjustmentChanged(SPColorScales *cs, guint channel); - - void _getRgbaFloatv(gfloat *rgba); - void _getCmykaFloatv(gfloat *cmyka); - guint32 _getRgba32(); - void _updateSliders(guint channels); - void _recalcColor(gboolean changing); - - void _setRangeLimit( gdouble upper ); - - SPColorScalesMode _mode; - gdouble _rangeLimit; - gboolean _updating : 1; - gboolean _dragging : 1; - GtkAdjustment *_a[5]; /* Channel adjustments */ - Inkscape::UI::Widget::ColorSlider *_s[5]; /* Channel sliders */ - GtkWidget *_b[5]; /* Spinbuttons */ - GtkWidget *_l[5]; /* Labels */ - -private: - // By default, disallow copy constructor and assignment operator - ColorScales(ColorScales const &obj); - ColorScales &operator=(ColorScales const &obj ); -}; - - - -#define SP_TYPE_COLOR_SCALES (sp_color_scales_get_type()) -#define SP_COLOR_SCALES(o) (G_TYPE_CHECK_INSTANCE_CAST((o), SP_TYPE_COLOR_SCALES, SPColorScales)) -#define SP_COLOR_SCALES_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), SP_TYPE_COLOR_SCALES, SPColorScalesClass)) -#define SP_IS_COLOR_SCALES(o) (G_TYPE_CHECK_INSTANCE_TYPE((o), SP_TYPE_COLOR_SCALES)) -#define SP_IS_COLOR_SCALES_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE((k), SP_TYPE_COLOR_SCALES)) - -struct SPColorScales { - SPColorSelector parent; -}; - -struct SPColorScalesClass { - SPColorSelectorClass parent_class; -}; - -GType sp_color_scales_get_type(); - -GtkWidget *sp_color_scales_new(); - - -class ColorScalesFactory: public Inkscape::UI::ColorSelectorFactory { -public: - ColorScalesFactory(SPColorScalesMode submode); - ~ColorScalesFactory(); - - Gtk::Widget *createWidget(Inkscape::UI::SelectedColor &color) const; - Glib::ustring modeName() const; - -private: - SPColorScalesMode _submode; -}; - - -#endif /* !SEEN_SP_COLOR_SCALES_H */ - -/* - Local Variables: - mode:c++ - c-file-style:"stroustrup" - c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) - indent-tabs-mode:nil - fill-column:99 - End: -*/ -// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 : -- cgit v1.2.3 From 0debbafdabda818d9f9a971be6cd225c50e51d1a Mon Sep 17 00:00:00 2001 From: Tomasz Boczkowski Date: Sat, 31 May 2014 15:12:26 +0200 Subject: updated CMakeLists (bzr r13341.6.39) --- src/ui/CMakeLists.txt | 8 ++++++++ src/widgets/CMakeLists.txt | 4 ---- 2 files changed, 8 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/ui/CMakeLists.txt b/src/ui/CMakeLists.txt index 883ba3427..65e93f1b0 100644 --- a/src/ui/CMakeLists.txt +++ b/src/ui/CMakeLists.txt @@ -3,6 +3,7 @@ set(ui_SRC clipboard.cpp control-manager.cpp previewholder.cpp + selected-color.cpp uxmanager.cpp cache/svg_preview_cache.cpp @@ -107,9 +108,12 @@ set(ui_SRC widget/anchor-selector.cpp widget/button.cpp + widget/color-entry.cpp widget/color-picker.cpp widget/color-preview.cpp + widget/color-scales.cpp widget/color-slider.cpp + widget/color-wheel-selector.cpp widget/dock-item.cpp widget/dock.cpp widget/entity-entry.cpp @@ -160,6 +164,7 @@ set(ui_SRC previewable.h previewfillable.h previewholder.h + selected-color.h uxmanager.h cache/svg_preview_cache.h @@ -269,9 +274,12 @@ set(ui_SRC widget/anchor-selector.h widget/attr-widget.h widget/button.h + widget/color-entry.h widget/color-picker.h widget/color-preview.h + widget/color-scales.h widget/color-slider.h + widget/color-wheel-selector.h widget/combo-enums.h widget/dock-item.h widget/dock.h diff --git a/src/widgets/CMakeLists.txt b/src/widgets/CMakeLists.txt index b65e0b1db..dd0cba0b2 100644 --- a/src/widgets/CMakeLists.txt +++ b/src/widgets/CMakeLists.txt @@ -38,9 +38,7 @@ set(widgets_SRC sp-attribute-widget.cpp sp-color-icc-selector.cpp sp-color-notebook.cpp - sp-color-scales.cpp sp-color-selector.cpp - sp-color-wheel-selector.cpp sp-widget.cpp sp-xmlview-attr-list.cpp sp-xmlview-content.cpp @@ -94,9 +92,7 @@ set(widgets_SRC sp-attribute-widget.h sp-color-icc-selector.h sp-color-notebook.h - sp-color-scales.h sp-color-selector.h - sp-color-wheel-selector.h sp-widget.h sp-xmlview-attr-list.h sp-xmlview-content.h -- cgit v1.2.3 From d128fc4fd60ebcd8ac820f584b5a4b3b35ad5b00 Mon Sep 17 00:00:00 2001 From: Tomasz Boczkowski Date: Sat, 31 May 2014 20:15:08 +0200 Subject: SPColorScales c++-sification - using SelectedColor (bzr r13341.6.40) --- src/ui/widget/color-scales.cpp | 253 ++++++++++------------------------ src/ui/widget/color-scales.h | 63 +++------ src/widgets/sp-color-icc-selector.cpp | 3 + src/widgets/sp-color-notebook.cpp | 6 +- src/widgets/sp-color-notebook.h | 1 + src/widgets/sp-color-selector.cpp | 2 +- 6 files changed, 101 insertions(+), 227 deletions(-) (limited to 'src') diff --git a/src/ui/widget/color-scales.cpp b/src/ui/widget/color-scales.cpp index bba44034a..234e7a2d1 100644 --- a/src/ui/widget/color-scales.cpp +++ b/src/ui/widget/color-scales.cpp @@ -32,27 +32,18 @@ #define CSC_CHANNELS_ALL 0 - -G_BEGIN_DECLS - -static void sp_color_scales_class_init (SPColorScalesClass *klass); -static void sp_color_scales_init (SPColorScales *cs); -static void sp_color_scales_dispose(GObject *object); - -static void sp_color_scales_show_all (GtkWidget *widget); -static void sp_color_scales_hide(GtkWidget *widget); - -static const gchar *sp_color_scales_hue_map (void); - -G_END_DECLS - -static SPColorSelectorClass *parent_class; - #define XPAD 4 #define YPAD 1 #define noDUMP_CHANGE_INFO 1 +namespace Inkscape { +namespace UI { +namespace Widget { + + +static const gchar * sp_color_scales_hue_map (); + const gchar* ColorScales::SUBMODE_NAMES[] = { N_("None"), N_("RGB"), @@ -60,54 +51,14 @@ const gchar* ColorScales::SUBMODE_NAMES[] = { N_("CMYK") }; -GType -sp_color_scales_get_type (void) -{ - static GType type = 0; - if (!type) { - static const GTypeInfo info = { - sizeof (SPColorScalesClass), - NULL, /* base_init */ - NULL, /* base_finalize */ - (GClassInitFunc) sp_color_scales_class_init, - NULL, /* class_finalize */ - NULL, /* class_data */ - sizeof (SPColorScales), - 0, /* n_preallocs */ - (GInstanceInitFunc) sp_color_scales_init, - NULL - }; - - type = g_type_register_static (SP_TYPE_COLOR_SELECTOR, - "SPColorScales", - &info, - static_cast< GTypeFlags > (0) ); - } - return type; -} - -static void -sp_color_scales_class_init (SPColorScalesClass *klass) -{ - static const gchar* nameset[] = {N_("RGB"), N_("HSL"), N_("CMYK"), 0}; - GObjectClass *object_class = G_OBJECT_CLASS(klass); - GtkWidgetClass *widget_class = GTK_WIDGET_CLASS(klass); - SPColorSelectorClass *selector_class = SP_COLOR_SELECTOR_CLASS (klass); - - parent_class = SP_COLOR_SELECTOR_CLASS (g_type_class_peek_parent (klass)); - - selector_class->name = nameset; - selector_class->submode_count = 3; - - object_class->dispose = sp_color_scales_dispose; - - widget_class->show_all = sp_color_scales_show_all; - widget_class->hide = sp_color_scales_hide; -} - -ColorScales::ColorScales( SPColorSelector* csel ) - : ColorSelector( csel ), - _mode( SP_COLOR_SCALES_MODE_NONE ), +ColorScales::ColorScales(SelectedColor &color, SPColorScalesMode mode) +#if GTK_CHECK_VERSION(3,0,0) + : Gtk::Grid() +#else + : Gtk::Table(5, 3, false) +#endif + , _color(color) + , _rangeLimit( 255.0 ), _updating( FALSE ), _dragging( FALSE ) @@ -118,6 +69,12 @@ ColorScales::ColorScales( SPColorSelector* csel ) _s[i] = 0; _b[i] = 0; } + + _initUI(mode); + + _color.signal_changed.connect(sigc::mem_fun(this, &ColorScales::_onColorChanged)); + _color.signal_dragged.connect(sigc::mem_fun(this, &ColorScales::_onColorChanged)); + } ColorScales::~ColorScales() @@ -130,30 +87,14 @@ ColorScales::~ColorScales() } } -void sp_color_scales_init (SPColorScales *cs) -{ - SP_COLOR_SELECTOR(cs)->base = new ColorScales( SP_COLOR_SELECTOR(cs) ); - - if ( SP_COLOR_SELECTOR(cs)->base ) - { - SP_COLOR_SELECTOR(cs)->base->init(); - } -} - -void ColorScales::init() +void ColorScales::_initUI(SPColorScalesMode mode) { gint i; _updating = FALSE; _dragging = FALSE; -#if GTK_CHECK_VERSION(3,0,0) - GtkWidget *t = gtk_grid_new(); -#else - GtkWidget *t = gtk_table_new (5, 3, FALSE); -#endif - gtk_widget_show (t); - gtk_box_pack_start (GTK_BOX (_csel), t, TRUE, TRUE, 4); + GtkWidget *t = GTK_WIDGET(gobj()); /* Create components */ for (i = 0; i < static_cast< gint > (G_N_ELEMENTS(_a)) ; i++) { @@ -211,42 +152,23 @@ void ColorScales::init() g_object_set_data (G_OBJECT (_a[i]), "channel", GINT_TO_POINTER (i)); /* Signals */ g_signal_connect (G_OBJECT (_a[i]), "value_changed", - G_CALLBACK (_adjustmentAnyChanged), _csel); + G_CALLBACK (_adjustmentAnyChanged), this); _s[i]->signal_grabbed.connect(sigc::mem_fun(this, &ColorScales::_sliderAnyGrabbed)); _s[i]->signal_released.connect(sigc::mem_fun(this, &ColorScales::_sliderAnyReleased)); _s[i]->signal_value_changed.connect(sigc::mem_fun(this, &ColorScales::_sliderAnyChanged)); } /* Initial mode is none, so it works */ - setMode(SP_COLOR_SCALES_MODE_RGB); -} - -static void sp_color_scales_dispose(GObject *object) -{ - if ((G_OBJECT_CLASS(parent_class))->dispose) - (* (G_OBJECT_CLASS(parent_class))->dispose) (object); -} - -static void -sp_color_scales_show_all (GtkWidget *widget) -{ - gtk_widget_show (widget); -} - -static void sp_color_scales_hide(GtkWidget *widget) -{ - gtk_widget_hide(widget); -} - -GtkWidget *sp_color_scales_new() -{ - SPColorScales *csel = SP_COLOR_SCALES(g_object_new (SP_TYPE_COLOR_SCALES, NULL)); - - return GTK_WIDGET (csel); + setMode(mode); } void ColorScales::_recalcColor( gboolean changing ) { + if (_updating) { + return; + } + _updating = true; + if ( changing ) { SPColor color; @@ -275,15 +197,14 @@ void ColorScales::_recalcColor( gboolean changing ) break; } - /* Preserve ICC */ - color.icc = _color.icc ? new SVGICCColor(*_color.icc) : 0; - - _updateInternals( color, alpha, _dragging ); + _color.preserveICC(); + _color.setColorAlpha(color, alpha, true); } else { - _updateInternals( _color, _alpha, _dragging ); + // _updateInternals( _color, _alpha, _dragging ); } + _updating = false; } /* Helpers for setting color value */ @@ -309,29 +230,34 @@ void ColorScales::_setRangeLimit( gdouble upper ) } } -void ColorScales::_colorChanged() +void ColorScales::_onColorChanged() { + if (_updating || !get_visible()) { + return; + } #ifdef DUMP_CHANGE_INFO - g_message("ColorScales::_colorChanged( this=%p, %f, %f, %f, %f)", this, _color.v.c[0], _color.v.c[1], _color.v.c[2], _alpha ); + g_message("ColorScales::_onColorChanged( this=%p, %f, %f, %f, %f)", this, _color.color().v.c[0], _color.color().v.c[1], _color.color().v.c[2], _color.alpha() ); #endif gfloat tmp[3]; gfloat c[5] = {0.0, 0.0, 0.0, 0.0}; + SPColor color = _color.color(); + switch (_mode) { case SP_COLOR_SCALES_MODE_RGB: - sp_color_get_rgb_floatv( &_color, c ); - c[3] = _alpha; + sp_color_get_rgb_floatv( &color, c ); + c[3] = _color.alpha(); c[4] = 0.0; break; case SP_COLOR_SCALES_MODE_HSV: - sp_color_get_rgb_floatv( &_color, tmp ); + sp_color_get_rgb_floatv( &color, tmp ); sp_color_rgb_to_hsl_floatv (c, tmp[0], tmp[1], tmp[2]); - c[3] = _alpha; + c[3] = _color.alpha(); c[4] = 0.0; break; case SP_COLOR_SCALES_MODE_CMYK: - sp_color_get_cmyk_floatv( &_color, c ); - c[4] = _alpha; + sp_color_get_cmyk_floatv( &color, c ); + c[4] = _color.alpha(); break; default: g_warning ("file %s: line %d: Illegal color selector mode %d", __FILE__, __LINE__, _mode); @@ -530,48 +456,7 @@ SPColorScalesMode ColorScales::getMode() const return _mode; } -void ColorScales::setSubmode( guint submode ) -{ - g_return_if_fail (_csel != NULL); - g_return_if_fail (SP_IS_COLOR_SCALES (_csel)); - g_return_if_fail (submode < 3); - - switch ( submode ) - { - default: - case 0: - setMode(SP_COLOR_SCALES_MODE_RGB); - break; - case 1: - setMode(SP_COLOR_SCALES_MODE_HSV); - break; - case 2: - setMode(SP_COLOR_SCALES_MODE_CMYK); - break; - } -} - -guint ColorScales::getSubmode() const -{ - guint submode = 0; - - switch ( _mode ) - { - case SP_COLOR_SCALES_MODE_HSV: - submode = 1; - break; - case SP_COLOR_SCALES_MODE_CMYK: - submode = 2; - break; - case SP_COLOR_SCALES_MODE_RGB: - default: - submode = 0; - } - - return submode; -} - -void ColorScales::_adjustmentAnyChanged( GtkAdjustment *adjustment, SPColorScales *cs ) +void ColorScales::_adjustmentAnyChanged( GtkAdjustment *adjustment, ColorScales *cs ) { gint channel = GPOINTER_TO_INT (g_object_get_data(G_OBJECT (adjustment), "channel")); @@ -580,39 +465,46 @@ void ColorScales::_adjustmentAnyChanged( GtkAdjustment *adjustment, SPColorScale void ColorScales::_sliderAnyGrabbed() { + if (_updating) { + return; + } + _updating = true; if (!_dragging) { _dragging = TRUE; - _grabbed(); + _color.setHeld(true); _recalcColor( FALSE ); } + _updating = false; } void ColorScales::_sliderAnyReleased() { + if (_updating) { + return; + } + _updating = true; if (_dragging) { _dragging = FALSE; - _released(); + _color.setHeld(false); _recalcColor( FALSE ); } + _updating = false; } void ColorScales::_sliderAnyChanged() { + if (_updating) { + return; + } _recalcColor( TRUE ); } -void ColorScales::_adjustmentChanged( SPColorScales *cs, guint channel ) +void ColorScales::_adjustmentChanged( ColorScales *scales, guint channel ) { - ColorScales* scales = static_cast(SP_COLOR_SELECTOR(cs)->base); if (scales->_updating) return; - scales->_updating = TRUE; - scales->_updateSliders( (1 << channel) ); - scales->_recalcColor (TRUE); - - scales->_updating = FALSE; } void ColorScales::_updateSliders( guint channels ) @@ -770,19 +662,14 @@ ColorScalesFactory::~ColorScalesFactory() { } Gtk::Widget *ColorScalesFactory::createWidget(Inkscape::UI::SelectedColor &color) const { - GtkWidget *w = sp_color_selector_new(SP_TYPE_COLOR_SCALES); - SPColorSelector* csel; - - csel = SP_COLOR_SELECTOR (w); - if ( _submode > 0 ) - { - csel->base->setSubmode( _submode - 1 ); - } - - Gtk::Widget *wrapped = Gtk::manage(Glib::wrap(w)); - return wrapped; + Gtk::Widget *w = Gtk::manage(new ColorScales(color, _submode)); + return w; } Glib::ustring ColorScalesFactory::modeName() const { return gettext(ColorScales::SUBMODE_NAMES[_submode]); } + +} +} +} diff --git a/src/ui/widget/color-scales.h b/src/ui/widget/color-scales.h index 946f0935e..21f9708c1 100644 --- a/src/ui/widget/color-scales.h +++ b/src/ui/widget/color-scales.h @@ -9,26 +9,23 @@ #include #endif +#include #include #include - -#include -#include +#if GTK_CHECK_VERSION(3,0,0) +#include +#else +#include +#endif #include "ui/selected-color.h" -struct SPColorScales; -struct SPColorScalesClass; - namespace Inkscape { namespace UI { namespace Widget { class ColorSlider; -} -} -} typedef enum { SP_COLOR_SCALES_MODE_NONE = 0, @@ -39,7 +36,12 @@ typedef enum { -class ColorScales: public ColorSelector +class ColorScales +#if GTK_CHECK_VERSION(3,0,0) + : public Gtk::Grid +#else + : public Gtk::Table +#endif { public: static const gchar* SUBMODE_NAMES[]; @@ -47,26 +49,22 @@ public: static gfloat getScaled( const GtkAdjustment *a ); static void setScaled( GtkAdjustment *a, gfloat v); - ColorScales(SPColorSelector *csel); + ColorScales(SelectedColor &color, SPColorScalesMode mode); virtual ~ColorScales(); - virtual void init(); - - virtual void setSubmode(guint submode); - virtual guint getSubmode() const; + virtual void _initUI(SPColorScalesMode mode); void setMode(SPColorScalesMode mode); SPColorScalesMode getMode() const; - protected: - virtual void _colorChanged(); + void _onColorChanged(); - static void _adjustmentAnyChanged(GtkAdjustment *adjustment, SPColorScales *cs); + static void _adjustmentAnyChanged(GtkAdjustment *adjustment, ColorScales *cs); void _sliderAnyGrabbed(); void _sliderAnyReleased(); void _sliderAnyChanged(); - static void _adjustmentChanged(SPColorScales *cs, guint channel); + static void _adjustmentChanged(ColorScales *cs, guint channel); void _getRgbaFloatv(gfloat *rgba); void _getCmykaFloatv(gfloat *cmyka); @@ -76,6 +74,7 @@ protected: void _setRangeLimit( gdouble upper ); + SelectedColor &_color; SPColorScalesMode _mode; gdouble _rangeLimit; gboolean _updating : 1; @@ -92,26 +91,6 @@ private: }; - -#define SP_TYPE_COLOR_SCALES (sp_color_scales_get_type()) -#define SP_COLOR_SCALES(o) (G_TYPE_CHECK_INSTANCE_CAST((o), SP_TYPE_COLOR_SCALES, SPColorScales)) -#define SP_COLOR_SCALES_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), SP_TYPE_COLOR_SCALES, SPColorScalesClass)) -#define SP_IS_COLOR_SCALES(o) (G_TYPE_CHECK_INSTANCE_TYPE((o), SP_TYPE_COLOR_SCALES)) -#define SP_IS_COLOR_SCALES_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE((k), SP_TYPE_COLOR_SCALES)) - -struct SPColorScales { - SPColorSelector parent; -}; - -struct SPColorScalesClass { - SPColorSelectorClass parent_class; -}; - -GType sp_color_scales_get_type(); - -GtkWidget *sp_color_scales_new(); - - class ColorScalesFactory: public Inkscape::UI::ColorSelectorFactory { public: ColorScalesFactory(SPColorScalesMode submode); @@ -124,9 +103,11 @@ private: SPColorScalesMode _submode; }; +} +} +} -#endif /* !SEEN_SP_COLOR_SCALES_H */ - +#endif /* Local Variables: mode:c++ diff --git a/src/widgets/sp-color-icc-selector.cpp b/src/widgets/sp-color-icc-selector.cpp index 808dfc925..f872a3164 100644 --- a/src/widgets/sp-color-icc-selector.cpp +++ b/src/widgets/sp-color-icc-selector.cpp @@ -33,6 +33,9 @@ #endif // defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) +using namespace Inkscape::UI::Widget; + + #ifdef DEBUG_LCMS extern guint update_in_progress; #define DEBUG_MESSAGE(key, ...) \ diff --git a/src/widgets/sp-color-notebook.cpp b/src/widgets/sp-color-notebook.cpp index 0e1634314..807fe38e0 100644 --- a/src/widgets/sp-color-notebook.cpp +++ b/src/widgets/sp-color-notebook.cpp @@ -455,7 +455,9 @@ ColorNotebook::Page::Page(Inkscape::UI::ColorSelectorFactory *selector_factory, void ColorNotebook::_colorChanged() { + _updating = true; _selected_color.setColorAlpha(_color, _alpha, true); + _updating = false; SPColorSelector* cselPage = getCurrentSelector(); if ( cselPage ) @@ -613,13 +615,13 @@ void ColorNotebook::_onSelectedColorDragged() { } bool oldState = _dragging; - _dragging = TRUE; + _dragging = true; SPColor color; gfloat alpha = 1.0; _updating = true; _selected_color.colorAlpha(color, alpha); - _updateInternals(color, alpha, _dragging); + _updateInternals(color, alpha, true); _updating = false; _dragging = oldState; diff --git a/src/widgets/sp-color-notebook.h b/src/widgets/sp-color-notebook.h index 7c6dbc770..ca9343bf0 100644 --- a/src/widgets/sp-color-notebook.h +++ b/src/widgets/sp-color-notebook.h @@ -23,6 +23,7 @@ #include #include #include +#include #include "../color.h" #include "sp-color-selector.h" diff --git a/src/widgets/sp-color-selector.cpp b/src/widgets/sp-color-selector.cpp index 05af162ef..58aa0e1af 100644 --- a/src/widgets/sp-color-selector.cpp +++ b/src/widgets/sp-color-selector.cpp @@ -312,7 +312,7 @@ void ColorSelector::_updateInternals( const SPColor& color, gfloat alpha, gboole (_held ? "CHANGED" : "DRAGGED" ), color.toRGBA32( alpha ), (color.icc?color.icc->colorProfile.c_str():""), FOO_NAME(_csel)); #endif - g_signal_emit(G_OBJECT(_csel), csel_signals[_held ? CHANGED : DRAGGED], 0); + g_signal_emit(G_OBJECT(_csel), csel_signals[_held ? DRAGGED : CHANGED], 0); } } -- cgit v1.2.3 From e1e64d41e2a71a5e9a18b5a40803a72ad288cd53 Mon Sep 17 00:00:00 2001 From: Tomasz Boczkowski Date: Sat, 31 May 2014 20:22:51 +0200 Subject: SPColorICC c++sification: moved to ui/widget/ (bzr r13341.6.41) --- src/ui/CMakeLists.txt | 2 + src/ui/widget/Makefile_insert | 2 + src/ui/widget/color-icc-selector.cpp | 1150 +++++++++++++++++++++++++++++++++ src/ui/widget/color-icc-selector.h | 81 +++ src/widgets/CMakeLists.txt | 2 - src/widgets/Makefile_insert | 2 - src/widgets/sp-color-icc-selector.cpp | 1150 --------------------------------- src/widgets/sp-color-icc-selector.h | 81 --- src/widgets/sp-color-notebook.cpp | 2 +- 9 files changed, 1236 insertions(+), 1236 deletions(-) create mode 100644 src/ui/widget/color-icc-selector.cpp create mode 100644 src/ui/widget/color-icc-selector.h delete mode 100644 src/widgets/sp-color-icc-selector.cpp delete mode 100644 src/widgets/sp-color-icc-selector.h (limited to 'src') diff --git a/src/ui/CMakeLists.txt b/src/ui/CMakeLists.txt index 65e93f1b0..dbfba0508 100644 --- a/src/ui/CMakeLists.txt +++ b/src/ui/CMakeLists.txt @@ -109,6 +109,7 @@ set(ui_SRC widget/anchor-selector.cpp widget/button.cpp widget/color-entry.cpp + widget/color-icc-selector.cpp widget/color-picker.cpp widget/color-preview.cpp widget/color-scales.cpp @@ -275,6 +276,7 @@ set(ui_SRC widget/attr-widget.h widget/button.h widget/color-entry.h + widget/color-icc-selector.h widget/color-picker.h widget/color-preview.h widget/color-scales.h diff --git a/src/ui/widget/Makefile_insert b/src/ui/widget/Makefile_insert index 039e2a8d9..f39236da7 100644 --- a/src/ui/widget/Makefile_insert +++ b/src/ui/widget/Makefile_insert @@ -8,6 +8,8 @@ ink_common_sources += \ ui/widget/button.cpp \ ui/widget/color-entry.cpp \ ui/widget/color-entry.h \ + ui/widget/color-icc-selector.cpp \ + ui/widget/color-icc-selector.h \ ui/widget/color-wheel-selector.cpp \ ui/widget/color-wheel-selector.h \ ui/widget/color-picker.cpp \ diff --git a/src/ui/widget/color-icc-selector.cpp b/src/ui/widget/color-icc-selector.cpp new file mode 100644 index 000000000..74e63f320 --- /dev/null +++ b/src/ui/widget/color-icc-selector.cpp @@ -0,0 +1,1150 @@ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include "widgets/gradient-vector.h" +#include +#include +#include +#include +#include +#include + +#include "dialogs/dialog-events.h" +#include "ui/widget/color-icc-selector.h" +#include "ui/widget/color-scales.h" +#include "ui/widget/color-slider.h" +#include "svg/svg-icc-color.h" +#include "colorspace.h" +#include "document.h" +#include "inkscape.h" +#include "profile-manager.h" + +#define noDEBUG_LCMS + +#if defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) +#include "color-profile.h" +#include "cms-system.h" +#include "color-profile-cms-fns.h" + +#ifdef DEBUG_LCMS +#include "preferences.h" +#endif // DEBUG_LCMS +#endif // defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) + + +using namespace Inkscape::UI::Widget; + + +#ifdef DEBUG_LCMS +extern guint update_in_progress; +#define DEBUG_MESSAGE(key, ...) \ +{\ + Inkscape::Preferences *prefs = Inkscape::Preferences::get();\ + bool dump = prefs->getBool("/options/scislac/" #key);\ + bool dumpD = prefs->getBool("/options/scislac/" #key "D");\ + bool dumpD2 = prefs->getBool("/options/scislac/" #key "D2");\ + dumpD &&= ( (update_in_progress == 0) || dumpD2 );\ + if ( dump )\ + {\ + g_message( __VA_ARGS__ );\ +\ + }\ + if ( dumpD )\ + {\ + GtkWidget *dialog = gtk_message_dialog_new(NULL,\ + GTK_DIALOG_DESTROY_WITH_PARENT, \ + GTK_MESSAGE_INFO, \ + GTK_BUTTONS_OK, \ + __VA_ARGS__ \ + );\ + g_signal_connect_swapped(dialog, "response",\ + G_CALLBACK(gtk_widget_destroy), \ + dialog); \ + gtk_widget_show_all( dialog );\ + }\ +} +#endif // DEBUG_LCMS + + + +G_BEGIN_DECLS + +static void sp_color_icc_selector_class_init (SPColorICCSelectorClass *klass); +static void sp_color_icc_selector_init (SPColorICCSelector *cs); +static void sp_color_icc_selector_dispose(GObject *object); + +static void sp_color_icc_selector_show_all (GtkWidget *widget); +static void sp_color_icc_selector_hide(GtkWidget *widget); + +G_END_DECLS + +/** + * Class containing the parts for a single color component's UI presence. + */ +class ComponentUI +{ +public: + ComponentUI() : + _component(), + _adj(0), + _slider(0), + _btn(0), + _label(0), + _map(0) + { + } + + ComponentUI(colorspace::Component const &component) : + _component(component), + _adj(0), + _slider(0), + _btn(0), + _label(0), + _map(0) + { + } + + colorspace::Component _component; + GtkAdjustment *_adj; // Component adjustment + Inkscape::UI::Widget::ColorSlider *_slider; + GtkWidget *_btn; // spinbutton + GtkWidget *_label; // Label + guchar *_map; +}; + +/** + * Class that implements the internals of the selector. + */ +class ColorICCSelectorImpl +{ +public: + + ColorICCSelectorImpl( ColorICCSelector *owner); + + ~ColorICCSelectorImpl(); + + static void _adjustmentChanged ( GtkAdjustment *adjustment, SPColorICCSelector *cs ); + + void _sliderGrabbed(); + void _sliderReleased(); + void _sliderChanged(); + + static void _profileSelected( GtkWidget* src, gpointer data ); + static void _fixupHit( GtkWidget* src, gpointer data ); + +#if defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) + void _setProfile( SVGICCColor* profile ); + void _switchToProfile( gchar const* name ); +#endif + void _updateSliders( gint ignore ); + void _profilesChanged( std::string const & name ); + + ColorICCSelector *_owner; + + gboolean _updating : 1; + gboolean _dragging : 1; + + guint32 _fixupNeeded; + GtkWidget* _fixupBtn; + GtkWidget* _profileSel; + + std::vector _compUI; + + GtkAdjustment* _adj; // Channel adjustment + Inkscape::UI::Widget::ColorSlider* _slider; + GtkWidget* _sbtn; // Spinbutton + GtkWidget* _label; // Label + +#if defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) + std::string _profileName; + Inkscape::ColorProfile* _prof; + guint _profChannelCount; + gulong _profChangedID; +#endif // defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) +}; + + +static SPColorSelectorClass *parent_class; + +#define XPAD 4 +#define YPAD 1 + +namespace +{ + +size_t maxColorspaceComponentCount = 0; + +#if defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) + +/** + * Internal variable to track all known colorspaces. + */ +std::set knownColorspaces; + +#endif + + +/** + * Simple helper to allow bitwise or on GtkAttachOptions. + */ +GtkAttachOptions operator|(GtkAttachOptions lhs, GtkAttachOptions rhs) +{ + return static_cast(static_cast(lhs) | static_cast(rhs)); +} + +/** + * Helper function to handle GTK2/GTK3 attachment #ifdef code. + */ +void attachToGridOrTable(GtkWidget *parent, + GtkWidget *child, + guint left, + guint top, + guint width, + guint height, + bool hexpand = false, + bool centered = false, + guint xpadding = XPAD, + guint ypadding = YPAD) +{ +#if GTK_CHECK_VERSION(3,0,0) + gtk_widget_set_margin_left( child, xpadding ); + gtk_widget_set_margin_right( child, xpadding ); + gtk_widget_set_margin_top( child, ypadding ); + gtk_widget_set_margin_bottom( child, ypadding ); + if (hexpand) { + gtk_widget_set_hexpand(child, TRUE); + } + if (centered) { + gtk_widget_set_halign( child, GTK_ALIGN_CENTER ); + gtk_widget_set_valign( child, GTK_ALIGN_CENTER ); + } + gtk_grid_attach( GTK_GRID(parent), child, left, top, width, height ); +#else + GtkAttachOptions xoptions = centered ? static_cast(0) : hexpand ? (GTK_EXPAND | GTK_FILL) : GTK_FILL; + GtkAttachOptions yoptions = centered ? static_cast(0) : GTK_FILL; + + gtk_table_attach( GTK_TABLE(parent), child, left, left + width, top, top + height, xoptions, yoptions, xpadding, ypadding ); +#endif +} + +} // namespace + +GType sp_color_icc_selector_get_type(void) +{ + static GType type = 0; + if (!type) { + static const GTypeInfo info = { + sizeof (SPColorICCSelectorClass), + NULL, // base_init + NULL, // base_finalize + (GClassInitFunc) sp_color_icc_selector_class_init, + NULL, // class_finalize + NULL, // class_data + sizeof (SPColorICCSelector), + 0, // n_preallocs + (GInstanceInitFunc) sp_color_icc_selector_init, + 0, // value_table + }; + + type = g_type_register_static (SP_TYPE_COLOR_SELECTOR, + "SPColorICCSelector", + &info, + static_cast< GTypeFlags > (0) ); + } + return type; +} + +static void sp_color_icc_selector_class_init(SPColorICCSelectorClass *klass) +{ + static const gchar* nameset[] = {N_("CMS"), 0}; + GObjectClass *object_class = G_OBJECT_CLASS(klass); + GtkWidgetClass *widget_class = GTK_WIDGET_CLASS(klass); + SPColorSelectorClass *selector_class = SP_COLOR_SELECTOR_CLASS (klass); + + parent_class = SP_COLOR_SELECTOR_CLASS (g_type_class_peek_parent (klass)); + + selector_class->name = nameset; + selector_class->submode_count = 1; + + object_class->dispose = sp_color_icc_selector_dispose; + + widget_class->show_all = sp_color_icc_selector_show_all; + widget_class->hide = sp_color_icc_selector_hide; +} + +const gchar* ColorICCSelector::MODE_NAME = N_("CMS"); + +ColorICCSelector::ColorICCSelector( SPColorSelector* csel ) + : ColorSelector( csel ), + _impl(NULL) +{ +} + +ColorICCSelector::~ColorICCSelector() +{ + if (_impl) + { + delete _impl; + _impl = 0; + } +} + +void sp_color_icc_selector_init(SPColorICCSelector *cs) +{ + SP_COLOR_SELECTOR(cs)->base = new ColorICCSelector( SP_COLOR_SELECTOR(cs) ); + + if ( SP_COLOR_SELECTOR(cs)->base ) + { + SP_COLOR_SELECTOR(cs)->base->init(); + } +} + + +/* +icSigRgbData +icSigCmykData +icSigCmyData +*/ +#define SPACE_ID_RGB 0 +#define SPACE_ID_CMY 1 +#define SPACE_ID_CMYK 2 + + +#if defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) +static cmsUInt16Number* getScratch() { + // bytes per pixel * input channels * width + static cmsUInt16Number* scritch = static_cast(g_new(cmsUInt16Number, 4 * 1024)); + + return scritch; +} + +colorspace::Component::Component() : + name(), + tip(), + scale(1) +{ +} + +colorspace::Component::Component(std::string const &name, std::string const &tip, guint scale) : + name(name), + tip(tip), + scale(scale) +{ +} + +std::vector colorspace::getColorSpaceInfo( uint32_t space ) +{ + static std::map > sets; + if (sets.empty()) + { + sets[cmsSigXYZData].push_back(Component("_X", "X", 2)); // TYPE_XYZ_16 + sets[cmsSigXYZData].push_back(Component("_Y", "Y", 1)); + sets[cmsSigXYZData].push_back(Component("_Z", "Z", 2)); + + sets[cmsSigLabData].push_back(Component("_L", "L", 100)); // TYPE_Lab_16 + sets[cmsSigLabData].push_back(Component("_a", "a", 256)); + sets[cmsSigLabData].push_back(Component("_b", "b", 256)); + + //cmsSigLuvData + + sets[cmsSigYCbCrData].push_back(Component("_Y", "Y", 1)); // TYPE_YCbCr_16 + sets[cmsSigYCbCrData].push_back(Component("C_b", "Cb", 1)); + sets[cmsSigYCbCrData].push_back(Component("C_r", "Cr", 1)); + + sets[cmsSigYxyData].push_back(Component("_Y", "Y", 1)); // TYPE_Yxy_16 + sets[cmsSigYxyData].push_back(Component("_x", "x", 1)); + sets[cmsSigYxyData].push_back(Component("y", "y", 1)); + + sets[cmsSigRgbData].push_back(Component(_("_R:"), _("Red"), 1)); // TYPE_RGB_16 + sets[cmsSigRgbData].push_back(Component(_("_G:"), _("Green"), 1)); + sets[cmsSigRgbData].push_back(Component(_("_B:"), _("Blue"), 1)); + + sets[cmsSigGrayData].push_back(Component(_("G:"), _("Gray"), 1)); // TYPE_GRAY_16 + + sets[cmsSigHsvData].push_back(Component(_("_H:"), _("Hue"), 360)); // TYPE_HSV_16 + sets[cmsSigHsvData].push_back(Component(_("_S:"), _("Saturation"), 1)); + sets[cmsSigHsvData].push_back(Component("_V:", "Value", 1)); + + sets[cmsSigHlsData].push_back(Component(_("_H:"), _("Hue"), 360)); // TYPE_HLS_16 + sets[cmsSigHlsData].push_back(Component(_("_L:"), _("Lightness"), 1)); + sets[cmsSigHlsData].push_back(Component(_("_S:"), _("Saturation"), 1)); + + sets[cmsSigCmykData].push_back(Component(_("_C:"), _("Cyan"), 1)); // TYPE_CMYK_16 + sets[cmsSigCmykData].push_back(Component(_("_M:"), _("Magenta"), 1)); + sets[cmsSigCmykData].push_back(Component(_("_Y:"), _("Yellow"), 1)); + sets[cmsSigCmykData].push_back(Component(_("_K:"), _("Black"), 1)); + + sets[cmsSigCmyData].push_back(Component(_("_C:"), _("Cyan"), 1)); // TYPE_CMY_16 + sets[cmsSigCmyData].push_back(Component(_("_M:"), _("Magenta"), 1)); + sets[cmsSigCmyData].push_back(Component(_("_Y:"), _("Yellow"), 1)); + + for (std::map >::iterator it = sets.begin(); it != sets.end(); ++it) + { + knownColorspaces.insert(it->first); + maxColorspaceComponentCount = std::max(maxColorspaceComponentCount, it->second.size()); + } + } + + std::vector target; + + if (sets.find(space) != sets.end()) + { + target = sets[space]; + } + return target; +} + + +std::vector colorspace::getColorSpaceInfo( Inkscape::ColorProfile *prof ) +{ + return getColorSpaceInfo( asICColorSpaceSig(prof->getColorSpace()) ); +} + +#endif // defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) + +ColorICCSelectorImpl::ColorICCSelectorImpl(ColorICCSelector *owner) : + _owner(owner), + _updating( FALSE ), + _dragging( FALSE ), + _fixupNeeded(0), + _fixupBtn(0), + _profileSel(0), + _compUI(), + _adj(0), + _slider(0), + _sbtn(0), + _label(0) +#if defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) + , + _profileName(), + _prof(0), + _profChannelCount(0), + _profChangedID(0) +#endif // defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) +{ +} + +ColorICCSelectorImpl::~ColorICCSelectorImpl() +{ + _adj = 0; + _sbtn = 0; + _label = 0; +} + +void ColorICCSelector::init() +{ + if (_impl) delete(_impl); + _impl = new ColorICCSelectorImpl(this); + gint row = 0; + + _impl->_updating = FALSE; + _impl->_dragging = FALSE; + +#if GTK_CHECK_VERSION(3,0,0) + GtkWidget *t = gtk_grid_new(); +#else + GtkWidget *t = gtk_table_new(5, 3, FALSE); +#endif + + gtk_widget_show (t); + gtk_box_pack_start (GTK_BOX (_csel), t, TRUE, TRUE, 4); + + _impl->_compUI.clear(); + + // Create components + row = 0; + + + _impl->_fixupBtn = gtk_button_new_with_label(_("Fix")); + g_signal_connect( G_OBJECT(_impl->_fixupBtn), "clicked", G_CALLBACK(ColorICCSelectorImpl::_fixupHit), (gpointer)_impl ); + gtk_widget_set_sensitive( _impl->_fixupBtn, FALSE ); + gtk_widget_set_tooltip_text( _impl->_fixupBtn, _("Fix RGB fallback to match icc-color() value.") ); + //gtk_misc_set_alignment( GTK_MISC (_impl->_fixupBtn), 1.0, 0.5 ); + gtk_widget_show( _impl->_fixupBtn ); + + attachToGridOrTable(t, _impl->_fixupBtn, 0, row, 1, 1); + + // Combobox and store with 2 columns : label (0) and full name (1) + GtkListStore *store = gtk_list_store_new (2, G_TYPE_STRING, G_TYPE_STRING); + _impl->_profileSel = gtk_combo_box_new_with_model (GTK_TREE_MODEL (store)); + + GtkCellRenderer *renderer = gtk_cell_renderer_text_new (); + gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(_impl->_profileSel), renderer, TRUE); + gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(_impl->_profileSel), renderer, "text", 0, NULL); + + GtkTreeIter iter; + gtk_list_store_append (store, &iter); + gtk_list_store_set (store, &iter, 0, _(""), 1, _(""), -1); + + gtk_widget_show( _impl->_profileSel ); + gtk_combo_box_set_active( GTK_COMBO_BOX(_impl->_profileSel), 0 ); + + attachToGridOrTable(t, _impl->_profileSel, 1, row, 1, 1); + +#if defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) + _impl->_profChangedID = g_signal_connect( G_OBJECT(_impl->_profileSel), "changed", G_CALLBACK(ColorICCSelectorImpl::_profileSelected), (gpointer)_impl ); +#else + gtk_widget_set_sensitive( _impl->_profileSel, false ); +#endif // defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) + + + row++; + + // populate the data for colorspaces and channels: +#if defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) + std::vector things = colorspace::getColorSpaceInfo( cmsSigRgbData ); +#endif // defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) + + for ( size_t i = 0; i < maxColorspaceComponentCount; i++ ) { +#if defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) + if (i < things.size()) { + _impl->_compUI.push_back(ComponentUI(things[i])); + } else { + _impl->_compUI.push_back(ComponentUI()); + } + + std::string labelStr = (i < things.size()) ? things[i].name.c_str() : ""; +#else + _impl->_compUI.push_back(ComponentUI()); + + std::string labelStr = "."; +#endif + + _impl->_compUI[i]._label = gtk_label_new_with_mnemonic( labelStr.c_str() ); + gtk_misc_set_alignment( GTK_MISC (_impl->_compUI[i]._label), 1.0, 0.5 ); + gtk_widget_show( _impl->_compUI[i]._label ); + + attachToGridOrTable(t, _impl->_compUI[i]._label, 0, row, 1, 1); + + // Adjustment + guint scaleValue = _impl->_compUI[i]._component.scale; + gdouble step = static_cast(scaleValue) / 100.0; + gdouble page = static_cast(scaleValue) / 10.0; + gint digits = (step > 0.9) ? 0 : 2; + _impl->_compUI[i]._adj = GTK_ADJUSTMENT( gtk_adjustment_new( 0.0, 0.0, scaleValue, step, page, page ) ); + + // Slider + _impl->_compUI[i]._slider = Gtk::manage(new Inkscape::UI::Widget::ColorSlider(Glib::wrap(_impl->_compUI[i]._adj, true))); +#if defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) + _impl->_compUI[i]._slider->set_tooltip_text((i < things.size()) ? things[i].tip.c_str() : ""); +#else + _impl->_compUI[i]._slider->set_tooltip_text("."); +#endif // defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) + _impl->_compUI[i]._slider->show(); + + attachToGridOrTable(t, _impl->_compUI[i]._slider->gobj(), 1, row, 1, 1, true); + + _impl->_compUI[i]._btn = gtk_spin_button_new( _impl->_compUI[i]._adj, step, digits ); +#if defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) + gtk_widget_set_tooltip_text( _impl->_compUI[i]._btn, (i < things.size()) ? things[i].tip.c_str() : "" ); +#else + gtk_widget_set_tooltip_text( _impl->_compUI[i]._btn, "." ); +#endif // defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) + sp_dialog_defocus_on_enter( _impl->_compUI[i]._btn ); + gtk_label_set_mnemonic_widget( GTK_LABEL(_impl->_compUI[i]._label), _impl->_compUI[i]._btn ); + gtk_widget_show( _impl->_compUI[i]._btn ); + + attachToGridOrTable(t, _impl->_compUI[i]._btn, 2, row, 1, 1, false, true); + + _impl->_compUI[i]._map = g_new( guchar, 4 * 1024 ); + memset( _impl->_compUI[i]._map, 0x0ff, 1024 * 4 ); + + + // Signals + g_signal_connect( G_OBJECT( _impl->_compUI[i]._adj ), "value_changed", G_CALLBACK( ColorICCSelectorImpl::_adjustmentChanged ), _csel ); + + _impl->_compUI[i]._slider->signal_grabbed.connect(sigc::mem_fun(_impl, &ColorICCSelectorImpl::_sliderGrabbed)); + _impl->_compUI[i]._slider->signal_released.connect(sigc::mem_fun(_impl, &ColorICCSelectorImpl::_sliderReleased)); + _impl->_compUI[i]._slider->signal_value_changed.connect(sigc::mem_fun(_impl, &ColorICCSelectorImpl::_sliderChanged)); + + row++; + } + + // Label + _impl->_label = gtk_label_new_with_mnemonic(_("_A:")); + gtk_misc_set_alignment(GTK_MISC(_impl->_label), 1.0, 0.5); + gtk_widget_show(_impl->_label); + + attachToGridOrTable(t, _impl->_label, 0, row, 1, 1); + + // Adjustment + _impl->_adj = GTK_ADJUSTMENT(gtk_adjustment_new(0.0, 0.0, 255.0, 1.0, 10.0, 10.0)); + + // Slider + _impl->_slider = Gtk::manage(new Inkscape::UI::Widget::ColorSlider(Glib::wrap(_impl->_adj, true))); + _impl->_slider->set_tooltip_text(_("Alpha (opacity)")); + _impl->_slider->show(); + + attachToGridOrTable(t, _impl->_slider->gobj(), 1, row, 1, 1, true); + + _impl->_slider->setColors(SP_RGBA32_F_COMPOSE( 1.0, 1.0, 1.0, 0.0 ), + SP_RGBA32_F_COMPOSE( 1.0, 1.0, 1.0, 0.5 ), + SP_RGBA32_F_COMPOSE( 1.0, 1.0, 1.0, 1.0 ) ); + + + // Spinbutton + _impl->_sbtn = gtk_spin_button_new(GTK_ADJUSTMENT(_impl->_adj), 1.0, 0); + gtk_widget_set_tooltip_text(_impl->_sbtn, _("Alpha (opacity)")); + sp_dialog_defocus_on_enter(_impl->_sbtn); + gtk_label_set_mnemonic_widget(GTK_LABEL(_impl->_label), _impl->_sbtn); + gtk_widget_show(_impl->_sbtn); + + attachToGridOrTable(t, _impl->_sbtn, 2, row, 1, 1, false, true); + + // Signals + g_signal_connect(G_OBJECT(_impl->_adj), "value_changed", G_CALLBACK(ColorICCSelectorImpl::_adjustmentChanged), _csel); + + _impl->_slider->signal_grabbed.connect(sigc::mem_fun(_impl, &ColorICCSelectorImpl::_sliderGrabbed)); + _impl->_slider->signal_released.connect(sigc::mem_fun(_impl, &ColorICCSelectorImpl::_sliderReleased)); + _impl->_slider->signal_value_changed.connect(sigc::mem_fun(_impl, &ColorICCSelectorImpl::_sliderChanged)); +} + +static void sp_color_icc_selector_dispose(GObject *object) +{ + if ((G_OBJECT_CLASS(parent_class))->dispose) { + (* (G_OBJECT_CLASS(parent_class))->dispose)(object); + } +} + +static void +sp_color_icc_selector_show_all (GtkWidget *widget) +{ + gtk_widget_show (widget); +} + +static void sp_color_icc_selector_hide(GtkWidget *widget) +{ + gtk_widget_hide(widget); +} + +GtkWidget * +sp_color_icc_selector_new (void) +{ + SPColorICCSelector *csel; + + csel = static_cast(g_object_new (SP_TYPE_COLOR_ICC_SELECTOR, NULL)); + + return GTK_WIDGET (csel); +} + + +void ColorICCSelectorImpl::_fixupHit( GtkWidget* /*src*/, gpointer data ) +{ + ColorICCSelectorImpl* self = reinterpret_cast(data); + gtk_widget_set_sensitive( self->_fixupBtn, FALSE ); + self->_adjustmentChanged( self->_compUI[0]._adj, SP_COLOR_ICC_SELECTOR(self->_owner->_csel) ); +} + +#if defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) +void ColorICCSelectorImpl::_profileSelected( GtkWidget* /*src*/, gpointer data ) +{ + ColorICCSelectorImpl* self = reinterpret_cast(data); + + GtkTreeIter iter; + if (gtk_combo_box_get_active_iter(GTK_COMBO_BOX(self->_profileSel), &iter)) { + GtkTreeModel *store = gtk_combo_box_get_model(GTK_COMBO_BOX(self->_profileSel)); + gchar* name = 0; + + gtk_tree_model_get(store, &iter, 1, &name, -1); + self->_switchToProfile( name ); + gtk_widget_set_tooltip_text(self->_profileSel, name ); + + if ( name ) { + g_free( name ); + } + } +} +#endif // defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) + +#if defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) +void ColorICCSelectorImpl::_switchToProfile( gchar const* name ) +{ + bool dirty = false; + SPColor tmp( _owner->_color ); + + if ( name ) { + if ( tmp.icc && tmp.icc->colorProfile == name ) { +#ifdef DEBUG_LCMS + g_message("Already at name [%s]", name ); +#endif // DEBUG_LCMS + } else { +#ifdef DEBUG_LCMS + g_message("Need to switch to profile [%s]", name ); +#endif // DEBUG_LCMS + if ( tmp.icc ) { + tmp.icc->colors.clear(); + } else { + tmp.icc = new SVGICCColor(); + } + tmp.icc->colorProfile = name; + Inkscape::ColorProfile* newProf = SP_ACTIVE_DOCUMENT->profileManager->find(name); + if ( newProf ) { + cmsHTRANSFORM trans = newProf->getTransfFromSRGB8(); + if ( trans ) { + guint32 val = _owner->_color.toRGBA32(0); + guchar pre[4] = { + static_cast(SP_RGBA32_R_U(val)), + static_cast(SP_RGBA32_G_U(val)), + static_cast(SP_RGBA32_B_U(val)), + 255}; +#ifdef DEBUG_LCMS + g_message("Shoving in [%02x] [%02x] [%02x]", pre[0], pre[1], pre[2]); +#endif // DEBUG_LCMS + cmsUInt16Number post[4] = {0,0,0,0}; + cmsDoTransform( trans, pre, post, 1 ); +#ifdef DEBUG_LCMS + g_message("got on out [%04x] [%04x] [%04x] [%04x]", post[0], post[1], post[2], post[3]); +#endif // DEBUG_LCMS +#if HAVE_LIBLCMS1 + guint count = _cmsChannelsOf( asICColorSpaceSig(newProf->getColorSpace()) ); +#elif HAVE_LIBLCMS2 + guint count = cmsChannelsOf( asICColorSpaceSig(newProf->getColorSpace()) ); +#endif + + std::vector things = colorspace::getColorSpaceInfo(asICColorSpaceSig(newProf->getColorSpace())); + + for ( guint i = 0; i < count; i++ ) { + gdouble val = (((gdouble)post[i])/65535.0) * (gdouble)((i < things.size()) ? things[i].scale : 1); +#ifdef DEBUG_LCMS + g_message(" scaled %d by %d to be %f", i, ((i < things.size()) ? things[i].scale : 1), val); +#endif // DEBUG_LCMS + tmp.icc->colors.push_back(val); + } + cmsHTRANSFORM retrans = newProf->getTransfToSRGB8(); + if ( retrans ) { + cmsDoTransform( retrans, post, pre, 1 ); +#ifdef DEBUG_LCMS + g_message(" back out [%02x] [%02x] [%02x]", pre[0], pre[1], pre[2]); +#endif // DEBUG_LCMS + tmp.set(SP_RGBA32_U_COMPOSE(pre[0], pre[1], pre[2], 0xff)); + } + } + } + dirty = true; + } + } else { +#ifdef DEBUG_LCMS + g_message("NUKE THE ICC"); +#endif // DEBUG_LCMS + if ( tmp.icc ) { + delete tmp.icc; + tmp.icc = 0; + dirty = true; + _fixupHit( 0, this ); + } else { +#ifdef DEBUG_LCMS + g_message("No icc to nuke"); +#endif // DEBUG_LCMS + } + } + + if ( dirty ) { +#ifdef DEBUG_LCMS + g_message("+----------------"); + g_message("+ new color is [%s]", tmp.toString().c_str()); +#endif // DEBUG_LCMS + _setProfile( tmp.icc ); + //_adjustmentChanged( _compUI[0]._adj, SP_COLOR_ICC_SELECTOR(_csel) ); + _owner->setColorAlpha( tmp, _owner->_alpha, true ); +#ifdef DEBUG_LCMS + g_message("+_________________"); +#endif // DEBUG_LCMS + } +} +#endif // defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) + +#if defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) +void ColorICCSelectorImpl::_profilesChanged( std::string const & name ) +{ + GtkComboBox* combo = GTK_COMBO_BOX(_profileSel); + + g_signal_handler_block( G_OBJECT(_profileSel), _profChangedID ); + + GtkListStore *store = GTK_LIST_STORE(gtk_combo_box_get_model(combo)); + gtk_list_store_clear(store); + + GtkTreeIter iter; + gtk_list_store_append (store, &iter); + gtk_list_store_set(store, &iter, 0, _(""), 1, _(""), -1); + + gtk_combo_box_set_active( combo, 0 ); + + int index = 1; + const GSList *current = SP_ACTIVE_DOCUMENT->getResourceList( "iccprofile" ); + while ( current ) { + SPObject* obj = SP_OBJECT(current->data); + Inkscape::ColorProfile* prof = reinterpret_cast(obj); + + gtk_list_store_append (store, &iter); + gtk_list_store_set(store, &iter, 0, gr_ellipsize_text(prof->name, 25).c_str(), 1, prof->name, -1); + + if ( name == prof->name ) { + gtk_combo_box_set_active( combo, index ); + gtk_widget_set_tooltip_text(_profileSel, prof->name ); + } + + index++; + current = g_slist_next(current); + } + + g_signal_handler_unblock( G_OBJECT(_profileSel), _profChangedID ); +} +#else +void ColorICCSelectorImpl::_profilesChanged( std::string const & /*name*/ ) +{ +} +#endif // defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) + +// Helpers for setting color value + +void ColorICCSelector::_colorChanged() +{ + _impl->_updating = TRUE; + //sp_color_icc_set_color( SP_COLOR_ICC( _icc ), &color ); + +#ifdef DEBUG_LCMS + g_message( "/^^^^^^^^^ %p::_colorChanged(%08x:%s)", this, + _color.toRGBA32(_alpha), ( (_color.icc) ? _color.icc->colorProfile.c_str(): "" ) + ); +#endif // DEBUG_LCMS + +#ifdef DEBUG_LCMS + g_message("FLIPPIES!!!! %p '%s'", _color.icc, (_color.icc ? _color.icc->colorProfile.c_str():"")); +#endif // DEBUG_LCMS + + _impl->_profilesChanged( (_color.icc) ? _color.icc->colorProfile : std::string("") ); + ColorScales::setScaled( _impl->_adj, _alpha ); + +#if defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) + _impl->_setProfile( _color.icc ); + _impl->_fixupNeeded = 0; + gtk_widget_set_sensitive( _impl->_fixupBtn, FALSE ); + + if (_impl->_prof) { + if (_impl->_prof->getTransfToSRGB8() ) { + cmsUInt16Number tmp[4]; + for ( guint i = 0; i < _impl->_profChannelCount; i++ ) { + gdouble val = 0.0; + if ( _color.icc->colors.size() > i ) { + if ( _impl->_compUI[i]._component.scale == 256 ) { + val = (_color.icc->colors[i] + 128.0) / static_cast(_impl->_compUI[i]._component.scale); + } else { + val = _color.icc->colors[i] / static_cast(_impl->_compUI[i]._component.scale); + } + } + tmp[i] = val * 0x0ffff; + } + guchar post[4] = {0,0,0,0}; + cmsHTRANSFORM trans = _impl->_prof->getTransfToSRGB8(); + if ( trans ) { + cmsDoTransform( trans, tmp, post, 1 ); + guint32 other = SP_RGBA32_U_COMPOSE(post[0], post[1], post[2], 255 ); + if ( other != _color.toRGBA32(255) ) { + _impl->_fixupNeeded = other; + gtk_widget_set_sensitive( _impl->_fixupBtn, TRUE ); +#ifdef DEBUG_LCMS + g_message("Color needs to change 0x%06x to 0x%06x", _color.toRGBA32(255) >> 8, other >> 8 ); +#endif // DEBUG_LCMS + } + } + } + } +#else + //(void)color; +#endif // defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) + _impl->_updateSliders( -1 ); + + + _impl->_updating = FALSE; +#ifdef DEBUG_LCMS + g_message( "\\_________ %p::_colorChanged()", this ); +#endif // DEBUG_LCMS +} + +#if defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) +void ColorICCSelectorImpl::_setProfile( SVGICCColor* profile ) +{ +#ifdef DEBUG_LCMS + g_message( "/^^^^^^^^^ %p::_setProfile(%s)", this, + ( (profile) ? profile->colorProfile.c_str() : "") + ); +#endif // DEBUG_LCMS + bool profChanged = false; + if ( _prof && (!profile || (_profileName != profile->colorProfile) ) ) { + // Need to clear out the prior one + profChanged = true; + _profileName.clear(); + _prof = 0; + _profChannelCount = 0; + } else if ( profile && !_prof ) { + profChanged = true; + } + + for ( size_t i = 0; i < _compUI.size(); i++ ) { + gtk_widget_hide( _compUI[i]._label ); + _compUI[i]._slider->hide(); + gtk_widget_hide( _compUI[i]._btn ); + } + + if ( profile ) { + _prof = SP_ACTIVE_DOCUMENT->profileManager->find(profile->colorProfile.c_str()); + if ( _prof && (asICColorProfileClassSig(_prof->getProfileClass()) != cmsSigNamedColorClass) ) { +#if HAVE_LIBLCMS1 + _profChannelCount = _cmsChannelsOf( asICColorSpaceSig(_prof->getColorSpace()) ); +#elif HAVE_LIBLCMS2 + _profChannelCount = cmsChannelsOf( asICColorSpaceSig(_prof->getColorSpace()) ); +#endif + + if ( profChanged ) { + std::vector things = colorspace::getColorSpaceInfo(asICColorSpaceSig(_prof->getColorSpace())); + for (size_t i = 0; (i < things.size()) && (i < _profChannelCount); ++i) + { + _compUI[i]._component = things[i]; + } + + for ( guint i = 0; i < _profChannelCount; i++ ) { + gtk_label_set_text_with_mnemonic( GTK_LABEL(_compUI[i]._label), (i < things.size()) ? things[i].name.c_str() : ""); + + _compUI[i]._slider->set_tooltip_text((i < things.size()) ? things[i].tip.c_str() : ""); + gtk_widget_set_tooltip_text( _compUI[i]._btn, (i < things.size()) ? things[i].tip.c_str() : "" ); + + _compUI[i]._slider->setColors(SPColor(0.0, 0.0, 0.0).toRGBA32(0xff), + SPColor(0.5, 0.5, 0.5).toRGBA32(0xff), + SPColor(1.0, 1.0, 1.0).toRGBA32(0xff) ); +/* + _compUI[i]._adj = GTK_ADJUSTMENT( gtk_adjustment_new( val, 0.0, _fooScales[i], step, page, page ) ); + g_signal_connect( G_OBJECT( _compUI[i]._adj ), "value_changed", G_CALLBACK( _adjustmentChanged ), _csel ); + + sp_color_slider_set_adjustment( SP_COLOR_SLIDER(_compUI[i]._slider), _compUI[i]._adj ); + gtk_spin_button_set_adjustment( GTK_SPIN_BUTTON(_compUI[i]._btn), _compUI[i]._adj ); + gtk_spin_button_set_digits( GTK_SPIN_BUTTON(_compUI[i]._btn), digits ); +*/ + gtk_widget_show( _compUI[i]._label ); + _compUI[i]._slider->show(); + gtk_widget_show( _compUI[i]._btn ); + //gtk_adjustment_set_value( _compUI[i]._adj, 0.0 ); + //gtk_adjustment_set_value( _compUI[i]._adj, val ); + } + for ( size_t i = _profChannelCount; i < _compUI.size(); i++ ) { + gtk_widget_hide( _compUI[i]._label ); + _compUI[i]._slider->hide(); + gtk_widget_hide( _compUI[i]._btn ); + } + } + } else { + // Give up for now on named colors + _prof = 0; + } + } + +#ifdef DEBUG_LCMS + g_message( "\\_________ %p::_setProfile()", this ); +#endif // DEBUG_LCMS +} +#endif // defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) + +void ColorICCSelectorImpl::_updateSliders( gint ignore ) +{ +#if defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) + if ( _owner->_color.icc ) + { + for ( guint i = 0; i < _profChannelCount; i++ ) { + gdouble val = 0.0; + if ( _owner->_color.icc->colors.size() > i ) { + if ( _compUI[i]._component.scale == 256 ) { + val = (_owner->_color.icc->colors[i] + 128.0) / static_cast(_compUI[i]._component.scale); + } else { + val = _owner->_color.icc->colors[i] / static_cast(_compUI[i]._component.scale); + } + } + gtk_adjustment_set_value( _compUI[i]._adj, val ); + } + + if ( _prof ) { + if ( _prof->getTransfToSRGB8() ) { + for ( guint i = 0; i < _profChannelCount; i++ ) { + if ( static_cast(i) != ignore ) { + cmsUInt16Number* scratch = getScratch(); + cmsUInt16Number filler[4] = {0, 0, 0, 0}; + for ( guint j = 0; j < _profChannelCount; j++ ) { + filler[j] = 0x0ffff * ColorScales::getScaled( _compUI[j]._adj ); + } + + cmsUInt16Number* p = scratch; + for ( guint x = 0; x < 1024; x++ ) { + for ( guint j = 0; j < _profChannelCount; j++ ) { + if ( j == i ) { + *p++ = x * 0x0ffff / 1024; + } else { + *p++ = filler[j]; + } + } + } + + cmsHTRANSFORM trans = _prof->getTransfToSRGB8(); + if ( trans ) { + cmsDoTransform( trans, scratch, _compUI[i]._map, 1024 ); + _compUI[i]._slider->setMap(_compUI[i]._map); + } + } + } + } + } + } +#else + (void)ignore; +#endif // defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) + + guint32 start = _owner->_color.toRGBA32( 0x00 ); + guint32 mid = _owner->_color.toRGBA32( 0x7f ); + guint32 end = _owner->_color.toRGBA32( 0xff ); + + _slider->setColors(start, mid, end); +} + + +void ColorICCSelectorImpl::_adjustmentChanged( GtkAdjustment *adjustment, SPColorICCSelector *cs ) +{ +// // TODO check this. It looks questionable: +// // if a value is entered between 0 and 1 exclusive, normalize it to (int) 0..255 or 0..100 +// if (adjustment->value > 0.0 && adjustment->value < 1.0) { +// gtk_adjustment_set_value( adjustment, floor ((adjustment->value) * adjustment->upper + 0.5) ); +// } + +#ifdef DEBUG_LCMS + g_message( "/^^^^^^^^^ %p::_adjustmentChanged()", cs ); +#endif // DEBUG_LCMS + + ColorICCSelector* iccSelector = static_cast(SP_COLOR_SELECTOR(cs)->base); + if (iccSelector->_impl->_updating) { + return; + } + + iccSelector->_impl->_updating = TRUE; + + gint match = -1; + + SPColor newColor( iccSelector->_color ); + gfloat scaled = ColorScales::getScaled( iccSelector->_impl->_adj ); + if ( iccSelector->_impl->_adj == adjustment ) { +#ifdef DEBUG_LCMS + g_message("ALPHA"); +#endif // DEBUG_LCMS + } else { +#if defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) + for ( size_t i = 0; i < iccSelector->_impl->_compUI.size(); i++ ) { + if ( iccSelector->_impl->_compUI[i]._adj == adjustment ) { + match = i; + break; + } + } + if ( match >= 0 ) { +#ifdef DEBUG_LCMS + g_message(" channel %d", match ); +#endif // DEBUG_LCMS + } + + + cmsUInt16Number tmp[4]; + for ( guint i = 0; i < 4; i++ ) { + tmp[i] = ColorScales::getScaled( iccSelector->_impl->_compUI[i]._adj ) * 0x0ffff; + } + guchar post[4] = {0,0,0,0}; + + cmsHTRANSFORM trans = iccSelector->_impl->_prof->getTransfToSRGB8(); + if ( trans ) { + cmsDoTransform( trans, tmp, post, 1 ); + } + + SPColor other( SP_RGBA32_U_COMPOSE(post[0], post[1], post[2], 255) ); + other.icc = new SVGICCColor(); + if ( iccSelector->_color.icc ) { + other.icc->colorProfile = iccSelector->_color.icc->colorProfile; + } + + guint32 prior = iccSelector->_color.toRGBA32(255); + guint32 newer = other.toRGBA32(255); + + if ( prior != newer ) { +#ifdef DEBUG_LCMS + g_message("Transformed color from 0x%08x to 0x%08x", prior, newer ); + g_message(" ~~~~ FLIP"); +#endif // DEBUG_LCMS + newColor = other; + newColor.icc->colors.clear(); + for ( guint i = 0; i < iccSelector->_impl->_profChannelCount; i++ ) { + gdouble val = ColorScales::getScaled( iccSelector->_impl->_compUI[i]._adj ); + val *= iccSelector->_impl->_compUI[i]._component.scale; + if ( iccSelector->_impl->_compUI[i]._component.scale == 256 ) { + val -= 128; + } + newColor.icc->colors.push_back( val ); + } + } +#endif // defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) + } + iccSelector->_updateInternals( newColor, scaled, iccSelector->_impl->_dragging ); + iccSelector->_impl->_updateSliders( match ); + + iccSelector->_impl->_updating = FALSE; +#ifdef DEBUG_LCMS + g_message( "\\_________ %p::_adjustmentChanged()", cs ); +#endif // DEBUG_LCMS +} + +void ColorICCSelectorImpl::_sliderGrabbed() +{ +// ColorICCSelector* iccSelector = dynamic_cast(SP_COLOR_SELECTOR(cs)->base); +// if (!iccSelector->_dragging) { +// iccSelector->_dragging = TRUE; +// iccSelector->_grabbed(); +// iccSelector->_updateInternals( iccSelector->_color, ColorScales::getScaled( iccSelector->_impl->_adj ), iccSelector->_dragging ); +// } +} + +void ColorICCSelectorImpl::_sliderReleased() +{ +// ColorICCSelector* iccSelector = dynamic_cast(SP_COLOR_SELECTOR(cs)->base); +// if (iccSelector->_dragging) { +// iccSelector->_dragging = FALSE; +// iccSelector->_released(); +// iccSelector->_updateInternals( iccSelector->_color, ColorScales::getScaled( iccSelector->_adj ), iccSelector->_dragging ); +// } +} + +#ifdef DEBUG_LCMS +void ColorICCSelectorImpl::_sliderChanged( SPColorSlider *slider, SPColorICCSelector *cs ) +#else +void ColorICCSelectorImpl::_sliderChanged() +#endif // DEBUG_LCMS +{ +#ifdef DEBUG_LCMS + g_message("Changed %p and %p", slider, cs ); +#endif // DEBUG_LCMS +// ColorICCSelector* iccSelector = dynamic_cast(SP_COLOR_SELECTOR(cs)->base); + +// iccSelector->_updateInternals( iccSelector->_color, ColorScales::getScaled( iccSelector->_adj ), iccSelector->_dragging ); +} + +Gtk::Widget *ColorICCSelectorFactory::createWidget(Inkscape::UI::SelectedColor &color) const { + GtkWidget *w = sp_color_selector_new(SP_TYPE_COLOR_ICC_SELECTOR); + Gtk::Widget *wrapped = Gtk::manage(Glib::wrap(w)); + return wrapped; +} + +Glib::ustring ColorICCSelectorFactory::modeName() const { + return gettext(ColorICCSelector::MODE_NAME); +} + + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 : diff --git a/src/ui/widget/color-icc-selector.h b/src/ui/widget/color-icc-selector.h new file mode 100644 index 000000000..cee8305cd --- /dev/null +++ b/src/ui/widget/color-icc-selector.h @@ -0,0 +1,81 @@ +#ifndef SEEN_SP_COLOR_ICC_SELECTOR_H +#define SEEN_SP_COLOR_ICC_SELECTOR_H + +#include +#include + +#include "widgets/sp-color-selector.h" +#include "ui/selected-color.h" + +namespace Inkscape { +class ColorProfile; +} + +struct SPColorICCSelector; +struct SPColorICCSelectorClass; + +class ColorICCSelectorImpl; + +class ColorICCSelector: public ColorSelector +{ +public: + static const gchar* MODE_NAME; + + ColorICCSelector( SPColorSelector* csel ); + virtual ~ColorICCSelector(); + + virtual void init(); + +protected: + virtual void _colorChanged(); + + void _recalcColor( gboolean changing ); + +private: + friend class ColorICCSelectorImpl; + + // By default, disallow copy constructor and assignment operator + ColorICCSelector( const ColorICCSelector& obj ); + ColorICCSelector& operator=( const ColorICCSelector& obj ); + + ColorICCSelectorImpl *_impl; +}; + + + +#define SP_TYPE_COLOR_ICC_SELECTOR (sp_color_icc_selector_get_type()) +#define SP_COLOR_ICC_SELECTOR(o) (G_TYPE_CHECK_INSTANCE_CAST((o), SP_TYPE_COLOR_ICC_SELECTOR, SPColorICCSelector)) +#define SP_COLOR_ICC_SELECTOR_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), SP_TYPE_COLOR_ICC_SELECTOR, SPColorICCSelectorClass)) +#define SP_IS_COLOR_ICC_SELECTOR(o) (G_TYPE_CHECK_INSTANCE_TYPE((o), SP_TYPE_COLOR_ICC_SELECTOR)) +#define SP_IS_COLOR_ICC_SELECTOR_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE((k), SP_TYPE_COLOR_ICC_SELECTOR)) + +struct SPColorICCSelector { + SPColorSelector parent; +}; + +struct SPColorICCSelectorClass { + SPColorSelectorClass parent_class; +}; + +GType sp_color_icc_selector_get_type(void); + +GtkWidget *sp_color_icc_selector_new(void); + +class ColorICCSelectorFactory: public Inkscape::UI::ColorSelectorFactory { +public: + Gtk::Widget* createWidget(Inkscape::UI::SelectedColor &color) const; + Glib::ustring modeName() const; +}; + +#endif // SEEN_SP_COLOR_ICC_SELECTOR_H + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 : diff --git a/src/widgets/CMakeLists.txt b/src/widgets/CMakeLists.txt index dd0cba0b2..f546c516f 100644 --- a/src/widgets/CMakeLists.txt +++ b/src/widgets/CMakeLists.txt @@ -36,7 +36,6 @@ set(widgets_SRC select-toolbar.cpp shrink-wrap-button.cpp sp-attribute-widget.cpp - sp-color-icc-selector.cpp sp-color-notebook.cpp sp-color-selector.cpp sp-widget.cpp @@ -90,7 +89,6 @@ set(widgets_SRC select-toolbar.h shrink-wrap-button.h sp-attribute-widget.h - sp-color-icc-selector.h sp-color-notebook.h sp-color-selector.h sp-widget.h diff --git a/src/widgets/Makefile_insert b/src/widgets/Makefile_insert index 6d860996a..88e79f118 100644 --- a/src/widgets/Makefile_insert +++ b/src/widgets/Makefile_insert @@ -66,8 +66,6 @@ ink_common_sources += \ widgets/spiral-toolbar.h \ widgets/sp-attribute-widget.cpp \ widgets/sp-attribute-widget.h \ - widgets/sp-color-icc-selector.cpp \ - widgets/sp-color-icc-selector.h \ widgets/sp-color-notebook.cpp \ widgets/sp-color-notebook.h \ widgets/sp-color-selector.cpp \ diff --git a/src/widgets/sp-color-icc-selector.cpp b/src/widgets/sp-color-icc-selector.cpp deleted file mode 100644 index f872a3164..000000000 --- a/src/widgets/sp-color-icc-selector.cpp +++ /dev/null @@ -1,1150 +0,0 @@ -#ifdef HAVE_CONFIG_H -# include "config.h" -#endif - -#include "gradient-vector.h" -#include -#include -#include -#include -#include -#include - -#include "../dialogs/dialog-events.h" -#include "sp-color-icc-selector.h" -#include "ui/widget/color-scales.h" -#include "ui/widget/color-slider.h" -#include "svg/svg-icc-color.h" -#include "colorspace.h" -#include "document.h" -#include "inkscape.h" -#include "profile-manager.h" - -#define noDEBUG_LCMS - -#if defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) -#include "color-profile.h" -#include "cms-system.h" -#include "color-profile-cms-fns.h" - -#ifdef DEBUG_LCMS -#include "preferences.h" -#endif // DEBUG_LCMS -#endif // defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) - - -using namespace Inkscape::UI::Widget; - - -#ifdef DEBUG_LCMS -extern guint update_in_progress; -#define DEBUG_MESSAGE(key, ...) \ -{\ - Inkscape::Preferences *prefs = Inkscape::Preferences::get();\ - bool dump = prefs->getBool("/options/scislac/" #key);\ - bool dumpD = prefs->getBool("/options/scislac/" #key "D");\ - bool dumpD2 = prefs->getBool("/options/scislac/" #key "D2");\ - dumpD &&= ( (update_in_progress == 0) || dumpD2 );\ - if ( dump )\ - {\ - g_message( __VA_ARGS__ );\ -\ - }\ - if ( dumpD )\ - {\ - GtkWidget *dialog = gtk_message_dialog_new(NULL,\ - GTK_DIALOG_DESTROY_WITH_PARENT, \ - GTK_MESSAGE_INFO, \ - GTK_BUTTONS_OK, \ - __VA_ARGS__ \ - );\ - g_signal_connect_swapped(dialog, "response",\ - G_CALLBACK(gtk_widget_destroy), \ - dialog); \ - gtk_widget_show_all( dialog );\ - }\ -} -#endif // DEBUG_LCMS - - - -G_BEGIN_DECLS - -static void sp_color_icc_selector_class_init (SPColorICCSelectorClass *klass); -static void sp_color_icc_selector_init (SPColorICCSelector *cs); -static void sp_color_icc_selector_dispose(GObject *object); - -static void sp_color_icc_selector_show_all (GtkWidget *widget); -static void sp_color_icc_selector_hide(GtkWidget *widget); - -G_END_DECLS - -/** - * Class containing the parts for a single color component's UI presence. - */ -class ComponentUI -{ -public: - ComponentUI() : - _component(), - _adj(0), - _slider(0), - _btn(0), - _label(0), - _map(0) - { - } - - ComponentUI(colorspace::Component const &component) : - _component(component), - _adj(0), - _slider(0), - _btn(0), - _label(0), - _map(0) - { - } - - colorspace::Component _component; - GtkAdjustment *_adj; // Component adjustment - Inkscape::UI::Widget::ColorSlider *_slider; - GtkWidget *_btn; // spinbutton - GtkWidget *_label; // Label - guchar *_map; -}; - -/** - * Class that implements the internals of the selector. - */ -class ColorICCSelectorImpl -{ -public: - - ColorICCSelectorImpl( ColorICCSelector *owner); - - ~ColorICCSelectorImpl(); - - static void _adjustmentChanged ( GtkAdjustment *adjustment, SPColorICCSelector *cs ); - - void _sliderGrabbed(); - void _sliderReleased(); - void _sliderChanged(); - - static void _profileSelected( GtkWidget* src, gpointer data ); - static void _fixupHit( GtkWidget* src, gpointer data ); - -#if defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) - void _setProfile( SVGICCColor* profile ); - void _switchToProfile( gchar const* name ); -#endif - void _updateSliders( gint ignore ); - void _profilesChanged( std::string const & name ); - - ColorICCSelector *_owner; - - gboolean _updating : 1; - gboolean _dragging : 1; - - guint32 _fixupNeeded; - GtkWidget* _fixupBtn; - GtkWidget* _profileSel; - - std::vector _compUI; - - GtkAdjustment* _adj; // Channel adjustment - Inkscape::UI::Widget::ColorSlider* _slider; - GtkWidget* _sbtn; // Spinbutton - GtkWidget* _label; // Label - -#if defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) - std::string _profileName; - Inkscape::ColorProfile* _prof; - guint _profChannelCount; - gulong _profChangedID; -#endif // defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) -}; - - -static SPColorSelectorClass *parent_class; - -#define XPAD 4 -#define YPAD 1 - -namespace -{ - -size_t maxColorspaceComponentCount = 0; - -#if defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) - -/** - * Internal variable to track all known colorspaces. - */ -std::set knownColorspaces; - -#endif - - -/** - * Simple helper to allow bitwise or on GtkAttachOptions. - */ -GtkAttachOptions operator|(GtkAttachOptions lhs, GtkAttachOptions rhs) -{ - return static_cast(static_cast(lhs) | static_cast(rhs)); -} - -/** - * Helper function to handle GTK2/GTK3 attachment #ifdef code. - */ -void attachToGridOrTable(GtkWidget *parent, - GtkWidget *child, - guint left, - guint top, - guint width, - guint height, - bool hexpand = false, - bool centered = false, - guint xpadding = XPAD, - guint ypadding = YPAD) -{ -#if GTK_CHECK_VERSION(3,0,0) - gtk_widget_set_margin_left( child, xpadding ); - gtk_widget_set_margin_right( child, xpadding ); - gtk_widget_set_margin_top( child, ypadding ); - gtk_widget_set_margin_bottom( child, ypadding ); - if (hexpand) { - gtk_widget_set_hexpand(child, TRUE); - } - if (centered) { - gtk_widget_set_halign( child, GTK_ALIGN_CENTER ); - gtk_widget_set_valign( child, GTK_ALIGN_CENTER ); - } - gtk_grid_attach( GTK_GRID(parent), child, left, top, width, height ); -#else - GtkAttachOptions xoptions = centered ? static_cast(0) : hexpand ? (GTK_EXPAND | GTK_FILL) : GTK_FILL; - GtkAttachOptions yoptions = centered ? static_cast(0) : GTK_FILL; - - gtk_table_attach( GTK_TABLE(parent), child, left, left + width, top, top + height, xoptions, yoptions, xpadding, ypadding ); -#endif -} - -} // namespace - -GType sp_color_icc_selector_get_type(void) -{ - static GType type = 0; - if (!type) { - static const GTypeInfo info = { - sizeof (SPColorICCSelectorClass), - NULL, // base_init - NULL, // base_finalize - (GClassInitFunc) sp_color_icc_selector_class_init, - NULL, // class_finalize - NULL, // class_data - sizeof (SPColorICCSelector), - 0, // n_preallocs - (GInstanceInitFunc) sp_color_icc_selector_init, - 0, // value_table - }; - - type = g_type_register_static (SP_TYPE_COLOR_SELECTOR, - "SPColorICCSelector", - &info, - static_cast< GTypeFlags > (0) ); - } - return type; -} - -static void sp_color_icc_selector_class_init(SPColorICCSelectorClass *klass) -{ - static const gchar* nameset[] = {N_("CMS"), 0}; - GObjectClass *object_class = G_OBJECT_CLASS(klass); - GtkWidgetClass *widget_class = GTK_WIDGET_CLASS(klass); - SPColorSelectorClass *selector_class = SP_COLOR_SELECTOR_CLASS (klass); - - parent_class = SP_COLOR_SELECTOR_CLASS (g_type_class_peek_parent (klass)); - - selector_class->name = nameset; - selector_class->submode_count = 1; - - object_class->dispose = sp_color_icc_selector_dispose; - - widget_class->show_all = sp_color_icc_selector_show_all; - widget_class->hide = sp_color_icc_selector_hide; -} - -const gchar* ColorICCSelector::MODE_NAME = N_("CMS"); - -ColorICCSelector::ColorICCSelector( SPColorSelector* csel ) - : ColorSelector( csel ), - _impl(NULL) -{ -} - -ColorICCSelector::~ColorICCSelector() -{ - if (_impl) - { - delete _impl; - _impl = 0; - } -} - -void sp_color_icc_selector_init(SPColorICCSelector *cs) -{ - SP_COLOR_SELECTOR(cs)->base = new ColorICCSelector( SP_COLOR_SELECTOR(cs) ); - - if ( SP_COLOR_SELECTOR(cs)->base ) - { - SP_COLOR_SELECTOR(cs)->base->init(); - } -} - - -/* -icSigRgbData -icSigCmykData -icSigCmyData -*/ -#define SPACE_ID_RGB 0 -#define SPACE_ID_CMY 1 -#define SPACE_ID_CMYK 2 - - -#if defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) -static cmsUInt16Number* getScratch() { - // bytes per pixel * input channels * width - static cmsUInt16Number* scritch = static_cast(g_new(cmsUInt16Number, 4 * 1024)); - - return scritch; -} - -colorspace::Component::Component() : - name(), - tip(), - scale(1) -{ -} - -colorspace::Component::Component(std::string const &name, std::string const &tip, guint scale) : - name(name), - tip(tip), - scale(scale) -{ -} - -std::vector colorspace::getColorSpaceInfo( uint32_t space ) -{ - static std::map > sets; - if (sets.empty()) - { - sets[cmsSigXYZData].push_back(Component("_X", "X", 2)); // TYPE_XYZ_16 - sets[cmsSigXYZData].push_back(Component("_Y", "Y", 1)); - sets[cmsSigXYZData].push_back(Component("_Z", "Z", 2)); - - sets[cmsSigLabData].push_back(Component("_L", "L", 100)); // TYPE_Lab_16 - sets[cmsSigLabData].push_back(Component("_a", "a", 256)); - sets[cmsSigLabData].push_back(Component("_b", "b", 256)); - - //cmsSigLuvData - - sets[cmsSigYCbCrData].push_back(Component("_Y", "Y", 1)); // TYPE_YCbCr_16 - sets[cmsSigYCbCrData].push_back(Component("C_b", "Cb", 1)); - sets[cmsSigYCbCrData].push_back(Component("C_r", "Cr", 1)); - - sets[cmsSigYxyData].push_back(Component("_Y", "Y", 1)); // TYPE_Yxy_16 - sets[cmsSigYxyData].push_back(Component("_x", "x", 1)); - sets[cmsSigYxyData].push_back(Component("y", "y", 1)); - - sets[cmsSigRgbData].push_back(Component(_("_R:"), _("Red"), 1)); // TYPE_RGB_16 - sets[cmsSigRgbData].push_back(Component(_("_G:"), _("Green"), 1)); - sets[cmsSigRgbData].push_back(Component(_("_B:"), _("Blue"), 1)); - - sets[cmsSigGrayData].push_back(Component(_("G:"), _("Gray"), 1)); // TYPE_GRAY_16 - - sets[cmsSigHsvData].push_back(Component(_("_H:"), _("Hue"), 360)); // TYPE_HSV_16 - sets[cmsSigHsvData].push_back(Component(_("_S:"), _("Saturation"), 1)); - sets[cmsSigHsvData].push_back(Component("_V:", "Value", 1)); - - sets[cmsSigHlsData].push_back(Component(_("_H:"), _("Hue"), 360)); // TYPE_HLS_16 - sets[cmsSigHlsData].push_back(Component(_("_L:"), _("Lightness"), 1)); - sets[cmsSigHlsData].push_back(Component(_("_S:"), _("Saturation"), 1)); - - sets[cmsSigCmykData].push_back(Component(_("_C:"), _("Cyan"), 1)); // TYPE_CMYK_16 - sets[cmsSigCmykData].push_back(Component(_("_M:"), _("Magenta"), 1)); - sets[cmsSigCmykData].push_back(Component(_("_Y:"), _("Yellow"), 1)); - sets[cmsSigCmykData].push_back(Component(_("_K:"), _("Black"), 1)); - - sets[cmsSigCmyData].push_back(Component(_("_C:"), _("Cyan"), 1)); // TYPE_CMY_16 - sets[cmsSigCmyData].push_back(Component(_("_M:"), _("Magenta"), 1)); - sets[cmsSigCmyData].push_back(Component(_("_Y:"), _("Yellow"), 1)); - - for (std::map >::iterator it = sets.begin(); it != sets.end(); ++it) - { - knownColorspaces.insert(it->first); - maxColorspaceComponentCount = std::max(maxColorspaceComponentCount, it->second.size()); - } - } - - std::vector target; - - if (sets.find(space) != sets.end()) - { - target = sets[space]; - } - return target; -} - - -std::vector colorspace::getColorSpaceInfo( Inkscape::ColorProfile *prof ) -{ - return getColorSpaceInfo( asICColorSpaceSig(prof->getColorSpace()) ); -} - -#endif // defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) - -ColorICCSelectorImpl::ColorICCSelectorImpl(ColorICCSelector *owner) : - _owner(owner), - _updating( FALSE ), - _dragging( FALSE ), - _fixupNeeded(0), - _fixupBtn(0), - _profileSel(0), - _compUI(), - _adj(0), - _slider(0), - _sbtn(0), - _label(0) -#if defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) - , - _profileName(), - _prof(0), - _profChannelCount(0), - _profChangedID(0) -#endif // defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) -{ -} - -ColorICCSelectorImpl::~ColorICCSelectorImpl() -{ - _adj = 0; - _sbtn = 0; - _label = 0; -} - -void ColorICCSelector::init() -{ - if (_impl) delete(_impl); - _impl = new ColorICCSelectorImpl(this); - gint row = 0; - - _impl->_updating = FALSE; - _impl->_dragging = FALSE; - -#if GTK_CHECK_VERSION(3,0,0) - GtkWidget *t = gtk_grid_new(); -#else - GtkWidget *t = gtk_table_new(5, 3, FALSE); -#endif - - gtk_widget_show (t); - gtk_box_pack_start (GTK_BOX (_csel), t, TRUE, TRUE, 4); - - _impl->_compUI.clear(); - - // Create components - row = 0; - - - _impl->_fixupBtn = gtk_button_new_with_label(_("Fix")); - g_signal_connect( G_OBJECT(_impl->_fixupBtn), "clicked", G_CALLBACK(ColorICCSelectorImpl::_fixupHit), (gpointer)_impl ); - gtk_widget_set_sensitive( _impl->_fixupBtn, FALSE ); - gtk_widget_set_tooltip_text( _impl->_fixupBtn, _("Fix RGB fallback to match icc-color() value.") ); - //gtk_misc_set_alignment( GTK_MISC (_impl->_fixupBtn), 1.0, 0.5 ); - gtk_widget_show( _impl->_fixupBtn ); - - attachToGridOrTable(t, _impl->_fixupBtn, 0, row, 1, 1); - - // Combobox and store with 2 columns : label (0) and full name (1) - GtkListStore *store = gtk_list_store_new (2, G_TYPE_STRING, G_TYPE_STRING); - _impl->_profileSel = gtk_combo_box_new_with_model (GTK_TREE_MODEL (store)); - - GtkCellRenderer *renderer = gtk_cell_renderer_text_new (); - gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(_impl->_profileSel), renderer, TRUE); - gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(_impl->_profileSel), renderer, "text", 0, NULL); - - GtkTreeIter iter; - gtk_list_store_append (store, &iter); - gtk_list_store_set (store, &iter, 0, _(""), 1, _(""), -1); - - gtk_widget_show( _impl->_profileSel ); - gtk_combo_box_set_active( GTK_COMBO_BOX(_impl->_profileSel), 0 ); - - attachToGridOrTable(t, _impl->_profileSel, 1, row, 1, 1); - -#if defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) - _impl->_profChangedID = g_signal_connect( G_OBJECT(_impl->_profileSel), "changed", G_CALLBACK(ColorICCSelectorImpl::_profileSelected), (gpointer)_impl ); -#else - gtk_widget_set_sensitive( _impl->_profileSel, false ); -#endif // defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) - - - row++; - - // populate the data for colorspaces and channels: -#if defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) - std::vector things = colorspace::getColorSpaceInfo( cmsSigRgbData ); -#endif // defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) - - for ( size_t i = 0; i < maxColorspaceComponentCount; i++ ) { -#if defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) - if (i < things.size()) { - _impl->_compUI.push_back(ComponentUI(things[i])); - } else { - _impl->_compUI.push_back(ComponentUI()); - } - - std::string labelStr = (i < things.size()) ? things[i].name.c_str() : ""; -#else - _impl->_compUI.push_back(ComponentUI()); - - std::string labelStr = "."; -#endif - - _impl->_compUI[i]._label = gtk_label_new_with_mnemonic( labelStr.c_str() ); - gtk_misc_set_alignment( GTK_MISC (_impl->_compUI[i]._label), 1.0, 0.5 ); - gtk_widget_show( _impl->_compUI[i]._label ); - - attachToGridOrTable(t, _impl->_compUI[i]._label, 0, row, 1, 1); - - // Adjustment - guint scaleValue = _impl->_compUI[i]._component.scale; - gdouble step = static_cast(scaleValue) / 100.0; - gdouble page = static_cast(scaleValue) / 10.0; - gint digits = (step > 0.9) ? 0 : 2; - _impl->_compUI[i]._adj = GTK_ADJUSTMENT( gtk_adjustment_new( 0.0, 0.0, scaleValue, step, page, page ) ); - - // Slider - _impl->_compUI[i]._slider = Gtk::manage(new Inkscape::UI::Widget::ColorSlider(Glib::wrap(_impl->_compUI[i]._adj, true))); -#if defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) - _impl->_compUI[i]._slider->set_tooltip_text((i < things.size()) ? things[i].tip.c_str() : ""); -#else - _impl->_compUI[i]._slider->set_tooltip_text("."); -#endif // defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) - _impl->_compUI[i]._slider->show(); - - attachToGridOrTable(t, _impl->_compUI[i]._slider->gobj(), 1, row, 1, 1, true); - - _impl->_compUI[i]._btn = gtk_spin_button_new( _impl->_compUI[i]._adj, step, digits ); -#if defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) - gtk_widget_set_tooltip_text( _impl->_compUI[i]._btn, (i < things.size()) ? things[i].tip.c_str() : "" ); -#else - gtk_widget_set_tooltip_text( _impl->_compUI[i]._btn, "." ); -#endif // defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) - sp_dialog_defocus_on_enter( _impl->_compUI[i]._btn ); - gtk_label_set_mnemonic_widget( GTK_LABEL(_impl->_compUI[i]._label), _impl->_compUI[i]._btn ); - gtk_widget_show( _impl->_compUI[i]._btn ); - - attachToGridOrTable(t, _impl->_compUI[i]._btn, 2, row, 1, 1, false, true); - - _impl->_compUI[i]._map = g_new( guchar, 4 * 1024 ); - memset( _impl->_compUI[i]._map, 0x0ff, 1024 * 4 ); - - - // Signals - g_signal_connect( G_OBJECT( _impl->_compUI[i]._adj ), "value_changed", G_CALLBACK( ColorICCSelectorImpl::_adjustmentChanged ), _csel ); - - _impl->_compUI[i]._slider->signal_grabbed.connect(sigc::mem_fun(_impl, &ColorICCSelectorImpl::_sliderGrabbed)); - _impl->_compUI[i]._slider->signal_released.connect(sigc::mem_fun(_impl, &ColorICCSelectorImpl::_sliderReleased)); - _impl->_compUI[i]._slider->signal_value_changed.connect(sigc::mem_fun(_impl, &ColorICCSelectorImpl::_sliderChanged)); - - row++; - } - - // Label - _impl->_label = gtk_label_new_with_mnemonic(_("_A:")); - gtk_misc_set_alignment(GTK_MISC(_impl->_label), 1.0, 0.5); - gtk_widget_show(_impl->_label); - - attachToGridOrTable(t, _impl->_label, 0, row, 1, 1); - - // Adjustment - _impl->_adj = GTK_ADJUSTMENT(gtk_adjustment_new(0.0, 0.0, 255.0, 1.0, 10.0, 10.0)); - - // Slider - _impl->_slider = Gtk::manage(new Inkscape::UI::Widget::ColorSlider(Glib::wrap(_impl->_adj, true))); - _impl->_slider->set_tooltip_text(_("Alpha (opacity)")); - _impl->_slider->show(); - - attachToGridOrTable(t, _impl->_slider->gobj(), 1, row, 1, 1, true); - - _impl->_slider->setColors(SP_RGBA32_F_COMPOSE( 1.0, 1.0, 1.0, 0.0 ), - SP_RGBA32_F_COMPOSE( 1.0, 1.0, 1.0, 0.5 ), - SP_RGBA32_F_COMPOSE( 1.0, 1.0, 1.0, 1.0 ) ); - - - // Spinbutton - _impl->_sbtn = gtk_spin_button_new(GTK_ADJUSTMENT(_impl->_adj), 1.0, 0); - gtk_widget_set_tooltip_text(_impl->_sbtn, _("Alpha (opacity)")); - sp_dialog_defocus_on_enter(_impl->_sbtn); - gtk_label_set_mnemonic_widget(GTK_LABEL(_impl->_label), _impl->_sbtn); - gtk_widget_show(_impl->_sbtn); - - attachToGridOrTable(t, _impl->_sbtn, 2, row, 1, 1, false, true); - - // Signals - g_signal_connect(G_OBJECT(_impl->_adj), "value_changed", G_CALLBACK(ColorICCSelectorImpl::_adjustmentChanged), _csel); - - _impl->_slider->signal_grabbed.connect(sigc::mem_fun(_impl, &ColorICCSelectorImpl::_sliderGrabbed)); - _impl->_slider->signal_released.connect(sigc::mem_fun(_impl, &ColorICCSelectorImpl::_sliderReleased)); - _impl->_slider->signal_value_changed.connect(sigc::mem_fun(_impl, &ColorICCSelectorImpl::_sliderChanged)); -} - -static void sp_color_icc_selector_dispose(GObject *object) -{ - if ((G_OBJECT_CLASS(parent_class))->dispose) { - (* (G_OBJECT_CLASS(parent_class))->dispose)(object); - } -} - -static void -sp_color_icc_selector_show_all (GtkWidget *widget) -{ - gtk_widget_show (widget); -} - -static void sp_color_icc_selector_hide(GtkWidget *widget) -{ - gtk_widget_hide(widget); -} - -GtkWidget * -sp_color_icc_selector_new (void) -{ - SPColorICCSelector *csel; - - csel = static_cast(g_object_new (SP_TYPE_COLOR_ICC_SELECTOR, NULL)); - - return GTK_WIDGET (csel); -} - - -void ColorICCSelectorImpl::_fixupHit( GtkWidget* /*src*/, gpointer data ) -{ - ColorICCSelectorImpl* self = reinterpret_cast(data); - gtk_widget_set_sensitive( self->_fixupBtn, FALSE ); - self->_adjustmentChanged( self->_compUI[0]._adj, SP_COLOR_ICC_SELECTOR(self->_owner->_csel) ); -} - -#if defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) -void ColorICCSelectorImpl::_profileSelected( GtkWidget* /*src*/, gpointer data ) -{ - ColorICCSelectorImpl* self = reinterpret_cast(data); - - GtkTreeIter iter; - if (gtk_combo_box_get_active_iter(GTK_COMBO_BOX(self->_profileSel), &iter)) { - GtkTreeModel *store = gtk_combo_box_get_model(GTK_COMBO_BOX(self->_profileSel)); - gchar* name = 0; - - gtk_tree_model_get(store, &iter, 1, &name, -1); - self->_switchToProfile( name ); - gtk_widget_set_tooltip_text(self->_profileSel, name ); - - if ( name ) { - g_free( name ); - } - } -} -#endif // defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) - -#if defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) -void ColorICCSelectorImpl::_switchToProfile( gchar const* name ) -{ - bool dirty = false; - SPColor tmp( _owner->_color ); - - if ( name ) { - if ( tmp.icc && tmp.icc->colorProfile == name ) { -#ifdef DEBUG_LCMS - g_message("Already at name [%s]", name ); -#endif // DEBUG_LCMS - } else { -#ifdef DEBUG_LCMS - g_message("Need to switch to profile [%s]", name ); -#endif // DEBUG_LCMS - if ( tmp.icc ) { - tmp.icc->colors.clear(); - } else { - tmp.icc = new SVGICCColor(); - } - tmp.icc->colorProfile = name; - Inkscape::ColorProfile* newProf = SP_ACTIVE_DOCUMENT->profileManager->find(name); - if ( newProf ) { - cmsHTRANSFORM trans = newProf->getTransfFromSRGB8(); - if ( trans ) { - guint32 val = _owner->_color.toRGBA32(0); - guchar pre[4] = { - static_cast(SP_RGBA32_R_U(val)), - static_cast(SP_RGBA32_G_U(val)), - static_cast(SP_RGBA32_B_U(val)), - 255}; -#ifdef DEBUG_LCMS - g_message("Shoving in [%02x] [%02x] [%02x]", pre[0], pre[1], pre[2]); -#endif // DEBUG_LCMS - cmsUInt16Number post[4] = {0,0,0,0}; - cmsDoTransform( trans, pre, post, 1 ); -#ifdef DEBUG_LCMS - g_message("got on out [%04x] [%04x] [%04x] [%04x]", post[0], post[1], post[2], post[3]); -#endif // DEBUG_LCMS -#if HAVE_LIBLCMS1 - guint count = _cmsChannelsOf( asICColorSpaceSig(newProf->getColorSpace()) ); -#elif HAVE_LIBLCMS2 - guint count = cmsChannelsOf( asICColorSpaceSig(newProf->getColorSpace()) ); -#endif - - std::vector things = colorspace::getColorSpaceInfo(asICColorSpaceSig(newProf->getColorSpace())); - - for ( guint i = 0; i < count; i++ ) { - gdouble val = (((gdouble)post[i])/65535.0) * (gdouble)((i < things.size()) ? things[i].scale : 1); -#ifdef DEBUG_LCMS - g_message(" scaled %d by %d to be %f", i, ((i < things.size()) ? things[i].scale : 1), val); -#endif // DEBUG_LCMS - tmp.icc->colors.push_back(val); - } - cmsHTRANSFORM retrans = newProf->getTransfToSRGB8(); - if ( retrans ) { - cmsDoTransform( retrans, post, pre, 1 ); -#ifdef DEBUG_LCMS - g_message(" back out [%02x] [%02x] [%02x]", pre[0], pre[1], pre[2]); -#endif // DEBUG_LCMS - tmp.set(SP_RGBA32_U_COMPOSE(pre[0], pre[1], pre[2], 0xff)); - } - } - } - dirty = true; - } - } else { -#ifdef DEBUG_LCMS - g_message("NUKE THE ICC"); -#endif // DEBUG_LCMS - if ( tmp.icc ) { - delete tmp.icc; - tmp.icc = 0; - dirty = true; - _fixupHit( 0, this ); - } else { -#ifdef DEBUG_LCMS - g_message("No icc to nuke"); -#endif // DEBUG_LCMS - } - } - - if ( dirty ) { -#ifdef DEBUG_LCMS - g_message("+----------------"); - g_message("+ new color is [%s]", tmp.toString().c_str()); -#endif // DEBUG_LCMS - _setProfile( tmp.icc ); - //_adjustmentChanged( _compUI[0]._adj, SP_COLOR_ICC_SELECTOR(_csel) ); - _owner->setColorAlpha( tmp, _owner->_alpha, true ); -#ifdef DEBUG_LCMS - g_message("+_________________"); -#endif // DEBUG_LCMS - } -} -#endif // defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) - -#if defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) -void ColorICCSelectorImpl::_profilesChanged( std::string const & name ) -{ - GtkComboBox* combo = GTK_COMBO_BOX(_profileSel); - - g_signal_handler_block( G_OBJECT(_profileSel), _profChangedID ); - - GtkListStore *store = GTK_LIST_STORE(gtk_combo_box_get_model(combo)); - gtk_list_store_clear(store); - - GtkTreeIter iter; - gtk_list_store_append (store, &iter); - gtk_list_store_set(store, &iter, 0, _(""), 1, _(""), -1); - - gtk_combo_box_set_active( combo, 0 ); - - int index = 1; - const GSList *current = SP_ACTIVE_DOCUMENT->getResourceList( "iccprofile" ); - while ( current ) { - SPObject* obj = SP_OBJECT(current->data); - Inkscape::ColorProfile* prof = reinterpret_cast(obj); - - gtk_list_store_append (store, &iter); - gtk_list_store_set(store, &iter, 0, gr_ellipsize_text(prof->name, 25).c_str(), 1, prof->name, -1); - - if ( name == prof->name ) { - gtk_combo_box_set_active( combo, index ); - gtk_widget_set_tooltip_text(_profileSel, prof->name ); - } - - index++; - current = g_slist_next(current); - } - - g_signal_handler_unblock( G_OBJECT(_profileSel), _profChangedID ); -} -#else -void ColorICCSelectorImpl::_profilesChanged( std::string const & /*name*/ ) -{ -} -#endif // defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) - -// Helpers for setting color value - -void ColorICCSelector::_colorChanged() -{ - _impl->_updating = TRUE; - //sp_color_icc_set_color( SP_COLOR_ICC( _icc ), &color ); - -#ifdef DEBUG_LCMS - g_message( "/^^^^^^^^^ %p::_colorChanged(%08x:%s)", this, - _color.toRGBA32(_alpha), ( (_color.icc) ? _color.icc->colorProfile.c_str(): "" ) - ); -#endif // DEBUG_LCMS - -#ifdef DEBUG_LCMS - g_message("FLIPPIES!!!! %p '%s'", _color.icc, (_color.icc ? _color.icc->colorProfile.c_str():"")); -#endif // DEBUG_LCMS - - _impl->_profilesChanged( (_color.icc) ? _color.icc->colorProfile : std::string("") ); - ColorScales::setScaled( _impl->_adj, _alpha ); - -#if defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) - _impl->_setProfile( _color.icc ); - _impl->_fixupNeeded = 0; - gtk_widget_set_sensitive( _impl->_fixupBtn, FALSE ); - - if (_impl->_prof) { - if (_impl->_prof->getTransfToSRGB8() ) { - cmsUInt16Number tmp[4]; - for ( guint i = 0; i < _impl->_profChannelCount; i++ ) { - gdouble val = 0.0; - if ( _color.icc->colors.size() > i ) { - if ( _impl->_compUI[i]._component.scale == 256 ) { - val = (_color.icc->colors[i] + 128.0) / static_cast(_impl->_compUI[i]._component.scale); - } else { - val = _color.icc->colors[i] / static_cast(_impl->_compUI[i]._component.scale); - } - } - tmp[i] = val * 0x0ffff; - } - guchar post[4] = {0,0,0,0}; - cmsHTRANSFORM trans = _impl->_prof->getTransfToSRGB8(); - if ( trans ) { - cmsDoTransform( trans, tmp, post, 1 ); - guint32 other = SP_RGBA32_U_COMPOSE(post[0], post[1], post[2], 255 ); - if ( other != _color.toRGBA32(255) ) { - _impl->_fixupNeeded = other; - gtk_widget_set_sensitive( _impl->_fixupBtn, TRUE ); -#ifdef DEBUG_LCMS - g_message("Color needs to change 0x%06x to 0x%06x", _color.toRGBA32(255) >> 8, other >> 8 ); -#endif // DEBUG_LCMS - } - } - } - } -#else - //(void)color; -#endif // defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) - _impl->_updateSliders( -1 ); - - - _impl->_updating = FALSE; -#ifdef DEBUG_LCMS - g_message( "\\_________ %p::_colorChanged()", this ); -#endif // DEBUG_LCMS -} - -#if defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) -void ColorICCSelectorImpl::_setProfile( SVGICCColor* profile ) -{ -#ifdef DEBUG_LCMS - g_message( "/^^^^^^^^^ %p::_setProfile(%s)", this, - ( (profile) ? profile->colorProfile.c_str() : "") - ); -#endif // DEBUG_LCMS - bool profChanged = false; - if ( _prof && (!profile || (_profileName != profile->colorProfile) ) ) { - // Need to clear out the prior one - profChanged = true; - _profileName.clear(); - _prof = 0; - _profChannelCount = 0; - } else if ( profile && !_prof ) { - profChanged = true; - } - - for ( size_t i = 0; i < _compUI.size(); i++ ) { - gtk_widget_hide( _compUI[i]._label ); - _compUI[i]._slider->hide(); - gtk_widget_hide( _compUI[i]._btn ); - } - - if ( profile ) { - _prof = SP_ACTIVE_DOCUMENT->profileManager->find(profile->colorProfile.c_str()); - if ( _prof && (asICColorProfileClassSig(_prof->getProfileClass()) != cmsSigNamedColorClass) ) { -#if HAVE_LIBLCMS1 - _profChannelCount = _cmsChannelsOf( asICColorSpaceSig(_prof->getColorSpace()) ); -#elif HAVE_LIBLCMS2 - _profChannelCount = cmsChannelsOf( asICColorSpaceSig(_prof->getColorSpace()) ); -#endif - - if ( profChanged ) { - std::vector things = colorspace::getColorSpaceInfo(asICColorSpaceSig(_prof->getColorSpace())); - for (size_t i = 0; (i < things.size()) && (i < _profChannelCount); ++i) - { - _compUI[i]._component = things[i]; - } - - for ( guint i = 0; i < _profChannelCount; i++ ) { - gtk_label_set_text_with_mnemonic( GTK_LABEL(_compUI[i]._label), (i < things.size()) ? things[i].name.c_str() : ""); - - _compUI[i]._slider->set_tooltip_text((i < things.size()) ? things[i].tip.c_str() : ""); - gtk_widget_set_tooltip_text( _compUI[i]._btn, (i < things.size()) ? things[i].tip.c_str() : "" ); - - _compUI[i]._slider->setColors(SPColor(0.0, 0.0, 0.0).toRGBA32(0xff), - SPColor(0.5, 0.5, 0.5).toRGBA32(0xff), - SPColor(1.0, 1.0, 1.0).toRGBA32(0xff) ); -/* - _compUI[i]._adj = GTK_ADJUSTMENT( gtk_adjustment_new( val, 0.0, _fooScales[i], step, page, page ) ); - g_signal_connect( G_OBJECT( _compUI[i]._adj ), "value_changed", G_CALLBACK( _adjustmentChanged ), _csel ); - - sp_color_slider_set_adjustment( SP_COLOR_SLIDER(_compUI[i]._slider), _compUI[i]._adj ); - gtk_spin_button_set_adjustment( GTK_SPIN_BUTTON(_compUI[i]._btn), _compUI[i]._adj ); - gtk_spin_button_set_digits( GTK_SPIN_BUTTON(_compUI[i]._btn), digits ); -*/ - gtk_widget_show( _compUI[i]._label ); - _compUI[i]._slider->show(); - gtk_widget_show( _compUI[i]._btn ); - //gtk_adjustment_set_value( _compUI[i]._adj, 0.0 ); - //gtk_adjustment_set_value( _compUI[i]._adj, val ); - } - for ( size_t i = _profChannelCount; i < _compUI.size(); i++ ) { - gtk_widget_hide( _compUI[i]._label ); - _compUI[i]._slider->hide(); - gtk_widget_hide( _compUI[i]._btn ); - } - } - } else { - // Give up for now on named colors - _prof = 0; - } - } - -#ifdef DEBUG_LCMS - g_message( "\\_________ %p::_setProfile()", this ); -#endif // DEBUG_LCMS -} -#endif // defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) - -void ColorICCSelectorImpl::_updateSliders( gint ignore ) -{ -#if defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) - if ( _owner->_color.icc ) - { - for ( guint i = 0; i < _profChannelCount; i++ ) { - gdouble val = 0.0; - if ( _owner->_color.icc->colors.size() > i ) { - if ( _compUI[i]._component.scale == 256 ) { - val = (_owner->_color.icc->colors[i] + 128.0) / static_cast(_compUI[i]._component.scale); - } else { - val = _owner->_color.icc->colors[i] / static_cast(_compUI[i]._component.scale); - } - } - gtk_adjustment_set_value( _compUI[i]._adj, val ); - } - - if ( _prof ) { - if ( _prof->getTransfToSRGB8() ) { - for ( guint i = 0; i < _profChannelCount; i++ ) { - if ( static_cast(i) != ignore ) { - cmsUInt16Number* scratch = getScratch(); - cmsUInt16Number filler[4] = {0, 0, 0, 0}; - for ( guint j = 0; j < _profChannelCount; j++ ) { - filler[j] = 0x0ffff * ColorScales::getScaled( _compUI[j]._adj ); - } - - cmsUInt16Number* p = scratch; - for ( guint x = 0; x < 1024; x++ ) { - for ( guint j = 0; j < _profChannelCount; j++ ) { - if ( j == i ) { - *p++ = x * 0x0ffff / 1024; - } else { - *p++ = filler[j]; - } - } - } - - cmsHTRANSFORM trans = _prof->getTransfToSRGB8(); - if ( trans ) { - cmsDoTransform( trans, scratch, _compUI[i]._map, 1024 ); - _compUI[i]._slider->setMap(_compUI[i]._map); - } - } - } - } - } - } -#else - (void)ignore; -#endif // defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) - - guint32 start = _owner->_color.toRGBA32( 0x00 ); - guint32 mid = _owner->_color.toRGBA32( 0x7f ); - guint32 end = _owner->_color.toRGBA32( 0xff ); - - _slider->setColors(start, mid, end); -} - - -void ColorICCSelectorImpl::_adjustmentChanged( GtkAdjustment *adjustment, SPColorICCSelector *cs ) -{ -// // TODO check this. It looks questionable: -// // if a value is entered between 0 and 1 exclusive, normalize it to (int) 0..255 or 0..100 -// if (adjustment->value > 0.0 && adjustment->value < 1.0) { -// gtk_adjustment_set_value( adjustment, floor ((adjustment->value) * adjustment->upper + 0.5) ); -// } - -#ifdef DEBUG_LCMS - g_message( "/^^^^^^^^^ %p::_adjustmentChanged()", cs ); -#endif // DEBUG_LCMS - - ColorICCSelector* iccSelector = static_cast(SP_COLOR_SELECTOR(cs)->base); - if (iccSelector->_impl->_updating) { - return; - } - - iccSelector->_impl->_updating = TRUE; - - gint match = -1; - - SPColor newColor( iccSelector->_color ); - gfloat scaled = ColorScales::getScaled( iccSelector->_impl->_adj ); - if ( iccSelector->_impl->_adj == adjustment ) { -#ifdef DEBUG_LCMS - g_message("ALPHA"); -#endif // DEBUG_LCMS - } else { -#if defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) - for ( size_t i = 0; i < iccSelector->_impl->_compUI.size(); i++ ) { - if ( iccSelector->_impl->_compUI[i]._adj == adjustment ) { - match = i; - break; - } - } - if ( match >= 0 ) { -#ifdef DEBUG_LCMS - g_message(" channel %d", match ); -#endif // DEBUG_LCMS - } - - - cmsUInt16Number tmp[4]; - for ( guint i = 0; i < 4; i++ ) { - tmp[i] = ColorScales::getScaled( iccSelector->_impl->_compUI[i]._adj ) * 0x0ffff; - } - guchar post[4] = {0,0,0,0}; - - cmsHTRANSFORM trans = iccSelector->_impl->_prof->getTransfToSRGB8(); - if ( trans ) { - cmsDoTransform( trans, tmp, post, 1 ); - } - - SPColor other( SP_RGBA32_U_COMPOSE(post[0], post[1], post[2], 255) ); - other.icc = new SVGICCColor(); - if ( iccSelector->_color.icc ) { - other.icc->colorProfile = iccSelector->_color.icc->colorProfile; - } - - guint32 prior = iccSelector->_color.toRGBA32(255); - guint32 newer = other.toRGBA32(255); - - if ( prior != newer ) { -#ifdef DEBUG_LCMS - g_message("Transformed color from 0x%08x to 0x%08x", prior, newer ); - g_message(" ~~~~ FLIP"); -#endif // DEBUG_LCMS - newColor = other; - newColor.icc->colors.clear(); - for ( guint i = 0; i < iccSelector->_impl->_profChannelCount; i++ ) { - gdouble val = ColorScales::getScaled( iccSelector->_impl->_compUI[i]._adj ); - val *= iccSelector->_impl->_compUI[i]._component.scale; - if ( iccSelector->_impl->_compUI[i]._component.scale == 256 ) { - val -= 128; - } - newColor.icc->colors.push_back( val ); - } - } -#endif // defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) - } - iccSelector->_updateInternals( newColor, scaled, iccSelector->_impl->_dragging ); - iccSelector->_impl->_updateSliders( match ); - - iccSelector->_impl->_updating = FALSE; -#ifdef DEBUG_LCMS - g_message( "\\_________ %p::_adjustmentChanged()", cs ); -#endif // DEBUG_LCMS -} - -void ColorICCSelectorImpl::_sliderGrabbed() -{ -// ColorICCSelector* iccSelector = dynamic_cast(SP_COLOR_SELECTOR(cs)->base); -// if (!iccSelector->_dragging) { -// iccSelector->_dragging = TRUE; -// iccSelector->_grabbed(); -// iccSelector->_updateInternals( iccSelector->_color, ColorScales::getScaled( iccSelector->_impl->_adj ), iccSelector->_dragging ); -// } -} - -void ColorICCSelectorImpl::_sliderReleased() -{ -// ColorICCSelector* iccSelector = dynamic_cast(SP_COLOR_SELECTOR(cs)->base); -// if (iccSelector->_dragging) { -// iccSelector->_dragging = FALSE; -// iccSelector->_released(); -// iccSelector->_updateInternals( iccSelector->_color, ColorScales::getScaled( iccSelector->_adj ), iccSelector->_dragging ); -// } -} - -#ifdef DEBUG_LCMS -void ColorICCSelectorImpl::_sliderChanged( SPColorSlider *slider, SPColorICCSelector *cs ) -#else -void ColorICCSelectorImpl::_sliderChanged() -#endif // DEBUG_LCMS -{ -#ifdef DEBUG_LCMS - g_message("Changed %p and %p", slider, cs ); -#endif // DEBUG_LCMS -// ColorICCSelector* iccSelector = dynamic_cast(SP_COLOR_SELECTOR(cs)->base); - -// iccSelector->_updateInternals( iccSelector->_color, ColorScales::getScaled( iccSelector->_adj ), iccSelector->_dragging ); -} - -Gtk::Widget *ColorICCSelectorFactory::createWidget(Inkscape::UI::SelectedColor &color) const { - GtkWidget *w = sp_color_selector_new(SP_TYPE_COLOR_ICC_SELECTOR); - Gtk::Widget *wrapped = Gtk::manage(Glib::wrap(w)); - return wrapped; -} - -Glib::ustring ColorICCSelectorFactory::modeName() const { - return gettext(ColorICCSelector::MODE_NAME); -} - - -/* - Local Variables: - mode:c++ - c-file-style:"stroustrup" - c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) - indent-tabs-mode:nil - fill-column:99 - End: -*/ -// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 : diff --git a/src/widgets/sp-color-icc-selector.h b/src/widgets/sp-color-icc-selector.h deleted file mode 100644 index a59d3fe7e..000000000 --- a/src/widgets/sp-color-icc-selector.h +++ /dev/null @@ -1,81 +0,0 @@ -#ifndef SEEN_SP_COLOR_ICC_SELECTOR_H -#define SEEN_SP_COLOR_ICC_SELECTOR_H - -#include -#include - -#include "sp-color-selector.h" -#include "ui/selected-color.h" - -namespace Inkscape { -class ColorProfile; -} - -struct SPColorICCSelector; -struct SPColorICCSelectorClass; - -class ColorICCSelectorImpl; - -class ColorICCSelector: public ColorSelector -{ -public: - static const gchar* MODE_NAME; - - ColorICCSelector( SPColorSelector* csel ); - virtual ~ColorICCSelector(); - - virtual void init(); - -protected: - virtual void _colorChanged(); - - void _recalcColor( gboolean changing ); - -private: - friend class ColorICCSelectorImpl; - - // By default, disallow copy constructor and assignment operator - ColorICCSelector( const ColorICCSelector& obj ); - ColorICCSelector& operator=( const ColorICCSelector& obj ); - - ColorICCSelectorImpl *_impl; -}; - - - -#define SP_TYPE_COLOR_ICC_SELECTOR (sp_color_icc_selector_get_type()) -#define SP_COLOR_ICC_SELECTOR(o) (G_TYPE_CHECK_INSTANCE_CAST((o), SP_TYPE_COLOR_ICC_SELECTOR, SPColorICCSelector)) -#define SP_COLOR_ICC_SELECTOR_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), SP_TYPE_COLOR_ICC_SELECTOR, SPColorICCSelectorClass)) -#define SP_IS_COLOR_ICC_SELECTOR(o) (G_TYPE_CHECK_INSTANCE_TYPE((o), SP_TYPE_COLOR_ICC_SELECTOR)) -#define SP_IS_COLOR_ICC_SELECTOR_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE((k), SP_TYPE_COLOR_ICC_SELECTOR)) - -struct SPColorICCSelector { - SPColorSelector parent; -}; - -struct SPColorICCSelectorClass { - SPColorSelectorClass parent_class; -}; - -GType sp_color_icc_selector_get_type(void); - -GtkWidget *sp_color_icc_selector_new(void); - -class ColorICCSelectorFactory: public Inkscape::UI::ColorSelectorFactory { -public: - Gtk::Widget* createWidget(Inkscape::UI::SelectedColor &color) const; - Glib::ustring modeName() const; -}; - -#endif // SEEN_SP_COLOR_ICC_SELECTOR_H - -/* - Local Variables: - mode:c++ - c-file-style:"stroustrup" - c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) - indent-tabs-mode:nil - fill-column:99 - End: -*/ -// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 : diff --git a/src/widgets/sp-color-notebook.cpp b/src/widgets/sp-color-notebook.cpp index 807fe38e0..2097737d4 100644 --- a/src/widgets/sp-color-notebook.cpp +++ b/src/widgets/sp-color-notebook.cpp @@ -30,7 +30,6 @@ #include "../preferences.h" #include "sp-color-notebook.h" #include "spw-utilities.h" -#include "sp-color-icc-selector.h" #include "svg/svg-icc-color.h" #include "../inkscape.h" #include "../document.h" @@ -40,6 +39,7 @@ #include "tools-switch.h" #include "ui/tools/tool-base.h" #include "ui/widget/color-entry.h" +#include "ui/widget/color-icc-selector.h" #include "ui/widget/color-scales.h" #include "ui/widget/color-wheel-selector.h" -- cgit v1.2.3 From 9d88682d5df45121fec6350cc028e5fb666e4776 Mon Sep 17 00:00:00 2001 From: Tomasz Boczkowski Date: Sat, 31 May 2014 21:34:24 +0200 Subject: SPColorICC c++sification: using SelectedColor (bzr r13341.6.42) --- src/ui/widget/color-icc-selector.cpp | 416 ++++++++++++++--------------------- src/ui/widget/color-icc-selector.h | 58 ++--- 2 files changed, 199 insertions(+), 275 deletions(-) (limited to 'src') diff --git a/src/ui/widget/color-icc-selector.cpp b/src/ui/widget/color-icc-selector.cpp index 74e63f320..1187dd081 100644 --- a/src/ui/widget/color-icc-selector.cpp +++ b/src/ui/widget/color-icc-selector.cpp @@ -32,10 +32,6 @@ #endif // DEBUG_LCMS #endif // defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) - -using namespace Inkscape::UI::Widget; - - #ifdef DEBUG_LCMS extern guint update_in_progress; #define DEBUG_MESSAGE(key, ...) \ @@ -67,106 +63,6 @@ extern guint update_in_progress; #endif // DEBUG_LCMS - -G_BEGIN_DECLS - -static void sp_color_icc_selector_class_init (SPColorICCSelectorClass *klass); -static void sp_color_icc_selector_init (SPColorICCSelector *cs); -static void sp_color_icc_selector_dispose(GObject *object); - -static void sp_color_icc_selector_show_all (GtkWidget *widget); -static void sp_color_icc_selector_hide(GtkWidget *widget); - -G_END_DECLS - -/** - * Class containing the parts for a single color component's UI presence. - */ -class ComponentUI -{ -public: - ComponentUI() : - _component(), - _adj(0), - _slider(0), - _btn(0), - _label(0), - _map(0) - { - } - - ComponentUI(colorspace::Component const &component) : - _component(component), - _adj(0), - _slider(0), - _btn(0), - _label(0), - _map(0) - { - } - - colorspace::Component _component; - GtkAdjustment *_adj; // Component adjustment - Inkscape::UI::Widget::ColorSlider *_slider; - GtkWidget *_btn; // spinbutton - GtkWidget *_label; // Label - guchar *_map; -}; - -/** - * Class that implements the internals of the selector. - */ -class ColorICCSelectorImpl -{ -public: - - ColorICCSelectorImpl( ColorICCSelector *owner); - - ~ColorICCSelectorImpl(); - - static void _adjustmentChanged ( GtkAdjustment *adjustment, SPColorICCSelector *cs ); - - void _sliderGrabbed(); - void _sliderReleased(); - void _sliderChanged(); - - static void _profileSelected( GtkWidget* src, gpointer data ); - static void _fixupHit( GtkWidget* src, gpointer data ); - -#if defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) - void _setProfile( SVGICCColor* profile ); - void _switchToProfile( gchar const* name ); -#endif - void _updateSliders( gint ignore ); - void _profilesChanged( std::string const & name ); - - ColorICCSelector *_owner; - - gboolean _updating : 1; - gboolean _dragging : 1; - - guint32 _fixupNeeded; - GtkWidget* _fixupBtn; - GtkWidget* _profileSel; - - std::vector _compUI; - - GtkAdjustment* _adj; // Channel adjustment - Inkscape::UI::Widget::ColorSlider* _slider; - GtkWidget* _sbtn; // Spinbutton - GtkWidget* _label; // Label - -#if defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) - std::string _profileName; - Inkscape::ColorProfile* _prof; - guint _profChannelCount; - gulong _profChangedID; -#endif // defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) -}; - - -static SPColorSelectorClass *parent_class; - #define XPAD 4 #define YPAD 1 @@ -230,77 +126,6 @@ void attachToGridOrTable(GtkWidget *parent, } // namespace -GType sp_color_icc_selector_get_type(void) -{ - static GType type = 0; - if (!type) { - static const GTypeInfo info = { - sizeof (SPColorICCSelectorClass), - NULL, // base_init - NULL, // base_finalize - (GClassInitFunc) sp_color_icc_selector_class_init, - NULL, // class_finalize - NULL, // class_data - sizeof (SPColorICCSelector), - 0, // n_preallocs - (GInstanceInitFunc) sp_color_icc_selector_init, - 0, // value_table - }; - - type = g_type_register_static (SP_TYPE_COLOR_SELECTOR, - "SPColorICCSelector", - &info, - static_cast< GTypeFlags > (0) ); - } - return type; -} - -static void sp_color_icc_selector_class_init(SPColorICCSelectorClass *klass) -{ - static const gchar* nameset[] = {N_("CMS"), 0}; - GObjectClass *object_class = G_OBJECT_CLASS(klass); - GtkWidgetClass *widget_class = GTK_WIDGET_CLASS(klass); - SPColorSelectorClass *selector_class = SP_COLOR_SELECTOR_CLASS (klass); - - parent_class = SP_COLOR_SELECTOR_CLASS (g_type_class_peek_parent (klass)); - - selector_class->name = nameset; - selector_class->submode_count = 1; - - object_class->dispose = sp_color_icc_selector_dispose; - - widget_class->show_all = sp_color_icc_selector_show_all; - widget_class->hide = sp_color_icc_selector_hide; -} - -const gchar* ColorICCSelector::MODE_NAME = N_("CMS"); - -ColorICCSelector::ColorICCSelector( SPColorSelector* csel ) - : ColorSelector( csel ), - _impl(NULL) -{ -} - -ColorICCSelector::~ColorICCSelector() -{ - if (_impl) - { - delete _impl; - _impl = 0; - } -} - -void sp_color_icc_selector_init(SPColorICCSelector *cs) -{ - SP_COLOR_SELECTOR(cs)->base = new ColorICCSelector( SP_COLOR_SELECTOR(cs) ); - - if ( SP_COLOR_SELECTOR(cs)->base ) - { - SP_COLOR_SELECTOR(cs)->base->init(); - } -} - - /* icSigRgbData icSigCmykData @@ -403,8 +228,141 @@ std::vector colorspace::getColorSpaceInfo( Inkscape::Colo #endif // defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) -ColorICCSelectorImpl::ColorICCSelectorImpl(ColorICCSelector *owner) : + + + + + + + + + + + + + + + + + +namespace Inkscape { +namespace UI { +namespace Widget { + +/** + * Class containing the parts for a single color component's UI presence. + */ +class ComponentUI +{ +public: + ComponentUI() : + _component(), + _adj(0), + _slider(0), + _btn(0), + _label(0), + _map(0) + { + } + + ComponentUI(colorspace::Component const &component) : + _component(component), + _adj(0), + _slider(0), + _btn(0), + _label(0), + _map(0) + { + } + + colorspace::Component _component; + GtkAdjustment *_adj; // Component adjustment + Inkscape::UI::Widget::ColorSlider *_slider; + GtkWidget *_btn; // spinbutton + GtkWidget *_label; // Label + guchar *_map; +}; + +/** + * Class that implements the internals of the selector. + */ +class ColorICCSelectorImpl +{ +public: + + ColorICCSelectorImpl(ColorICCSelector *owner, SelectedColor &color); + + ~ColorICCSelectorImpl(); + + static void _adjustmentChanged ( GtkAdjustment *adjustment, ColorICCSelectorImpl *cs ); + + void _sliderGrabbed(); + void _sliderReleased(); + void _sliderChanged(); + + static void _profileSelected( GtkWidget* src, gpointer data ); + static void _fixupHit( GtkWidget* src, gpointer data ); + +#if defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) + void _setProfile( SVGICCColor* profile ); + void _switchToProfile( gchar const* name ); +#endif + void _updateSliders( gint ignore ); + void _profilesChanged( std::string const & name ); + + ColorICCSelector *_owner; + SelectedColor &_color; + + gboolean _updating : 1; + gboolean _dragging : 1; + + guint32 _fixupNeeded; + GtkWidget* _fixupBtn; + GtkWidget* _profileSel; + + std::vector _compUI; + + GtkAdjustment* _adj; // Channel adjustment + Inkscape::UI::Widget::ColorSlider* _slider; + GtkWidget* _sbtn; // Spinbutton + GtkWidget* _label; // Label + +#if defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) + std::string _profileName; + Inkscape::ColorProfile* _prof; + guint _profChannelCount; + gulong _profChangedID; +#endif // defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) +}; + + + + +const gchar* ColorICCSelector::MODE_NAME = N_("CMS"); + +ColorICCSelector::ColorICCSelector(SelectedColor &color) + : _impl(NULL) +{ + _impl = new ColorICCSelectorImpl(this, color); + init(); + color.signal_changed.connect(sigc::mem_fun(this, &ColorICCSelector::_colorChanged)); + //color.signal_dragged.connect(sigc::mem_fun(this, &ColorICCSelector::_colorChanged)); +} + +ColorICCSelector::~ColorICCSelector() +{ + if (_impl) + { + delete _impl; + _impl = 0; + } +} + + + +ColorICCSelectorImpl::ColorICCSelectorImpl(ColorICCSelector *owner, SelectedColor &color) : _owner(owner), + _color(color), _updating( FALSE ), _dragging( FALSE ), _fixupNeeded(0), @@ -434,21 +392,14 @@ ColorICCSelectorImpl::~ColorICCSelectorImpl() void ColorICCSelector::init() { - if (_impl) delete(_impl); - _impl = new ColorICCSelectorImpl(this); gint row = 0; _impl->_updating = FALSE; _impl->_dragging = FALSE; -#if GTK_CHECK_VERSION(3,0,0) - GtkWidget *t = gtk_grid_new(); -#else - GtkWidget *t = gtk_table_new(5, 3, FALSE); -#endif + GtkWidget* t = GTK_WIDGET(gobj()); gtk_widget_show (t); - gtk_box_pack_start (GTK_BOX (_csel), t, TRUE, TRUE, 4); _impl->_compUI.clear(); @@ -552,7 +503,7 @@ void ColorICCSelector::init() // Signals - g_signal_connect( G_OBJECT( _impl->_compUI[i]._adj ), "value_changed", G_CALLBACK( ColorICCSelectorImpl::_adjustmentChanged ), _csel ); + g_signal_connect( G_OBJECT( _impl->_compUI[i]._adj ), "value_changed", G_CALLBACK( ColorICCSelectorImpl::_adjustmentChanged ), _impl ); _impl->_compUI[i]._slider->signal_grabbed.connect(sigc::mem_fun(_impl, &ColorICCSelectorImpl::_sliderGrabbed)); _impl->_compUI[i]._slider->signal_released.connect(sigc::mem_fun(_impl, &ColorICCSelectorImpl::_sliderReleased)); @@ -593,47 +544,18 @@ void ColorICCSelector::init() attachToGridOrTable(t, _impl->_sbtn, 2, row, 1, 1, false, true); // Signals - g_signal_connect(G_OBJECT(_impl->_adj), "value_changed", G_CALLBACK(ColorICCSelectorImpl::_adjustmentChanged), _csel); + g_signal_connect(G_OBJECT(_impl->_adj), "value_changed", G_CALLBACK(ColorICCSelectorImpl::_adjustmentChanged), _impl); _impl->_slider->signal_grabbed.connect(sigc::mem_fun(_impl, &ColorICCSelectorImpl::_sliderGrabbed)); _impl->_slider->signal_released.connect(sigc::mem_fun(_impl, &ColorICCSelectorImpl::_sliderReleased)); _impl->_slider->signal_value_changed.connect(sigc::mem_fun(_impl, &ColorICCSelectorImpl::_sliderChanged)); } -static void sp_color_icc_selector_dispose(GObject *object) -{ - if ((G_OBJECT_CLASS(parent_class))->dispose) { - (* (G_OBJECT_CLASS(parent_class))->dispose)(object); - } -} - -static void -sp_color_icc_selector_show_all (GtkWidget *widget) -{ - gtk_widget_show (widget); -} - -static void sp_color_icc_selector_hide(GtkWidget *widget) -{ - gtk_widget_hide(widget); -} - -GtkWidget * -sp_color_icc_selector_new (void) -{ - SPColorICCSelector *csel; - - csel = static_cast(g_object_new (SP_TYPE_COLOR_ICC_SELECTOR, NULL)); - - return GTK_WIDGET (csel); -} - - void ColorICCSelectorImpl::_fixupHit( GtkWidget* /*src*/, gpointer data ) { ColorICCSelectorImpl* self = reinterpret_cast(data); gtk_widget_set_sensitive( self->_fixupBtn, FALSE ); - self->_adjustmentChanged( self->_compUI[0]._adj, SP_COLOR_ICC_SELECTOR(self->_owner->_csel) ); + self->_adjustmentChanged( self->_compUI[0]._adj, self ); } #if defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) @@ -661,7 +583,7 @@ void ColorICCSelectorImpl::_profileSelected( GtkWidget* /*src*/, gpointer data ) void ColorICCSelectorImpl::_switchToProfile( gchar const* name ) { bool dirty = false; - SPColor tmp( _owner->_color ); + SPColor tmp( _color.color() ); if ( name ) { if ( tmp.icc && tmp.icc->colorProfile == name ) { @@ -682,7 +604,7 @@ void ColorICCSelectorImpl::_switchToProfile( gchar const* name ) if ( newProf ) { cmsHTRANSFORM trans = newProf->getTransfFromSRGB8(); if ( trans ) { - guint32 val = _owner->_color.toRGBA32(0); + guint32 val = _color.color().toRGBA32(0); guchar pre[4] = { static_cast(SP_RGBA32_R_U(val)), static_cast(SP_RGBA32_G_U(val)), @@ -746,7 +668,7 @@ void ColorICCSelectorImpl::_switchToProfile( gchar const* name ) #endif // DEBUG_LCMS _setProfile( tmp.icc ); //_adjustmentChanged( _compUI[0]._adj, SP_COLOR_ICC_SELECTOR(_csel) ); - _owner->setColorAlpha( tmp, _owner->_alpha, true ); + _color.setColor(tmp); #ifdef DEBUG_LCMS g_message("+_________________"); #endif // DEBUG_LCMS @@ -805,19 +727,19 @@ void ColorICCSelector::_colorChanged() #ifdef DEBUG_LCMS g_message( "/^^^^^^^^^ %p::_colorChanged(%08x:%s)", this, - _color.toRGBA32(_alpha), ( (_color.icc) ? _color.icc->colorProfile.c_str(): "" ) + _impl->_color.color().toRGBA32(_impl->_color.alpha()), ( (_impl->_color.color().icc) ? _impl->_color.color().icc->colorProfile.c_str(): "" ) ); #endif // DEBUG_LCMS #ifdef DEBUG_LCMS - g_message("FLIPPIES!!!! %p '%s'", _color.icc, (_color.icc ? _color.icc->colorProfile.c_str():"")); + g_message("FLIPPIES!!!! %p '%s'", _impl->_color.color().icc, (_impl->_color.color().icc ? _impl->_color.color().icc->colorProfile.c_str():"")); #endif // DEBUG_LCMS - _impl->_profilesChanged( (_color.icc) ? _color.icc->colorProfile : std::string("") ); - ColorScales::setScaled( _impl->_adj, _alpha ); + _impl->_profilesChanged( (_impl->_color.color().icc) ? _impl->_color.color().icc->colorProfile : std::string("") ); + ColorScales::setScaled( _impl->_adj, _impl->_color.alpha() ); #if defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) - _impl->_setProfile( _color.icc ); + _impl->_setProfile( _impl->_color.color().icc ); _impl->_fixupNeeded = 0; gtk_widget_set_sensitive( _impl->_fixupBtn, FALSE ); @@ -826,11 +748,11 @@ void ColorICCSelector::_colorChanged() cmsUInt16Number tmp[4]; for ( guint i = 0; i < _impl->_profChannelCount; i++ ) { gdouble val = 0.0; - if ( _color.icc->colors.size() > i ) { + if ( _impl->_color.color().icc->colors.size() > i ) { if ( _impl->_compUI[i]._component.scale == 256 ) { - val = (_color.icc->colors[i] + 128.0) / static_cast(_impl->_compUI[i]._component.scale); + val = (_impl->_color.color().icc->colors[i] + 128.0) / static_cast(_impl->_compUI[i]._component.scale); } else { - val = _color.icc->colors[i] / static_cast(_impl->_compUI[i]._component.scale); + val = _impl->_color.color().icc->colors[i] / static_cast(_impl->_compUI[i]._component.scale); } } tmp[i] = val * 0x0ffff; @@ -840,7 +762,7 @@ void ColorICCSelector::_colorChanged() if ( trans ) { cmsDoTransform( trans, tmp, post, 1 ); guint32 other = SP_RGBA32_U_COMPOSE(post[0], post[1], post[2], 255 ); - if ( other != _color.toRGBA32(255) ) { + if ( other != _impl->_color.color().toRGBA32(255) ) { _impl->_fixupNeeded = other; gtk_widget_set_sensitive( _impl->_fixupBtn, TRUE ); #ifdef DEBUG_LCMS @@ -947,15 +869,15 @@ void ColorICCSelectorImpl::_setProfile( SVGICCColor* profile ) void ColorICCSelectorImpl::_updateSliders( gint ignore ) { #if defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) - if ( _owner->_color.icc ) + if ( _color.color().icc ) { for ( guint i = 0; i < _profChannelCount; i++ ) { gdouble val = 0.0; - if ( _owner->_color.icc->colors.size() > i ) { + if ( _color.color().icc->colors.size() > i ) { if ( _compUI[i]._component.scale == 256 ) { - val = (_owner->_color.icc->colors[i] + 128.0) / static_cast(_compUI[i]._component.scale); + val = (_color.color().icc->colors[i] + 128.0) / static_cast(_compUI[i]._component.scale); } else { - val = _owner->_color.icc->colors[i] / static_cast(_compUI[i]._component.scale); + val = _color.color().icc->colors[i] / static_cast(_compUI[i]._component.scale); } } gtk_adjustment_set_value( _compUI[i]._adj, val ); @@ -996,15 +918,15 @@ void ColorICCSelectorImpl::_updateSliders( gint ignore ) (void)ignore; #endif // defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) - guint32 start = _owner->_color.toRGBA32( 0x00 ); - guint32 mid = _owner->_color.toRGBA32( 0x7f ); - guint32 end = _owner->_color.toRGBA32( 0xff ); + guint32 start = _color.color().toRGBA32( 0x00 ); + guint32 mid = _color.color().toRGBA32( 0x7f ); + guint32 end = _color.color().toRGBA32( 0xff ); _slider->setColors(start, mid, end); } -void ColorICCSelectorImpl::_adjustmentChanged( GtkAdjustment *adjustment, SPColorICCSelector *cs ) +void ColorICCSelectorImpl::_adjustmentChanged( GtkAdjustment *adjustment, ColorICCSelectorImpl *cs ) { // // TODO check this. It looks questionable: // // if a value is entered between 0 and 1 exclusive, normalize it to (int) 0..255 or 0..100 @@ -1016,7 +938,7 @@ void ColorICCSelectorImpl::_adjustmentChanged( GtkAdjustment *adjustment, SPColo g_message( "/^^^^^^^^^ %p::_adjustmentChanged()", cs ); #endif // DEBUG_LCMS - ColorICCSelector* iccSelector = static_cast(SP_COLOR_SELECTOR(cs)->base); + ColorICCSelector* iccSelector = cs->_owner; if (iccSelector->_impl->_updating) { return; } @@ -1025,7 +947,7 @@ void ColorICCSelectorImpl::_adjustmentChanged( GtkAdjustment *adjustment, SPColo gint match = -1; - SPColor newColor( iccSelector->_color ); + SPColor newColor( iccSelector->_impl->_color.color() ); gfloat scaled = ColorScales::getScaled( iccSelector->_impl->_adj ); if ( iccSelector->_impl->_adj == adjustment ) { #ifdef DEBUG_LCMS @@ -1059,11 +981,11 @@ void ColorICCSelectorImpl::_adjustmentChanged( GtkAdjustment *adjustment, SPColo SPColor other( SP_RGBA32_U_COMPOSE(post[0], post[1], post[2], 255) ); other.icc = new SVGICCColor(); - if ( iccSelector->_color.icc ) { - other.icc->colorProfile = iccSelector->_color.icc->colorProfile; + if ( iccSelector->_impl->_color.color().icc ) { + other.icc->colorProfile = iccSelector->_impl->_color.color().icc->colorProfile; } - guint32 prior = iccSelector->_color.toRGBA32(255); + guint32 prior = iccSelector->_impl->_color.color().toRGBA32(255); guint32 newer = other.toRGBA32(255); if ( prior != newer ) { @@ -1084,7 +1006,8 @@ void ColorICCSelectorImpl::_adjustmentChanged( GtkAdjustment *adjustment, SPColo } #endif // defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) } - iccSelector->_updateInternals( newColor, scaled, iccSelector->_impl->_dragging ); + iccSelector->_impl->_color.setColorAlpha(newColor, scaled, true); + //iccSelector->_updateInternals( newColor, scaled, iccSelector->_impl->_dragging ); iccSelector->_impl->_updateSliders( match ); iccSelector->_impl->_updating = FALSE; @@ -1128,16 +1051,17 @@ void ColorICCSelectorImpl::_sliderChanged() } Gtk::Widget *ColorICCSelectorFactory::createWidget(Inkscape::UI::SelectedColor &color) const { - GtkWidget *w = sp_color_selector_new(SP_TYPE_COLOR_ICC_SELECTOR); - Gtk::Widget *wrapped = Gtk::manage(Glib::wrap(w)); - return wrapped; + Gtk::Widget *w = Gtk::manage(new ColorICCSelector(color)); + return w; } Glib::ustring ColorICCSelectorFactory::modeName() const { return gettext(ColorICCSelector::MODE_NAME); } - +} +} +} /* Local Variables: mode:c++ diff --git a/src/ui/widget/color-icc-selector.h b/src/ui/widget/color-icc-selector.h index cee8305cd..b917066dd 100644 --- a/src/ui/widget/color-icc-selector.h +++ b/src/ui/widget/color-icc-selector.h @@ -1,27 +1,43 @@ #ifndef SEEN_SP_COLOR_ICC_SELECTOR_H #define SEEN_SP_COLOR_ICC_SELECTOR_H -#include -#include +#ifdef HAVE_CONFIG_H +# include +#endif + +#if GLIBMM_DISABLE_DEPRECATED && HAVE_GLIBMM_THREADS_H +#include +#endif + +#include +#if GTK_CHECK_VERSION(3,0,0) +#include +#else +#include +#endif -#include "widgets/sp-color-selector.h" #include "ui/selected-color.h" namespace Inkscape { + class ColorProfile; -} -struct SPColorICCSelector; -struct SPColorICCSelectorClass; +namespace UI { +namespace Widget { class ColorICCSelectorImpl; -class ColorICCSelector: public ColorSelector +class ColorICCSelector +#if GTK_CHECK_VERSION(3,0,0) + : public Gtk::Grid +#else + : public Gtk::Table +#endif { public: static const gchar* MODE_NAME; - ColorICCSelector( SPColorSelector* csel ); + ColorICCSelector(SelectedColor &color); virtual ~ColorICCSelector(); virtual void init(); @@ -42,31 +58,15 @@ private: }; - -#define SP_TYPE_COLOR_ICC_SELECTOR (sp_color_icc_selector_get_type()) -#define SP_COLOR_ICC_SELECTOR(o) (G_TYPE_CHECK_INSTANCE_CAST((o), SP_TYPE_COLOR_ICC_SELECTOR, SPColorICCSelector)) -#define SP_COLOR_ICC_SELECTOR_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), SP_TYPE_COLOR_ICC_SELECTOR, SPColorICCSelectorClass)) -#define SP_IS_COLOR_ICC_SELECTOR(o) (G_TYPE_CHECK_INSTANCE_TYPE((o), SP_TYPE_COLOR_ICC_SELECTOR)) -#define SP_IS_COLOR_ICC_SELECTOR_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE((k), SP_TYPE_COLOR_ICC_SELECTOR)) - -struct SPColorICCSelector { - SPColorSelector parent; -}; - -struct SPColorICCSelectorClass { - SPColorSelectorClass parent_class; -}; - -GType sp_color_icc_selector_get_type(void); - -GtkWidget *sp_color_icc_selector_new(void); - -class ColorICCSelectorFactory: public Inkscape::UI::ColorSelectorFactory { +class ColorICCSelectorFactory: public ColorSelectorFactory { public: - Gtk::Widget* createWidget(Inkscape::UI::SelectedColor &color) const; + Gtk::Widget* createWidget(SelectedColor &color) const; Glib::ustring modeName() const; }; +} +} +} #endif // SEEN_SP_COLOR_ICC_SELECTOR_H /* -- cgit v1.2.3 From ade68e2b3601c0ef2912440b028e7b9e1f326bcc Mon Sep 17 00:00:00 2001 From: Tomasz Boczkowski Date: Sun, 1 Jun 2014 10:41:10 +0200 Subject: inhibit SelectedColor::setColorAlpha in the callbacks of it's signals (bzr r13341.6.43) --- src/ui/selected-color.cpp | 29 ++++++++++++++++++++--------- src/ui/selected-color.h | 4 +++- src/ui/widget/color-entry.cpp | 8 +------- src/ui/widget/color-icc-selector.cpp | 2 +- src/ui/widget/color-scales.cpp | 18 +++++------------- src/ui/widget/color-wheel-selector.cpp | 14 ++------------ src/widgets/sp-color-notebook.cpp | 4 ++-- 7 files changed, 34 insertions(+), 45 deletions(-) (limited to 'src') diff --git a/src/ui/selected-color.cpp b/src/ui/selected-color.cpp index 10ca68b21..24720f870 100644 --- a/src/ui/selected-color.cpp +++ b/src/ui/selected-color.cpp @@ -28,6 +28,7 @@ SelectedColor::SelectedColor() , _alpha(1.0) , _held(false) , _virgin(true) + , _updating(false) { } @@ -38,7 +39,7 @@ SelectedColor::~SelectedColor() { void SelectedColor::setColor(SPColor const &color) { - setColorAlpha( color, _alpha, true); + setColorAlpha( color, _alpha); } SPColor SelectedColor::color() const @@ -49,7 +50,7 @@ SPColor SelectedColor::color() const void SelectedColor::setAlpha(gfloat alpha) { g_return_if_fail( ( 0.0 <= alpha ) && ( alpha <= 1.0 ) ); - setColorAlpha( _color, alpha, true); + setColorAlpha( _color, alpha); } gfloat SelectedColor::alpha() const @@ -57,13 +58,17 @@ gfloat SelectedColor::alpha() const return _alpha; } -void SelectedColor::setColorAlpha(SPColor const &color, gfloat alpha, bool emit) +void SelectedColor::setColorAlpha(SPColor const &color, gfloat alpha) { #ifdef DUMP_CHANGE_INFO g_message("SelectedColor::setColorAlpha( this=%p, %f, %f, %f, %s, %f, %s) in %s", this, color.v.c[0], color.v.c[1], color.v.c[2], (color.icc?color.icc->colorProfile.c_str():""), alpha, (emit?"YES":"no"), FOO_NAME(_csel)); #endif g_return_if_fail( ( 0.0 <= alpha ) && ( alpha <= 1.0 ) ); + if (_updating) { + return; + } + #ifdef DUMP_CHANGE_INFO g_message("---- SelectedColor::setColorAlpha virgin:%s !close:%s alpha is:%s in %s", (_virgin?"YES":"no"), @@ -81,13 +86,14 @@ void SelectedColor::setColorAlpha(SPColor const &color, gfloat alpha, bool emit) _color = color; _alpha = alpha; - if (emit) { - if (_held) { - signal_dragged.emit(); - } else { - signal_changed.emit(); - } + _updating = true; + if (_held) { + signal_dragged.emit(); + } else { + signal_changed.emit(); } + _updating = false; + #ifdef DUMP_CHANGE_INFO } else { g_message("++++ SelectedColor::setColorAlpha color:%08x ==> _color:%08X isClose:%s in %s", color.toRGBA32(alpha), _color.toRGBA32(_alpha), @@ -102,11 +108,15 @@ void SelectedColor::colorAlpha(SPColor &color, gfloat &alpha) const { } void SelectedColor::setHeld(bool held) { + if (_updating) { + return; + } bool grabbed = held && !_held; bool released = !held && _held; _held = held; + _updating = true; if (grabbed) { signal_grabbed.emit(); } @@ -115,6 +125,7 @@ void SelectedColor::setHeld(bool held) { signal_released.emit(); signal_changed.emit(); } + _updating = false; } void SelectedColor::preserveICC() { diff --git a/src/ui/selected-color.h b/src/ui/selected-color.h index 5d3d89672..9f86d4255 100644 --- a/src/ui/selected-color.h +++ b/src/ui/selected-color.h @@ -39,7 +39,7 @@ public: void setAlpha(gfloat alpha); gfloat alpha() const; - void setColorAlpha(SPColor const &color, gfloat alpha, bool emit = false); + void setColorAlpha(SPColor const &color, gfloat alpha); void colorAlpha(SPColor &color, gfloat &alpha) const; void setHeld(bool held); @@ -67,6 +67,8 @@ private: */ bool _virgin; + bool _updating; + static double const _EPSILON; }; diff --git a/src/ui/widget/color-entry.cpp b/src/ui/widget/color-entry.cpp index 56fd6080e..e26cb4ade 100644 --- a/src/ui/widget/color-entry.cpp +++ b/src/ui/widget/color-entry.cpp @@ -71,23 +71,17 @@ void ColorEntry::on_changed() { if (len < 8) { rgba = rgba << (4 * (8 - len)); } - _updating = true; if (changed) { set_text(str); } SPColor color(rgba); - _color.setColorAlpha(color, SP_RGBA32_A_F(rgba), true); - _updating = false; + _color.setColorAlpha(color, SP_RGBA32_A_F(rgba)); } g_free(str); } void ColorEntry::_onColorChanged() { - if (_updating) { - return; - } - SPColor color = _color.color(); gdouble alpha = _color.alpha(); diff --git a/src/ui/widget/color-icc-selector.cpp b/src/ui/widget/color-icc-selector.cpp index 1187dd081..d679f9273 100644 --- a/src/ui/widget/color-icc-selector.cpp +++ b/src/ui/widget/color-icc-selector.cpp @@ -1006,7 +1006,7 @@ void ColorICCSelectorImpl::_adjustmentChanged( GtkAdjustment *adjustment, ColorI } #endif // defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) } - iccSelector->_impl->_color.setColorAlpha(newColor, scaled, true); + iccSelector->_impl->_color.setColorAlpha(newColor, scaled); //iccSelector->_updateInternals( newColor, scaled, iccSelector->_impl->_dragging ); iccSelector->_impl->_updateSliders( match ); diff --git a/src/ui/widget/color-scales.cpp b/src/ui/widget/color-scales.cpp index 234e7a2d1..ac1f52da3 100644 --- a/src/ui/widget/color-scales.cpp +++ b/src/ui/widget/color-scales.cpp @@ -164,11 +164,6 @@ void ColorScales::_initUI(SPColorScalesMode mode) void ColorScales::_recalcColor( gboolean changing ) { - if (_updating) { - return; - } - _updating = true; - if ( changing ) { SPColor color; @@ -198,13 +193,12 @@ void ColorScales::_recalcColor( gboolean changing ) } _color.preserveICC(); - _color.setColorAlpha(color, alpha, true); + _color.setColorAlpha(color, alpha); } else { // _updateInternals( _color, _alpha, _dragging ); } - _updating = false; } /* Helpers for setting color value */ @@ -232,7 +226,7 @@ void ColorScales::_setRangeLimit( gdouble upper ) void ColorScales::_onColorChanged() { - if (_updating || !get_visible()) { + if (!get_visible()) { return; } #ifdef DUMP_CHANGE_INFO @@ -468,13 +462,11 @@ void ColorScales::_sliderAnyGrabbed() if (_updating) { return; } - _updating = true; if (!_dragging) { _dragging = TRUE; _color.setHeld(true); _recalcColor( FALSE ); } - _updating = false; } void ColorScales::_sliderAnyReleased() @@ -482,13 +474,11 @@ void ColorScales::_sliderAnyReleased() if (_updating) { return; } - _updating = true; if (_dragging) { _dragging = FALSE; _color.setHeld(false); _recalcColor( FALSE ); } - _updating = false; } void ColorScales::_sliderAnyChanged() @@ -501,7 +491,9 @@ void ColorScales::_sliderAnyChanged() void ColorScales::_adjustmentChanged( ColorScales *scales, guint channel ) { - if (scales->_updating) return; + if (scales->_updating) { + return; + } scales->_updateSliders( (1 << channel) ); scales->_recalcColor (TRUE); diff --git a/src/ui/widget/color-wheel-selector.cpp b/src/ui/widget/color-wheel-selector.cpp index 4bf40dbb6..5f7260635 100644 --- a/src/ui/widget/color-wheel-selector.cpp +++ b/src/ui/widget/color-wheel-selector.cpp @@ -161,10 +161,8 @@ void ColorWheelSelector::_colorChanged() #ifdef DUMP_CHANGE_INFO g_message("ColorWheelSelector::_colorChanged( this=%p, %f, %f, %f, %f)", this, _color.color().v.c[0], _color.color().v.c[1], _color.color().v.c[2], alpha ); #endif - if (_updating) { - return; - } + bool oldval = _updating; _updating = true; { float hsv[3] = {0,0,0}; @@ -180,7 +178,7 @@ void ColorWheelSelector::_colorChanged() ColorScales::setScaled(_alpha_adjustment->gobj(), _color.alpha()); - _updating = false; + _updating = oldval; } void ColorWheelSelector::_adjustmentChanged() @@ -188,7 +186,6 @@ void ColorWheelSelector::_adjustmentChanged() if (_updating) { return; } - _updating = true; // TODO check this. It looks questionable: // if a value is entered between 0 and 1 exclusive, normalize it to (int) 0..255 or 0..100 @@ -200,8 +197,6 @@ void ColorWheelSelector::_adjustmentChanged() _color.preserveICC(); _color.setAlpha(ColorScales::getScaled(_alpha_adjustment->gobj())); - - _updating = false; } void ColorWheelSelector::_sliderGrabbed() @@ -222,10 +217,8 @@ void ColorWheelSelector::_sliderChanged() return; } - _updating = true; _color.preserveICC(); _color.setAlpha(ColorScales::getScaled(_alpha_adjustment->gobj())); - _updating = false; } void ColorWheelSelector::_wheelChanged(GimpColorWheel *wheel, ColorWheelSelector *wheelSelector) @@ -233,7 +226,6 @@ void ColorWheelSelector::_wheelChanged(GimpColorWheel *wheel, ColorWheelSelector if (wheelSelector->_updating){ return; } - wheelSelector->_updating = true; gdouble h = 0; gdouble s = 0; @@ -255,8 +247,6 @@ void ColorWheelSelector::_wheelChanged(GimpColorWheel *wheel, ColorWheelSelector wheelSelector->_color.setHeld(gimp_color_wheel_is_adjusting(wheel)); wheelSelector->_color.setColor(color); - - wheelSelector->_updating = false; } diff --git a/src/widgets/sp-color-notebook.cpp b/src/widgets/sp-color-notebook.cpp index 2097737d4..5bfe1f400 100644 --- a/src/widgets/sp-color-notebook.cpp +++ b/src/widgets/sp-color-notebook.cpp @@ -456,7 +456,7 @@ ColorNotebook::Page::Page(Inkscape::UI::ColorSelectorFactory *selector_factory, void ColorNotebook::_colorChanged() { _updating = true; - _selected_color.setColorAlpha(_color, _alpha, true); + _selected_color.setColorAlpha(_color, _alpha); _updating = false; SPColorSelector* cselPage = getCurrentSelector(); @@ -590,7 +590,7 @@ void ColorNotebook::_entryModified (SPColorSelector *csel, SPColorNotebook *colo csel->base->getColorAlpha( color, alpha ); nb->_updating = true; - nb->_selected_color.setColorAlpha(color, alpha, true); + nb->_selected_color.setColorAlpha(color, alpha); nb->_updating = false; nb->_updateInternals( color, alpha, nb->_dragging ); } -- cgit v1.2.3 From 41d146e6c99b26bc5ce2a377fc70fe28e5bb8db5 Mon Sep 17 00:00:00 2001 From: Tomasz Boczkowski Date: Sun, 1 Jun 2014 11:06:36 +0200 Subject: SPColorNotebook cleanup (bzr r13341.6.44) --- src/widgets/sp-color-notebook.cpp | 146 ++++---------------------------------- src/widgets/sp-color-notebook.h | 12 +--- 2 files changed, 16 insertions(+), 142 deletions(-) (limited to 'src') diff --git a/src/widgets/sp-color-notebook.cpp b/src/widgets/sp-color-notebook.cpp index 5bfe1f400..420efacc1 100644 --- a/src/widgets/sp-color-notebook.cpp +++ b/src/widgets/sp-color-notebook.cpp @@ -112,42 +112,12 @@ sp_color_notebook_switch_page(GtkNotebook *notebook, { if ( colorbook ) { - ColorNotebook* nb = dynamic_cast(SP_COLOR_SELECTOR(colorbook)->base); - nb->switchPage( notebook, page, page_num ); - // remember the page we switched to Inkscape::Preferences *prefs = Inkscape::Preferences::get(); prefs->setInt("/colorselector/page", page_num); } } -void ColorNotebook::switchPage(GtkNotebook*, - GtkWidget*, - guint page_num) -{ - SPColorSelector* csel; - GtkWidget* widget; - - if ( gtk_notebook_get_current_page (GTK_NOTEBOOK (_book)) >= 0 ) - { - csel = getCurrentSelector(); - if (csel) { - csel->base->getColorAlpha(_color, _alpha); - } - } - widget = gtk_notebook_get_nth_page (GTK_NOTEBOOK (_book), page_num); - if ( widget && SP_IS_COLOR_SELECTOR(widget) ) - { - csel = SP_COLOR_SELECTOR (widget); - if (csel) { - csel->base->setColorAlpha( _color, _alpha ); - } - - // Temporary workaround to undo a spurious GRABBED - _released(); - } -} - static void sp_color_notebook_init (SPColorNotebook *colorbook) { @@ -430,23 +400,6 @@ ColorNotebook::ColorNotebook( SPColorSelector* csel ) #endif } -SPColorSelector* ColorNotebook::getCurrentSelector() -{ - SPColorSelector* csel = NULL; - gint current_page = gtk_notebook_get_current_page (GTK_NOTEBOOK (_book)); - - if ( current_page >= 0 ) - { - GtkWidget* widget = gtk_notebook_get_nth_page (GTK_NOTEBOOK (_book), current_page); - if ( SP_IS_COLOR_SELECTOR (widget) ) - { - csel = SP_COLOR_SELECTOR (widget); - } - } - - return csel; -} - ColorNotebook::Page::Page(Inkscape::UI::ColorSelectorFactory *selector_factory, bool enabled_full) : selector_factory(selector_factory) , enabled_full(enabled_full) @@ -457,13 +410,8 @@ void ColorNotebook::_colorChanged() { _updating = true; _selected_color.setColorAlpha(_color, _alpha); + _updateICCButtons(); _updating = false; - - SPColorSelector* cselPage = getCurrentSelector(); - if ( cselPage ) - { - cselPage->base->setColorAlpha( _color, _alpha ); - } } void ColorNotebook::_picker_clicked(GtkWidget * /*widget*/, SPColorNotebook * /*colorbook*/) @@ -475,8 +423,11 @@ void ColorNotebook::_picker_clicked(GtkWidget * /*widget*/, SPColorNotebook * /* } // TODO pass in param so as to avoid the need for SP_ACTIVE_DOCUMENT -void ColorNotebook::_updateRgbaEntry( const SPColor& color, gfloat alpha ) +void ColorNotebook::_updateICCButtons() { + SPColor color = _selected_color.color(); + gfloat alpha = _selected_color.alpha(); + g_return_if_fail( ( 0.0 <= alpha ) && ( alpha <= 1.0 ) ); #if defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) @@ -538,63 +489,6 @@ void ColorNotebook::_buttonClicked(GtkWidget *widget, SPColorNotebook *colorboo } } -void ColorNotebook::_entryGrabbed (SPColorSelector *, SPColorNotebook *colorbook) -{ - ColorNotebook* nb = dynamic_cast(SP_COLOR_SELECTOR(colorbook)->base); - nb->_grabbed(); -} - -void ColorNotebook::_entryDragged (SPColorSelector *csel, SPColorNotebook *colorbook) -{ - gboolean oldState; - ColorNotebook* nb = dynamic_cast(SP_COLOR_SELECTOR(colorbook)->base); - - oldState = nb->_dragging; - - nb->_dragging = TRUE; - nb->_entryModified( csel, colorbook ); - - nb->_dragging = oldState; -} - -void ColorNotebook::_entryReleased (SPColorSelector *, SPColorNotebook *colorbook) -{ - ColorNotebook* nb = dynamic_cast(SP_COLOR_SELECTOR(colorbook)->base); - nb->_released(); -} - -void ColorNotebook::_entryChanged (SPColorSelector *csel, SPColorNotebook *colorbook) -{ - gboolean oldState; - ColorNotebook* nb = dynamic_cast(SP_COLOR_SELECTOR(colorbook)->base); - - oldState = nb->_dragging; - - nb->_dragging = FALSE; - nb->_entryModified( csel, colorbook ); - - nb->_dragging = oldState; -} - -void ColorNotebook::_entryModified (SPColorSelector *csel, SPColorNotebook *colorbook) -{ - g_return_if_fail (colorbook != NULL); - g_return_if_fail (SP_IS_COLOR_NOTEBOOK (colorbook)); - g_return_if_fail (csel != NULL); - g_return_if_fail (SP_IS_COLOR_SELECTOR (csel)); - - ColorNotebook* nb = dynamic_cast(SP_COLOR_SELECTOR(colorbook)->base); - SPColor color; - gfloat alpha = 1.0; - - csel->base->getColorAlpha( color, alpha ); - - nb->_updating = true; - nb->_selected_color.setColorAlpha(color, alpha); - nb->_updating = false; - nb->_updateInternals( color, alpha, nb->_dragging ); -} - void ColorNotebook::_onSelectedColorChanged() { if (_updating) { return; @@ -602,36 +496,34 @@ void ColorNotebook::_onSelectedColorChanged() { SPColor color; gfloat alpha = 1.0; - - _updating = true; _selected_color.colorAlpha(color, alpha); - _updateInternals(color, alpha, _dragging); - _updating = false; + _updateInternals(color, alpha, false); + _updateICCButtons(); } void ColorNotebook::_onSelectedColorDragged() { if (_updating) { return; } - bool oldState = _dragging; - - _dragging = true; SPColor color; gfloat alpha = 1.0; - - _updating = true; _selected_color.colorAlpha(color, alpha); _updateInternals(color, alpha, true); - _updating = false; - - _dragging = oldState; + _updateICCButtons(); } void ColorNotebook::_onSelectedColorGrabbed() { + if (_updating) { + return; + } + _grabbed(); } void ColorNotebook::_onSelectedColorReleased() { + if (_updating) { + return; + } _released(); } @@ -656,14 +548,6 @@ GtkWidget* ColorNotebook::_addPage(Page& page) { gtk_box_pack_start (GTK_BOX (_buttonbox), _buttons[page_num], TRUE, TRUE, 0); g_signal_connect (G_OBJECT (_buttons[page_num]), "clicked", G_CALLBACK (_buttonClicked), _csel); - - if (SP_IS_COLOR_SELECTOR(selector_widget->gobj())) { - //Connect glib signals of non-refactored widgets - g_signal_connect (selector_widget->gobj(), "grabbed", G_CALLBACK (_entryGrabbed), _csel); - g_signal_connect (selector_widget->gobj(), "dragged", G_CALLBACK (_entryDragged), _csel); - g_signal_connect (selector_widget->gobj(), "released", G_CALLBACK (_entryReleased), _csel); - g_signal_connect (selector_widget->gobj(), "changed", G_CALLBACK (_entryChanged), _csel); - } } return selector_widget->gobj(); diff --git a/src/widgets/sp-color-notebook.h b/src/widgets/sp-color-notebook.h index ca9343bf0..cc3fb4c76 100644 --- a/src/widgets/sp-color-notebook.h +++ b/src/widgets/sp-color-notebook.h @@ -40,9 +40,6 @@ public: virtual void init(); - SPColorSelector* getCurrentSelector(); - void switchPage( GtkNotebook *notebook, GtkWidget *page, guint page_num ); - protected: struct Page { Page(Inkscape::UI::ColorSelectorFactory *selector_factory, bool enabled_full); @@ -51,11 +48,6 @@ protected: bool enabled_full; }; - static void _entryGrabbed( SPColorSelector *csel, SPColorNotebook *colorbook ); - static void _entryDragged( SPColorSelector *csel, SPColorNotebook *colorbook ); - static void _entryReleased( SPColorSelector *csel, SPColorNotebook *colorbook ); - static void _entryChanged( SPColorSelector *csel, SPColorNotebook *colorbook ); - static void _entryModified( SPColorSelector *csel, SPColorNotebook *colorbook ); static void _buttonClicked(GtkWidget *widget, SPColorNotebook *colorbook); static void _picker_clicked(GtkWidget *widget, SPColorNotebook *colorbook); @@ -66,15 +58,13 @@ protected: virtual void _onSelectedColorGrabbed(); virtual void _onSelectedColorReleased(); - void _updateRgbaEntry( const SPColor& color, gfloat alpha ); + void _updateICCButtons(); void _setCurrentPage(int i); GtkWidget* _addPage(Page& page); Inkscape::UI::SelectedColor _selected_color; gboolean _updating : 1; - gboolean _updatingrgba : 1; - gboolean _dragging : 1; gulong _switchId; gulong _entryId; GtkWidget *_book; -- cgit v1.2.3 From bb5dacfc027558432b9a46f61329d7bd02731571 Mon Sep 17 00:00:00 2001 From: Tomasz Boczkowski Date: Sun, 1 Jun 2014 13:03:36 +0200 Subject: Using SelectedColor in extenstion/param/color (bzr r13341.6.45) --- src/extension/param/color.cpp | 51 ++++++++++++++++----------------------- src/extension/param/color.h | 9 +++++-- src/ui/selected-color.cpp | 12 +++++++++ src/ui/selected-color.h | 3 +++ src/widgets/sp-color-notebook.cpp | 9 +++++++ src/widgets/sp-color-notebook.h | 6 ++++- 6 files changed, 57 insertions(+), 33 deletions(-) (limited to 'src') diff --git a/src/extension/param/color.cpp b/src/extension/param/color.cpp index 0a2598c56..0eca52f8e 100644 --- a/src/extension/param/color.cpp +++ b/src/extension/param/color.cpp @@ -36,9 +36,6 @@ namespace Inkscape { namespace Extension { -void sp_color_param_changed(SPColorSelector *csel, GObject *cp); - - ParamColor::~ParamColor(void) { @@ -46,17 +43,19 @@ ParamColor::~ParamColor(void) guint32 ParamColor::set( guint32 in, SPDocument * /*doc*/, Inkscape::XML::Node * /*node*/ ) { - _value = in; + _color_changed.block(true); + _color.setValue(in); + _color_changed.block(false); gchar * prefname = this->pref_name(); std::string value; string(value); - + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); prefs->setString(extension_pref_root + prefname, value); g_free(prefname); - return _value; + return in; } ParamColor::ParamColor (const gchar * name, const gchar * guitext, const gchar * desc, const Parameter::_scope_t scope, bool gui_hidden, const gchar * gui_tip, Inkscape::Extension::Extension * ext, Inkscape::XML::Node * xml) : @@ -75,13 +74,15 @@ ParamColor::ParamColor (const gchar * name, const gchar * guitext, const gchar * if (!paramval.empty()) defaulthex = paramval.data(); - _value = atoi(defaulthex); + _color.setValue(atoi(defaulthex)); + _color_changed = _color.signal_changed.connect(sigc::mem_fun(this, &ParamColor::_onColorChanged)); + } void ParamColor::string(std::string &string) const { char str[16]; - sprintf(str, "%i", _value); + sprintf(str, "%i", _color.value()); string += str; } @@ -90,35 +91,25 @@ Gtk::Widget *ParamColor::get_widget( SPDocument * /*doc*/, Inkscape::XML::Node * if (_gui_hidden) return NULL; _changeSignal = new sigc::signal(*changeSignal); - Gtk::HBox * hbox = Gtk::manage(new Gtk::HBox(false, 4)); - SPColorSelector* spColorSelector = (SPColorSelector*)sp_color_selector_new(SP_TYPE_COLOR_NOTEBOOK); - ColorSelector* colorSelector = spColorSelector->base; - if (_value < 1) { - _value = 0xFF000000; + if (_color.value() < 1) { + _color_changed.block(true); + _color.setValue(0xFF000000); + _color_changed.block(false); } - SPColor *color = new SPColor( _value ); - float alpha = (_value & 0xff) / 255.0F; - colorSelector->setColorAlpha(*color, alpha); - hbox->pack_start (*Glib::wrap(&spColorSelector->vbox), true, true, 0); - g_signal_connect(G_OBJECT(spColorSelector), "changed", G_CALLBACK(sp_color_param_changed), (void*)this); - - gtk_widget_show(GTK_WIDGET(spColorSelector)); + Gtk::HBox *hbox = Gtk::manage(new Gtk::HBox(false, 4)); + Gtk::Widget *selector = Gtk::manage(ColorNotebook::create(_color)); + hbox->pack_start (*selector, true, true, 0); + selector->show(); hbox->show(); - - return dynamic_cast(hbox); + return hbox; } -void sp_color_param_changed(SPColorSelector *csel, GObject *obj) +void ParamColor::_onColorChanged() { - const SPColor color = csel->base->getColor(); - float alpha = csel->base->getAlpha(); - - ParamColor* ptr = reinterpret_cast(obj); - ptr->set(color.toRGBA32( alpha ), NULL, NULL); - - ptr->_changeSignal->emit(); + if (_changeSignal) + _changeSignal->emit(); } }; /* namespace Extension */ diff --git a/src/extension/param/color.h b/src/extension/param/color.h index 9894965a9..ed2e57ceb 100644 --- a/src/extension/param/color.h +++ b/src/extension/param/color.h @@ -9,6 +9,7 @@ */ #include "parameter.h" +#include "ui/selected-color.h" class SPDocument; @@ -25,14 +26,17 @@ namespace Extension { class ParamColor : public Parameter { private: - guint32 _value; + void _onColorChanged(); + + Inkscape::UI::SelectedColor _color; + sigc::connection _color_changed; public: ParamColor(const gchar * name, const gchar * guitext, const gchar * desc, const Parameter::_scope_t scope, bool gui_hidden, const gchar * gui_tip, Inkscape::Extension::Extension * ext, Inkscape::XML::Node * xml); virtual ~ParamColor(void); /** Returns \c _value, with a \i const to protect it. */ - guint32 get( SPDocument const * /*doc*/, Inkscape::XML::Node const * /*node*/ ) const { return _value; } + guint32 get( SPDocument const * /*doc*/, Inkscape::XML::Node const * /*node*/ ) const { return _color.value(); } guint32 set (guint32 in, SPDocument * doc, Inkscape::XML::Node * node); @@ -44,6 +48,7 @@ public: virtual void string (std::string &string) const; sigc::signal * _changeSignal; + }; // class ParamColor } // namespace Extension diff --git a/src/ui/selected-color.cpp b/src/ui/selected-color.cpp index 24720f870..ed3e06e2f 100644 --- a/src/ui/selected-color.cpp +++ b/src/ui/selected-color.cpp @@ -58,6 +58,18 @@ gfloat SelectedColor::alpha() const return _alpha; } +void SelectedColor::setValue(guint32 value) +{ + SPColor color(value); + gfloat alpha = SP_RGBA32_A_F(value); + setColorAlpha(color, alpha); +} + +guint32 SelectedColor::value() const +{ + return color().toRGBA32(_alpha); +} + void SelectedColor::setColorAlpha(SPColor const &color, gfloat alpha) { #ifdef DUMP_CHANGE_INFO diff --git a/src/ui/selected-color.h b/src/ui/selected-color.h index 9f86d4255..b4268f553 100644 --- a/src/ui/selected-color.h +++ b/src/ui/selected-color.h @@ -39,6 +39,9 @@ public: void setAlpha(gfloat alpha); gfloat alpha() const; + void setValue(guint32 value); + guint32 value() const; + void setColorAlpha(SPColor const &color, gfloat alpha); void colorAlpha(SPColor &color, gfloat &alpha) const; diff --git a/src/widgets/sp-color-notebook.cpp b/src/widgets/sp-color-notebook.cpp index 420efacc1..38ea04372 100644 --- a/src/widgets/sp-color-notebook.cpp +++ b/src/widgets/sp-color-notebook.cpp @@ -45,6 +45,7 @@ using Inkscape::CMSSystem; +using namespace Inkscape::UI; using namespace Inkscape::UI::Widget; struct SPColorNotebookTracker { @@ -383,6 +384,7 @@ GtkWidget *sp_color_notebook_new() ColorNotebook::ColorNotebook( SPColorSelector* csel ) : ColorSelector( csel ) + , _selected_color(_selected_color_tmp) { Page *page; @@ -400,6 +402,13 @@ ColorNotebook::ColorNotebook( SPColorSelector* csel ) #endif } +Gtk::Widget *ColorNotebook::create(SelectedColor &color) { + GtkWidget *w = sp_color_selector_new(SP_TYPE_COLOR_NOTEBOOK); + SPColorSelector *s = SP_COLOR_SELECTOR(w); + ColorNotebook* nb = dynamic_cast(s->base); + return Glib::wrap(w); +} + ColorNotebook::Page::Page(Inkscape::UI::ColorSelectorFactory *selector_factory, bool enabled_full) : selector_factory(selector_factory) , enabled_full(enabled_full) diff --git a/src/widgets/sp-color-notebook.h b/src/widgets/sp-color-notebook.h index cc3fb4c76..42fb0ed97 100644 --- a/src/widgets/sp-color-notebook.h +++ b/src/widgets/sp-color-notebook.h @@ -38,6 +38,9 @@ public: ColorNotebook( SPColorSelector* csel ); virtual ~ColorNotebook(); + //Temporary factory method - transition from SPColorSelector + static Gtk::Widget* create(Inkscape::UI::SelectedColor &color); + virtual void init(); protected: @@ -63,7 +66,8 @@ protected: GtkWidget* _addPage(Page& page); - Inkscape::UI::SelectedColor _selected_color; + Inkscape::UI::SelectedColor _selected_color_tmp; + Inkscape::UI::SelectedColor &_selected_color; gboolean _updating : 1; gulong _switchId; gulong _entryId; -- cgit v1.2.3 From 0d71d02e49a5eab7f9e79b246961c1349320a986 Mon Sep 17 00:00:00 2001 From: Tomasz Boczkowski Date: Sun, 1 Jun 2014 13:24:00 +0200 Subject: using SelectedColor in ColorPicker (bzr r13341.6.46) --- src/ui/widget/color-picker.cpp | 70 ++++++++++++++++++------------------------ src/ui/widget/color-picker.h | 8 +++-- 2 files changed, 35 insertions(+), 43 deletions(-) (limited to 'src') diff --git a/src/ui/widget/color-picker.cpp b/src/ui/widget/color-picker.cpp index 5585f2db4..f909535b1 100644 --- a/src/ui/widget/color-picker.cpp +++ b/src/ui/widget/color-picker.cpp @@ -27,8 +27,6 @@ namespace Inkscape { namespace UI { namespace Widget { -void sp_color_picker_color_mod(SPColorSelector *csel, GObject *cp); - ColorPicker::ColorPicker (const Glib::ustring& title, const Glib::ustring& tip, guint32 rgba, bool undo) : _preview(rgba), _title(title), _rgba(rgba), _undo(undo), @@ -39,12 +37,15 @@ ColorPicker::ColorPicker (const Glib::ustring& title, const Glib::ustring& tip, _preview.show(); add (_preview); set_tooltip_text (tip); + + _selected_color.signal_changed.connect(sigc::mem_fun(this, &ColorPicker::_onSelectedColorChanged)); + _selected_color.signal_dragged.connect(sigc::mem_fun(this, &ColorPicker::_onSelectedColorChanged)); + _selected_color.signal_released.connect(sigc::mem_fun(this, &ColorPicker::_onSelectedColorChanged)); } ColorPicker::~ColorPicker() { closeWindow(); - _colorSelector = NULL; } void ColorPicker::setupDialog(const Glib::ustring &title) @@ -55,25 +56,17 @@ void ColorPicker::setupDialog(const Glib::ustring &title) _colorSelectorDialog.hide(); _colorSelectorDialog.set_title (title); _colorSelectorDialog.set_border_width (4); - _colorSelector = SP_COLOR_SELECTOR(sp_color_selector_new(SP_TYPE_COLOR_NOTEBOOK)); + + _color_selector = Gtk::manage(ColorNotebook::create(_selected_color)); #if WITH_GTKMM_3_0 _colorSelectorDialog.get_content_area()->pack_start ( - *Glib::wrap(&_colorSelector->vbox), true, true, 0); + *_color_selector, true, true, 0); #else _colorSelectorDialog.get_vbox()->pack_start ( - *Glib::wrap(&_colorSelector->vbox), true, true, 0); + *_color_selector, true, true, 0); #endif - - g_signal_connect(G_OBJECT(_colorSelector), "dragged", - G_CALLBACK(sp_color_picker_color_mod), (void *)this); - g_signal_connect(G_OBJECT(_colorSelector), "released", - G_CALLBACK(sp_color_picker_color_mod), (void *)this); - g_signal_connect(G_OBJECT(_colorSelector), "changed", - G_CALLBACK(sp_color_picker_color_mod), (void *)this); - - gtk_widget_show(GTK_WIDGET(_colorSelector)); - + _color_selector->show(); } void ColorPicker::setRgba32 (guint32 rgba) @@ -82,11 +75,11 @@ void ColorPicker::setRgba32 (guint32 rgba) _preview.setRgba32 (rgba); _rgba = rgba; - if (_colorSelector) + if (_color_selector) { - SPColor color; - color.set( rgba ); - _colorSelector->base->setColorAlpha(color, SP_RGBA32_A_F(rgba)); + _updating = true; + _selected_color.setValue(rgba); + _updating = false; } } @@ -97,11 +90,11 @@ void ColorPicker::closeWindow() void ColorPicker::on_clicked() { - if (_colorSelector) + if (_color_selector) { - SPColor color; - color.set( _rgba ); - _colorSelector->base->setColorAlpha(color, SP_RGBA32_A_F(_rgba)); + _updating = true; + _selected_color.setValue(_rgba); + _updating = false; } _colorSelectorDialog.show(); } @@ -110,34 +103,31 @@ void ColorPicker::on_changed (guint32) { } -void sp_color_picker_color_mod(SPColorSelector *csel, GObject *cp) -{ +void ColorPicker::_onSelectedColorChanged() { + if (_updating) { + return; + } + if (_in_use) { return; } else { _in_use = true; } - SPColor color; - float alpha = 0; - csel->base->getColorAlpha(color, alpha); - guint32 rgba = color.toRGBA32( alpha ); - - ColorPicker *ptr = reinterpret_cast(cp); - - (ptr->_preview).setRgba32 (rgba); + guint32 rgba = _selected_color.value(); + _preview.setRgba32(rgba); - if (ptr->_undo && SP_ACTIVE_DESKTOP) + if (_undo && SP_ACTIVE_DESKTOP) { DocumentUndo::done(sp_desktop_document(SP_ACTIVE_DESKTOP), SP_VERB_NONE, - /* TODO: annotate */ "color-picker.cpp:130"); + /* TODO: annotate */ "color-picker.cpp:130"); + } - ptr->on_changed (rgba); + on_changed(rgba); _in_use = false; - ptr->_changed_signal.emit (rgba); - ptr->_rgba = rgba; + _changed_signal.emit(rgba); + _rgba = rgba; } - }//namespace Widget }//namespace UI }//namespace Inkscape diff --git a/src/ui/widget/color-picker.h b/src/ui/widget/color-picker.h index b4da5dbf2..49275a04c 100644 --- a/src/ui/widget/color-picker.h +++ b/src/ui/widget/color-picker.h @@ -26,6 +26,7 @@ #include #include #include +#include "ui/selected-color.h" #include "ui/widget/color-preview.h" struct SPColorSelector; @@ -57,7 +58,7 @@ public: protected: - friend void sp_color_picker_color_mod(SPColorSelector *csel, GObject *cp); + void _onSelectedColorChanged(); virtual void on_clicked(); virtual void on_changed (guint32); @@ -67,13 +68,14 @@ protected: sigc::signal _changed_signal; guint32 _rgba; bool _undo; - + bool _updating; //Dialog void setupDialog(const Glib::ustring &title); //Inkscape::UI::Dialog::Dialog _colorSelectorDialog; Gtk::Dialog _colorSelectorDialog; - SPColorSelector *_colorSelector; + SelectedColor _selected_color; + Gtk::Widget *_color_selector; }; }//namespace Widget -- cgit v1.2.3 From 8df6d8e46c8b7e9a96529ee38af62a0f8ea9c831 Mon Sep 17 00:00:00 2001 From: Tomasz Boczkowski Date: Sun, 1 Jun 2014 13:26:17 +0200 Subject: disconnecting in ParamColor destructor (bzr r13341.6.47) --- src/extension/param/color.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/extension/param/color.cpp b/src/extension/param/color.cpp index 0eca52f8e..5b2a4ad0c 100644 --- a/src/extension/param/color.cpp +++ b/src/extension/param/color.cpp @@ -38,7 +38,7 @@ namespace Extension { ParamColor::~ParamColor(void) { - + _color_changed.disconnect(); } guint32 ParamColor::set( guint32 in, SPDocument * /*doc*/, Inkscape::XML::Node * /*node*/ ) -- cgit v1.2.3 From 05cc0e453380e6ddc80ba433b6240f4e881afee4 Mon Sep 17 00:00:00 2001 From: Tomasz Boczkowski Date: Sun, 1 Jun 2014 15:30:36 +0200 Subject: using ColorSelector in gradient vector selector widget (bzr r13341.6.48) --- src/widgets/gradient-vector.cpp | 59 +++++++++++++++++++++++++++++++---------- 1 file changed, 45 insertions(+), 14 deletions(-) (limited to 'src') diff --git a/src/widgets/gradient-vector.cpp b/src/widgets/gradient-vector.cpp index 17ac887c4..0ea5f5506 100644 --- a/src/widgets/gradient-vector.cpp +++ b/src/widgets/gradient-vector.cpp @@ -54,7 +54,10 @@ #include #include "document-undo.h" +#include "ui/selected-color.h" + using Inkscape::DocumentUndo; +using Inkscape::UI::SelectedColor; enum { VECTOR_SET, @@ -511,8 +514,8 @@ static void sp_gradient_vector_widget_destroy(GtkObject *object, gpointer data); static void sp_gradient_vector_gradient_release(SPObject *obj, GtkWidget *widget); static void sp_gradient_vector_gradient_modified(SPObject *obj, guint flags, GtkWidget *widget); -static void sp_gradient_vector_color_dragged(SPColorSelector *csel, GObject *object); -static void sp_gradient_vector_color_changed(SPColorSelector *csel, GObject *object); +static void sp_gradient_vector_color_dragged(Inkscape::UI::SelectedColor *selected_color, GObject *object); +static void sp_gradient_vector_color_changed(Inkscape::UI::SelectedColor *selected_color, GObject *object); static void update_stop_list( GtkWidget *vb, SPGradient *gradient, SPStop *new_stop); static gboolean blocked = FALSE; @@ -668,9 +671,11 @@ static void sp_grad_edit_combo_box_changed (GtkComboBox * /*widget*/, GtkWidget blocked = TRUE; - SPColorSelector *csel = static_cast(g_object_get_data(G_OBJECT(tbl), "cselector")); + SelectedColor *csel = static_cast(g_object_get_data(G_OBJECT(tbl), "cselector")); // set its color, from the stored array - csel->base->setColorAlpha( stop->getEffectiveColor(), stop->opacity ); + g_object_set_data(G_OBJECT(tbl), "updating_color", reinterpret_cast(1)); + csel->setColorAlpha(stop->getEffectiveColor(), stop->opacity); + g_object_set_data(G_OBJECT(tbl), "updating_color", reinterpret_cast(0)); GtkWidget *offspin = GTK_WIDGET(g_object_get_data(G_OBJECT(tbl), "offspn")); GtkWidget *offslide =GTK_WIDGET(g_object_get_data(G_OBJECT(tbl), "offslide")); @@ -851,7 +856,7 @@ static void sp_grd_ed_del_stop(GtkWidget */*widget*/, GtkWidget *vb) static GtkWidget * sp_gradient_vector_widget_new(SPGradient *gradient, SPStop *select_stop) { - GtkWidget *vb, *w, *f, *csel; + GtkWidget *vb, *w, *f; g_return_val_if_fail(!gradient || SP_IS_GRADIENT(gradient), NULL); @@ -979,12 +984,23 @@ static GtkWidget * sp_gradient_vector_widget_new(SPGradient *gradient, SPStop *s f = gtk_frame_new(_("Stop Color")); gtk_widget_show(f); gtk_box_pack_start(GTK_BOX(vb), f, TRUE, TRUE, PAD); - csel = static_cast(sp_color_selector_new(SP_TYPE_COLOR_NOTEBOOK)); - g_object_set_data(G_OBJECT(vb), "cselector", csel); + + Inkscape::UI::SelectedColor *selected_color = new Inkscape::UI::SelectedColor; + g_object_set_data(G_OBJECT(vb), "cselector", selected_color); + g_object_set_data(G_OBJECT(vb), "updating_color", reinterpret_cast(0)); + selected_color->signal_dragged.connect(sigc::bind(sigc::ptr_fun(&sp_gradient_vector_color_dragged), selected_color, G_OBJECT(vb))); + selected_color->signal_dragged.connect(sigc::bind(sigc::ptr_fun(&sp_gradient_vector_color_changed), selected_color, G_OBJECT(vb))); + + Gtk::Widget *color_selector = Gtk::manage(ColorNotebook::create(*selected_color)); + color_selector->show(); + gtk_container_add(GTK_CONTAINER(f), color_selector->gobj()); + + /* gtk_widget_show(csel); gtk_container_add(GTK_CONTAINER(f), csel); g_signal_connect(G_OBJECT(csel), "dragged", G_CALLBACK(sp_gradient_vector_color_dragged), vb); g_signal_connect(G_OBJECT(csel), "changed", G_CALLBACK(sp_gradient_vector_color_changed), vb); + */ gtk_widget_show(vb); @@ -1130,9 +1146,11 @@ static void sp_gradient_vector_widget_load_gradient(GtkWidget *widget, SPGradien } // get the color selector - SPColorSelector *csel = SP_COLOR_SELECTOR(g_object_get_data(G_OBJECT(widget), "cselector")); + SelectedColor *csel = static_cast(g_object_get_data(G_OBJECT(widget), "cselector")); - csel->base->setColorAlpha( stop->getEffectiveColor(), stop->opacity ); + g_object_set_data(G_OBJECT(widget), "updating_color", reinterpret_cast(1)); + csel->setColorAlpha(stop->getEffectiveColor(), stop->opacity); + g_object_set_data(G_OBJECT(widget), "updating_color", reinterpret_cast(0)); /* Fill preview */ GtkWidget *w = static_cast(g_object_get_data(G_OBJECT(widget), "preview")); @@ -1210,6 +1228,12 @@ static void sp_gradient_vector_widget_destroy(GtkObject *object, gpointer /*data sp_repr_remove_listener_by_data(gradient->getRepr(), object); } } + + SelectedColor *selected_color = static_cast(g_object_get_data(G_OBJECT(object), "cselector")); + if (selected_color) { + delete selected_color; + g_object_set_data(G_OBJECT(object), "cselector", NULL); + } } static void sp_gradient_vector_gradient_release(SPObject */*object*/, GtkWidget *widget) @@ -1227,7 +1251,7 @@ static void sp_gradient_vector_gradient_modified(SPObject *object, guint /*flags } } -static void sp_gradient_vector_color_dragged(SPColorSelector *csel, GObject *object) +static void sp_gradient_vector_color_dragged(Inkscape::UI::SelectedColor *selected_color, GObject *object) { SPGradient *gradient, *ngr; @@ -1255,14 +1279,21 @@ static void sp_gradient_vector_color_dragged(SPColorSelector *csel, GObject *obj return; } - csel->base->getColorAlpha(stop->specified_color, stop->opacity); + selected_color->colorAlpha(stop->specified_color, stop->opacity); stop->currentColor = false; blocked = FALSE; } -static void sp_gradient_vector_color_changed(SPColorSelector *csel, GObject *object) +static void sp_gradient_vector_color_changed(Inkscape::UI::SelectedColor *selected_color, GObject *object) { + (void)selected_color; + + void* updating_color = g_object_get_data(G_OBJECT(object), "updating_color"); + if (updating_color) { + return; + } + if (blocked) { return; } @@ -1291,10 +1322,10 @@ static void sp_gradient_vector_color_changed(SPColorSelector *csel, GObject *obj return; } - csel = static_cast(g_object_get_data(G_OBJECT(object), "cselector")); + SelectedColor *csel = static_cast(g_object_get_data(G_OBJECT(object), "cselector")); SPColor color; float alpha = 0; - csel->base->getColorAlpha( color, alpha ); + csel->colorAlpha(color, alpha); sp_repr_set_css_double(stop->getRepr(), "offset", stop->offset); Inkscape::CSSOStringStream os; -- cgit v1.2.3 From 58637d547a0ce3a4a3bd64628e1a9095c6d3bd35 Mon Sep 17 00:00:00 2001 From: Tomasz Boczkowski Date: Sun, 1 Jun 2014 16:17:42 +0200 Subject: using ColorSelector in SPPaintSelector (bzr r13341.6.49) --- src/widgets/paint-selector.cpp | 84 ++++++++++++++++++++---------------------- src/widgets/paint-selector.h | 19 ++++++++-- 2 files changed, 56 insertions(+), 47 deletions(-) (limited to 'src') diff --git a/src/widgets/paint-selector.cpp b/src/widgets/paint-selector.cpp index 39336267b..274ad7bdf 100644 --- a/src/widgets/paint-selector.cpp +++ b/src/widgets/paint-selector.cpp @@ -60,6 +60,7 @@ #include using Inkscape::Widgets::SwatchSelector; +using Inkscape::UI::SelectedColor; enum { MODE_CHANGED, @@ -303,8 +304,13 @@ sp_paint_selector_init(SPPaintSelector *psel) /* Last used color */ - psel->color.set( 0.0, 0.0, 0.0 ); - psel->alpha = 1.0; + psel->selected_color = new SelectedColor; + psel->updating_color = false; + + psel->selected_color->signal_grabbed.connect(sigc::mem_fun(psel, &SPPaintSelector::onSelectedColorGrabbed)); + psel->selected_color->signal_grabbed.connect(sigc::mem_fun(psel, &SPPaintSelector::onSelectedColorDragged)); + psel->selected_color->signal_grabbed.connect(sigc::mem_fun(psel, &SPPaintSelector::onSelectedColorReleased)); + psel->selected_color->signal_grabbed.connect(sigc::mem_fun(psel, &SPPaintSelector::onSelectedColorChanged)); } static void sp_paint_selector_dispose(GObject *object) @@ -314,6 +320,11 @@ static void sp_paint_selector_dispose(GObject *object) // clean up our long-living pattern menu g_object_set_data(G_OBJECT(psel),"patternmenu",NULL); + if (psel->selected_color) { + delete psel->selected_color; + psel->selected_color = NULL; + } + if ((G_OBJECT_CLASS(parent_class))->dispose) (* (G_OBJECT_CLASS(parent_class))->dispose)(object); } @@ -446,7 +457,6 @@ void SPPaintSelector::setFillrule(FillRule fillrule) void SPPaintSelector::setColorAlpha(SPColor const &color, float alpha) { g_return_if_fail( ( 0.0 <= alpha ) && ( alpha <= 1.0 ) ); - SPColorSelector *csel = 0; /* guint32 rgba = 0; @@ -466,9 +476,10 @@ void SPPaintSelector::setColorAlpha(SPColor const &color, float alpha) setMode(MODE_COLOR_RGB); } - csel = reinterpret_cast(g_object_get_data(G_OBJECT(selector), "color-selector")); + updating_color = true; + selected_color->setColorAlpha(color, alpha); + updating_color = false; //rgba = color.toRGBA32( alpha ); - csel->base->setColorAlpha( color, alpha ); } void SPPaintSelector::setSwatch(SPGradient *vector ) @@ -534,11 +545,7 @@ void SPPaintSelector::getGradientProperties( SPGradientUnits &units, SPGradientS */ void SPPaintSelector::getColorAlpha(SPColor &color, gfloat &alpha) const { - SPColorSelector *csel; - - csel = reinterpret_cast(g_object_get_data(G_OBJECT(selector), "color-selector")); - - csel->base->getColorAlpha( color, alpha ); + selected_color->colorAlpha(color, alpha); g_assert( ( 0.0 <= alpha ) && ( alpha <= 1.0 ) ); @@ -626,39 +633,36 @@ sp_paint_selector_set_mode_none(SPPaintSelector *psel) /* Color paint */ -static void sp_paint_selector_color_grabbed(SPColorSelector * /*csel*/, SPPaintSelector *psel) -{ - g_signal_emit(G_OBJECT(psel), psel_signals[GRABBED], 0); +void SPPaintSelector::onSelectedColorGrabbed() { + g_signal_emit(G_OBJECT(this), psel_signals[GRABBED], 0); } -static void sp_paint_selector_color_dragged(SPColorSelector * /*csel*/, SPPaintSelector *psel) -{ - g_signal_emit(G_OBJECT(psel), psel_signals[DRAGGED], 0); +void SPPaintSelector::onSelectedColorDragged() { + if (updating_color) { + return; + } + g_signal_emit(G_OBJECT(this), psel_signals[DRAGGED], 0); } -static void sp_paint_selector_color_released(SPColorSelector * /*csel*/, SPPaintSelector *psel) -{ - g_signal_emit(G_OBJECT(psel), psel_signals[RELEASED], 0); +void SPPaintSelector::onSelectedColorReleased() { + g_signal_emit(G_OBJECT(this), psel_signals[RELEASED], 0); } -static void -sp_paint_selector_color_changed(SPColorSelector *csel, SPPaintSelector *psel) -{ - csel->base->getColorAlpha( psel->color, psel->alpha ); - - g_signal_emit(G_OBJECT(psel), psel_signals[CHANGED], 0); +void SPPaintSelector::onSelectedColorChanged() { + if (updating_color) { + return; + } + g_signal_emit(G_OBJECT(this), psel_signals[CHANGED], 0); } static void sp_paint_selector_set_mode_color(SPPaintSelector *psel, SPPaintSelector::Mode /*mode*/) { - GtkWidget *csel; - sp_paint_selector_set_style_buttons(psel, psel->solid); gtk_widget_set_sensitive(psel->style, TRUE); if ((psel->mode == SPPaintSelector::MODE_COLOR_RGB) || (psel->mode == SPPaintSelector::MODE_COLOR_CMYK)) { /* Already have color selector */ - csel = GTK_WIDGET(g_object_get_data(G_OBJECT(psel->selector), "color-selector")); + // Do nothing } else { sp_paint_selector_clear_frame(psel); @@ -673,22 +677,14 @@ static void sp_paint_selector_set_mode_color(SPPaintSelector *psel, SPPaintSelec gtk_widget_show(vb); /* Color selector */ - csel = sp_color_selector_new( SP_TYPE_COLOR_NOTEBOOK ); - gtk_widget_show(csel); - g_object_set_data(G_OBJECT(vb), "color-selector", csel); - gtk_box_pack_start(GTK_BOX(vb), csel, TRUE, TRUE, 0); - g_signal_connect(G_OBJECT(csel), "grabbed", G_CALLBACK(sp_paint_selector_color_grabbed), psel); - g_signal_connect(G_OBJECT(csel), "dragged", G_CALLBACK(sp_paint_selector_color_dragged), psel); - g_signal_connect(G_OBJECT(csel), "released", G_CALLBACK(sp_paint_selector_color_released), psel); - g_signal_connect(G_OBJECT(csel), "changed", G_CALLBACK(sp_paint_selector_color_changed), psel); + Gtk::Widget *color_selector = Gtk::manage(ColorNotebook::create(*(psel->selected_color))); + color_selector->show(); + gtk_box_pack_start(GTK_BOX(vb), color_selector->gobj(), TRUE, TRUE, 0); + /* Pack everything to frame */ gtk_container_add(GTK_CONTAINER(psel->frame), vb); psel->selector = vb; - - /* Set color */ - SP_COLOR_SELECTOR( csel )->base->setColorAlpha( psel->color, psel->alpha ); - } gtk_label_set_markup(GTK_LABEL(psel->label), _("Flat color")); @@ -700,22 +696,22 @@ static void sp_paint_selector_set_mode_color(SPPaintSelector *psel, SPPaintSelec /* Gradient */ -static void sp_paint_selector_gradient_grabbed(SPColorSelector * /*csel*/, SPPaintSelector *psel) +static void sp_paint_selector_gradient_grabbed(SPGradientSelector * /*csel*/, SPPaintSelector *psel) { g_signal_emit(G_OBJECT(psel), psel_signals[GRABBED], 0); } -static void sp_paint_selector_gradient_dragged(SPColorSelector * /*csel*/, SPPaintSelector *psel) +static void sp_paint_selector_gradient_dragged(SPGradientSelector * /*csel*/, SPPaintSelector *psel) { g_signal_emit(G_OBJECT(psel), psel_signals[DRAGGED], 0); } -static void sp_paint_selector_gradient_released(SPColorSelector * /*csel*/, SPPaintSelector *psel) +static void sp_paint_selector_gradient_released(SPGradientSelector * /*csel*/, SPPaintSelector *psel) { g_signal_emit(G_OBJECT(psel), psel_signals[RELEASED], 0); } -static void sp_paint_selector_gradient_changed(SPColorSelector * /*csel*/, SPPaintSelector *psel) +static void sp_paint_selector_gradient_changed(SPGradientSelector * /*csel*/, SPPaintSelector *psel) { g_signal_emit(G_OBJECT(psel), psel_signals[CHANGED], 0); } diff --git a/src/widgets/paint-selector.h b/src/widgets/paint-selector.h index d6ad3f50c..c151be526 100644 --- a/src/widgets/paint-selector.h +++ b/src/widgets/paint-selector.h @@ -12,6 +12,14 @@ * */ +#ifdef HAVE_CONFIG_H +# include +#endif + +#if GLIBMM_DISABLE_DEPRECATED && HAVE_GLIBMM_THREADS_H +#include +#endif + #include #include @@ -19,6 +27,7 @@ #include "fill-or-stroke.h" #include "sp-gradient-spread.h" #include "sp-gradient-units.h" +#include "ui/selected-color.h" class SPGradient; class SPDesktop; @@ -74,9 +83,8 @@ struct SPPaintSelector { GtkWidget *frame, *selector; GtkWidget *label; - SPColor color; - float alpha; - + Inkscape::UI::SelectedColor *selected_color; + bool updating_color; static Mode getModeForStyle(SPStyle const & style, FillOrStroke kind); @@ -102,6 +110,11 @@ struct SPPaintSelector { // TODO move this elsewhere: void setFlatColor( SPDesktop *desktop, const gchar *color_property, const gchar *opacity_property ); + + void onSelectedColorGrabbed(); + void onSelectedColorDragged(); + void onSelectedColorReleased(); + void onSelectedColorChanged(); }; enum {COMBO_COL_LABEL=0, COMBO_COL_STOCK=1, COMBO_COL_PATTERN=2, COMBO_COL_SEP=3, COMBO_N_COLS=4}; -- cgit v1.2.3 From 65782d9a28fe5745e672b33c005edfda715c2ed8 Mon Sep 17 00:00:00 2001 From: Tomasz Boczkowski Date: Sun, 1 Jun 2014 16:41:20 +0200 Subject: using ColorSelector in SwatchSelector (bzr r13341.6.50) --- src/widgets/swatch-selector.cpp | 102 +++++++++++++++++----------------------- src/widgets/swatch-selector.h | 12 +++-- 2 files changed, 51 insertions(+), 63 deletions(-) (limited to 'src') diff --git a/src/widgets/swatch-selector.cpp b/src/widgets/swatch-selector.cpp index 7178ad072..b7de6657c 100644 --- a/src/widgets/swatch-selector.cpp +++ b/src/widgets/swatch-selector.cpp @@ -20,7 +20,7 @@ namespace Widgets SwatchSelector::SwatchSelector() : Gtk::VBox(), _gsel(0), - _csel(0) + _updating_color(false) { GtkWidget *gsel = sp_gradient_selector_new(); _gsel = SP_GRADIENT_SELECTOR(gsel); @@ -31,27 +31,18 @@ SwatchSelector::SwatchSelector() : pack_start(*Gtk::manage(Glib::wrap(gsel))); + Gtk::Widget *color_selector = Gtk::manage(ColorNotebook::create(_selected_color)); + color_selector->show(); + pack_start(*color_selector); - GtkWidget *csel = sp_color_selector_new( SP_TYPE_COLOR_NOTEBOOK ); - _csel = SP_COLOR_SELECTOR(csel); - Gtk::Widget *wrappedCSel = Glib::wrap(csel); - wrappedCSel->show(); - //gtk_widget_show(csel); - - - GObject *obj = G_OBJECT(csel); - - g_signal_connect(obj, "grabbed", G_CALLBACK(_grabbedCb), this); - g_signal_connect(obj, "dragged", G_CALLBACK(_draggedCb), this); - g_signal_connect(obj, "released", G_CALLBACK(_releasedCb), this); - g_signal_connect(obj, "changed", G_CALLBACK(_changedCb), this); - - pack_start(*Gtk::manage(wrappedCSel)); + _selected_color.signal_grabbed.connect(sigc::mem_fun(this, &SwatchSelector::_grabbedCb)); + _selected_color.signal_dragged.connect(sigc::mem_fun(this, &SwatchSelector::_draggedCb)); + _selected_color.signal_released.connect(sigc::mem_fun(this, &SwatchSelector::_releasedCb)); + _selected_color.signal_changed.connect(sigc::mem_fun(this, &SwatchSelector::_changedCb)); } SwatchSelector::~SwatchSelector() { - _csel = 0; // dtor should be handled by Gtk::manage() _gsel = 0; } @@ -60,13 +51,13 @@ SPGradientSelector *SwatchSelector::getGradientSelector() return _gsel; } -void SwatchSelector::_grabbedCb(SPColorSelector * /*csel*/, void * /*data*/) +void SwatchSelector::_grabbedCb() { } -void SwatchSelector::_draggedCb(SPColorSelector * /*csel*/, void *data) +void SwatchSelector::_draggedCb() { - if (data) { + // if (data) { //SwatchSelector *swsel = reinterpret_cast(data); // TODO might have to block cycles @@ -92,50 +83,46 @@ void SwatchSelector::_draggedCb(SPColorSelector * /*csel*/, void *data) } } */ - } + // } } -void SwatchSelector::_releasedCb(SPColorSelector * /*csel*/, void * /*data*/) +void SwatchSelector::_releasedCb() { } -void SwatchSelector::_changedCb(SPColorSelector */*csel*/, void *data) +void SwatchSelector::_changedCb() { - if (data) { - SwatchSelector *swsel = reinterpret_cast(data); + if (_updating_color) { + return; + } + // TODO might have to block cycles + + if (_gsel && _gsel->getVector()) { + SPGradient *gradient = _gsel->getVector(); + SPGradient *ngr = sp_gradient_ensure_vector_normalized(gradient); + if (ngr != gradient) { + /* Our master gradient has changed */ + // TODO replace with proper - sp_gradient_vector_widget_load_gradient(GTK_WIDGET(swsel->_gsel), ngr); + } - // TODO might have to block cycles + ngr->ensureVector(); - if (swsel->_gsel && swsel->_gsel->getVector()) { - SPGradient *gradient = swsel->_gsel->getVector(); - SPGradient *ngr = sp_gradient_ensure_vector_normalized(gradient); - if (ngr != gradient) { - /* Our master gradient has changed */ - // TODO replace with proper - sp_gradient_vector_widget_load_gradient(GTK_WIDGET(swsel->_gsel), ngr); - } - ngr->ensureVector(); + SPStop* stop = ngr->getFirstStop(); + if (stop) { + SPColor color = _selected_color.color(); + gfloat alpha = _selected_color.alpha(); + guint32 rgb = color.toRGBA32( 0x00 ); + // TODO replace with generic shared code that also handles icc-color + Inkscape::CSSOStringStream os; + gchar c[64]; + sp_svg_write_color(c, sizeof(c), rgb); + os << "stop-color:" << c << ";stop-opacity:" << static_cast(alpha) <<";"; + stop->getRepr()->setAttribute("style", os.str().c_str()); - SPStop* stop = ngr->getFirstStop(); - if (stop) { - SPColor color; - float alpha = 0; - guint32 rgb = 0; - - swsel->_csel->base->getColorAlpha( color, alpha ); - rgb = color.toRGBA32( 0x00 ); - - // TODO replace with generic shared code that also handles icc-color - Inkscape::CSSOStringStream os; - gchar c[64]; - sp_svg_write_color(c, sizeof(c), rgb); - os << "stop-color:" << c << ";stop-opacity:" << static_cast(alpha) <<";"; - stop->getRepr()->setAttribute("style", os.str().c_str()); - - DocumentUndo::done(ngr->document, SP_VERB_CONTEXT_GRADIENT, - _("Change swatch color")); - } + DocumentUndo::done(ngr->document, SP_VERB_CONTEXT_GRADIENT, + _("Change swatch color")); } } } @@ -173,11 +160,10 @@ void SwatchSelector::setVector(SPDocument */*doc*/, SPGradient *vector) SPStop* stop = vector->getFirstStop(); guint32 const colorVal = stop->get_rgba32(); - _csel->base->setAlpha(SP_RGBA32_A_F(colorVal)); - SPColor color( SP_RGBA32_R_F(colorVal), SP_RGBA32_G_F(colorVal), SP_RGBA32_B_F(colorVal) ); - // set its color, from the stored array - _csel->base->setColor( color ); - gtk_widget_show_all( GTK_WIDGET(_csel) ); + _updating_color = true; + _selected_color.setValue(colorVal); + _updating_color = false; + // gtk_widget_show_all( GTK_WIDGET(_csel) ); } else { //gtk_widget_hide( GTK_WIDGET(_csel) ); } diff --git a/src/widgets/swatch-selector.h b/src/widgets/swatch-selector.h index c8c9983a6..d447fff37 100644 --- a/src/widgets/swatch-selector.h +++ b/src/widgets/swatch-selector.h @@ -10,6 +10,7 @@ #endif #include +#include "ui/selected-color.h" class SPDocument; class SPGradient; @@ -37,13 +38,14 @@ public: SPGradientSelector *getGradientSelector(); private: - static void _grabbedCb(SPColorSelector *csel, void *data); - static void _draggedCb(SPColorSelector *csel, void *data); - static void _releasedCb(SPColorSelector *csel, void *data); - static void _changedCb(SPColorSelector *csel, void *data); + void _grabbedCb(); + void _draggedCb(); + void _releasedCb(); + void _changedCb(); SPGradientSelector *_gsel; - SPColorSelector *_csel; + Inkscape::UI::SelectedColor _selected_color; + bool _updating_color; }; -- cgit v1.2.3 From 66275a3a9f7666fe68355c1d8c452395b706db30 Mon Sep 17 00:00:00 2001 From: Tomasz Boczkowski Date: Sun, 1 Jun 2014 17:29:01 +0200 Subject: moved ColorNotebook to ui/widget (bzr r13341.6.51) --- src/extension/param/color.cpp | 2 +- src/extension/param/parameter.cpp | 3 +- src/ui/CMakeLists.txt | 2 + src/ui/widget/Makefile_insert | 2 + src/ui/widget/color-notebook.cpp | 675 ++++++++++++++++++++++++++++++++++++++ src/ui/widget/color-notebook.h | 150 +++++++++ src/ui/widget/color-picker.cpp | 2 +- src/widgets/CMakeLists.txt | 2 - src/widgets/Makefile_insert | 2 - src/widgets/gradient-vector.cpp | 4 +- src/widgets/paint-selector.cpp | 2 +- src/widgets/sp-color-notebook.cpp | 675 -------------------------------------- src/widgets/sp-color-notebook.h | 150 --------- src/widgets/swatch-selector.cpp | 2 +- 14 files changed, 836 insertions(+), 837 deletions(-) create mode 100644 src/ui/widget/color-notebook.cpp create mode 100644 src/ui/widget/color-notebook.h delete mode 100644 src/widgets/sp-color-notebook.cpp delete mode 100644 src/widgets/sp-color-notebook.h (limited to 'src') diff --git a/src/extension/param/color.cpp b/src/extension/param/color.cpp index 5b2a4ad0c..6748c8f5f 100644 --- a/src/extension/param/color.cpp +++ b/src/extension/param/color.cpp @@ -29,7 +29,7 @@ #include #include "widgets/sp-color-selector.h" -#include "widgets/sp-color-notebook.h" +#include "ui/widget/color-notebook.h" #include "preferences.h" diff --git a/src/extension/param/parameter.cpp b/src/extension/param/parameter.cpp index b18525215..8c99ee55d 100644 --- a/src/extension/param/parameter.cpp +++ b/src/extension/param/parameter.cpp @@ -30,8 +30,7 @@ #include "document-private.h" #include "sp-object.h" #include -#include "widgets/sp-color-selector.h" -#include "widgets/sp-color-notebook.h" +#include "ui/widget/color-notebook.h" #include "parameter.h" #include "bool.h" diff --git a/src/ui/CMakeLists.txt b/src/ui/CMakeLists.txt index dbfba0508..45b4c7960 100644 --- a/src/ui/CMakeLists.txt +++ b/src/ui/CMakeLists.txt @@ -110,6 +110,7 @@ set(ui_SRC widget/button.cpp widget/color-entry.cpp widget/color-icc-selector.cpp + widget/color-notebook.cpp widget/color-picker.cpp widget/color-preview.cpp widget/color-scales.cpp @@ -277,6 +278,7 @@ set(ui_SRC widget/button.h widget/color-entry.h widget/color-icc-selector.h + widget/color-notebook.h widget/color-picker.h widget/color-preview.h widget/color-scales.h diff --git a/src/ui/widget/Makefile_insert b/src/ui/widget/Makefile_insert index f39236da7..ddb641069 100644 --- a/src/ui/widget/Makefile_insert +++ b/src/ui/widget/Makefile_insert @@ -10,6 +10,8 @@ ink_common_sources += \ ui/widget/color-entry.h \ ui/widget/color-icc-selector.cpp \ ui/widget/color-icc-selector.h \ + ui/widget/color-notebook.cpp \ + ui/widget/color-notebook.h \ ui/widget/color-wheel-selector.cpp \ ui/widget/color-wheel-selector.h \ ui/widget/color-picker.cpp \ diff --git a/src/ui/widget/color-notebook.cpp b/src/ui/widget/color-notebook.cpp new file mode 100644 index 000000000..2b592e620 --- /dev/null +++ b/src/ui/widget/color-notebook.cpp @@ -0,0 +1,675 @@ +/* + * A notebook with RGB, CMYK, CMS, HSL, and Wheel pages + * + * Author: + * Lauris Kaplinski + * bulia byak + * + * Copyright (C) 2001-2002 Lauris Kaplinski + * + * This code is in public domain + */ + +#undef SPCS_PREVIEW +#define noDUMP_CHANGE_INFO + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include "widgets/icon.h" +#include +#include +#include +#include +#include +#include +#include + +#include "dialogs/dialog-events.h" +#include "preferences.h" +#include "widgets/spw-utilities.h" +#include "svg/svg-icc-color.h" +#include "inkscape.h" +#include "document.h" +#include "profile-manager.h" +#include "color-profile.h" +#include "cms-system.h" +#include "tools-switch.h" +#include "ui/tools/tool-base.h" +#include "ui/widget/color-entry.h" +#include "ui/widget/color-icc-selector.h" +#include "ui/widget/color-notebook.h" +#include "ui/widget/color-scales.h" +#include "ui/widget/color-wheel-selector.h" + +using Inkscape::CMSSystem; + +using namespace Inkscape::UI; +using namespace Inkscape::UI::Widget; + +struct SPColorNotebookTracker { + const gchar* name; + const gchar* className; + GType type; + guint submode; + gboolean enabledFull; + gboolean enabledBrief; + SPColorNotebook *backPointer; +}; + + +static void sp_color_notebook_class_init (SPColorNotebookClass *klass); +static void sp_color_notebook_init (SPColorNotebook *colorbook); +static void sp_color_notebook_dispose(GObject *object); + +static void sp_color_notebook_show_all (GtkWidget *widget); +static void sp_color_notebook_hide(GtkWidget *widget); + +static SPColorSelectorClass *parent_class; + +#define XPAD 4 +#define YPAD 1 + +GType sp_color_notebook_get_type(void) +{ + static GType type = 0; + if (!type) { + GTypeInfo info = { + sizeof(SPColorNotebookClass), + 0, // base_init + 0, // base_finalize + (GClassInitFunc)sp_color_notebook_class_init, + 0, // class_finalize + 0, // class_data + sizeof(SPColorNotebook), + 0, // n_preallocs + (GInstanceInitFunc)sp_color_notebook_init, + 0 // value_table + }; + type = g_type_register_static(SP_TYPE_COLOR_SELECTOR, "SPColorNotebook", &info, static_cast(0)); + } + return type; +} + +static void sp_color_notebook_class_init(SPColorNotebookClass *klass) +{ + GObjectClass *object_class = reinterpret_cast(klass); + GtkWidgetClass *widget_class = reinterpret_cast(klass); + + parent_class = SP_COLOR_SELECTOR_CLASS(g_type_class_peek_parent(klass)); + + object_class->dispose = sp_color_notebook_dispose; + + widget_class->show_all = sp_color_notebook_show_all; + widget_class->hide = sp_color_notebook_hide; +} + +static void +sp_color_notebook_switch_page(GtkNotebook *notebook, + GtkWidget *page, + guint page_num, + SPColorNotebook *colorbook) +{ + if ( colorbook ) + { + // remember the page we switched to + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + prefs->setInt("/colorselector/page", page_num); + } +} + +static void +sp_color_notebook_init (SPColorNotebook *colorbook) +{ + SP_COLOR_SELECTOR(colorbook)->base = new ColorNotebook( SP_COLOR_SELECTOR(colorbook) ); + + if ( SP_COLOR_SELECTOR(colorbook)->base ) + { + SP_COLOR_SELECTOR(colorbook)->base->init(); + } +} + +void ColorNotebook::init() +{ + guint row = 0; + + _updating = false; + + _book = gtk_notebook_new (); + gtk_widget_show (_book); + + // Dont show the notebook tabs, use radiobuttons instead + gtk_notebook_set_show_border (GTK_NOTEBOOK (_book), false); + gtk_notebook_set_show_tabs (GTK_NOTEBOOK (_book), false); + +#if GTK_CHECK_VERSION(3,0,0) + _buttonbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 2); + gtk_box_set_homogeneous(GTK_BOX(_buttonbox), TRUE); +#else + _buttonbox = gtk_hbox_new (TRUE, 2); +#endif + + gtk_widget_show (_buttonbox); + _buttons = new GtkWidget *[_available_pages.size()]; + + for (int i = 0; static_cast(i) < _available_pages.size(); i++ ) + { + _addPage(_available_pages[i]); + } + +#if GTK_CHECK_VERSION(3,0,0) + GtkWidget* table = gtk_grid_new(); +#else + GtkWidget* table = gtk_table_new(2, 3, FALSE); +#endif + + gtk_widget_show (table); + + gtk_box_pack_start (GTK_BOX (_csel), table, TRUE, TRUE, 0); + + sp_set_font_size_smaller (_buttonbox); + +#if GTK_CHECK_VERSION(3,0,0) + gtk_widget_set_margin_left(_buttonbox, XPAD); + gtk_widget_set_margin_right(_buttonbox, XPAD); + gtk_widget_set_margin_top(_buttonbox, YPAD); + gtk_widget_set_margin_bottom(_buttonbox, YPAD); + gtk_widget_set_hexpand(_buttonbox, TRUE); + gtk_widget_set_valign(_buttonbox, GTK_ALIGN_CENTER); + gtk_grid_attach(GTK_GRID(table), _buttonbox, 0, row, 2, 1); +#else + gtk_table_attach (GTK_TABLE (table), _buttonbox, 0, 2, row, row + 1, + static_cast(GTK_EXPAND|GTK_FILL), + static_cast(0), + XPAD, YPAD); +#endif + + row++; + +#if GTK_CHECK_VERSION(3,0,0) + gtk_widget_set_margin_left(_book, XPAD*2); + gtk_widget_set_margin_right(_book, XPAD*2); + gtk_widget_set_margin_top(_book, YPAD); + gtk_widget_set_margin_bottom(_book, YPAD); + gtk_widget_set_hexpand(_book, TRUE); + gtk_widget_set_vexpand(_book, TRUE); + gtk_grid_attach(GTK_GRID(table), _book, 0, row, 2, 1); +#else + gtk_table_attach (GTK_TABLE (table), _book, 0, 2, row, row + 1, + static_cast(GTK_EXPAND|GTK_FILL), + static_cast(GTK_EXPAND|GTK_FILL), + XPAD*2, YPAD); +#endif + + // restore the last active page + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + _setCurrentPage(prefs->getInt("/colorselector/page", 0)); + + + /* Commented out: see comment at the bottom of the header file + { + gboolean found = FALSE; + + _popup = gtk_menu_new(); + GtkMenu *menu = GTK_MENU (_popup); + + for (int i = 0; i < _trackerList->len; i++ ) + { + SPColorNotebookTracker *entry = reinterpret_cast< SPColorNotebookTracker* > (g_ptr_array_index (_trackerList, i)); + if ( entry ) + { + GtkWidget *item = gtk_check_menu_item_new_with_label (_(entry->name)); + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), entry->enabledFull); + gtk_widget_show (item); + gtk_menu_shell_append (GTK_MENU_SHELL(menu), item); + + g_signal_connect (G_OBJECT (item), "activate", + G_CALLBACK (sp_color_notebook_menuitem_response), + reinterpret_cast< gpointer > (entry) ); + found = TRUE; + } + } + + GtkWidget *arrow = gtk_arrow_new(GTK_ARROW_RIGHT, GTK_SHADOW_NONE); + gtk_widget_show (arrow); + + _btn = gtk_button_new (); + gtk_widget_show (_btn); + gtk_container_add (GTK_CONTAINER (_btn), arrow); + + GtkWidget *align = gtk_alignment_new (1.0, 0.0, 0.0, 0.0); + gtk_widget_show (align); + gtk_container_add (GTK_CONTAINER (align), _btn); + + // uncomment to reenable the "show/hide modes" menu, + // but first fix it so it remembers its settings in prefs and does not take that much space (entire vertical column!) + gtk_table_attach (GTK_TABLE (table), align, 2, 3, row, row + 1, GTK_FILL, GTK_FILL, XPAD, YPAD); + + g_signal_connect_swapped(G_OBJECT(_btn), "event", G_CALLBACK (sp_color_notebook_menu_handler), G_OBJECT(_csel)); + if ( !found ) + { + gtk_widget_set_sensitive (_btn, FALSE); + } + } + */ + + row++; + +#if GTK_CHECK_VERSION(3,0,0) + GtkWidget *rgbabox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0); +#else + GtkWidget *rgbabox = gtk_hbox_new (FALSE, 0); +#endif + +#if defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) + /* Create color management icons */ + _box_colormanaged = gtk_event_box_new (); + GtkWidget *colormanaged = gtk_image_new_from_icon_name ("color-management-icon", GTK_ICON_SIZE_SMALL_TOOLBAR); + gtk_container_add (GTK_CONTAINER (_box_colormanaged), colormanaged); + gtk_widget_set_tooltip_text (_box_colormanaged, _("Color Managed")); + gtk_widget_set_sensitive (_box_colormanaged, false); + gtk_box_pack_start(GTK_BOX(rgbabox), _box_colormanaged, FALSE, FALSE, 2); + + _box_outofgamut = gtk_event_box_new (); + GtkWidget *outofgamut = gtk_image_new_from_icon_name ("out-of-gamut-icon", GTK_ICON_SIZE_SMALL_TOOLBAR); + gtk_container_add (GTK_CONTAINER (_box_outofgamut), outofgamut); + gtk_widget_set_tooltip_text (_box_outofgamut, _("Out of gamut!")); + gtk_widget_set_sensitive (_box_outofgamut, false); + gtk_box_pack_start(GTK_BOX(rgbabox), _box_outofgamut, FALSE, FALSE, 2); + + _box_toomuchink = gtk_event_box_new (); + GtkWidget *toomuchink = gtk_image_new_from_icon_name ("too-much-ink-icon", GTK_ICON_SIZE_SMALL_TOOLBAR); + gtk_container_add (GTK_CONTAINER (_box_toomuchink), toomuchink); + gtk_widget_set_tooltip_text (_box_toomuchink, _("Too much ink!")); + gtk_widget_set_sensitive (_box_toomuchink, false); + gtk_box_pack_start(GTK_BOX(rgbabox), _box_toomuchink, FALSE, FALSE, 2); +#endif //defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) + + + /* Color picker */ + GtkWidget *picker = gtk_image_new_from_icon_name ("color-picker", GTK_ICON_SIZE_SMALL_TOOLBAR); + _btn_picker = gtk_button_new (); + gtk_button_set_relief(GTK_BUTTON(_btn_picker), GTK_RELIEF_NONE); + gtk_container_add (GTK_CONTAINER (_btn_picker), picker); + gtk_widget_set_tooltip_text (_btn_picker, _("Pick colors from image")); + gtk_box_pack_start(GTK_BOX(rgbabox), _btn_picker, FALSE, FALSE, 2); + g_signal_connect(G_OBJECT(_btn_picker), "clicked", G_CALLBACK(ColorNotebook::_picker_clicked), _csel); + + /* Create RGBA entry and color preview */ + _rgbal = gtk_label_new_with_mnemonic (_("RGBA_:")); + gtk_misc_set_alignment (GTK_MISC (_rgbal), 1.0, 0.5); + gtk_box_pack_start(GTK_BOX(rgbabox), _rgbal, TRUE, TRUE, 2); + + ColorEntry* rgba_entry = Gtk::manage(new ColorEntry(_selected_color)); + sp_dialog_defocus_on_enter (GTK_WIDGET(rgba_entry->gobj())); + gtk_box_pack_start(GTK_BOX(rgbabox), GTK_WIDGET(rgba_entry->gobj()), FALSE, FALSE, 0); + gtk_label_set_mnemonic_widget (GTK_LABEL(_rgbal), GTK_WIDGET(rgba_entry->gobj())); + + sp_set_font_size_smaller (rgbabox); + gtk_widget_show_all (rgbabox); + +#if defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) + //the "too much ink" icon is initially hidden + gtk_widget_hide(GTK_WIDGET(_box_toomuchink)); +#endif //defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) + +#if GTK_CHECK_VERSION(3,0,0) + gtk_widget_set_margin_left(rgbabox, XPAD); + gtk_widget_set_margin_right(rgbabox, XPAD); + gtk_widget_set_margin_top(rgbabox, YPAD); + gtk_widget_set_margin_bottom(rgbabox, YPAD); + gtk_grid_attach(GTK_GRID(table), rgbabox, 0, row, 2, 1); +#else + gtk_table_attach (GTK_TABLE (table), rgbabox, 0, 2, row, row + 1, GTK_FILL, GTK_SHRINK, XPAD, YPAD); +#endif + +#ifdef SPCS_PREVIEW + _p = sp_color_preview_new (0xffffffff); + gtk_widget_show (_p); + gtk_table_attach (GTK_TABLE (table), _p, 2, 3, row, row + 1, GTK_FILL, GTK_FILL, XPAD, YPAD); +#endif + + _switchId = g_signal_connect(G_OBJECT (_book), "switch-page", + G_CALLBACK (sp_color_notebook_switch_page), SP_COLOR_NOTEBOOK(_csel)); + + _selected_color.signal_changed.connect(sigc::mem_fun(this, &ColorNotebook::_onSelectedColorChanged)); + _selected_color.signal_dragged.connect(sigc::mem_fun(this, &ColorNotebook::_onSelectedColorDragged)); + _selected_color.signal_grabbed.connect(sigc::mem_fun(this, &ColorNotebook::_onSelectedColorGrabbed)); + _selected_color.signal_released.connect(sigc::mem_fun(this, &ColorNotebook::_onSelectedColorReleased)); +} + +static void sp_color_notebook_dispose(GObject *object) +{ + if (((GObjectClass *) (parent_class))->dispose) + (* ((GObjectClass *) (parent_class))->dispose) (object); +} + +ColorNotebook::~ColorNotebook() +{ + if ( _switchId ) + { + if ( _book ) + { + g_signal_handler_disconnect (_book, _switchId); + _switchId = 0; + } + } + + if ( _buttons ) + { + delete [] _buttons; + _buttons = 0; + } + +} + +static void +sp_color_notebook_show_all (GtkWidget *widget) +{ + gtk_widget_show (widget); +} + +static void sp_color_notebook_hide(GtkWidget *widget) +{ + gtk_widget_hide(widget); +} + +GtkWidget *sp_color_notebook_new() +{ + SPColorNotebook *colorbook = SP_COLOR_NOTEBOOK(g_object_new (SP_TYPE_COLOR_NOTEBOOK, NULL)); + + return GTK_WIDGET(colorbook); +} + +ColorNotebook::ColorNotebook( SPColorSelector* csel ) + : ColorSelector( csel ) + , _selected_color(_selected_color_tmp) +{ + Page *page; + + page = new Page(new ColorScalesFactory(SP_COLOR_SCALES_MODE_RGB), true); + _available_pages.push_back(page); + page = new Page(new ColorScalesFactory(SP_COLOR_SCALES_MODE_HSV), true); + _available_pages.push_back(page); + page = new Page(new ColorScalesFactory(SP_COLOR_SCALES_MODE_CMYK), true); + _available_pages.push_back(page); + page = new Page(new ColorWheelSelectorFactory, true); + _available_pages.push_back(page); +#if defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) + page = new Page(new ColorICCSelectorFactory, true); + _available_pages.push_back(page); +#endif +} + +Gtk::Widget *ColorNotebook::create(SelectedColor &color) { + GtkWidget *w = sp_color_selector_new(SP_TYPE_COLOR_NOTEBOOK); + SPColorSelector *s = SP_COLOR_SELECTOR(w); + ColorNotebook* nb = dynamic_cast(s->base); + return Glib::wrap(w); +} + +ColorNotebook::Page::Page(Inkscape::UI::ColorSelectorFactory *selector_factory, bool enabled_full) + : selector_factory(selector_factory) + , enabled_full(enabled_full) +{ +} + +void ColorNotebook::_colorChanged() +{ + _updating = true; + _selected_color.setColorAlpha(_color, _alpha); + _updateICCButtons(); + _updating = false; +} + +void ColorNotebook::_picker_clicked(GtkWidget * /*widget*/, SPColorNotebook * /*colorbook*/) +{ + // Set the dropper into a "one click" mode, so it reverts to the previous tool after a click + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + prefs->setBool("/tools/dropper/onetimepick", true); + Inkscape::UI::Tools::sp_toggle_dropper(SP_ACTIVE_DESKTOP); +} + +// TODO pass in param so as to avoid the need for SP_ACTIVE_DOCUMENT +void ColorNotebook::_updateICCButtons() +{ + SPColor color = _selected_color.color(); + gfloat alpha = _selected_color.alpha(); + + g_return_if_fail( ( 0.0 <= alpha ) && ( alpha <= 1.0 ) ); + +#if defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) + /* update color management icon*/ + gtk_widget_set_sensitive (_box_colormanaged, color.icc != NULL); + + /* update out-of-gamut icon */ + gtk_widget_set_sensitive (_box_outofgamut, false); + if (color.icc){ + Inkscape::ColorProfile* target_profile = SP_ACTIVE_DOCUMENT->profileManager->find(color.icc->colorProfile.c_str()); + if ( target_profile ) + gtk_widget_set_sensitive(_box_outofgamut, target_profile->GamutCheck(color)); + } + + /* update too-much-ink icon */ + gtk_widget_set_sensitive (_box_toomuchink, false); + if (color.icc){ + Inkscape::ColorProfile* prof = SP_ACTIVE_DOCUMENT->profileManager->find(color.icc->colorProfile.c_str()); + if ( prof && CMSSystem::isPrintColorSpace(prof) ) { + gtk_widget_show(GTK_WIDGET(_box_toomuchink)); + double ink_sum = 0; + for (unsigned int i=0; icolors.size(); i++){ + ink_sum += color.icc->colors[i]; + } + + /* Some literature states that when the sum of paint values exceed 320%, it is considered to be a satured color, + which means the paper can get too wet due to an excessive ammount of ink. This may lead to several issues + such as misalignment and poor quality of printing in general.*/ + if ( ink_sum > 3.2 ) + gtk_widget_set_sensitive (_box_toomuchink, true); + } else { + gtk_widget_hide(GTK_WIDGET(_box_toomuchink)); + } + } +#endif //defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) +} + +void ColorNotebook::_setCurrentPage(int i) +{ + gtk_notebook_set_current_page(GTK_NOTEBOOK(_book), i); + + if (_buttons && (static_cast(i) < _available_pages.size())) { + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(_buttons[i]), TRUE); + } +} + +void ColorNotebook::_buttonClicked(GtkWidget *widget, SPColorNotebook *colorbook) +{ + ColorNotebook* nb = dynamic_cast(SP_COLOR_SELECTOR(colorbook)->base); + + if (!gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(widget))) { + return; + } + + for(gint i = 0; i < gtk_notebook_get_n_pages (GTK_NOTEBOOK (nb->_book)); i++) { + if (nb->_buttons[i] == widget) { + gtk_notebook_set_current_page (GTK_NOTEBOOK (nb->_book), i); + } + } +} + +void ColorNotebook::_onSelectedColorChanged() { + if (_updating) { + return; + } + + SPColor color; + gfloat alpha = 1.0; + _selected_color.colorAlpha(color, alpha); + _updateInternals(color, alpha, false); + _updateICCButtons(); +} + +void ColorNotebook::_onSelectedColorDragged() { + if (_updating) { + return; + } + SPColor color; + gfloat alpha = 1.0; + _selected_color.colorAlpha(color, alpha); + _updateInternals(color, alpha, true); + _updateICCButtons(); +} + +void ColorNotebook::_onSelectedColorGrabbed() { + if (_updating) { + return; + } + + _grabbed(); +} + +void ColorNotebook::_onSelectedColorReleased() { + if (_updating) { + return; + } + _released(); +} + +GtkWidget* ColorNotebook::_addPage(Page& page) { + Gtk::Widget *selector_widget; + + selector_widget = page.selector_factory->createWidget(_selected_color); + if (selector_widget) { + selector_widget->show(); + + Glib::ustring mode_name = page.selector_factory->modeName(); + Gtk::Widget* tab_label = Gtk::manage(new Gtk::Label(mode_name)); + gint page_num = gtk_notebook_append_page( GTK_NOTEBOOK(_book), selector_widget->gobj(), tab_label->gobj()); + + _buttons[page_num] = gtk_radio_button_new_with_label(NULL, mode_name.c_str()); + gtk_toggle_button_set_mode(GTK_TOGGLE_BUTTON(_buttons[page_num]), FALSE); + if (page_num > 0) { + GSList *group = gtk_radio_button_get_group (GTK_RADIO_BUTTON(_buttons[0])); + gtk_radio_button_set_group (GTK_RADIO_BUTTON(_buttons[page_num]), group); + } + gtk_widget_show (_buttons[page_num]); + gtk_box_pack_start (GTK_BOX (_buttonbox), _buttons[page_num], TRUE, TRUE, 0); + + g_signal_connect (G_OBJECT (_buttons[page_num]), "clicked", G_CALLBACK (_buttonClicked), _csel); + } + + return selector_widget->gobj(); +} + + +/* Commented out: see comment at the bottom of the header file + +GtkWidget* ColorNotebook::getPage(GType page_type, guint submode) +{ + gint count = 0; + gint i = 0; + GtkWidget* page = 0; + +// count = gtk_notebook_get_n_pages (_book); + count = 200; + for ( i = 0; i < count && !page; i++ ) + { + page = gtk_notebook_get_nth_page (GTK_NOTEBOOK (_book), i); + if ( page ) + { + SPColorSelector* csel; + guint pagemode; + csel = SP_COLOR_SELECTOR (page); + pagemode = csel->base->getSubmode(); + if ( G_TYPE_FROM_INSTANCE (page) == page_type + && pagemode == submode ) + { + // found it. + break; + } + else + { + page = 0; + } + } + else + { + break; + } + } + return page; +} + +void ColorNotebook::removePage( GType page_type, guint submode ) +{ + GtkWidget *page = 0; + + page = getPage(page_type, submode); + if ( page ) + { + gint where = gtk_notebook_page_num (GTK_NOTEBOOK (_book), page); + if ( where >= 0 ) + { + if ( gtk_notebook_get_current_page (GTK_NOTEBOOK (_book)) == where ) + { +// getColorAlpha(_color, &_alpha); + } + gtk_notebook_remove_page (GTK_NOTEBOOK (_book), where); + } + } +} + + +static gint sp_color_notebook_menu_handler( GtkWidget *widget, GdkEvent *event ) +{ + if (event->type == GDK_BUTTON_PRESS) + { + SPColorSelector* csel = SP_COLOR_SELECTOR(widget); + (dynamic_cast(csel->base))->menuHandler( event ); + + // Tell calling code that we have handled this event; the buck + // stops here. + return TRUE; + } + + //Tell calling code that we have not handled this event; pass it on. + return FALSE; +} + +gint ColorNotebook::menuHandler( GdkEvent* event ) +{ + GdkEventButton *bevent = (GdkEventButton *) event; + gtk_menu_popup (GTK_MENU( _popup ), NULL, NULL, NULL, NULL, + bevent->button, bevent->time); + return TRUE; +} + +static void sp_color_notebook_menuitem_response (GtkMenuItem *menuitem, gpointer user_data) +{ + gboolean active = gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (menuitem)); + SPColorNotebookTracker *entry = reinterpret_cast< SPColorNotebookTracker* > (user_data); + if ( entry ) + { + if ( active ) + { + (dynamic_cast(SP_COLOR_SELECTOR(entry->backPointer)->base))->addPage(entry->type, entry->submode); + } + else + { + (dynamic_cast(SP_COLOR_SELECTOR(entry->backPointer)->base))->removePage(entry->type, entry->submode); + } + } +} +*/ + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 : diff --git a/src/ui/widget/color-notebook.h b/src/ui/widget/color-notebook.h new file mode 100644 index 000000000..177519e25 --- /dev/null +++ b/src/ui/widget/color-notebook.h @@ -0,0 +1,150 @@ +#ifndef SEEN_SP_COLOR_NOTEBOOK_H +#define SEEN_SP_COLOR_NOTEBOOK_H + +/* + * A notebook with RGB, CMYK, CMS, HSL, and Wheel pages + * + * Author: + * Lauris Kaplinski + * + * Copyright (C) 2001-2002 Lauris Kaplinski + * + * This code is in public domain + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#if GLIBMM_DISABLE_DEPRECATED && HAVE_GLIBMM_THREADS_H +#include +#endif + +#include +#include +#include +#include + +#include "color.h" +#include "widgets/sp-color-selector.h" +#include "ui/selected-color.h" + + +struct SPColorNotebook; + +class ColorNotebook: public ColorSelector +{ +public: + ColorNotebook( SPColorSelector* csel ); + virtual ~ColorNotebook(); + + //Temporary factory method - transition from SPColorSelector + static Gtk::Widget* create(Inkscape::UI::SelectedColor &color); + + virtual void init(); + +protected: + struct Page { + Page(Inkscape::UI::ColorSelectorFactory *selector_factory, bool enabled_full); + + Inkscape::UI::ColorSelectorFactory *selector_factory; + bool enabled_full; + }; + + static void _buttonClicked(GtkWidget *widget, SPColorNotebook *colorbook); + static void _picker_clicked(GtkWidget *widget, SPColorNotebook *colorbook); + + virtual void _colorChanged(); + + virtual void _onSelectedColorChanged(); + virtual void _onSelectedColorDragged(); + virtual void _onSelectedColorGrabbed(); + virtual void _onSelectedColorReleased(); + + void _updateICCButtons(); + void _setCurrentPage(int i); + + GtkWidget* _addPage(Page& page); + + Inkscape::UI::SelectedColor _selected_color_tmp; + Inkscape::UI::SelectedColor &_selected_color; + gboolean _updating : 1; + gulong _switchId; + gulong _entryId; + GtkWidget *_book; + GtkWidget *_buttonbox; + GtkWidget **_buttons; + GtkWidget *_rgbal; /* RGBA entry */ +#if defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) + GtkWidget *_box_outofgamut, *_box_colormanaged, *_box_toomuchink; +#endif //defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) + GtkWidget *_btn_picker; + GtkWidget *_p; /* Color preview */ + boost::ptr_vector _available_pages; + +private: + // By default, disallow copy constructor and assignment operator + ColorNotebook( const ColorNotebook& obj ); + ColorNotebook& operator=( const ColorNotebook& obj ); + + /* Following methods support the pop-up menu to choose + * active color selectors (notebook tabs). This function + * is not used in Inkscape. If you want to re-enable it you have to + * * port the code to c++ + * * fix it so it remembers its settings in prefs + * * fix it so it does not take that much space (entire vertical column!) + * Current class design supports dynamic addtion and removal of color selectors + * + GtkWidget* addPage( GType page_type, guint submode ); + void removePage( GType page_type, guint submode ); + GtkWidget* getPage( GType page_type, guint submode ); + gint menuHandler( GdkEvent* event ); + + */ +}; + + + + + +#define SP_TYPE_COLOR_NOTEBOOK (sp_color_notebook_get_type ()) +#define SP_COLOR_NOTEBOOK(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), SP_TYPE_COLOR_NOTEBOOK, SPColorNotebook)) +#define SP_COLOR_NOTEBOOK_CLASS(k) (G_TYPE_CHECK_CLASS_CAST ((k), SP_TYPE_COLOR_NOTEBOOK, SPColorNotebookClass)) +#define SP_IS_COLOR_NOTEBOOK(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), SP_TYPE_COLOR_NOTEBOOK)) +#define SP_IS_COLOR_NOTEBOOK_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), SP_TYPE_COLOR_NOTEBOOK)) + +struct SPColorNotebook { + SPColorSelector parent; /* Parent */ +}; + +struct SPColorNotebookClass { + SPColorSelectorClass parent_class; + + void (* grabbed) (SPColorNotebook *rgbsel); + void (* dragged) (SPColorNotebook *rgbsel); + void (* released) (SPColorNotebook *rgbsel); + void (* changed) (SPColorNotebook *rgbsel); +}; + +GType sp_color_notebook_get_type(void); + +GtkWidget *sp_color_notebook_new (void); + +/* void sp_color_notebook_set_mode (SPColorNotebook *csel, SPColorNotebookMode mode); */ +/* SPColorNotebookMode sp_color_notebook_get_mode (SPColorNotebook *csel); */ + + + +#endif // SEEN_SP_COLOR_NOTEBOOK_H + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 : + diff --git a/src/ui/widget/color-picker.cpp b/src/ui/widget/color-picker.cpp index f909535b1..dc827f377 100644 --- a/src/ui/widget/color-picker.cpp +++ b/src/ui/widget/color-picker.cpp @@ -17,7 +17,7 @@ #include "document-undo.h" #include "dialogs/dialog-events.h" -#include "widgets/sp-color-notebook.h" +#include "ui/widget/color-notebook.h" #include "verbs.h" diff --git a/src/widgets/CMakeLists.txt b/src/widgets/CMakeLists.txt index f546c516f..d5910e8af 100644 --- a/src/widgets/CMakeLists.txt +++ b/src/widgets/CMakeLists.txt @@ -36,7 +36,6 @@ set(widgets_SRC select-toolbar.cpp shrink-wrap-button.cpp sp-attribute-widget.cpp - sp-color-notebook.cpp sp-color-selector.cpp sp-widget.cpp sp-xmlview-attr-list.cpp @@ -89,7 +88,6 @@ set(widgets_SRC select-toolbar.h shrink-wrap-button.h sp-attribute-widget.h - sp-color-notebook.h sp-color-selector.h sp-widget.h sp-xmlview-attr-list.h diff --git a/src/widgets/Makefile_insert b/src/widgets/Makefile_insert index 88e79f118..5e38b5df7 100644 --- a/src/widgets/Makefile_insert +++ b/src/widgets/Makefile_insert @@ -66,8 +66,6 @@ ink_common_sources += \ widgets/spiral-toolbar.h \ widgets/sp-attribute-widget.cpp \ widgets/sp-attribute-widget.h \ - widgets/sp-color-notebook.cpp \ - widgets/sp-color-notebook.h \ widgets/sp-color-selector.cpp \ widgets/sp-color-selector.h \ widgets/spinbutton-events.cpp \ diff --git a/src/widgets/gradient-vector.cpp b/src/widgets/gradient-vector.cpp index 0ea5f5506..2d654ac43 100644 --- a/src/widgets/gradient-vector.cpp +++ b/src/widgets/gradient-vector.cpp @@ -55,6 +55,7 @@ #include "document-undo.h" #include "ui/selected-color.h" +#include "ui/widget/color-notebook.h" using Inkscape::DocumentUndo; using Inkscape::UI::SelectedColor; @@ -491,11 +492,10 @@ void SPGradientVectorSelector::setSwatched() ### Vector Editing Widget ##################################################################*/ -#include "../widgets/sp-color-notebook.h" #include "../widgets/widget-sizes.h" #include "../xml/node-event-vector.h" #include "../svg/svg-color.h" - +#include "ui/widget/color-notebook.h" #define PAD 4 diff --git a/src/widgets/paint-selector.cpp b/src/widgets/paint-selector.cpp index 274ad7bdf..3f2edb4f2 100644 --- a/src/widgets/paint-selector.cpp +++ b/src/widgets/paint-selector.cpp @@ -35,7 +35,6 @@ #include "widgets/widget-sizes.h" #include "xml/repr.h" -#include "sp-color-notebook.h" #include "sp-linear-gradient.h" #include "sp-radial-gradient.h" /* fixme: Move it from dialogs to here */ @@ -50,6 +49,7 @@ #include "io/sys.h" #include "helper/stock-items.h" #include "ui/icon-names.h" +#include "ui/widget/color-notebook.h" #include "paint-selector.h" diff --git a/src/widgets/sp-color-notebook.cpp b/src/widgets/sp-color-notebook.cpp deleted file mode 100644 index 38ea04372..000000000 --- a/src/widgets/sp-color-notebook.cpp +++ /dev/null @@ -1,675 +0,0 @@ -/* - * A notebook with RGB, CMYK, CMS, HSL, and Wheel pages - * - * Author: - * Lauris Kaplinski - * bulia byak - * - * Copyright (C) 2001-2002 Lauris Kaplinski - * - * This code is in public domain - */ - -#undef SPCS_PREVIEW -#define noDUMP_CHANGE_INFO - -#ifdef HAVE_CONFIG_H -# include "config.h" -#endif - -#include "widgets/icon.h" -#include -#include -#include -#include -#include -#include -#include - -#include "../dialogs/dialog-events.h" -#include "../preferences.h" -#include "sp-color-notebook.h" -#include "spw-utilities.h" -#include "svg/svg-icc-color.h" -#include "../inkscape.h" -#include "../document.h" -#include "../profile-manager.h" -#include "color-profile.h" -#include "cms-system.h" -#include "tools-switch.h" -#include "ui/tools/tool-base.h" -#include "ui/widget/color-entry.h" -#include "ui/widget/color-icc-selector.h" -#include "ui/widget/color-scales.h" -#include "ui/widget/color-wheel-selector.h" - -using Inkscape::CMSSystem; - -using namespace Inkscape::UI; -using namespace Inkscape::UI::Widget; - -struct SPColorNotebookTracker { - const gchar* name; - const gchar* className; - GType type; - guint submode; - gboolean enabledFull; - gboolean enabledBrief; - SPColorNotebook *backPointer; -}; - - -static void sp_color_notebook_class_init (SPColorNotebookClass *klass); -static void sp_color_notebook_init (SPColorNotebook *colorbook); -static void sp_color_notebook_dispose(GObject *object); - -static void sp_color_notebook_show_all (GtkWidget *widget); -static void sp_color_notebook_hide(GtkWidget *widget); - -static SPColorSelectorClass *parent_class; - -#define XPAD 4 -#define YPAD 1 - -GType sp_color_notebook_get_type(void) -{ - static GType type = 0; - if (!type) { - GTypeInfo info = { - sizeof(SPColorNotebookClass), - 0, // base_init - 0, // base_finalize - (GClassInitFunc)sp_color_notebook_class_init, - 0, // class_finalize - 0, // class_data - sizeof(SPColorNotebook), - 0, // n_preallocs - (GInstanceInitFunc)sp_color_notebook_init, - 0 // value_table - }; - type = g_type_register_static(SP_TYPE_COLOR_SELECTOR, "SPColorNotebook", &info, static_cast(0)); - } - return type; -} - -static void sp_color_notebook_class_init(SPColorNotebookClass *klass) -{ - GObjectClass *object_class = reinterpret_cast(klass); - GtkWidgetClass *widget_class = reinterpret_cast(klass); - - parent_class = SP_COLOR_SELECTOR_CLASS(g_type_class_peek_parent(klass)); - - object_class->dispose = sp_color_notebook_dispose; - - widget_class->show_all = sp_color_notebook_show_all; - widget_class->hide = sp_color_notebook_hide; -} - -static void -sp_color_notebook_switch_page(GtkNotebook *notebook, - GtkWidget *page, - guint page_num, - SPColorNotebook *colorbook) -{ - if ( colorbook ) - { - // remember the page we switched to - Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - prefs->setInt("/colorselector/page", page_num); - } -} - -static void -sp_color_notebook_init (SPColorNotebook *colorbook) -{ - SP_COLOR_SELECTOR(colorbook)->base = new ColorNotebook( SP_COLOR_SELECTOR(colorbook) ); - - if ( SP_COLOR_SELECTOR(colorbook)->base ) - { - SP_COLOR_SELECTOR(colorbook)->base->init(); - } -} - -void ColorNotebook::init() -{ - guint row = 0; - - _updating = false; - - _book = gtk_notebook_new (); - gtk_widget_show (_book); - - // Dont show the notebook tabs, use radiobuttons instead - gtk_notebook_set_show_border (GTK_NOTEBOOK (_book), false); - gtk_notebook_set_show_tabs (GTK_NOTEBOOK (_book), false); - -#if GTK_CHECK_VERSION(3,0,0) - _buttonbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 2); - gtk_box_set_homogeneous(GTK_BOX(_buttonbox), TRUE); -#else - _buttonbox = gtk_hbox_new (TRUE, 2); -#endif - - gtk_widget_show (_buttonbox); - _buttons = new GtkWidget *[_available_pages.size()]; - - for (int i = 0; static_cast(i) < _available_pages.size(); i++ ) - { - _addPage(_available_pages[i]); - } - -#if GTK_CHECK_VERSION(3,0,0) - GtkWidget* table = gtk_grid_new(); -#else - GtkWidget* table = gtk_table_new(2, 3, FALSE); -#endif - - gtk_widget_show (table); - - gtk_box_pack_start (GTK_BOX (_csel), table, TRUE, TRUE, 0); - - sp_set_font_size_smaller (_buttonbox); - -#if GTK_CHECK_VERSION(3,0,0) - gtk_widget_set_margin_left(_buttonbox, XPAD); - gtk_widget_set_margin_right(_buttonbox, XPAD); - gtk_widget_set_margin_top(_buttonbox, YPAD); - gtk_widget_set_margin_bottom(_buttonbox, YPAD); - gtk_widget_set_hexpand(_buttonbox, TRUE); - gtk_widget_set_valign(_buttonbox, GTK_ALIGN_CENTER); - gtk_grid_attach(GTK_GRID(table), _buttonbox, 0, row, 2, 1); -#else - gtk_table_attach (GTK_TABLE (table), _buttonbox, 0, 2, row, row + 1, - static_cast(GTK_EXPAND|GTK_FILL), - static_cast(0), - XPAD, YPAD); -#endif - - row++; - -#if GTK_CHECK_VERSION(3,0,0) - gtk_widget_set_margin_left(_book, XPAD*2); - gtk_widget_set_margin_right(_book, XPAD*2); - gtk_widget_set_margin_top(_book, YPAD); - gtk_widget_set_margin_bottom(_book, YPAD); - gtk_widget_set_hexpand(_book, TRUE); - gtk_widget_set_vexpand(_book, TRUE); - gtk_grid_attach(GTK_GRID(table), _book, 0, row, 2, 1); -#else - gtk_table_attach (GTK_TABLE (table), _book, 0, 2, row, row + 1, - static_cast(GTK_EXPAND|GTK_FILL), - static_cast(GTK_EXPAND|GTK_FILL), - XPAD*2, YPAD); -#endif - - // restore the last active page - Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - _setCurrentPage(prefs->getInt("/colorselector/page", 0)); - - - /* Commented out: see comment at the bottom of the header file - { - gboolean found = FALSE; - - _popup = gtk_menu_new(); - GtkMenu *menu = GTK_MENU (_popup); - - for (int i = 0; i < _trackerList->len; i++ ) - { - SPColorNotebookTracker *entry = reinterpret_cast< SPColorNotebookTracker* > (g_ptr_array_index (_trackerList, i)); - if ( entry ) - { - GtkWidget *item = gtk_check_menu_item_new_with_label (_(entry->name)); - gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), entry->enabledFull); - gtk_widget_show (item); - gtk_menu_shell_append (GTK_MENU_SHELL(menu), item); - - g_signal_connect (G_OBJECT (item), "activate", - G_CALLBACK (sp_color_notebook_menuitem_response), - reinterpret_cast< gpointer > (entry) ); - found = TRUE; - } - } - - GtkWidget *arrow = gtk_arrow_new(GTK_ARROW_RIGHT, GTK_SHADOW_NONE); - gtk_widget_show (arrow); - - _btn = gtk_button_new (); - gtk_widget_show (_btn); - gtk_container_add (GTK_CONTAINER (_btn), arrow); - - GtkWidget *align = gtk_alignment_new (1.0, 0.0, 0.0, 0.0); - gtk_widget_show (align); - gtk_container_add (GTK_CONTAINER (align), _btn); - - // uncomment to reenable the "show/hide modes" menu, - // but first fix it so it remembers its settings in prefs and does not take that much space (entire vertical column!) - gtk_table_attach (GTK_TABLE (table), align, 2, 3, row, row + 1, GTK_FILL, GTK_FILL, XPAD, YPAD); - - g_signal_connect_swapped(G_OBJECT(_btn), "event", G_CALLBACK (sp_color_notebook_menu_handler), G_OBJECT(_csel)); - if ( !found ) - { - gtk_widget_set_sensitive (_btn, FALSE); - } - } - */ - - row++; - -#if GTK_CHECK_VERSION(3,0,0) - GtkWidget *rgbabox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0); -#else - GtkWidget *rgbabox = gtk_hbox_new (FALSE, 0); -#endif - -#if defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) - /* Create color management icons */ - _box_colormanaged = gtk_event_box_new (); - GtkWidget *colormanaged = gtk_image_new_from_icon_name ("color-management-icon", GTK_ICON_SIZE_SMALL_TOOLBAR); - gtk_container_add (GTK_CONTAINER (_box_colormanaged), colormanaged); - gtk_widget_set_tooltip_text (_box_colormanaged, _("Color Managed")); - gtk_widget_set_sensitive (_box_colormanaged, false); - gtk_box_pack_start(GTK_BOX(rgbabox), _box_colormanaged, FALSE, FALSE, 2); - - _box_outofgamut = gtk_event_box_new (); - GtkWidget *outofgamut = gtk_image_new_from_icon_name ("out-of-gamut-icon", GTK_ICON_SIZE_SMALL_TOOLBAR); - gtk_container_add (GTK_CONTAINER (_box_outofgamut), outofgamut); - gtk_widget_set_tooltip_text (_box_outofgamut, _("Out of gamut!")); - gtk_widget_set_sensitive (_box_outofgamut, false); - gtk_box_pack_start(GTK_BOX(rgbabox), _box_outofgamut, FALSE, FALSE, 2); - - _box_toomuchink = gtk_event_box_new (); - GtkWidget *toomuchink = gtk_image_new_from_icon_name ("too-much-ink-icon", GTK_ICON_SIZE_SMALL_TOOLBAR); - gtk_container_add (GTK_CONTAINER (_box_toomuchink), toomuchink); - gtk_widget_set_tooltip_text (_box_toomuchink, _("Too much ink!")); - gtk_widget_set_sensitive (_box_toomuchink, false); - gtk_box_pack_start(GTK_BOX(rgbabox), _box_toomuchink, FALSE, FALSE, 2); -#endif //defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) - - - /* Color picker */ - GtkWidget *picker = gtk_image_new_from_icon_name ("color-picker", GTK_ICON_SIZE_SMALL_TOOLBAR); - _btn_picker = gtk_button_new (); - gtk_button_set_relief(GTK_BUTTON(_btn_picker), GTK_RELIEF_NONE); - gtk_container_add (GTK_CONTAINER (_btn_picker), picker); - gtk_widget_set_tooltip_text (_btn_picker, _("Pick colors from image")); - gtk_box_pack_start(GTK_BOX(rgbabox), _btn_picker, FALSE, FALSE, 2); - g_signal_connect(G_OBJECT(_btn_picker), "clicked", G_CALLBACK(ColorNotebook::_picker_clicked), _csel); - - /* Create RGBA entry and color preview */ - _rgbal = gtk_label_new_with_mnemonic (_("RGBA_:")); - gtk_misc_set_alignment (GTK_MISC (_rgbal), 1.0, 0.5); - gtk_box_pack_start(GTK_BOX(rgbabox), _rgbal, TRUE, TRUE, 2); - - ColorEntry* rgba_entry = Gtk::manage(new ColorEntry(_selected_color)); - sp_dialog_defocus_on_enter (GTK_WIDGET(rgba_entry->gobj())); - gtk_box_pack_start(GTK_BOX(rgbabox), GTK_WIDGET(rgba_entry->gobj()), FALSE, FALSE, 0); - gtk_label_set_mnemonic_widget (GTK_LABEL(_rgbal), GTK_WIDGET(rgba_entry->gobj())); - - sp_set_font_size_smaller (rgbabox); - gtk_widget_show_all (rgbabox); - -#if defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) - //the "too much ink" icon is initially hidden - gtk_widget_hide(GTK_WIDGET(_box_toomuchink)); -#endif //defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) - -#if GTK_CHECK_VERSION(3,0,0) - gtk_widget_set_margin_left(rgbabox, XPAD); - gtk_widget_set_margin_right(rgbabox, XPAD); - gtk_widget_set_margin_top(rgbabox, YPAD); - gtk_widget_set_margin_bottom(rgbabox, YPAD); - gtk_grid_attach(GTK_GRID(table), rgbabox, 0, row, 2, 1); -#else - gtk_table_attach (GTK_TABLE (table), rgbabox, 0, 2, row, row + 1, GTK_FILL, GTK_SHRINK, XPAD, YPAD); -#endif - -#ifdef SPCS_PREVIEW - _p = sp_color_preview_new (0xffffffff); - gtk_widget_show (_p); - gtk_table_attach (GTK_TABLE (table), _p, 2, 3, row, row + 1, GTK_FILL, GTK_FILL, XPAD, YPAD); -#endif - - _switchId = g_signal_connect(G_OBJECT (_book), "switch-page", - G_CALLBACK (sp_color_notebook_switch_page), SP_COLOR_NOTEBOOK(_csel)); - - _selected_color.signal_changed.connect(sigc::mem_fun(this, &ColorNotebook::_onSelectedColorChanged)); - _selected_color.signal_dragged.connect(sigc::mem_fun(this, &ColorNotebook::_onSelectedColorDragged)); - _selected_color.signal_grabbed.connect(sigc::mem_fun(this, &ColorNotebook::_onSelectedColorGrabbed)); - _selected_color.signal_released.connect(sigc::mem_fun(this, &ColorNotebook::_onSelectedColorReleased)); -} - -static void sp_color_notebook_dispose(GObject *object) -{ - if (((GObjectClass *) (parent_class))->dispose) - (* ((GObjectClass *) (parent_class))->dispose) (object); -} - -ColorNotebook::~ColorNotebook() -{ - if ( _switchId ) - { - if ( _book ) - { - g_signal_handler_disconnect (_book, _switchId); - _switchId = 0; - } - } - - if ( _buttons ) - { - delete [] _buttons; - _buttons = 0; - } - -} - -static void -sp_color_notebook_show_all (GtkWidget *widget) -{ - gtk_widget_show (widget); -} - -static void sp_color_notebook_hide(GtkWidget *widget) -{ - gtk_widget_hide(widget); -} - -GtkWidget *sp_color_notebook_new() -{ - SPColorNotebook *colorbook = SP_COLOR_NOTEBOOK(g_object_new (SP_TYPE_COLOR_NOTEBOOK, NULL)); - - return GTK_WIDGET(colorbook); -} - -ColorNotebook::ColorNotebook( SPColorSelector* csel ) - : ColorSelector( csel ) - , _selected_color(_selected_color_tmp) -{ - Page *page; - - page = new Page(new ColorScalesFactory(SP_COLOR_SCALES_MODE_RGB), true); - _available_pages.push_back(page); - page = new Page(new ColorScalesFactory(SP_COLOR_SCALES_MODE_HSV), true); - _available_pages.push_back(page); - page = new Page(new ColorScalesFactory(SP_COLOR_SCALES_MODE_CMYK), true); - _available_pages.push_back(page); - page = new Page(new ColorWheelSelectorFactory, true); - _available_pages.push_back(page); -#if defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) - page = new Page(new ColorICCSelectorFactory, true); - _available_pages.push_back(page); -#endif -} - -Gtk::Widget *ColorNotebook::create(SelectedColor &color) { - GtkWidget *w = sp_color_selector_new(SP_TYPE_COLOR_NOTEBOOK); - SPColorSelector *s = SP_COLOR_SELECTOR(w); - ColorNotebook* nb = dynamic_cast(s->base); - return Glib::wrap(w); -} - -ColorNotebook::Page::Page(Inkscape::UI::ColorSelectorFactory *selector_factory, bool enabled_full) - : selector_factory(selector_factory) - , enabled_full(enabled_full) -{ -} - -void ColorNotebook::_colorChanged() -{ - _updating = true; - _selected_color.setColorAlpha(_color, _alpha); - _updateICCButtons(); - _updating = false; -} - -void ColorNotebook::_picker_clicked(GtkWidget * /*widget*/, SPColorNotebook * /*colorbook*/) -{ - // Set the dropper into a "one click" mode, so it reverts to the previous tool after a click - Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - prefs->setBool("/tools/dropper/onetimepick", true); - Inkscape::UI::Tools::sp_toggle_dropper(SP_ACTIVE_DESKTOP); -} - -// TODO pass in param so as to avoid the need for SP_ACTIVE_DOCUMENT -void ColorNotebook::_updateICCButtons() -{ - SPColor color = _selected_color.color(); - gfloat alpha = _selected_color.alpha(); - - g_return_if_fail( ( 0.0 <= alpha ) && ( alpha <= 1.0 ) ); - -#if defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) - /* update color management icon*/ - gtk_widget_set_sensitive (_box_colormanaged, color.icc != NULL); - - /* update out-of-gamut icon */ - gtk_widget_set_sensitive (_box_outofgamut, false); - if (color.icc){ - Inkscape::ColorProfile* target_profile = SP_ACTIVE_DOCUMENT->profileManager->find(color.icc->colorProfile.c_str()); - if ( target_profile ) - gtk_widget_set_sensitive(_box_outofgamut, target_profile->GamutCheck(color)); - } - - /* update too-much-ink icon */ - gtk_widget_set_sensitive (_box_toomuchink, false); - if (color.icc){ - Inkscape::ColorProfile* prof = SP_ACTIVE_DOCUMENT->profileManager->find(color.icc->colorProfile.c_str()); - if ( prof && CMSSystem::isPrintColorSpace(prof) ) { - gtk_widget_show(GTK_WIDGET(_box_toomuchink)); - double ink_sum = 0; - for (unsigned int i=0; icolors.size(); i++){ - ink_sum += color.icc->colors[i]; - } - - /* Some literature states that when the sum of paint values exceed 320%, it is considered to be a satured color, - which means the paper can get too wet due to an excessive ammount of ink. This may lead to several issues - such as misalignment and poor quality of printing in general.*/ - if ( ink_sum > 3.2 ) - gtk_widget_set_sensitive (_box_toomuchink, true); - } else { - gtk_widget_hide(GTK_WIDGET(_box_toomuchink)); - } - } -#endif //defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) -} - -void ColorNotebook::_setCurrentPage(int i) -{ - gtk_notebook_set_current_page(GTK_NOTEBOOK(_book), i); - - if (_buttons && (static_cast(i) < _available_pages.size())) { - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(_buttons[i]), TRUE); - } -} - -void ColorNotebook::_buttonClicked(GtkWidget *widget, SPColorNotebook *colorbook) -{ - ColorNotebook* nb = dynamic_cast(SP_COLOR_SELECTOR(colorbook)->base); - - if (!gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(widget))) { - return; - } - - for(gint i = 0; i < gtk_notebook_get_n_pages (GTK_NOTEBOOK (nb->_book)); i++) { - if (nb->_buttons[i] == widget) { - gtk_notebook_set_current_page (GTK_NOTEBOOK (nb->_book), i); - } - } -} - -void ColorNotebook::_onSelectedColorChanged() { - if (_updating) { - return; - } - - SPColor color; - gfloat alpha = 1.0; - _selected_color.colorAlpha(color, alpha); - _updateInternals(color, alpha, false); - _updateICCButtons(); -} - -void ColorNotebook::_onSelectedColorDragged() { - if (_updating) { - return; - } - SPColor color; - gfloat alpha = 1.0; - _selected_color.colorAlpha(color, alpha); - _updateInternals(color, alpha, true); - _updateICCButtons(); -} - -void ColorNotebook::_onSelectedColorGrabbed() { - if (_updating) { - return; - } - - _grabbed(); -} - -void ColorNotebook::_onSelectedColorReleased() { - if (_updating) { - return; - } - _released(); -} - -GtkWidget* ColorNotebook::_addPage(Page& page) { - Gtk::Widget *selector_widget; - - selector_widget = page.selector_factory->createWidget(_selected_color); - if (selector_widget) { - selector_widget->show(); - - Glib::ustring mode_name = page.selector_factory->modeName(); - Gtk::Widget* tab_label = Gtk::manage(new Gtk::Label(mode_name)); - gint page_num = gtk_notebook_append_page( GTK_NOTEBOOK(_book), selector_widget->gobj(), tab_label->gobj()); - - _buttons[page_num] = gtk_radio_button_new_with_label(NULL, mode_name.c_str()); - gtk_toggle_button_set_mode(GTK_TOGGLE_BUTTON(_buttons[page_num]), FALSE); - if (page_num > 0) { - GSList *group = gtk_radio_button_get_group (GTK_RADIO_BUTTON(_buttons[0])); - gtk_radio_button_set_group (GTK_RADIO_BUTTON(_buttons[page_num]), group); - } - gtk_widget_show (_buttons[page_num]); - gtk_box_pack_start (GTK_BOX (_buttonbox), _buttons[page_num], TRUE, TRUE, 0); - - g_signal_connect (G_OBJECT (_buttons[page_num]), "clicked", G_CALLBACK (_buttonClicked), _csel); - } - - return selector_widget->gobj(); -} - - -/* Commented out: see comment at the bottom of the header file - -GtkWidget* ColorNotebook::getPage(GType page_type, guint submode) -{ - gint count = 0; - gint i = 0; - GtkWidget* page = 0; - -// count = gtk_notebook_get_n_pages (_book); - count = 200; - for ( i = 0; i < count && !page; i++ ) - { - page = gtk_notebook_get_nth_page (GTK_NOTEBOOK (_book), i); - if ( page ) - { - SPColorSelector* csel; - guint pagemode; - csel = SP_COLOR_SELECTOR (page); - pagemode = csel->base->getSubmode(); - if ( G_TYPE_FROM_INSTANCE (page) == page_type - && pagemode == submode ) - { - // found it. - break; - } - else - { - page = 0; - } - } - else - { - break; - } - } - return page; -} - -void ColorNotebook::removePage( GType page_type, guint submode ) -{ - GtkWidget *page = 0; - - page = getPage(page_type, submode); - if ( page ) - { - gint where = gtk_notebook_page_num (GTK_NOTEBOOK (_book), page); - if ( where >= 0 ) - { - if ( gtk_notebook_get_current_page (GTK_NOTEBOOK (_book)) == where ) - { -// getColorAlpha(_color, &_alpha); - } - gtk_notebook_remove_page (GTK_NOTEBOOK (_book), where); - } - } -} - - -static gint sp_color_notebook_menu_handler( GtkWidget *widget, GdkEvent *event ) -{ - if (event->type == GDK_BUTTON_PRESS) - { - SPColorSelector* csel = SP_COLOR_SELECTOR(widget); - (dynamic_cast(csel->base))->menuHandler( event ); - - // Tell calling code that we have handled this event; the buck - // stops here. - return TRUE; - } - - //Tell calling code that we have not handled this event; pass it on. - return FALSE; -} - -gint ColorNotebook::menuHandler( GdkEvent* event ) -{ - GdkEventButton *bevent = (GdkEventButton *) event; - gtk_menu_popup (GTK_MENU( _popup ), NULL, NULL, NULL, NULL, - bevent->button, bevent->time); - return TRUE; -} - -static void sp_color_notebook_menuitem_response (GtkMenuItem *menuitem, gpointer user_data) -{ - gboolean active = gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (menuitem)); - SPColorNotebookTracker *entry = reinterpret_cast< SPColorNotebookTracker* > (user_data); - if ( entry ) - { - if ( active ) - { - (dynamic_cast(SP_COLOR_SELECTOR(entry->backPointer)->base))->addPage(entry->type, entry->submode); - } - else - { - (dynamic_cast(SP_COLOR_SELECTOR(entry->backPointer)->base))->removePage(entry->type, entry->submode); - } - } -} -*/ - -/* - Local Variables: - mode:c++ - c-file-style:"stroustrup" - c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) - indent-tabs-mode:nil - fill-column:99 - End: -*/ -// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 : diff --git a/src/widgets/sp-color-notebook.h b/src/widgets/sp-color-notebook.h deleted file mode 100644 index 42fb0ed97..000000000 --- a/src/widgets/sp-color-notebook.h +++ /dev/null @@ -1,150 +0,0 @@ -#ifndef SEEN_SP_COLOR_NOTEBOOK_H -#define SEEN_SP_COLOR_NOTEBOOK_H - -/* - * A notebook with RGB, CMYK, CMS, HSL, and Wheel pages - * - * Author: - * Lauris Kaplinski - * - * Copyright (C) 2001-2002 Lauris Kaplinski - * - * This code is in public domain - */ - -#ifdef HAVE_CONFIG_H -# include -#endif - -#if GLIBMM_DISABLE_DEPRECATED && HAVE_GLIBMM_THREADS_H -#include -#endif - -#include -#include -#include -#include - -#include "../color.h" -#include "sp-color-selector.h" -#include "ui/selected-color.h" - - -struct SPColorNotebook; - -class ColorNotebook: public ColorSelector -{ -public: - ColorNotebook( SPColorSelector* csel ); - virtual ~ColorNotebook(); - - //Temporary factory method - transition from SPColorSelector - static Gtk::Widget* create(Inkscape::UI::SelectedColor &color); - - virtual void init(); - -protected: - struct Page { - Page(Inkscape::UI::ColorSelectorFactory *selector_factory, bool enabled_full); - - Inkscape::UI::ColorSelectorFactory *selector_factory; - bool enabled_full; - }; - - static void _buttonClicked(GtkWidget *widget, SPColorNotebook *colorbook); - static void _picker_clicked(GtkWidget *widget, SPColorNotebook *colorbook); - - virtual void _colorChanged(); - - virtual void _onSelectedColorChanged(); - virtual void _onSelectedColorDragged(); - virtual void _onSelectedColorGrabbed(); - virtual void _onSelectedColorReleased(); - - void _updateICCButtons(); - void _setCurrentPage(int i); - - GtkWidget* _addPage(Page& page); - - Inkscape::UI::SelectedColor _selected_color_tmp; - Inkscape::UI::SelectedColor &_selected_color; - gboolean _updating : 1; - gulong _switchId; - gulong _entryId; - GtkWidget *_book; - GtkWidget *_buttonbox; - GtkWidget **_buttons; - GtkWidget *_rgbal; /* RGBA entry */ -#if defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) - GtkWidget *_box_outofgamut, *_box_colormanaged, *_box_toomuchink; -#endif //defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) - GtkWidget *_btn_picker; - GtkWidget *_p; /* Color preview */ - boost::ptr_vector _available_pages; - -private: - // By default, disallow copy constructor and assignment operator - ColorNotebook( const ColorNotebook& obj ); - ColorNotebook& operator=( const ColorNotebook& obj ); - - /* Following methods support the pop-up menu to choose - * active color selectors (notebook tabs). This function - * is not used in Inkscape. If you want to re-enable it you have to - * * port the code to c++ - * * fix it so it remembers its settings in prefs - * * fix it so it does not take that much space (entire vertical column!) - * Current class design supports dynamic addtion and removal of color selectors - * - GtkWidget* addPage( GType page_type, guint submode ); - void removePage( GType page_type, guint submode ); - GtkWidget* getPage( GType page_type, guint submode ); - gint menuHandler( GdkEvent* event ); - - */ -}; - - - - - -#define SP_TYPE_COLOR_NOTEBOOK (sp_color_notebook_get_type ()) -#define SP_COLOR_NOTEBOOK(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), SP_TYPE_COLOR_NOTEBOOK, SPColorNotebook)) -#define SP_COLOR_NOTEBOOK_CLASS(k) (G_TYPE_CHECK_CLASS_CAST ((k), SP_TYPE_COLOR_NOTEBOOK, SPColorNotebookClass)) -#define SP_IS_COLOR_NOTEBOOK(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), SP_TYPE_COLOR_NOTEBOOK)) -#define SP_IS_COLOR_NOTEBOOK_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), SP_TYPE_COLOR_NOTEBOOK)) - -struct SPColorNotebook { - SPColorSelector parent; /* Parent */ -}; - -struct SPColorNotebookClass { - SPColorSelectorClass parent_class; - - void (* grabbed) (SPColorNotebook *rgbsel); - void (* dragged) (SPColorNotebook *rgbsel); - void (* released) (SPColorNotebook *rgbsel); - void (* changed) (SPColorNotebook *rgbsel); -}; - -GType sp_color_notebook_get_type(void); - -GtkWidget *sp_color_notebook_new (void); - -/* void sp_color_notebook_set_mode (SPColorNotebook *csel, SPColorNotebookMode mode); */ -/* SPColorNotebookMode sp_color_notebook_get_mode (SPColorNotebook *csel); */ - - - -#endif // SEEN_SP_COLOR_NOTEBOOK_H - -/* - Local Variables: - mode:c++ - c-file-style:"stroustrup" - c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) - indent-tabs-mode:nil - fill-column:99 - End: -*/ -// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 : - diff --git a/src/widgets/swatch-selector.cpp b/src/widgets/swatch-selector.cpp index b7de6657c..eb8bf7a4f 100644 --- a/src/widgets/swatch-selector.cpp +++ b/src/widgets/swatch-selector.cpp @@ -5,11 +5,11 @@ #include "document-undo.h" #include "gradient-chemistry.h" #include "gradient-selector.h" -#include "sp-color-notebook.h" #include "sp-stop.h" #include "svg/css-ostringstream.h" #include "svg/svg-color.h" #include "verbs.h" +#include "ui/widget/color-notebook.h" #include "xml/node.h" namespace Inkscape -- cgit v1.2.3 From 761b8956cc9cb923a7e7c5a95eacfaf7ba36d475 Mon Sep 17 00:00:00 2001 From: Tomasz Boczkowski Date: Sun, 1 Jun 2014 19:00:26 +0200 Subject: ColorNotebook is Gtk::Widget and uses ColorSelector (bzr r13341.6.52) --- src/extension/param/color.cpp | 5 +- src/ui/widget/color-notebook.cpp | 334 +++++++++++---------------------------- src/ui/widget/color-notebook.h | 94 ++++------- src/ui/widget/color-picker.cpp | 2 +- src/widgets/gradient-vector.cpp | 4 +- src/widgets/paint-selector.cpp | 4 +- src/widgets/swatch-selector.cpp | 4 +- 7 files changed, 134 insertions(+), 313 deletions(-) (limited to 'src') diff --git a/src/extension/param/color.cpp b/src/extension/param/color.cpp index 6748c8f5f..ef3887a12 100644 --- a/src/extension/param/color.cpp +++ b/src/extension/param/color.cpp @@ -32,7 +32,6 @@ #include "ui/widget/color-notebook.h" #include "preferences.h" - namespace Inkscape { namespace Extension { @@ -88,6 +87,8 @@ void ParamColor::string(std::string &string) const Gtk::Widget *ParamColor::get_widget( SPDocument * /*doc*/, Inkscape::XML::Node * /*node*/, sigc::signal * changeSignal ) { + using Inkscape::UI::Widget::ColorNotebook; + if (_gui_hidden) return NULL; _changeSignal = new sigc::signal(*changeSignal); @@ -99,7 +100,7 @@ Gtk::Widget *ParamColor::get_widget( SPDocument * /*doc*/, Inkscape::XML::Node * } Gtk::HBox *hbox = Gtk::manage(new Gtk::HBox(false, 4)); - Gtk::Widget *selector = Gtk::manage(ColorNotebook::create(_color)); + Gtk::Widget *selector = Gtk::manage(new ColorNotebook(_color)); hbox->pack_start (*selector, true, true, 0); selector->show(); hbox->show(); diff --git a/src/ui/widget/color-notebook.cpp b/src/ui/widget/color-notebook.cpp index 2b592e620..32a141e08 100644 --- a/src/ui/widget/color-notebook.cpp +++ b/src/ui/widget/color-notebook.cpp @@ -1,11 +1,13 @@ -/* - * A notebook with RGB, CMYK, CMS, HSL, and Wheel pages - * - * Author: +/** + * @file + * A notebook with RGB, CMYK, CMS, HSL, and Wheel pages - implementation + */ +/* Authors: * Lauris Kaplinski * bulia byak + * Tomasz Boczkowski (c++-sification) * - * Copyright (C) 2001-2002 Lauris Kaplinski + * Copyright (C) 2001-2014 Authors * * This code is in public domain */ @@ -25,6 +27,7 @@ #include #include #include +#include #include "dialogs/dialog-events.h" #include "preferences.h" @@ -45,103 +48,70 @@ using Inkscape::CMSSystem; -using namespace Inkscape::UI; -using namespace Inkscape::UI::Widget; - -struct SPColorNotebookTracker { - const gchar* name; - const gchar* className; - GType type; - guint submode; - gboolean enabledFull; - gboolean enabledBrief; - SPColorNotebook *backPointer; -}; - - -static void sp_color_notebook_class_init (SPColorNotebookClass *klass); -static void sp_color_notebook_init (SPColorNotebook *colorbook); -static void sp_color_notebook_dispose(GObject *object); - -static void sp_color_notebook_show_all (GtkWidget *widget); -static void sp_color_notebook_hide(GtkWidget *widget); - -static SPColorSelectorClass *parent_class; - #define XPAD 4 #define YPAD 1 -GType sp_color_notebook_get_type(void) -{ - static GType type = 0; - if (!type) { - GTypeInfo info = { - sizeof(SPColorNotebookClass), - 0, // base_init - 0, // base_finalize - (GClassInitFunc)sp_color_notebook_class_init, - 0, // class_finalize - 0, // class_data - sizeof(SPColorNotebook), - 0, // n_preallocs - (GInstanceInitFunc)sp_color_notebook_init, - 0 // value_table - }; - type = g_type_register_static(SP_TYPE_COLOR_SELECTOR, "SPColorNotebook", &info, static_cast(0)); - } - return type; -} +namespace Inkscape { +namespace UI { +namespace Widget { + + +ColorNotebook::ColorNotebook(SelectedColor &color) +#if GTK_CHECK_VERSION(3,0,0) + : Gtk::Grid() +#else + : Gtk::Table(2, 3, false) +#endif + , _selected_color(color) -static void sp_color_notebook_class_init(SPColorNotebookClass *klass) { - GObjectClass *object_class = reinterpret_cast(klass); - GtkWidgetClass *widget_class = reinterpret_cast(klass); + Page *page; - parent_class = SP_COLOR_SELECTOR_CLASS(g_type_class_peek_parent(klass)); + page = new Page(new ColorScalesFactory(SP_COLOR_SCALES_MODE_RGB), true); + _available_pages.push_back(page); + page = new Page(new ColorScalesFactory(SP_COLOR_SCALES_MODE_HSV), true); + _available_pages.push_back(page); + page = new Page(new ColorScalesFactory(SP_COLOR_SCALES_MODE_CMYK), true); + _available_pages.push_back(page); + page = new Page(new ColorWheelSelectorFactory, true); + _available_pages.push_back(page); +#if defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) + page = new Page(new ColorICCSelectorFactory, true); + _available_pages.push_back(page); +#endif - object_class->dispose = sp_color_notebook_dispose; + _initUI(); - widget_class->show_all = sp_color_notebook_show_all; - widget_class->hide = sp_color_notebook_hide; + _selected_color.signal_changed.connect(sigc::mem_fun(this, &ColorNotebook::_onSelectedColorChanged)); + _selected_color.signal_dragged.connect(sigc::mem_fun(this, &ColorNotebook::_onSelectedColorChanged)); } -static void -sp_color_notebook_switch_page(GtkNotebook *notebook, - GtkWidget *page, - guint page_num, - SPColorNotebook *colorbook) +ColorNotebook::~ColorNotebook() { - if ( colorbook ) + if ( _buttons ) { - // remember the page we switched to - Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - prefs->setInt("/colorselector/page", page_num); + delete [] _buttons; + _buttons = 0; } + } -static void -sp_color_notebook_init (SPColorNotebook *colorbook) +ColorNotebook::Page::Page(Inkscape::UI::ColorSelectorFactory *selector_factory, bool enabled_full) + : selector_factory(selector_factory) + , enabled_full(enabled_full) { - SP_COLOR_SELECTOR(colorbook)->base = new ColorNotebook( SP_COLOR_SELECTOR(colorbook) ); - - if ( SP_COLOR_SELECTOR(colorbook)->base ) - { - SP_COLOR_SELECTOR(colorbook)->base->init(); - } } -void ColorNotebook::init() + +void ColorNotebook::_initUI() { guint row = 0; - _updating = false; - - _book = gtk_notebook_new (); - gtk_widget_show (_book); - - // Dont show the notebook tabs, use radiobuttons instead - gtk_notebook_set_show_border (GTK_NOTEBOOK (_book), false); - gtk_notebook_set_show_tabs (GTK_NOTEBOOK (_book), false); + Gtk::Notebook *notebook = Gtk::manage(new Gtk::Notebook); + notebook->show(); + notebook->set_show_border(false); + notebook->set_show_tabs(false); + _book = GTK_WIDGET(notebook->gobj()); #if GTK_CHECK_VERSION(3,0,0) _buttonbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 2); @@ -158,16 +128,6 @@ void ColorNotebook::init() _addPage(_available_pages[i]); } -#if GTK_CHECK_VERSION(3,0,0) - GtkWidget* table = gtk_grid_new(); -#else - GtkWidget* table = gtk_table_new(2, 3, FALSE); -#endif - - gtk_widget_show (table); - - gtk_box_pack_start (GTK_BOX (_csel), table, TRUE, TRUE, 0); - sp_set_font_size_smaller (_buttonbox); #if GTK_CHECK_VERSION(3,0,0) @@ -177,12 +137,9 @@ void ColorNotebook::init() gtk_widget_set_margin_bottom(_buttonbox, YPAD); gtk_widget_set_hexpand(_buttonbox, TRUE); gtk_widget_set_valign(_buttonbox, GTK_ALIGN_CENTER); - gtk_grid_attach(GTK_GRID(table), _buttonbox, 0, row, 2, 1); + attach(*Glib::wrap(_buttonbox), 0, row, 2, 1); #else - gtk_table_attach (GTK_TABLE (table), _buttonbox, 0, 2, row, row + 1, - static_cast(GTK_EXPAND|GTK_FILL), - static_cast(0), - XPAD, YPAD); + attach(*Glib::wrap(_buttonbox), 0, 2, row, row+1, Gtk::EXPAND | Gtk::FILL, static_cast(0), XPAD, YPAD); #endif row++; @@ -194,12 +151,9 @@ void ColorNotebook::init() gtk_widget_set_margin_bottom(_book, YPAD); gtk_widget_set_hexpand(_book, TRUE); gtk_widget_set_vexpand(_book, TRUE); - gtk_grid_attach(GTK_GRID(table), _book, 0, row, 2, 1); + attach(*notebook, 0, row, 2, 1); #else - gtk_table_attach (GTK_TABLE (table), _book, 0, 2, row, row + 1, - static_cast(GTK_EXPAND|GTK_FILL), - static_cast(GTK_EXPAND|GTK_FILL), - XPAD*2, YPAD); + attach(*notebook, 0, 2, row, row+1, Gtk::EXPAND | Gtk::FILL, Gtk::EXPAND | Gtk::FILL, XPAD * 2, YPAD); #endif // restore the last active page @@ -294,7 +248,7 @@ void ColorNotebook::init() gtk_container_add (GTK_CONTAINER (_btn_picker), picker); gtk_widget_set_tooltip_text (_btn_picker, _("Pick colors from image")); gtk_box_pack_start(GTK_BOX(rgbabox), _btn_picker, FALSE, FALSE, 2); - g_signal_connect(G_OBJECT(_btn_picker), "clicked", G_CALLBACK(ColorNotebook::_picker_clicked), _csel); + g_signal_connect(G_OBJECT(_btn_picker), "clicked", G_CALLBACK(ColorNotebook::_onPickerClicked), this); /* Create RGBA entry and color preview */ _rgbal = gtk_label_new_with_mnemonic (_("RGBA_:")); @@ -319,118 +273,60 @@ void ColorNotebook::init() gtk_widget_set_margin_right(rgbabox, XPAD); gtk_widget_set_margin_top(rgbabox, YPAD); gtk_widget_set_margin_bottom(rgbabox, YPAD); + attach(*Glib::wrap(rgbabox), 0, row, 2, 1); gtk_grid_attach(GTK_GRID(table), rgbabox, 0, row, 2, 1); #else - gtk_table_attach (GTK_TABLE (table), rgbabox, 0, 2, row, row + 1, GTK_FILL, GTK_SHRINK, XPAD, YPAD); + attach(*Glib::wrap(rgbabox), 0, 2, row, row + 1, Gtk::FILL, Gtk::SHRINK, XPAD, YPAD); #endif #ifdef SPCS_PREVIEW _p = sp_color_preview_new (0xffffffff); gtk_widget_show (_p); - gtk_table_attach (GTK_TABLE (table), _p, 2, 3, row, row + 1, GTK_FILL, GTK_FILL, XPAD, YPAD); + attach(*Glib::wrap(_p), 2, 3, row, row + 1, Gtk::FILL, Gtk::FILL, XPAD, YPAD); #endif - _switchId = g_signal_connect(G_OBJECT (_book), "switch-page", - G_CALLBACK (sp_color_notebook_switch_page), SP_COLOR_NOTEBOOK(_csel)); - - _selected_color.signal_changed.connect(sigc::mem_fun(this, &ColorNotebook::_onSelectedColorChanged)); - _selected_color.signal_dragged.connect(sigc::mem_fun(this, &ColorNotebook::_onSelectedColorDragged)); - _selected_color.signal_grabbed.connect(sigc::mem_fun(this, &ColorNotebook::_onSelectedColorGrabbed)); - _selected_color.signal_released.connect(sigc::mem_fun(this, &ColorNotebook::_onSelectedColorReleased)); + g_signal_connect(G_OBJECT (_book), "switch-page", + G_CALLBACK (ColorNotebook::_onPageSwitched), this); } -static void sp_color_notebook_dispose(GObject *object) +void ColorNotebook::_onPickerClicked(GtkWidget * /*widget*/, ColorNotebook * /*colorbook*/) { - if (((GObjectClass *) (parent_class))->dispose) - (* ((GObjectClass *) (parent_class))->dispose) (object); + // Set the dropper into a "one click" mode, so it reverts to the previous tool after a click + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + prefs->setBool("/tools/dropper/onetimepick", true); + Inkscape::UI::Tools::sp_toggle_dropper(SP_ACTIVE_DESKTOP); } -ColorNotebook::~ColorNotebook() +void ColorNotebook::_onButtonClicked(GtkWidget *widget, ColorNotebook *nb) { - if ( _switchId ) - { - if ( _book ) - { - g_signal_handler_disconnect (_book, _switchId); - _switchId = 0; - } + if (!gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(widget))) { + return; } - if ( _buttons ) - { - delete [] _buttons; - _buttons = 0; + for(gint i = 0; i < gtk_notebook_get_n_pages (GTK_NOTEBOOK (nb->_book)); i++) { + if (nb->_buttons[i] == widget) { + gtk_notebook_set_current_page (GTK_NOTEBOOK (nb->_book), i); + } } - } -static void -sp_color_notebook_show_all (GtkWidget *widget) -{ - gtk_widget_show (widget); -} - -static void sp_color_notebook_hide(GtkWidget *widget) -{ - gtk_widget_hide(widget); -} - -GtkWidget *sp_color_notebook_new() -{ - SPColorNotebook *colorbook = SP_COLOR_NOTEBOOK(g_object_new (SP_TYPE_COLOR_NOTEBOOK, NULL)); - - return GTK_WIDGET(colorbook); -} - -ColorNotebook::ColorNotebook( SPColorSelector* csel ) - : ColorSelector( csel ) - , _selected_color(_selected_color_tmp) -{ - Page *page; - - page = new Page(new ColorScalesFactory(SP_COLOR_SCALES_MODE_RGB), true); - _available_pages.push_back(page); - page = new Page(new ColorScalesFactory(SP_COLOR_SCALES_MODE_HSV), true); - _available_pages.push_back(page); - page = new Page(new ColorScalesFactory(SP_COLOR_SCALES_MODE_CMYK), true); - _available_pages.push_back(page); - page = new Page(new ColorWheelSelectorFactory, true); - _available_pages.push_back(page); -#if defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) - page = new Page(new ColorICCSelectorFactory, true); - _available_pages.push_back(page); -#endif -} - -Gtk::Widget *ColorNotebook::create(SelectedColor &color) { - GtkWidget *w = sp_color_selector_new(SP_TYPE_COLOR_NOTEBOOK); - SPColorSelector *s = SP_COLOR_SELECTOR(w); - ColorNotebook* nb = dynamic_cast(s->base); - return Glib::wrap(w); -} - -ColorNotebook::Page::Page(Inkscape::UI::ColorSelectorFactory *selector_factory, bool enabled_full) - : selector_factory(selector_factory) - , enabled_full(enabled_full) -{ -} - -void ColorNotebook::_colorChanged() -{ - _updating = true; - _selected_color.setColorAlpha(_color, _alpha); +void ColorNotebook::_onSelectedColorChanged() { _updateICCButtons(); - _updating = false; } -void ColorNotebook::_picker_clicked(GtkWidget * /*widget*/, SPColorNotebook * /*colorbook*/) +void ColorNotebook::_onPageSwitched(GtkNotebook *notebook, + GtkWidget *page, + guint page_num, + ColorNotebook *colorbook) { - // Set the dropper into a "one click" mode, so it reverts to the previous tool after a click - Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - prefs->setBool("/tools/dropper/onetimepick", true); - Inkscape::UI::Tools::sp_toggle_dropper(SP_ACTIVE_DESKTOP); + if (colorbook) { + // remember the page we switched to + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + prefs->setInt("/colorselector/page", page_num); + } } + // TODO pass in param so as to avoid the need for SP_ACTIVE_DOCUMENT void ColorNotebook::_updateICCButtons() { @@ -483,60 +379,7 @@ void ColorNotebook::_setCurrentPage(int i) } } -void ColorNotebook::_buttonClicked(GtkWidget *widget, SPColorNotebook *colorbook) -{ - ColorNotebook* nb = dynamic_cast(SP_COLOR_SELECTOR(colorbook)->base); - - if (!gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(widget))) { - return; - } - - for(gint i = 0; i < gtk_notebook_get_n_pages (GTK_NOTEBOOK (nb->_book)); i++) { - if (nb->_buttons[i] == widget) { - gtk_notebook_set_current_page (GTK_NOTEBOOK (nb->_book), i); - } - } -} - -void ColorNotebook::_onSelectedColorChanged() { - if (_updating) { - return; - } - - SPColor color; - gfloat alpha = 1.0; - _selected_color.colorAlpha(color, alpha); - _updateInternals(color, alpha, false); - _updateICCButtons(); -} - -void ColorNotebook::_onSelectedColorDragged() { - if (_updating) { - return; - } - SPColor color; - gfloat alpha = 1.0; - _selected_color.colorAlpha(color, alpha); - _updateInternals(color, alpha, true); - _updateICCButtons(); -} - -void ColorNotebook::_onSelectedColorGrabbed() { - if (_updating) { - return; - } - - _grabbed(); -} - -void ColorNotebook::_onSelectedColorReleased() { - if (_updating) { - return; - } - _released(); -} - -GtkWidget* ColorNotebook::_addPage(Page& page) { +void ColorNotebook::_addPage(Page& page) { Gtk::Widget *selector_widget; selector_widget = page.selector_factory->createWidget(_selected_color); @@ -556,12 +399,13 @@ GtkWidget* ColorNotebook::_addPage(Page& page) { gtk_widget_show (_buttons[page_num]); gtk_box_pack_start (GTK_BOX (_buttonbox), _buttons[page_num], TRUE, TRUE, 0); - g_signal_connect (G_OBJECT (_buttons[page_num]), "clicked", G_CALLBACK (_buttonClicked), _csel); + g_signal_connect (G_OBJECT (_buttons[page_num]), "clicked", G_CALLBACK (_onButtonClicked), this); } - - return selector_widget->gobj(); } +} +} +} /* Commented out: see comment at the bottom of the header file diff --git a/src/ui/widget/color-notebook.h b/src/ui/widget/color-notebook.h index 177519e25..8b74f20f1 100644 --- a/src/ui/widget/color-notebook.h +++ b/src/ui/widget/color-notebook.h @@ -1,16 +1,18 @@ -#ifndef SEEN_SP_COLOR_NOTEBOOK_H -#define SEEN_SP_COLOR_NOTEBOOK_H - -/* +/** + * @file * A notebook with RGB, CMYK, CMS, HSL, and Wheel pages - * - * Author: + */ +/* Authors: * Lauris Kaplinski + * bulia byak + * Tomasz Boczkowski (c++-sification) * - * Copyright (C) 2001-2002 Lauris Kaplinski + * Copyright (C) 2001-2014 Authors * * This code is in public domain */ +#ifndef SEEN_SP_COLOR_NOTEBOOK_H +#define SEEN_SP_COLOR_NOTEBOOK_H #ifdef HAVE_CONFIG_H # include @@ -23,26 +25,30 @@ #include #include #include +#if GTK_CHECK_VERSION(3,0,0) +#include +#else #include +#endif #include "color.h" -#include "widgets/sp-color-selector.h" #include "ui/selected-color.h" +namespace Inkscape { +namespace UI { +namespace Widget { -struct SPColorNotebook; - -class ColorNotebook: public ColorSelector +class ColorNotebook +#if GTK_CHECK_VERSION(3,0,0) + : public Gtk::Grid +#else + : public Gtk::Table +#endif { public: - ColorNotebook( SPColorSelector* csel ); + ColorNotebook(SelectedColor &color); virtual ~ColorNotebook(); - //Temporary factory method - transition from SPColorSelector - static Gtk::Widget* create(Inkscape::UI::SelectedColor &color); - - virtual void init(); - protected: struct Page { Page(Inkscape::UI::ColorSelectorFactory *selector_factory, bool enabled_full); @@ -51,25 +57,19 @@ protected: bool enabled_full; }; - static void _buttonClicked(GtkWidget *widget, SPColorNotebook *colorbook); - static void _picker_clicked(GtkWidget *widget, SPColorNotebook *colorbook); - - virtual void _colorChanged(); + virtual void _initUI(); + void _addPage(Page& page); + static void _onButtonClicked(GtkWidget *widget, ColorNotebook *colorbook); + static void _onPickerClicked(GtkWidget *widget, ColorNotebook *colorbook); + static void _onPageSwitched(GtkNotebook *notebook, GtkWidget *page, + guint page_num, ColorNotebook *colorbook); virtual void _onSelectedColorChanged(); - virtual void _onSelectedColorDragged(); - virtual void _onSelectedColorGrabbed(); - virtual void _onSelectedColorReleased(); void _updateICCButtons(); void _setCurrentPage(int i); - GtkWidget* _addPage(Page& page); - - Inkscape::UI::SelectedColor _selected_color_tmp; Inkscape::UI::SelectedColor &_selected_color; - gboolean _updating : 1; - gulong _switchId; gulong _entryId; GtkWidget *_book; GtkWidget *_buttonbox; @@ -103,40 +103,10 @@ private: */ }; - - - - -#define SP_TYPE_COLOR_NOTEBOOK (sp_color_notebook_get_type ()) -#define SP_COLOR_NOTEBOOK(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), SP_TYPE_COLOR_NOTEBOOK, SPColorNotebook)) -#define SP_COLOR_NOTEBOOK_CLASS(k) (G_TYPE_CHECK_CLASS_CAST ((k), SP_TYPE_COLOR_NOTEBOOK, SPColorNotebookClass)) -#define SP_IS_COLOR_NOTEBOOK(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), SP_TYPE_COLOR_NOTEBOOK)) -#define SP_IS_COLOR_NOTEBOOK_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), SP_TYPE_COLOR_NOTEBOOK)) - -struct SPColorNotebook { - SPColorSelector parent; /* Parent */ -}; - -struct SPColorNotebookClass { - SPColorSelectorClass parent_class; - - void (* grabbed) (SPColorNotebook *rgbsel); - void (* dragged) (SPColorNotebook *rgbsel); - void (* released) (SPColorNotebook *rgbsel); - void (* changed) (SPColorNotebook *rgbsel); -}; - -GType sp_color_notebook_get_type(void); - -GtkWidget *sp_color_notebook_new (void); - -/* void sp_color_notebook_set_mode (SPColorNotebook *csel, SPColorNotebookMode mode); */ -/* SPColorNotebookMode sp_color_notebook_get_mode (SPColorNotebook *csel); */ - - - +} +} +} #endif // SEEN_SP_COLOR_NOTEBOOK_H - /* Local Variables: mode:c++ diff --git a/src/ui/widget/color-picker.cpp b/src/ui/widget/color-picker.cpp index dc827f377..a9948309e 100644 --- a/src/ui/widget/color-picker.cpp +++ b/src/ui/widget/color-picker.cpp @@ -57,7 +57,7 @@ void ColorPicker::setupDialog(const Glib::ustring &title) _colorSelectorDialog.set_title (title); _colorSelectorDialog.set_border_width (4); - _color_selector = Gtk::manage(ColorNotebook::create(_selected_color)); + _color_selector = Gtk::manage(new ColorNotebook(_selected_color)); #if WITH_GTKMM_3_0 _colorSelectorDialog.get_content_area()->pack_start ( diff --git a/src/widgets/gradient-vector.cpp b/src/widgets/gradient-vector.cpp index 2d654ac43..e751f4872 100644 --- a/src/widgets/gradient-vector.cpp +++ b/src/widgets/gradient-vector.cpp @@ -856,6 +856,8 @@ static void sp_grd_ed_del_stop(GtkWidget */*widget*/, GtkWidget *vb) static GtkWidget * sp_gradient_vector_widget_new(SPGradient *gradient, SPStop *select_stop) { + using Inkscape::UI::Widget::ColorNotebook; + GtkWidget *vb, *w, *f; g_return_val_if_fail(!gradient || SP_IS_GRADIENT(gradient), NULL); @@ -991,7 +993,7 @@ static GtkWidget * sp_gradient_vector_widget_new(SPGradient *gradient, SPStop *s selected_color->signal_dragged.connect(sigc::bind(sigc::ptr_fun(&sp_gradient_vector_color_dragged), selected_color, G_OBJECT(vb))); selected_color->signal_dragged.connect(sigc::bind(sigc::ptr_fun(&sp_gradient_vector_color_changed), selected_color, G_OBJECT(vb))); - Gtk::Widget *color_selector = Gtk::manage(ColorNotebook::create(*selected_color)); + Gtk::Widget *color_selector = Gtk::manage(new ColorNotebook(*selected_color)); color_selector->show(); gtk_container_add(GTK_CONTAINER(f), color_selector->gobj()); diff --git a/src/widgets/paint-selector.cpp b/src/widgets/paint-selector.cpp index 3f2edb4f2..a7e8e9750 100644 --- a/src/widgets/paint-selector.cpp +++ b/src/widgets/paint-selector.cpp @@ -657,6 +657,8 @@ void SPPaintSelector::onSelectedColorChanged() { static void sp_paint_selector_set_mode_color(SPPaintSelector *psel, SPPaintSelector::Mode /*mode*/) { + using Inkscape::UI::Widget::ColorNotebook; + sp_paint_selector_set_style_buttons(psel, psel->solid); gtk_widget_set_sensitive(psel->style, TRUE); @@ -677,7 +679,7 @@ static void sp_paint_selector_set_mode_color(SPPaintSelector *psel, SPPaintSelec gtk_widget_show(vb); /* Color selector */ - Gtk::Widget *color_selector = Gtk::manage(ColorNotebook::create(*(psel->selected_color))); + Gtk::Widget *color_selector = Gtk::manage(new ColorNotebook(*(psel->selected_color))); color_selector->show(); gtk_box_pack_start(GTK_BOX(vb), color_selector->gobj(), TRUE, TRUE, 0); diff --git a/src/widgets/swatch-selector.cpp b/src/widgets/swatch-selector.cpp index eb8bf7a4f..6f2807255 100644 --- a/src/widgets/swatch-selector.cpp +++ b/src/widgets/swatch-selector.cpp @@ -22,6 +22,8 @@ SwatchSelector::SwatchSelector() : _gsel(0), _updating_color(false) { + using Inkscape::UI::Widget::ColorNotebook; + GtkWidget *gsel = sp_gradient_selector_new(); _gsel = SP_GRADIENT_SELECTOR(gsel); g_object_set_data( G_OBJECT(gobj()), "base", this ); @@ -31,7 +33,7 @@ SwatchSelector::SwatchSelector() : pack_start(*Gtk::manage(Glib::wrap(gsel))); - Gtk::Widget *color_selector = Gtk::manage(ColorNotebook::create(_selected_color)); + Gtk::Widget *color_selector = Gtk::manage(new ColorNotebook(_selected_color)); color_selector->show(); pack_start(*color_selector); -- cgit v1.2.3 From efd7b21b6d262e6bfe63106883e072e6e49142f4 Mon Sep 17 00:00:00 2001 From: Tomasz Boczkowski Date: Sun, 1 Jun 2014 20:44:37 +0200 Subject: fixed updating drawing when dragging a color slider (bzr r13341.6.53) --- src/widgets/paint-selector.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/widgets/paint-selector.cpp b/src/widgets/paint-selector.cpp index a7e8e9750..fe71df150 100644 --- a/src/widgets/paint-selector.cpp +++ b/src/widgets/paint-selector.cpp @@ -308,9 +308,9 @@ sp_paint_selector_init(SPPaintSelector *psel) psel->updating_color = false; psel->selected_color->signal_grabbed.connect(sigc::mem_fun(psel, &SPPaintSelector::onSelectedColorGrabbed)); - psel->selected_color->signal_grabbed.connect(sigc::mem_fun(psel, &SPPaintSelector::onSelectedColorDragged)); - psel->selected_color->signal_grabbed.connect(sigc::mem_fun(psel, &SPPaintSelector::onSelectedColorReleased)); - psel->selected_color->signal_grabbed.connect(sigc::mem_fun(psel, &SPPaintSelector::onSelectedColorChanged)); + psel->selected_color->signal_dragged.connect(sigc::mem_fun(psel, &SPPaintSelector::onSelectedColorDragged)); + psel->selected_color->signal_released.connect(sigc::mem_fun(psel, &SPPaintSelector::onSelectedColorReleased)); + psel->selected_color->signal_changed.connect(sigc::mem_fun(psel, &SPPaintSelector::onSelectedColorChanged)); } static void sp_paint_selector_dispose(GObject *object) -- cgit v1.2.3 From 52bcd98c0adb78d5c5ae8c74c993d5fd04689079 Mon Sep 17 00:00:00 2001 From: Tomasz Boczkowski Date: Sun, 1 Jun 2014 20:57:39 +0200 Subject: gtk3 compile fix (bzr r13341.6.54) --- src/ui/widget/color-notebook.cpp | 1 - 1 file changed, 1 deletion(-) (limited to 'src') diff --git a/src/ui/widget/color-notebook.cpp b/src/ui/widget/color-notebook.cpp index 32a141e08..2a2cb22a6 100644 --- a/src/ui/widget/color-notebook.cpp +++ b/src/ui/widget/color-notebook.cpp @@ -274,7 +274,6 @@ void ColorNotebook::_initUI() gtk_widget_set_margin_top(rgbabox, YPAD); gtk_widget_set_margin_bottom(rgbabox, YPAD); attach(*Glib::wrap(rgbabox), 0, row, 2, 1); - gtk_grid_attach(GTK_GRID(table), rgbabox, 0, row, 2, 1); #else attach(*Glib::wrap(rgbabox), 0, 2, row, row + 1, Gtk::FILL, Gtk::SHRINK, XPAD, YPAD); #endif -- cgit v1.2.3 From a7f2b2ba3f13ceb60376802f4a31e104153839e8 Mon Sep 17 00:00:00 2001 From: Marc Jeanmougin Date: Tue, 17 Feb 2015 03:00:37 +0100 Subject: At first, I was thinking "I just have to go to the selection file, and change that GSList* with a std::list, then resolve the few problems" So, i tried that. And I will continue tomorrow, and the days after, on and on. (bzr r13922.1.1) --- src/conn-avoid-ref.cpp | 5 +- src/desktop-style.cpp | 120 ++-- src/desktop-style.h | 25 +- src/extension/execution-env.cpp | 8 +- src/extension/implementation/implementation.cpp | 7 +- src/extension/implementation/script.cpp | 7 +- src/extension/internal/bitmap/imagemagick.cpp | 16 +- src/extension/internal/bluredge.cpp | 7 +- src/extension/internal/cairo-renderer.cpp | 8 +- src/extension/internal/filter/filter.cpp | 8 +- src/extension/internal/grid.cpp | 7 +- src/extension/internal/latex-text-renderer.cpp | 8 +- src/file.cpp | 6 +- src/filter-chemistry.cpp | 2 +- src/gradient-chemistry.cpp | 12 +- src/gradient-drag.cpp | 17 +- src/graphlayout.cpp | 10 +- src/graphlayout.h | 4 +- src/helper/png-write.cpp | 12 +- src/helper/png-write.h | 9 +- src/live_effects/lpe-knot.cpp | 6 +- src/main.cpp | 23 +- src/object-snapper.cpp | 5 +- src/path-chemistry.cpp | 125 ++-- src/path-chemistry.h | 2 +- src/removeoverlap.cpp | 12 +- src/removeoverlap.h | 2 +- src/selcue.cpp | 19 +- src/selection-chemistry.cpp | 779 +++++++++++------------- src/selection-chemistry.h | 11 +- src/selection-describer.cpp | 34 +- src/selection.cpp | 159 +++-- src/selection.h | 38 +- src/seltrans.cpp | 54 +- src/seltrans.h | 2 +- src/snap.cpp | 14 +- src/snap.h | 8 +- src/sp-conn-end.cpp | 5 +- src/sp-defs.cpp | 9 +- src/sp-filter.cpp | 9 +- src/sp-item-group.cpp | 91 ++- src/sp-item-group.h | 5 +- src/sp-lpe-item.cpp | 30 +- src/sp-marker.cpp | 6 +- src/sp-marker.h | 2 +- src/sp-object.cpp | 6 +- src/sp-object.h | 10 +- src/sp-pattern.cpp | 6 +- src/sp-pattern.h | 2 +- src/sp-switch.cpp | 24 +- src/sp-switch.h | 2 +- src/splivarot.cpp | 102 ++-- src/text-chemistry.cpp | 83 ++- src/text-editing.cpp | 7 +- src/trace/trace.cpp | 8 +- src/ui/clipboard.cpp | 33 +- src/ui/dialog/align-and-distribute.cpp | 87 +-- src/ui/dialog/clonetiler.cpp | 14 +- src/ui/dialog/export.cpp | 28 +- src/ui/dialog/filter-effects-dialog.cpp | 27 +- src/ui/dialog/find.cpp | 92 +-- src/ui/dialog/find.h | 11 +- src/ui/dialog/glyphs.cpp | 12 +- src/ui/interface.cpp | 17 +- src/unclump.cpp | 57 +- src/unclump.h | 3 +- src/vanishing-point.cpp | 26 +- src/widgets/arc-toolbar.cpp | 33 +- src/widgets/connector-toolbar.cpp | 16 +- src/widgets/fill-style.cpp | 32 +- src/widgets/gradient-toolbar.cpp | 15 +- src/widgets/mesh-toolbar.cpp | 10 +- src/widgets/rect-toolbar.cpp | 18 +- src/widgets/spiral-toolbar.cpp | 16 +- src/widgets/star-toolbar.cpp | 38 +- src/widgets/stroke-style.cpp | 29 +- src/widgets/stroke-style.h | 2 +- src/widgets/text-toolbar.cpp | 34 +- 78 files changed, 1283 insertions(+), 1365 deletions(-) (limited to 'src') diff --git a/src/conn-avoid-ref.cpp b/src/conn-avoid-ref.cpp index c13b9a5d3..f2cde352c 100644 --- a/src/conn-avoid-ref.cpp +++ b/src/conn-avoid-ref.cpp @@ -252,8 +252,9 @@ static std::vector approxItemWithPoints(SPItem const *item, const G { SPGroup* group = SP_GROUP(item); // consider all first-order children - for (GSList const* i = sp_item_group_item_list(group); i != NULL; i = i->next) { - SPItem* child_item = SP_ITEM(i->data); + SelContainer itemlist = sp_item_group_item_list(group); + for (SelContainer::const_iterator i=itemlist.begin();i!=itemlist.end();i++) { + SPItem* child_item = SP_ITEM(*i); std::vector child_points = approxItemWithPoints(child_item, item_transform * child_item->transform); poly_points.insert(poly_points.end(), child_points.begin(), child_points.end()); } diff --git a/src/desktop-style.cpp b/src/desktop-style.cpp index ee9fa39ec..39dfad44b 100644 --- a/src/desktop-style.cpp +++ b/src/desktop-style.cpp @@ -194,10 +194,10 @@ sp_desktop_set_style(SPDesktop *desktop, SPCSSAttr *css, bool change, bool write sp_repr_css_merge(css_write, css); sp_css_attr_unset_uris(css_write); prefs->mergeStyle("/desktop/style", css_write); - - for (const GSList *i = desktop->selection->itemList(); i != NULL; i = i->next) { + SelContainer const itemlist = desktop->selection->itemList(); + for (SelContainer::const_iterator i=itemlist.begin();i!=itemlist.end();i++) { /* last used styles for 3D box faces are stored separately */ - SPObject *obj = reinterpret_cast(i->data); // TODO unsafe until Selection is refactored. + SPObject *obj = reinterpret_cast(*i); // TODO unsafe until Selection is refactored. Box3DSide *side = dynamic_cast(obj); if (side) { const char * descr = box3d_side_axes_string(side); @@ -234,8 +234,9 @@ sp_desktop_set_style(SPDesktop *desktop, SPCSSAttr *css, bool change, bool write sp_repr_css_merge(css_no_text, css); css_no_text = sp_css_attr_unset_text(css_no_text); - for (GSList const *i = desktop->selection->itemList(); i != NULL; i = i->next) { - SPItem *item = reinterpret_cast(i->data); + SelContainer const itemlist = desktop->selection->itemList(); + for (SelContainer::const_iterator i=itemlist.begin();i!=itemlist.end();i++) { + SPItem *item = reinterpret_cast(*i); // If not text, don't apply text attributes (can a group have text attributes? Yes! FIXME) if (isTextualItem(item)) { @@ -438,17 +439,16 @@ sp_desktop_get_font_size_tool(SPDesktop *desktop) /** Determine average stroke width, simple method */ // see TODO in dialogs/stroke-style.cpp on how to get rid of this eventually gdouble -stroke_average_width (GSList const *objects) +stroke_average_width (const SelContainer &objects) { - if (g_slist_length ((GSList *) objects) == 0) + if (objects.empty()) return Geom::infinity(); gdouble avgwidth = 0.0; bool notstroked = true; int n_notstroked = 0; - - for (GSList const *l = objects; l != NULL; l = l->next) { - SPObject *obj = reinterpret_cast(l->data); + for (SelContainer::const_iterator i=objects.begin();i!=objects.end();i++) { + SPObject *obj = reinterpret_cast(*i); SPItem *item = dynamic_cast(obj); if (!item) { continue; @@ -471,7 +471,7 @@ stroke_average_width (GSList const *objects) if (notstroked) return Geom::infinity(); - return avgwidth / (g_slist_length ((GSList *) objects) - n_notstroked); + return avgwidth / (objects.size() - n_notstroked); } static bool vectorsClose( std::vector const &lhs, std::vector const &rhs ) @@ -492,9 +492,9 @@ static bool vectorsClose( std::vector const &lhs, std::vector co * Write to style_res the average fill or stroke of list of objects, if applicable. */ int -objects_query_fillstroke (GSList *objects, SPStyle *style_res, bool const isfill) +objects_query_fillstroke (const SelContainer &objects, SPStyle *style_res, bool const isfill) { - if (g_slist_length(objects) == 0) { + if (objects.empty()) { /* No objects, set empty */ return QUERY_STYLE_NOTHING; } @@ -514,8 +514,8 @@ objects_query_fillstroke (GSList *objects, SPStyle *style_res, bool const isfill prev[0] = prev[1] = prev[2] = 0.0; bool same_color = true; - for (GSList const *i = objects; i != NULL; i = i->next) { - SPObject *obj = reinterpret_cast(i->data); + for (SelContainer::const_iterator i=objects.begin();i!=objects.end();i++) { + SPObject *obj = reinterpret_cast(*i); if (!obj) { continue; } @@ -674,7 +674,7 @@ objects_query_fillstroke (GSList *objects, SPStyle *style_res, bool const isfill } // Not color - if (g_slist_length(objects) > 1) { + if (objects.size() > 1) { return QUERY_STYLE_MULTIPLE_SAME; } else { return QUERY_STYLE_SINGLE; @@ -685,9 +685,9 @@ objects_query_fillstroke (GSList *objects, SPStyle *style_res, bool const isfill * Write to style_res the average opacity of a list of objects. */ int -objects_query_opacity (GSList *objects, SPStyle *style_res) +objects_query_opacity (const SelContainer &objects, SPStyle *style_res) { - if (g_slist_length(objects) == 0) { + if (objects.empty()) { /* No objects, set empty */ return QUERY_STYLE_NOTHING; } @@ -698,8 +698,8 @@ objects_query_opacity (GSList *objects, SPStyle *style_res) guint opacity_items = 0; - for (GSList const *i = objects; i != NULL; i = i->next) { - SPObject *obj = reinterpret_cast(i->data); + for (SelContainer::const_iterator i=objects.begin();i!=objects.end();i++) { + SPObject *obj = reinterpret_cast(*i); if (!obj) { continue; } @@ -739,9 +739,9 @@ objects_query_opacity (GSList *objects, SPStyle *style_res) * Write to style_res the average stroke width of a list of objects. */ int -objects_query_strokewidth (GSList *objects, SPStyle *style_res) +objects_query_strokewidth (const SelContainer &objects, SPStyle *style_res) { - if (g_slist_length(objects) == 0) { + if (objects.empty()) { /* No objects, set empty */ return QUERY_STYLE_NOTHING; } @@ -754,8 +754,8 @@ objects_query_strokewidth (GSList *objects, SPStyle *style_res) int n_stroked = 0; - for (GSList const *i = objects; i != NULL; i = i->next) { - SPObject *obj = reinterpret_cast(i->data); + for (SelContainer::const_iterator i=objects.begin();i!=objects.end();i++) { + SPObject *obj = reinterpret_cast(*i); if (!obj) { continue; } @@ -815,9 +815,9 @@ objects_query_strokewidth (GSList *objects, SPStyle *style_res) * Write to style_res the average miter limit of a list of objects. */ int -objects_query_miterlimit (GSList *objects, SPStyle *style_res) +objects_query_miterlimit (const SelContainer &objects, SPStyle *style_res) { - if (g_slist_length(objects) == 0) { + if (objects.empty()) { /* No objects, set empty */ return QUERY_STYLE_NOTHING; } @@ -828,8 +828,8 @@ objects_query_miterlimit (GSList *objects, SPStyle *style_res) gdouble prev_ml = -1; bool same_ml = true; - for (GSList const *i = objects; i != NULL; i = i->next) { - SPObject *obj = reinterpret_cast(i->data); + for (SelContainer::const_iterator i=objects.begin();i!=objects.end();i++) { + SPObject *obj = reinterpret_cast(*i); if (!dynamic_cast(obj)) { continue; } @@ -875,9 +875,9 @@ objects_query_miterlimit (GSList *objects, SPStyle *style_res) * Write to style_res the stroke cap of a list of objects. */ int -objects_query_strokecap (GSList *objects, SPStyle *style_res) +objects_query_strokecap (const SelContainer &objects, SPStyle *style_res) { - if (g_slist_length(objects) == 0) { + if (objects.empty()) { /* No objects, set empty */ return QUERY_STYLE_NOTHING; } @@ -887,8 +887,8 @@ objects_query_strokecap (GSList *objects, SPStyle *style_res) bool same_cap = true; int n_stroked = 0; - for (GSList const *i = objects; i != NULL; i = i->next) { - SPObject *obj = reinterpret_cast(i->data); + for (SelContainer::const_iterator i=objects.begin();i!=objects.end();i++) { + SPObject *obj = reinterpret_cast(*i); if (!dynamic_cast(obj)) { continue; } @@ -929,9 +929,9 @@ objects_query_strokecap (GSList *objects, SPStyle *style_res) * Write to style_res the stroke join of a list of objects. */ int -objects_query_strokejoin (GSList *objects, SPStyle *style_res) +objects_query_strokejoin (const SelContainer &objects, SPStyle *style_res) { - if (g_slist_length(objects) == 0) { + if (objects.empty()) { /* No objects, set empty */ return QUERY_STYLE_NOTHING; } @@ -941,8 +941,8 @@ objects_query_strokejoin (GSList *objects, SPStyle *style_res) bool same_join = true; int n_stroked = 0; - for (GSList const *i = objects; i != NULL; i = i->next) { - SPObject *obj = reinterpret_cast(i->data); + for (SelContainer::const_iterator i=objects.begin();i!=objects.end();i++) { + SPObject *obj = reinterpret_cast(*i); if (!dynamic_cast(obj)) { continue; } @@ -984,7 +984,7 @@ objects_query_strokejoin (GSList *objects, SPStyle *style_res) * Write to style_res the average font size and spacing of objects. */ int -objects_query_fontnumbers (GSList *objects, SPStyle *style_res) +objects_query_fontnumbers (const SelContainer &objects, SPStyle *style_res) { bool different = false; @@ -1004,8 +1004,8 @@ objects_query_fontnumbers (GSList *objects, SPStyle *style_res) int texts = 0; int no_size = 0; - for (GSList const *i = objects; i != NULL; i = i->next) { - SPObject *obj = reinterpret_cast(i->data); + for (SelContainer::const_iterator i=objects.begin();i!=objects.end();i++) { + SPObject *obj = reinterpret_cast(*i); if (!isTextualItem(obj)) { continue; @@ -1116,15 +1116,15 @@ objects_query_fontnumbers (GSList *objects, SPStyle *style_res) * Write to style_res the average font style of objects. */ int -objects_query_fontstyle (GSList *objects, SPStyle *style_res) +objects_query_fontstyle (const SelContainer &objects, SPStyle *style_res) { bool different = false; bool set = false; int texts = 0; - for (GSList const *i = objects; i != NULL; i = i->next) { - SPObject *obj = reinterpret_cast(i->data); + for (SelContainer::const_iterator i=objects.begin();i!=objects.end();i++) { + SPObject *obj = reinterpret_cast(*i); if (!isTextualItem(obj)) { continue; @@ -1173,7 +1173,7 @@ objects_query_fontstyle (GSList *objects, SPStyle *style_res) * Write to style_res the baseline numbers. */ static int -objects_query_baselines (GSList *objects, SPStyle *style_res) +objects_query_baselines (const SelContainer &objects, SPStyle *style_res) { bool different = false; @@ -1192,8 +1192,8 @@ objects_query_baselines (GSList *objects, SPStyle *style_res) int texts = 0; - for (GSList const *i = objects; i != NULL; i = i->next) { - SPObject *obj = reinterpret_cast(i->data); + for (SelContainer::const_iterator i=objects.begin();i!=objects.end();i++) { + SPObject *obj = reinterpret_cast(*i); if (!isTextualItem(obj)) { continue; @@ -1269,7 +1269,7 @@ objects_query_baselines (GSList *objects, SPStyle *style_res) * Write to style_res the average font family of objects. */ int -objects_query_fontfamily (GSList *objects, SPStyle *style_res) +objects_query_fontfamily (const SelContainer &objects, SPStyle *style_res) { bool different = false; int texts = 0; @@ -1280,8 +1280,8 @@ objects_query_fontfamily (GSList *objects, SPStyle *style_res) } style_res->font_family.set = FALSE; - for (GSList const *i = objects; i != NULL; i = i->next) { - SPObject *obj = reinterpret_cast(i->data); + for (SelContainer::const_iterator i=objects.begin();i!=objects.end();i++) { + SPObject *obj = reinterpret_cast(*i); // std::cout << " " << reinterpret_cast(i->data)->getId() << std::endl; if (!isTextualItem(obj)) { @@ -1325,7 +1325,7 @@ objects_query_fontfamily (GSList *objects, SPStyle *style_res) } static int -objects_query_fontspecification (GSList *objects, SPStyle *style_res) +objects_query_fontspecification (const SelContainer &objects, SPStyle *style_res) { bool different = false; int texts = 0; @@ -1336,8 +1336,8 @@ objects_query_fontspecification (GSList *objects, SPStyle *style_res) } style_res->font_specification.set = FALSE; - for (GSList const *i = objects; i != NULL; i = i->next) { - SPObject *obj = reinterpret_cast(i->data); + for (SelContainer::const_iterator i=objects.begin();i!=objects.end();i++) { + SPObject *obj = reinterpret_cast(*i); // std::cout << " " << reinterpret_cast(i->data)->getId() << std::endl; if (!isTextualItem(obj)) { @@ -1385,7 +1385,7 @@ objects_query_fontspecification (GSList *objects, SPStyle *style_res) } static int -objects_query_blend (GSList *objects, SPStyle *style_res) +objects_query_blend (const SelContainer &objects, SPStyle *style_res) { const int empty_prev = -2; const int complex_filter = 5; @@ -1394,8 +1394,8 @@ objects_query_blend (GSList *objects, SPStyle *style_res) bool same_blend = true; guint items = 0; - for (GSList const *i = objects; i != NULL; i = i->next) { - SPObject *obj = reinterpret_cast(i->data); + for (SelContainer::const_iterator i=objects.begin();i!=objects.end();i++) { + SPObject *obj = reinterpret_cast(*i); if (!obj) { continue; } @@ -1471,9 +1471,9 @@ objects_query_blend (GSList *objects, SPStyle *style_res) * Write to style_res the average blurring of a list of objects. */ int -objects_query_blur (GSList *objects, SPStyle *style_res) +objects_query_blur (const SelContainer &objects, SPStyle *style_res) { - if (g_slist_length(objects) == 0) { + if (objects.empty()) { /* No objects, set empty */ return QUERY_STYLE_NOTHING; } @@ -1484,8 +1484,8 @@ objects_query_blur (GSList *objects, SPStyle *style_res) guint blur_items = 0; guint items = 0; - for (GSList const *i = objects; i != NULL; i = i->next) { - SPObject *obj = reinterpret_cast(i->data); + for (SelContainer::const_iterator i=objects.begin();i!=objects.end();i++) { + SPObject *obj = reinterpret_cast(*i); if (!obj) { continue; } @@ -1553,7 +1553,7 @@ objects_query_blur (GSList *objects, SPStyle *style_res) * the result to style, return appropriate flag. */ int -sp_desktop_query_style_from_list (GSList *list, SPStyle *style, int property) +sp_desktop_query_style_from_list (const SelContainer &list, SPStyle *style, int property) { if (property == QUERY_STYLE_PROPERTY_FILL) { return objects_query_fillstroke (list, style, true); @@ -1606,7 +1606,7 @@ sp_desktop_query_style(SPDesktop *desktop, SPStyle *style, int property) // otherwise, do querying and averaging over selection if (desktop->selection != NULL) { - return sp_desktop_query_style_from_list ((GSList *) desktop->selection->itemList(), style, property); + return sp_desktop_query_style_from_list (desktop->selection->itemList(), style, property); } return QUERY_STYLE_NOTHING; diff --git a/src/desktop-style.h b/src/desktop-style.h index 40ca27e9e..0e40a2652 100644 --- a/src/desktop-style.h +++ b/src/desktop-style.h @@ -13,6 +13,7 @@ * Released under GNU GPL, read the file 'COPYING' for more information */ +#include "selection.h" // SelContainer class ColorRGBA; class SPCSSAttr; class SPDesktop; @@ -64,21 +65,21 @@ guint32 sp_desktop_get_color_tool(SPDesktop *desktop, Glib::ustring const &tool, double sp_desktop_get_font_size_tool (SPDesktop *desktop); void sp_desktop_apply_style_tool(SPDesktop *desktop, Inkscape::XML::Node *repr, Glib::ustring const &tool, bool with_text); -gdouble stroke_average_width (GSList const *objects); +gdouble stroke_average_width (const SelContainer &objects); -int objects_query_fillstroke (GSList *objects, SPStyle *style_res, bool const isfill); -int objects_query_fontnumbers (GSList *objects, SPStyle *style_res); -int objects_query_fontstyle (GSList *objects, SPStyle *style_res); -int objects_query_fontfamily (GSList *objects, SPStyle *style_res); -int objects_query_opacity (GSList *objects, SPStyle *style_res); -int objects_query_strokewidth (GSList *objects, SPStyle *style_res); -int objects_query_miterlimit (GSList *objects, SPStyle *style_res); -int objects_query_strokecap (GSList *objects, SPStyle *style_res); -int objects_query_strokejoin (GSList *objects, SPStyle *style_res); +int objects_query_fillstroke (const SelContainer &objects, SPStyle *style_res, bool const isfill); +int objects_query_fontnumbers (const SelContainer &objects, SPStyle *style_res); +int objects_query_fontstyle (const SelContainer &objects, SPStyle *style_res); +int objects_query_fontfamily (const SelContainer &objects, SPStyle *style_res); +int objects_query_opacity (const SelContainer &objects, SPStyle *style_res); +int objects_query_strokewidth (const SelContainer &objects, SPStyle *style_res); +int objects_query_miterlimit (const SelContainer &objects, SPStyle *style_res); +int objects_query_strokecap (const SelContainer &objects, SPStyle *style_res); +int objects_query_strokejoin (const SelContainer &objects, SPStyle *style_res); -int objects_query_blur (GSList *objects, SPStyle *style_res); +int objects_query_blur (const SelContainer &objects, SPStyle *style_res); -int sp_desktop_query_style_from_list (GSList *list, SPStyle *style, int property); +int sp_desktop_query_style_from_list (const SelContainer &list, SPStyle *style, int property); int sp_desktop_query_style(SPDesktop *desktop, SPStyle *style, int property); bool sp_desktop_query_style_all (SPDesktop *desktop, SPStyle *query); diff --git a/src/extension/execution-env.cpp b/src/extension/execution-env.cpp index 13b8d60c4..66a8c4358 100644 --- a/src/extension/execution-env.cpp +++ b/src/extension/execution-env.cpp @@ -64,14 +64,12 @@ ExecutionEnv::ExecutionEnv (Effect * effect, Inkscape::UI::View::View * doc, Imp sp_namedview_document_from_window(desktop); if (desktop != NULL) { - Inkscape::Util::GSListConstIterator selected = - desktop->getSelection()->itemList(); - while ( selected != NULL ) { + SelContainer selected = desktop->getSelection()->itemList(); + for(SelContainer::const_iterator x=selected.begin();x!=selected.end();x++){ Glib::ustring selected_id; - selected_id = (*selected)->getId(); + selected_id = (*x)->getId(); _selected.insert(_selected.end(), selected_id); //std::cout << "Selected: " << selected_id << std::endl; - ++selected; } } diff --git a/src/extension/implementation/implementation.cpp b/src/extension/implementation/implementation.cpp index 52f63499a..6eff3ede3 100644 --- a/src/extension/implementation/implementation.cpp +++ b/src/extension/implementation/implementation.cpp @@ -48,11 +48,10 @@ Gtk::Widget *Implementation::prefs_effect(Inkscape::Extension::Effect *module, I SPDocument * current_document = view->doc(); using Inkscape::Util::GSListConstIterator; - // FIXME very unsafe cast - GSListConstIterator selected = ((SPDesktop *)view)->getSelection()->itemList(); + SelContainer selected = ((SPDesktop *)view)->getSelection()->itemList(); Inkscape::XML::Node const* first_select = NULL; - if (selected != NULL) { - const SPItem * item = *selected; + if (!selected.empty()) { + const SPItem * item = SP_ITEM(selected.front()); first_select = item->getRepr(); } diff --git a/src/extension/implementation/script.cpp b/src/extension/implementation/script.cpp index bbc567f75..f396e9848 100644 --- a/src/extension/implementation/script.cpp +++ b/src/extension/implementation/script.cpp @@ -689,14 +689,13 @@ void Script::effect(Inkscape::Extension::Effect *module, return; } - Inkscape::Util::GSListConstIterator selected = + SelContainer selected = desktop->getSelection()->itemList(); //desktop should not be NULL since doc was checked and desktop is a casted pointer - while ( selected != NULL ) { + for(SelContainer::const_iterator x=selected.begin();x!=selected.end();x++){ Glib::ustring selected_id; selected_id += "--id="; - selected_id += (*selected)->getId(); + selected_id += (*x)->getId(); params.insert(params.begin(), selected_id); - ++selected; } file_listener fileout; diff --git a/src/extension/internal/bitmap/imagemagick.cpp b/src/extension/internal/bitmap/imagemagick.cpp index 76f35415e..87ef30887 100644 --- a/src/extension/internal/bitmap/imagemagick.cpp +++ b/src/extension/internal/bitmap/imagemagick.cpp @@ -70,8 +70,8 @@ ImageMagickDocCache::ImageMagickDocCache(Inkscape::UI::View::View * view) : _imageItems(NULL) { SPDesktop *desktop = (SPDesktop*)view; - const GSList *selectedItemList = desktop->selection->itemList(); - int selectCount = g_slist_length((GSList *)selectedItemList); + const SelContainer selectedItemList = desktop->selection->itemList(); + int selectCount = selectedItemList.size(); // Init the data-holders _nodes = new Inkscape::XML::Node*[selectCount]; @@ -83,9 +83,8 @@ ImageMagickDocCache::ImageMagickDocCache(Inkscape::UI::View::View * view) : _imageItems = new SPItem*[selectCount]; // Loop through selected items - for (; selectedItemList != NULL; selectedItemList = g_slist_next(selectedItemList)) - { - SPItem *item = SP_ITEM(selectedItemList->data); + for (SelContainer::const_iterator i=selectedItemList.begin();i!=selectedItemList.end();i++) { + SPItem *item = static_cast(*i); Inkscape::XML::Node *node = reinterpret_cast(item->getRepr()); if (!strcmp(node->name(), "image") || !strcmp(node->name(), "svg:image")) { @@ -243,11 +242,10 @@ ImageMagick::prefs_effect(Inkscape::Extension::Effect *module, Inkscape::UI::Vie using Inkscape::Util::GSListConstIterator; - // FIXME very unsafe cast - GSListConstIterator selected = ((SPDesktop *)view)->getSelection()->itemList(); + SelContainer selected = ((SPDesktop *)view)->getSelection()->itemList(); Inkscape::XML::Node * first_select = NULL; - if (selected != NULL) { - first_select = (*selected)->getRepr(); + if (!selected.empty()) { + first_select = (selected.front())->getRepr(); } return module->autogui(current_document, first_select, changeSignal); diff --git a/src/extension/internal/bluredge.cpp b/src/extension/internal/bluredge.cpp index 3ce537d9f..138172715 100644 --- a/src/extension/internal/bluredge.cpp +++ b/src/extension/internal/bluredge.cpp @@ -65,13 +65,12 @@ BlurEdge::effect (Inkscape::Extension::Effect *module, Inkscape::UI::View::View using Inkscape::Util::GSListConstIterator; // TODO need to properly refcount the items, at least - std::list items; - items.insert >(items.end(), selection->itemList(), NULL); + SelContainer items(selection->itemList()); selection->clear(); - for(std::list::iterator item = items.begin(); + for(SelContainer::iterator item = items.begin(); item != items.end(); ++item) { - SPItem * spitem = *item; + SPItem * spitem = static_cast(*item); std::vector new_items(steps); Inkscape::XML::Document *xml_doc = desktop->doc()->getReprDoc(); diff --git a/src/extension/internal/cairo-renderer.cpp b/src/extension/internal/cairo-renderer.cpp index 1f48d2097..7ce5cdf8a 100644 --- a/src/extension/internal/cairo-renderer.cpp +++ b/src/extension/internal/cairo-renderer.cpp @@ -294,14 +294,14 @@ static void sp_group_render(SPGroup *group, CairoRenderContext *ctx) CairoRenderer *renderer = ctx->getRenderer(); TRACE(("sp_group_render opacity: %f\n", SP_SCALE24_TO_FLOAT(item->style->opacity.value))); - GSList *l = g_slist_reverse(group->childList(false)); - while (l) { - SPObject *o = reinterpret_cast(l->data); + SelContainer l(group->childList(false)); + l.reverse(); + for(SelContainer::const_iterator x=l.begin();x!=l.end();x++){ + SPObject *o = reinterpret_cast(*x); SPItem *item = dynamic_cast(o); if (item) { renderer->renderItem(ctx, item); } - l = g_slist_remove (l, o); } } diff --git a/src/extension/internal/filter/filter.cpp b/src/extension/internal/filter/filter.cpp index a2c565699..821c023ac 100644 --- a/src/extension/internal/filter/filter.cpp +++ b/src/extension/internal/filter/filter.cpp @@ -125,17 +125,15 @@ void Filter::effect(Inkscape::Extension::Effect *module, Inkscape::UI::View::Vie //printf("Calling filter effect\n"); Inkscape::Selection * selection = ((SPDesktop *)document)->selection; - using Inkscape::Util::GSListConstIterator; // TODO need to properly refcount the items, at least - std::list items; - items.insert >(items.end(), selection->itemList(), NULL); + SelContainer items(selection->itemList()); Inkscape::XML::Document * xmldoc = document->doc()->getReprDoc(); Inkscape::XML::Node * defsrepr = document->doc()->getDefs()->getRepr(); - for(std::list::iterator item = items.begin(); + for(SelContainer::iterator item = items.begin(); item != items.end(); ++item) { - SPItem * spitem = *item; + SPItem * spitem = static_cast(*item); Inkscape::XML::Node * node = spitem->getRepr(); SPCSSAttr * css = sp_repr_css_attr(node, "style"); diff --git a/src/extension/internal/grid.cpp b/src/extension/internal/grid.cpp index 270edfe44..4c12f629c 100644 --- a/src/extension/internal/grid.cpp +++ b/src/extension/internal/grid.cpp @@ -192,11 +192,10 @@ Grid::prefs_effect(Inkscape::Extension::Effect *module, Inkscape::UI::View::View using Inkscape::Util::GSListConstIterator; - // FIXME very unsafe cast - GSListConstIterator selected = ((SPDesktop *)view)->getSelection()->itemList(); + SelContainer selected = ((SPDesktop *)view)->getSelection()->itemList(); Inkscape::XML::Node * first_select = NULL; - if (selected != NULL) { - first_select = (*selected)->getRepr(); + if (!selected.empty()) { + first_select = (selected.front())->getRepr(); } return module->autogui(current_document, first_select, changeSignal); diff --git a/src/extension/internal/latex-text-renderer.cpp b/src/extension/internal/latex-text-renderer.cpp index ab0733848..dab27a0e1 100644 --- a/src/extension/internal/latex-text-renderer.cpp +++ b/src/extension/internal/latex-text-renderer.cpp @@ -228,14 +228,14 @@ LaTeXTextRenderer::writePostamble() void LaTeXTextRenderer::sp_group_render(SPGroup *group) { - GSList *l = g_slist_reverse(group->childList(false)); - while (l) { - SPObject *o = reinterpret_cast(l->data); + SelContainer l = (group->childList(false)); + l.reverse(); + for(SelContainer::const_iterator x=l.begin();x!=l.end();x++){ + SPObject *o = reinterpret_cast(*x); SPItem *item = dynamic_cast(o); if (item) { renderItem(item); } - l = g_slist_remove (l, o); } } diff --git a/src/file.cpp b/src/file.cpp index 72516d776..4325c838b 100644 --- a/src/file.cpp +++ b/src/file.cpp @@ -1063,7 +1063,7 @@ void sp_import_document(SPDesktop *desktop, SPDocument *clipdoc, bool in_place) desktop->doc()->importDefs(clipdoc); // copy objects - GSList *pasted_objects = NULL; + std::list pasted_objects; for (Inkscape::XML::Node *obj = root->firstChild() ; obj ; obj = obj->next()) { // Don't copy metadata, defs, named views and internal clipboard contents to the document if (!strcmp(obj->name(), "svg:defs")) { @@ -1082,7 +1082,7 @@ void sp_import_document(SPDesktop *desktop, SPDocument *clipdoc, bool in_place) target_parent->appendChild(obj_copy); Inkscape::GC::release(obj_copy); - pasted_objects = g_slist_prepend(pasted_objects, (gpointer) obj_copy); + pasted_objects.push_front(dynamic_cast(obj_copy)); } // Change the selection to the freshly pasted objects @@ -1123,8 +1123,6 @@ void sp_import_document(SPDesktop *desktop, SPDocument *clipdoc, bool in_place) sp_selection_move_relative(selection, offset); } - - g_slist_free(pasted_objects); } diff --git a/src/filter-chemistry.cpp b/src/filter-chemistry.cpp index 9298a1ffc..c89cf6220 100644 --- a/src/filter-chemistry.cpp +++ b/src/filter-chemistry.cpp @@ -23,9 +23,9 @@ #include "filter-chemistry.h" #include "filter-enums.h" - #include "filters/blend.h" #include "filters/gaussian-blur.h" +#include "selection.h" #include "sp-filter.h" #include "sp-filter-reference.h" #include "svg/css-ostringstream.h" diff --git a/src/gradient-chemistry.cpp b/src/gradient-chemistry.cpp index cf75f6cf0..5f1da6cf1 100644 --- a/src/gradient-chemistry.cpp +++ b/src/gradient-chemistry.cpp @@ -1570,8 +1570,9 @@ void sp_gradient_invert_selected_gradients(SPDesktop *desktop, Inkscape::PaintTa { Inkscape::Selection *selection = desktop->getSelection(); - for (GSList const* i = selection->itemList(); i != NULL; i = i->next) { - sp_item_gradient_invert_vector_color(SP_ITEM(i->data), fill_or_stroke); + const SelContainer list=selection->itemList(); + for (SelContainer::const_iterator i=list.begin();i!=list.end();i++) { + sp_item_gradient_invert_vector_color(SP_ITEM(*i), fill_or_stroke); } // we did an undoable action @@ -1594,9 +1595,10 @@ void sp_gradient_reverse_selected_gradients(SPDesktop *desktop) if (drag && drag->selected) { drag->selected_reverse_vector(); } else { // If no drag or no dragger selected, act on selection (both fill and stroke gradients) - for (GSList const* i = selection->itemList(); i != NULL; i = i->next) { - sp_item_gradient_reverse_vector(SP_ITEM(i->data), Inkscape::FOR_FILL); - sp_item_gradient_reverse_vector(SP_ITEM(i->data), Inkscape::FOR_STROKE); + const SelContainer list=selection->itemList(); + for (SelContainer::const_iterator i=list.begin();i!=list.end();i++) { + sp_item_gradient_reverse_vector(SP_ITEM(*i), Inkscape::FOR_FILL); + sp_item_gradient_reverse_vector(SP_ITEM(*i), Inkscape::FOR_STROKE); } } diff --git a/src/gradient-drag.cpp b/src/gradient-drag.cpp index 154b7339b..649928060 100644 --- a/src/gradient-drag.cpp +++ b/src/gradient-drag.cpp @@ -2082,9 +2082,9 @@ void GrDrag::updateDraggers() this->draggers = NULL; g_return_if_fail(this->selection != NULL); - - for (GSList const* i = this->selection->itemList(); i != NULL; i = i->next) { - SPItem *item = SP_ITEM(i->data); + SelContainer list = this->selection->itemList(); + for (SelContainer::const_iterator i=list.begin();i!=list.end();i++) { + SPItem *item = SP_ITEM(*i); SPStyle *style = item->style; if (style && (style->fill.isPaintserver())) { @@ -2151,9 +2151,9 @@ void GrDrag::updateLines() g_return_if_fail(this->selection != NULL); - for (GSList const* i = this->selection->itemList(); i != NULL; i = i->next) { - - SPItem *item = SP_ITEM(i->data); + SelContainer list = this->selection->itemList(); + for (SelContainer::const_iterator i=list.begin();i!=list.end();i++) { + SPItem *item = SP_ITEM(*i); SPStyle *style = item->style; @@ -2295,8 +2295,9 @@ void GrDrag::updateLevels() g_return_if_fail (this->selection != NULL); - for (GSList const* i = this->selection->itemList(); i != NULL; i = i->next) { - SPItem *item = SP_ITEM(i->data); + SelContainer list = this->selection->itemList(); + for (SelContainer::const_iterator i=list.begin();i!=list.end();i++) { + SPItem *item = SP_ITEM(*i); Geom::OptRect rect = item->desktopVisualBounds(); if (rect) { // Remember the edges of the bbox and the center axis diff --git a/src/graphlayout.cpp b/src/graphlayout.cpp index e5d61ab64..613440269 100644 --- a/src/graphlayout.cpp +++ b/src/graphlayout.cpp @@ -88,9 +88,9 @@ struct CheckProgress : TestConvergence { * Scans the items list and places those items that are * not connectors in filtered */ -void filterConnectors(GSList const *const items, list &filtered) { - for(GSList *i=(GSList *)items; i!=NULL; i=i->next) { - SPItem *item=SP_ITEM(i->data); +void filterConnectors(SelContainer const &items, list &filtered) { + for(SelContainer::const_iterator i=items.begin();i!=items.end();i++){ + SPItem *item = SP_ITEM(*i); if(!isConnector(item)) { filtered.push_back(item); } @@ -101,8 +101,8 @@ void filterConnectors(GSList const *const items, list &filtered) { * connectors between them, and uses graph layout techniques to find * a nice layout */ -void graphlayout(GSList const *const items) { - if(!items) { +void graphlayout(SelContainer const &items) { + if(items.empty()) { return; } diff --git a/src/graphlayout.h b/src/graphlayout.h index 0ffb645b6..c38f9471c 100644 --- a/src/graphlayout.h +++ b/src/graphlayout.h @@ -19,10 +19,10 @@ typedef struct _GSList GSList; class SPItem; -void graphlayout(GSList const *const items); +void graphlayout(SelContainer const &items); bool isConnector(SPItem const *const item); -void filterConnectors(GSList const *const items, std::list &filtered); +void filterConnectors(SelContainer const &items, std::list &filtered); #endif // SEEN_GRAPHLAYOUT_H diff --git a/src/helper/png-write.cpp b/src/helper/png-write.cpp index 32e50b537..55fef5a4c 100644 --- a/src/helper/png-write.cpp +++ b/src/helper/png-write.cpp @@ -361,19 +361,19 @@ sp_export_get_rows(guchar const **rows, void **to_free, int row, int num_rows, v /** * Hide all items that are not listed in list, recursively, skipping groups and defs. */ -static void hide_other_items_recursively(SPObject *o, GSList *list, unsigned dkey) +static void hide_other_items_recursively(SPObject *o, const SelContainer &list, unsigned dkey) { if ( SP_IS_ITEM(o) && !SP_IS_DEFS(o) && !SP_IS_ROOT(o) && !SP_IS_GROUP(o) - && !g_slist_find(list, o) ) + && list.end()==find(list.begin(),list.end(),o)) { SP_ITEM(o)->invoke_hide(dkey); } // recurse - if (!g_slist_find(list, o)) { + if (list.end()==find(list.begin(),list.end(),o)) { for ( SPObject *child = o->firstChild() ; child; child = child->getNext() ) { hide_other_items_recursively(child, list, dkey); } @@ -387,7 +387,7 @@ ExportResult sp_export_png_file(SPDocument *doc, gchar const *filename, unsigned long bgcolor, unsigned int (*status) (float, void *), void *data, bool force_overwrite, - GSList *items_only) + const SelContainer &items_only) { return sp_export_png_file(doc, filename, Geom::Rect(Geom::Point(x0,y0),Geom::Point(x1,y1)), width, height, xdpi, ydpi, bgcolor, status, data, force_overwrite, items_only); @@ -399,7 +399,7 @@ ExportResult sp_export_png_file(SPDocument *doc, gchar const *filename, unsigned long bgcolor, unsigned (*status)(float, void *), void *data, bool force_overwrite, - GSList *items_only) + const SelContainer &items_only) { g_return_val_if_fail(doc != NULL, EXPORT_ERROR); g_return_val_if_fail(filename != NULL, EXPORT_ERROR); @@ -457,7 +457,7 @@ ExportResult sp_export_png_file(SPDocument *doc, gchar const *filename, // We show all and then hide all items we don't want, instead of showing only requested items, // because that would not work if the shown item references something in defs - if (items_only) { + if (!items_only.empty()) { hide_other_items_recursively(doc->getRoot(), items_only, dkey); } diff --git a/src/helper/png-write.h b/src/helper/png-write.h index 8c04b25dc..47fad1b41 100644 --- a/src/helper/png-write.h +++ b/src/helper/png-write.h @@ -16,6 +16,11 @@ #include #include <2geom/forward.h> + +//should be in selection.h +typedef std::list SelContainer; + + class SPDocument; enum ExportResult { @@ -33,12 +38,12 @@ ExportResult sp_export_png_file(SPDocument *doc, gchar const *filename, double x0, double y0, double x1, double y1, unsigned long int width, unsigned long int height, double xdpi, double ydpi, unsigned long bgcolor, - unsigned int (*status) (float, void *), void *data, bool force_overwrite = false, GSList *items_only = NULL); + unsigned int (*status) (float, void *), void *data, bool force_overwrite = false, const SelContainer &items_only = SelContainer()); ExportResult sp_export_png_file(SPDocument *doc, gchar const *filename, Geom::Rect const &area, unsigned long int width, unsigned long int height, double xdpi, double ydpi, unsigned long bgcolor, - unsigned int (*status) (float, void *), void *data, bool force_overwrite = false, GSList *items_only = NULL); + unsigned int (*status) (float, void *), void *data, bool force_overwrite = false, const SelContainer &items_only = SelContainer()); #endif // SEEN_SP_PNG_WRITE_H diff --git a/src/live_effects/lpe-knot.cpp b/src/live_effects/lpe-knot.cpp index 3876aa24b..95a6b16dd 100644 --- a/src/live_effects/lpe-knot.cpp +++ b/src/live_effects/lpe-knot.cpp @@ -505,9 +505,9 @@ LPEKnot::doEffect_path (std::vector const &path_in) static void collectPathsAndWidths (SPLPEItem const *lpeitem, std::vector &paths, std::vector &stroke_widths){ if (SP_IS_GROUP(lpeitem)) { - GSList const *item_list = sp_item_group_item_list(SP_GROUP(lpeitem)); - for ( GSList const *iter = item_list; iter; iter = iter->next ) { - SPObject *subitem = static_cast(iter->data); + SelContainer item_list = sp_item_group_item_list(SP_GROUP(lpeitem)); + for ( SelContainer::const_iterator iter=item_list.begin();iter!=item_list.end();iter++) { + SPObject *subitem = static_cast(*iter); if (SP_IS_LPE_ITEM(subitem)) { collectPathsAndWidths(SP_LPE_ITEM(subitem), paths, stroke_widths); } diff --git a/src/main.cpp b/src/main.cpp index 15576109d..25dc91f14 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1156,7 +1156,7 @@ static int sp_process_file_list(GSList *fl) } if (sp_export_svg) { if (sp_export_text_to_path) { - GSList *items = NULL; + SelContainer items; SPRoot *root = doc->getRoot(); doc->ensureUpToDate(); for ( SPObject *iter = root->firstChild(); iter ; iter = iter->getNext()) { @@ -1166,17 +1166,17 @@ static int sp_process_file_list(GSList *fl) } te_update_layout_now_recursive(item); - items = g_slist_append(items, item); + items.push_back(item); } - GSList *selected = NULL; - GSList *to_select = NULL; + SelContainer selected; + SelContainer to_select; - sp_item_list_to_curves(items, &selected, &to_select); + sp_item_list_to_curves(items, selected, to_select); - g_slist_free (items); - g_slist_free (selected); - g_slist_free (to_select); + items.clear(); + selected.clear(); + to_select.clear(); } if(sp_export_id) { doc->ensureUpToDate(); @@ -1435,7 +1435,7 @@ static int sp_do_export_png(SPDocument *doc) g_warning ("--export-use-hints can only be used with --export-id or --export-area-drawing; ignored."); } - GSList *items = NULL; + SelContainer items; Geom::Rect area; if (sp_export_id || sp_export_area_drawing) { @@ -1459,7 +1459,7 @@ static int sp_do_export_png(SPDocument *doc) return 1; } - items = g_slist_prepend (items, SP_ITEM(o)); + items.push_front(SP_ITEM(o)); if (sp_export_id_only) { g_print("Exporting only object with id=\"%s\"; all other objects hidden\n", sp_export_id); @@ -1647,7 +1647,7 @@ static int sp_do_export_png(SPDocument *doc) if ((width >= 1) && (height >= 1) && (width <= PNG_UINT_31_MAX) && (height <= PNG_UINT_31_MAX)) { if( sp_export_png_file(doc, path.c_str(), area, width, height, dpi, - dpi, bgcolor, NULL, NULL, true, sp_export_id_only ? items : NULL) == 1 ) { + dpi, bgcolor, NULL, NULL, true, sp_export_id_only ? items : SelContainer()) == 1 ) { g_print("Bitmap saved as: %s\n", filename.c_str()); } else { g_warning("Bitmap failed to save to: %s", filename.c_str()); @@ -1657,7 +1657,6 @@ static int sp_do_export_png(SPDocument *doc) } } - g_slist_free (items); return retcode; } diff --git a/src/object-snapper.cpp b/src/object-snapper.cpp index 338f91463..960b5087b 100644 --- a/src/object-snapper.cpp +++ b/src/object-snapper.cpp @@ -237,8 +237,9 @@ void Inkscape::ObjectSnapper::_collectNodes(SnapSourceType const &t, // current selection (see the comment in SelTrans::centerRequest()) bool old_pref2 = _snapmanager->snapprefs.isTargetSnappable(SNAPTARGET_ROTATION_CENTER); if (old_pref2) { - for ( GSList const *itemlist = _snapmanager->getRotationCenterSource(); itemlist != NULL; itemlist = g_slist_next(itemlist) ) { - if ((*i).item == reinterpret_cast(itemlist->data)) { + SelContainer rotationSource=_snapmanager->getRotationCenterSource(); + for ( SelContainer::const_iterator itemlist=rotationSource.begin();itemlist!=rotationSource.end();itemlist++) { + if ((*i).item == reinterpret_cast(*itemlist)) { // don't snap to this item's rotation center _snapmanager->snapprefs.setTargetSnappable(SNAPTARGET_ROTATION_CENTER, false); break; diff --git a/src/path-chemistry.cpp b/src/path-chemistry.cpp index 5f6e1495b..a5e71b720 100644 --- a/src/path-chemistry.cpp +++ b/src/path-chemistry.cpp @@ -44,13 +44,22 @@ using Inkscape::DocumentUndo; + +inline bool less_than_objects(SPObject const *first, SPObject const *second) +{ + return sp_repr_compare_position(first->getRepr(), + second->getRepr())<0; +} + void sp_selected_path_combine(SPDesktop *desktop) { Inkscape::Selection *selection = desktop->getSelection(); SPDocument *doc = desktop->getDocument(); + + SelContainer items(selection->itemList()); - if (g_slist_length((GSList *) selection->itemList()) < 1) { + if (items.size() < 1) { desktop->getMessageStack()->flash(Inkscape::WARNING_MESSAGE, _("Select object(s) to combine.")); return; } @@ -59,28 +68,26 @@ sp_selected_path_combine(SPDesktop *desktop) // set "busy" cursor desktop->setWaitingCursor(); - GSList *items = g_slist_copy((GSList *) selection->itemList()); - items = sp_degroup_list (items); // descend into any groups in selection - GSList *to_paths = NULL; - for (GSList *i = items; i != NULL; i = i->next) { - SPItem *item = (SPItem *) i->data; + SelContainer to_paths; + for (SelContainer::const_iterator i=items.begin();i!=items.end();i++) { + SPItem *item = (SPItem *) (*i); if (!dynamic_cast(item) && !dynamic_cast(item)) { - to_paths = g_slist_prepend(to_paths, item); + to_paths.push_front(item); } } - GSList *converted = NULL; - bool did = sp_item_list_to_curves(to_paths, &items, &converted); - g_slist_free(to_paths); - for (GSList *i = converted; i != NULL; i = i->next) - items = g_slist_prepend(items, doc->getObjectByRepr((Inkscape::XML::Node*)(i->data))); + SelContainer converted; + bool did = sp_item_list_to_curves(to_paths, items, converted); + to_paths.clear(); + for (SelContainer::const_iterator i=converted.begin();i!=converted.end();i++) + items.push_front(doc->getObjectByRepr((Inkscape::XML::Node*)(*i))); items = sp_degroup_list (items); // converting to path may have added more groups, descend again - items = g_slist_sort(items, (GCompareFunc) sp_item_repr_compare_position); - items = g_slist_reverse(items); - assert(items); // cannot be NULL because of list length check at top of function + items.sort(less_than_objects); + items.reverse(); + assert(!items.empty()); // cannot be NULL because of list length check at top of function // remember the position, id, transform and style of the topmost path, they will be assigned to the combined one gint position = 0; @@ -97,9 +104,9 @@ sp_selected_path_combine(SPDesktop *desktop) selection->clear(); } - for (GSList *i = items; i != NULL; i = i->next) { // going from top to bottom + for (SelContainer::const_iterator i=items.begin();i!=items.end();i++){ - SPItem *item = (SPItem *) i->data; + SPItem *item = (SPItem *) (*i); SPPath *path = dynamic_cast(item); if (!path) { continue; @@ -136,7 +143,6 @@ sp_selected_path_combine(SPDesktop *desktop) } } - g_slist_free(items); if (did) { first->deleteObject(false); @@ -200,11 +206,10 @@ sp_selected_path_break_apart(SPDesktop *desktop) bool did = false; - for (GSList *items = g_slist_copy((GSList *) selection->itemList()); - items != NULL; - items = items->next) { + SelContainer itemlist(selection->itemList()); + for (SelContainer::const_iterator i=itemlist.begin();i!=itemlist.end();i++){ - SPItem *item = (SPItem *) items->data; + SPItem *item = (SPItem *) (*i); SPPath *path = dynamic_cast(item); if (!path) { @@ -241,7 +246,7 @@ sp_selected_path_break_apart(SPDesktop *desktop) curve->unref(); - GSList *reprs = NULL; + SelContainer reprs; for (GSList *l = list; l != NULL; l = l->next) { curve = (SPCurve *) l->data; @@ -267,14 +272,14 @@ sp_selected_path_break_apart(SPDesktop *desktop) if (l == list) repr->setAttribute("id", id); - reprs = g_slist_prepend (reprs, repr); + reprs.push_front(dynamic_cast(repr)); Inkscape::GC::release(repr); } selection->setReprList(reprs); - g_slist_free(reprs); + reprs.clear(); g_slist_free(list); g_free(style); g_free(path_effect); @@ -307,18 +312,18 @@ sp_selected_path_to_curves(Inkscape::Selection *selection, SPDesktop *desktop, b desktop->setWaitingCursor(); } - GSList *selected = g_slist_copy((GSList *) selection->itemList()); - GSList *to_select = NULL; + SelContainer selected(selection->itemList()); + SelContainer to_select; selection->clear(); - GSList *items = g_slist_copy(selected); + SelContainer items(selected); - did = sp_item_list_to_curves(items, &selected, &to_select); + did = sp_item_list_to_curves(items, selected, to_select); - g_slist_free (items); + items.clear(); selection->setReprList(to_select); selection->addList(selected); - g_slist_free (to_select); - g_slist_free (selected); + to_select.clear(); + selected.clear(); if (interactive && desktop) { desktop->clearWaitingCursor(); @@ -341,33 +346,29 @@ void sp_selected_to_lpeitems(SPDesktop *desktop) return; } - GSList *selected = g_slist_copy((GSList *) selection->itemList()); - GSList *to_select = NULL; + SelContainer selected(selection->itemList()); + SelContainer to_select; selection->clear(); - GSList *items = g_slist_copy(selected); + SelContainer items(selected); + - sp_item_list_to_curves(items, &selected, &to_select, true); + sp_item_list_to_curves(items, selected, to_select, true); - g_slist_free(items); - items = 0; + items.clear(); selection->setReprList(to_select); selection->addList(selected); - g_slist_free(to_select); - to_select = 0; - g_slist_free(selected); - selected = 0; + to_select.clear(); + selected.clear(); } bool -sp_item_list_to_curves(const GSList *items, GSList **selected, GSList **to_select, bool skip_all_lpeitems) +sp_item_list_to_curves(const SelContainer &items, SelContainer& selected, SelContainer &to_select, bool skip_all_lpeitems) { bool did = false; - for (; - items != NULL; - items = items->next) { + for (SelContainer::const_iterator i=items.begin();i!=items.end();i++){ - SPItem *item = dynamic_cast(static_cast(items->data)); + SPItem *item = dynamic_cast(static_cast(*i)); g_assert(item != NULL); SPDocument *document = item->document; @@ -398,9 +399,9 @@ sp_item_list_to_curves(const GSList *items, GSList **selected, GSList **to_selec Inkscape::XML::Node *repr = box3d_convert_to_group(box)->getRepr(); if (repr) { - *to_select = g_slist_prepend (*to_select, repr); + to_select.push_front(dynamic_cast(repr)); did = true; - *selected = g_slist_remove (*selected, item); + selected.remove(item); } continue; @@ -408,17 +409,17 @@ sp_item_list_to_curves(const GSList *items, GSList **selected, GSList **to_selec if (group) { group->removeAllPathEffects(true); - GSList *item_list = sp_item_group_item_list(group); + SelContainer item_list = sp_item_group_item_list(group); - GSList *item_to_select = NULL; - GSList *item_selected = NULL; + SelContainer item_to_select; + SelContainer item_selected; - if (sp_item_list_to_curves(item_list, &item_selected, &item_to_select)) + if (sp_item_list_to_curves(item_list, item_selected, item_to_select)) did = true; - g_slist_free(item_list); - g_slist_free(item_to_select); - g_slist_free(item_selected); + item_list.clear(); + item_to_select.clear(); + item_selected.clear(); continue; } @@ -428,7 +429,7 @@ sp_item_list_to_curves(const GSList *items, GSList **selected, GSList **to_selec continue; did = true; - *selected = g_slist_remove (*selected, item); + selected.remove(item); // remember the position of the item gint pos = item->getRepr()->position(); @@ -470,7 +471,7 @@ sp_item_list_to_curves(const GSList *items, GSList **selected, GSList **to_selec /* Buglet: We don't re-add the (new version of the) object to the selection of any other * desktops where it was previously selected. */ - *to_select = g_slist_prepend (*to_select, repr); + to_select.push_front(dynamic_cast(repr)); Inkscape::GC::release(repr); } @@ -612,9 +613,9 @@ void sp_selected_path_reverse(SPDesktop *desktop) { Inkscape::Selection *selection = desktop->getSelection(); - GSList *items = (GSList *) selection->itemList(); + SelContainer items = selection->itemList(); - if (!items) { + if (items.empty()) { desktop->getMessageStack()->flash(Inkscape::WARNING_MESSAGE, _("Select path(s) to reverse.")); return; } @@ -626,9 +627,9 @@ sp_selected_path_reverse(SPDesktop *desktop) bool did = false; desktop->messageStack()->flash(Inkscape::IMMEDIATE_MESSAGE, _("Reversing paths...")); - for (GSList *i = items; i != NULL; i = i->next) { + for (SelContainer::const_iterator i=items.begin();i!=items.end();i++){ - SPPath *path = dynamic_cast(static_cast(i->data)); + SPPath *path = dynamic_cast(static_cast(*i)); if (!path) { continue; } diff --git a/src/path-chemistry.h b/src/path-chemistry.h index a2150440c..388268af4 100644 --- a/src/path-chemistry.h +++ b/src/path-chemistry.h @@ -33,7 +33,7 @@ void sp_selected_path_to_curves (Inkscape::Selection *selection, SPDesktop *desk void sp_selected_to_lpeitems(SPDesktop *desktop); Inkscape::XML::Node *sp_selected_item_to_curved_repr(SPItem *item, guint32 text_grouping_policy); void sp_selected_path_reverse (SPDesktop *desktop); -bool sp_item_list_to_curves(const GSList *items, GSList **selected, GSList **to_select, bool skip_all_lpeitems = false); +bool sp_item_list_to_curves(const SelContainer &items, SelContainer &selected, SelContainer &to_select, bool skip_all_lpeitems = false); #endif // SEEN_PATH_CHEMISTRY_H diff --git a/src/removeoverlap.cpp b/src/removeoverlap.cpp index ba5740e55..9009de5e9 100644 --- a/src/removeoverlap.cpp +++ b/src/removeoverlap.cpp @@ -38,20 +38,20 @@ namespace { * such that rectangular bounding boxes are separated by at least xGap * horizontally and yGap vertically */ -void removeoverlap(GSList const *const items, double const xGap, double const yGap) { +void removeoverlap(SelContainer const &items, double const xGap, double const yGap) { using Inkscape::Util::GSListConstIterator; - std::list selected; - selected.insert >(selected.end(), items, NULL); + SelContainer selected(items); std::vector records; std::vector rs; Geom::Point const gap(xGap, yGap); - for (std::list::iterator it(selected.begin()); + for (SelContainer::iterator it(selected.begin()); it != selected.end(); ++it) { + SPItem* item=static_cast(*it); using Geom::X; using Geom::Y; - Geom::OptRect item_box((*it)->desktopVisualBounds()); + Geom::OptRect item_box((item)->desktopVisualBounds()); if (item_box) { Geom::Point min(item_box->min() - .5*gap); Geom::Point max(item_box->max() + .5*gap); @@ -67,7 +67,7 @@ void removeoverlap(GSList const *const items, double const xGap, double const yG min[Y] = max[Y] = (min[Y] + max[Y])/2; } Rectangle *vspc_rect = new Rectangle(min[X], max[X], min[Y], max[Y]); - records.push_back(Record(*it, item_box->midpoint(), vspc_rect)); + records.push_back(Record(item, item_box->midpoint(), vspc_rect)); rs.push_back(vspc_rect); } } diff --git a/src/removeoverlap.h b/src/removeoverlap.h index 7109c9513..d050ca9ef 100644 --- a/src/removeoverlap.h +++ b/src/removeoverlap.h @@ -15,6 +15,6 @@ typedef struct _GSList GSList; -void removeoverlap(GSList const *items, double xGap, double yGap); +void removeoverlap(SelContainer const &items, double xGap, double yGap); #endif // SEEN_REMOVEOVERLAP_H diff --git a/src/selcue.cpp b/src/selcue.cpp index d2fa0970a..0fab6e5a8 100644 --- a/src/selcue.cpp +++ b/src/selcue.cpp @@ -96,15 +96,16 @@ void Inkscape::SelCue::_updateItemBboxes(Inkscape::Preferences *prefs) void Inkscape::SelCue::_updateItemBboxes(gint mode, int prefs_bbox) { - GSList const *items = _selection->itemList(); - if (_item_bboxes.size() != g_slist_length((GSList *) items)) { + const SelContainer items = _selection->itemList(); + if (_item_bboxes.size() != items.size()) { _newItemBboxes(); return; } int bcount = 0; - for (GSList const *l = _selection->itemList(); l != NULL; l = l->next) { - SPItem *item = static_cast(l->data); + SelContainer ll=_selection->itemList(); + for (SelContainer::const_iterator l=ll.begin();l!=ll.end();l++) { + SPItem *item = static_cast(*l); SPCanvasItem* box = _item_bboxes[bcount ++]; if (box) { @@ -145,8 +146,9 @@ void Inkscape::SelCue::_newItemBboxes() int prefs_bbox = prefs->getBool("/tools/bounding_box"); - for (GSList const *l = _selection->itemList(); l != NULL; l = l->next) { - SPItem *item = static_cast(l->data); + SelContainer ll=_selection->itemList(); + for (SelContainer::const_iterator l=ll.begin();l!=ll.end();l++) { + SPItem *item = static_cast(*l); Geom::OptRect const b = (prefs_bbox == 0) ? item->desktopVisualBounds() : item->desktopGeometricBounds(); @@ -199,8 +201,9 @@ void Inkscape::SelCue::_newTextBaselines() } _text_baselines.clear(); - for (GSList const *l = _selection->itemList(); l != NULL; l = l->next) { - SPItem *item = static_cast(l->data); + SelContainer ll=_selection->itemList(); + for (SelContainer::const_iterator l=ll.begin();l!=ll.end();l++) { + SPItem *item = static_cast(*l); SPCanvasItem* baseline_point = NULL; if (SP_IS_TEXT(item) || SP_IS_FLOWTEXT(item)) { // visualize baseline diff --git a/src/selection-chemistry.cpp b/src/selection-chemistry.cpp index c9837aabe..f20df1594 100644 --- a/src/selection-chemistry.cpp +++ b/src/selection-chemistry.cpp @@ -279,25 +279,23 @@ void SelectionHelper::fixSelection(SPDesktop *dt) Inkscape::Selection *selection = dt->getSelection(); - GSList *items = NULL; + SelContainer items ; - GSList const *selList = selection->itemList(); + SelContainer const selList = selection->itemList(); - for( GSList const *i = selList; i; i = i->next ) { - SPItem *item = dynamic_cast(static_cast(i->data)); + for( SelContainer::const_iterator i=selList.begin();i!=selList.end();i++ ) { + SPItem *item = dynamic_cast(static_cast(*i)); if( item && !dt->isLayer(item) && (!item->isLocked())) { - items = g_slist_prepend(items, item); + items.push_front(item); } } selection->setList(items); - if(items) { - g_slist_free(items); - } + items.clear(); } } // namespace Inkscape @@ -307,7 +305,7 @@ void SelectionHelper::fixSelection(SPDesktop *dt) * Copies repr and its inherited css style elements, along with the accumulated transform 'full_t', * then prepends the copy to 'clip'. */ -static void sp_selection_copy_one(Inkscape::XML::Node *repr, Geom::Affine full_t, GSList **clip, Inkscape::XML::Document* xml_doc) +static void sp_selection_copy_one(Inkscape::XML::Node *repr, Geom::Affine full_t, SelContainer &clip, Inkscape::XML::Document* xml_doc) { Inkscape::XML::Node *copy = repr->duplicate(xml_doc); @@ -323,18 +321,18 @@ static void sp_selection_copy_one(Inkscape::XML::Node *repr, Geom::Affine full_t copy->setAttribute("transform", affinestr); g_free(affinestr); - *clip = g_slist_prepend(*clip, copy); + clip.push_front(dynamic_cast(copy)); } -static void sp_selection_copy_impl(GSList const *items, GSList **clip, Inkscape::XML::Document* xml_doc) +static void sp_selection_copy_impl(SelContainer const &items, SelContainer &clip, Inkscape::XML::Document* xml_doc) { // Sort items: - GSList *sorted_items = g_slist_copy(const_cast(items)); - sorted_items = g_slist_sort(static_cast(sorted_items), (GCompareFunc) sp_object_compare_position); + SelContainer sorted_items(items); + sorted_items.sort(sp_object_compare_position); // Copy item reprs: - for (GSList *i = sorted_items; i != NULL; i = i->next) { - SPItem *item = dynamic_cast(SP_OBJECT(i->data)); + for (SelContainer::const_iterator i = sorted_items.begin();i!=sorted_items.end();i++) { + SPItem *item = dynamic_cast(SP_OBJECT(*i)); if (item) { sp_selection_copy_one(item->getRepr(), item->i2doc_affine(), clip, xml_doc); } else { @@ -342,22 +340,22 @@ static void sp_selection_copy_impl(GSList const *items, GSList **clip, Inkscape: } } - *clip = g_slist_reverse(*clip); - g_slist_free(static_cast(sorted_items)); + clip.reverse(); + sorted_items.clear(); } // TODO check if parent parameter should be changed to SPItem, of if the code should handle non-items. -static GSList *sp_selection_paste_impl(SPDocument *doc, SPObject *parent, GSList **clip) +static SelContainer sp_selection_paste_impl(SPDocument *doc, SPObject *parent, SelContainer &clip) { Inkscape::XML::Document *xml_doc = doc->getReprDoc(); SPItem *parentItem = dynamic_cast(parent); g_assert(parentItem != NULL); - GSList *copied = NULL; + SelContainer copied; // add objects to document - for (GSList *l = *clip; l != NULL; l = l->next) { - Inkscape::XML::Node *repr = static_cast(l->data); + for (SelContainer::const_iterator l=clip.begin();l!=clip.end();l++) { + Inkscape::XML::Node *repr = dynamic_cast(*l); Inkscape::XML::Node *copy = repr->duplicate(xml_doc); // premultiply the item transform by the accumulated parent transform in the paste layer @@ -375,19 +373,19 @@ static GSList *sp_selection_paste_impl(SPDocument *doc, SPObject *parent, GSList } parent->appendChildRepr(copy); - copied = g_slist_prepend(copied, copy); + copied.push_front(dynamic_cast(copy)); Inkscape::GC::release(copy); } return copied; } -static void sp_selection_delete_impl(GSList const *items, bool propagate = true, bool propagate_descendants = true) +static void sp_selection_delete_impl(SelContainer const &items, bool propagate = true, bool propagate_descendants = true) { - for (GSList const *i = items ; i ; i = i->next ) { - sp_object_ref(static_cast(i->data), NULL); + for (SelContainer::const_iterator i=items.begin();i!=items.end();i++) { + sp_object_ref(static_cast(*i), NULL); } - for (GSList const *i = items; i != NULL; i = i->next) { - SPItem *item = static_cast(i->data); + for (SelContainer::const_iterator i=items.begin();i!=items.end();i++) { + SPItem *item = static_cast(*i); item->deleteObject(propagate, propagate_descendants); sp_object_unref(item, NULL); } @@ -414,11 +412,10 @@ void sp_selection_delete(SPDesktop *desktop) desktop->messageStack()->flash(Inkscape::WARNING_MESSAGE, _("Nothing was deleted.")); return; } - - GSList *selected = g_slist_copy(const_cast(selection->itemList())); + SelContainer selected(selection->itemList()); selection->clear(); sp_selection_delete_impl(selected); - g_slist_free(selected); + selected.clear(); desktop->currentLayer()->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); /* a tool may have set up private information in it's selection context @@ -446,6 +443,10 @@ static void add_ids_recursive(std::vector &ids, SPObject *obj) } } +bool sp_repr_compare_position_obj(SPObject* &a,SPObject* &b){ + return sp_repr_compare_position(dynamic_cast(a),dynamic_cast(b)); +} + void sp_selection_duplicate(SPDesktop *desktop, bool suppressDone) { if (desktop == NULL) { @@ -461,16 +462,15 @@ void sp_selection_duplicate(SPDesktop *desktop, bool suppressDone) desktop->messageStack()->flash(Inkscape::WARNING_MESSAGE, _("Select object(s) to duplicate.")); return; } - - GSList *reprs = g_slist_copy(const_cast(selection->reprList())); + SelContainer reprs(selection->reprList()); selection->clear(); // sorting items from different parents sorts each parent's subset without possibly mixing // them, just what we need - reprs = g_slist_sort(reprs, (GCompareFunc) sp_repr_compare_position); + reprs.sort(sp_repr_compare_position_obj); - GSList *newsel = NULL; + SelContainer newsel; std::vector old_ids; std::vector new_ids; @@ -478,8 +478,8 @@ void sp_selection_duplicate(SPDesktop *desktop, bool suppressDone) bool relink_clones = prefs->getBool("/options/relinkclonesonduplicate/value"); const bool fork_livepatheffects = prefs->getBool("/options/forklpeonduplicate/value", true); - while (reprs) { - Inkscape::XML::Node *old_repr = static_cast(reprs->data); + while (!reprs.empty()) { + Inkscape::XML::Node *old_repr = dynamic_cast(reprs.front()); Inkscape::XML::Node *parent = old_repr->parent(); Inkscape::XML::Node *copy = old_repr->duplicate(xml_doc); @@ -500,8 +500,8 @@ void sp_selection_duplicate(SPDesktop *desktop, bool suppressDone) } } - newsel = g_slist_prepend(newsel, copy); - reprs = g_slist_remove(reprs, reprs->data); + newsel.push_front(dynamic_cast(copy)); + reprs.pop_front(); Inkscape::GC::release(copy); } @@ -548,7 +548,7 @@ void sp_selection_duplicate(SPDesktop *desktop, bool suppressDone) selection->setReprList(newsel); - g_slist_free(newsel); + newsel.clear(); } void sp_edit_clear_all(Inkscape::Selection *selection) @@ -561,11 +561,11 @@ void sp_edit_clear_all(Inkscape::Selection *selection) SPGroup *group = dynamic_cast(selection->layers()->currentLayer()); g_return_if_fail(group != NULL); - GSList *items = sp_item_group_item_list(group); + SelContainer items = sp_item_group_item_list(group); - while (items) { - reinterpret_cast(items->data)->deleteObject(); - items = g_slist_remove(items, items->data); + while (!items.empty()) { + reinterpret_cast(items.front())->deleteObject(); + items.pop_front(); } DocumentUndo::done(doc, SP_VERB_EDIT_CLEAR_ALL, @@ -582,7 +582,7 @@ void sp_edit_clear_all(Inkscape::Selection *selection) * onlysensitive - TRUE includes only non-locked items * ingroups - TRUE to recursively get grouped items children */ -GSList *get_all_items(GSList *list, SPObject *from, SPDesktop *desktop, bool onlyvisible, bool onlysensitive, bool ingroups, GSList const *exclude) +SelContainer &get_all_items(SelContainer &list, SPObject *from, SPDesktop *desktop, bool onlyvisible, bool onlysensitive, bool ingroups, SelContainer const &exclude) { for ( SPObject *child = from->firstChild() ; child; child = child->getNext() ) { SPItem *item = dynamic_cast(child); @@ -590,10 +590,10 @@ GSList *get_all_items(GSList *list, SPObject *from, SPDesktop *desktop, bool onl !desktop->isLayer(item) && (!onlysensitive || !item->isLocked()) && (!onlyvisible || !desktop->itemIsHidden(item)) && - (!exclude || !g_slist_find(const_cast(exclude), child)) + (exclude.empty() || exclude.end() == std::find(exclude.begin(),exclude.end(),child)) ) { - list = g_slist_prepend(list, item); + list.push_front(item); } if (ingroups || (item && desktop->isLayer(item))) { @@ -618,9 +618,9 @@ static void sp_edit_select_all_full(SPDesktop *dt, bool force_all_layers, bool i bool onlyvisible = prefs->getBool("/options/kbselection/onlyvisible", true); bool onlysensitive = prefs->getBool("/options/kbselection/onlysensitive", true); - GSList *items = NULL; + SelContainer items ; - GSList const *exclude = NULL; + SelContainer exclude; if (invert) { exclude = selection->itemList(); } @@ -634,39 +634,41 @@ static void sp_edit_select_all_full(SPDesktop *dt, bool force_all_layers, bool i (onlyvisible && dt->itemIsHidden(dynamic_cast(dt->currentLayer()))) ) return; - GSList *all_items = sp_item_group_item_list(dynamic_cast(dt->currentLayer())); + SelContainer all_items = sp_item_group_item_list(dynamic_cast(dt->currentLayer())); - for (GSList *i = all_items; i; i = i->next) { - SPItem *item = dynamic_cast(static_cast(i->data)); + for (SelContainer::const_iterator i=all_items.begin();i!=all_items.end();i++) { + SPItem *item = dynamic_cast(static_cast(*i)); if (item && (!onlysensitive || !item->isLocked())) { if (!onlyvisible || !dt->itemIsHidden(item)) { if (!dt->isLayer(item)) { - if (!invert || !g_slist_find(const_cast(exclude), item)) { - items = g_slist_prepend(items, item); // leave it in the list + if (!invert || exclude.end() == std::find(exclude.begin(),exclude.end(),item)) { + items.push_front(item); // leave it in the list } } } } } - g_slist_free(all_items); + all_items.clear(); break; } case PREFS_SELECTION_LAYER_RECURSIVE: { - items = get_all_items(NULL, dt->currentLayer(), dt, onlyvisible, onlysensitive, FALSE, exclude); + SelContainer x; + items = get_all_items(x, dt->currentLayer(), dt, onlyvisible, onlysensitive, FALSE, exclude); break; } default: { - items = get_all_items(NULL, dt->currentRoot(), dt, onlyvisible, onlysensitive, FALSE, exclude); + SelContainer x; + items = get_all_items(x, dt->currentRoot(), dt, onlyvisible, onlysensitive, FALSE, exclude); break; } } selection->setList(items); - if (items) { - g_slist_free(items); + if (!items.empty()) { + items.clear(); } } @@ -690,16 +692,16 @@ void sp_edit_invert_in_all_layers(SPDesktop *desktop) sp_edit_select_all_full(desktop, true, true); } -static void sp_selection_group_impl(GSList *p, Inkscape::XML::Node *group, Inkscape::XML::Document *xml_doc, SPDocument *doc) { +static void sp_selection_group_impl(SelContainer p, Inkscape::XML::Node *group, Inkscape::XML::Document *xml_doc, SPDocument *doc) { - p = g_slist_sort(p, (GCompareFunc) sp_repr_compare_position); + p.sort(sp_repr_compare_position_obj); // Remember the position and parent of the topmost object. - gint topmost = (static_cast(g_slist_last(p)->data))->position(); - Inkscape::XML::Node *topmost_parent = (static_cast(g_slist_last(p)->data))->parent(); + gint topmost = (dynamic_cast(p.back()))->position(); + Inkscape::XML::Node *topmost_parent = (dynamic_cast(p.back()))->parent(); - while (p) { - Inkscape::XML::Node *current = static_cast(p->data); + while (!p.empty()) { + Inkscape::XML::Node *current = dynamic_cast(p.front()); if (current->parent() == topmost_parent) { Inkscape::XML::Node *spnew = current->duplicate(xml_doc); @@ -708,7 +710,7 @@ static void sp_selection_group_impl(GSList *p, Inkscape::XML::Node *group, Inksc Inkscape::GC::release(spnew); topmost --; // only reduce count for those items deleted from topmost_parent } else { // move it to topmost_parent first - GSList *temp_clip = NULL; + SelContainer temp_clip; // At this point, current may already have no item, due to its being a clone whose original is already moved away // So we copy it artificially calculating the transform from its repr->attr("transform") and the parent transform @@ -724,15 +726,15 @@ static void sp_selection_group_impl(GSList *p, Inkscape::XML::Node *group, Inksc // then, if this is clone, looking up its original in that array and pre-multiplying // it by the inverse of that original's transform diff. - sp_selection_copy_one(current, item_t, &temp_clip, xml_doc); + sp_selection_copy_one(current, item_t, temp_clip, xml_doc); sp_repr_unparent(current); // paste into topmost_parent (temporarily) - GSList *copied = sp_selection_paste_impl(doc, doc->getObjectByRepr(topmost_parent), &temp_clip); - if (temp_clip) g_slist_free(temp_clip); - if (copied) { // if success, + SelContainer copied = sp_selection_paste_impl(doc, doc->getObjectByRepr(topmost_parent), temp_clip); + if (!temp_clip.empty())temp_clip.clear() ; + if (!copied.empty()) { // if success, // take pasted object (now in topmost_parent) - Inkscape::XML::Node *in_topmost = static_cast(copied->data); + Inkscape::XML::Node *in_topmost = dynamic_cast(copied.front()); // make a copy Inkscape::XML::Node *spnew = in_topmost->duplicate(xml_doc); // remove pasted @@ -740,10 +742,10 @@ static void sp_selection_group_impl(GSList *p, Inkscape::XML::Node *group, Inksc // put its copy into group group->appendChild(spnew); Inkscape::GC::release(spnew); - g_slist_free(copied); + copied.clear(); } } - p = g_slist_remove(p, current); + p.pop_front(); } // Add the new group to the topmost members' parent @@ -764,9 +766,7 @@ void sp_selection_group(Inkscape::Selection *selection, SPDesktop *desktop) return; } - GSList const *l = const_cast(selection->reprList()); - - GSList *p = g_slist_copy(const_cast(l)); + SelContainer p (selection->reprList()); selection->clear(); @@ -802,11 +802,11 @@ void sp_selection_ungroup(Inkscape::Selection *selection, SPDesktop *desktop) } // first check whether there is anything to ungroup - GSList *old_select = const_cast(selection->itemList()); - GSList *new_select = NULL; + SelContainer old_select = selection->itemList(); + SelContainer new_select; GSList *groups = NULL; - for (GSList *item = old_select; item; item = item->next) { - SPItem *obj = static_cast(item->data); + for (SelContainer::const_iterator item = old_select.begin(); item!=old_select.end(); item++) { + SPItem *obj = static_cast(*item); if (dynamic_cast(obj)) { groups = g_slist_prepend(groups, obj); } @@ -818,14 +818,14 @@ void sp_selection_ungroup(Inkscape::Selection *selection, SPDesktop *desktop) return; } - GSList *items = g_slist_copy(old_select); + SelContainer items(old_select); selection->clear(); // If any of the clones refer to the groups, unlink them and replace them with successors // in the items list. GSList *clones_to_unlink = NULL; - for (GSList *item = items; item; item = item->next) { - SPUse *use = dynamic_cast(static_cast(item->data)); + for (SelContainer::const_iterator item = items.begin(); item!=items.end(); item++) { + SPUse *use = dynamic_cast(static_cast(*item)); SPItem *original = use; while (dynamic_cast(original)) { @@ -833,7 +833,7 @@ void sp_selection_ungroup(Inkscape::Selection *selection, SPDesktop *desktop) } if (g_slist_find(groups, original) != NULL) { - clones_to_unlink = g_slist_prepend(clones_to_unlink, item->data); + clones_to_unlink = g_slist_prepend(clones_to_unlink, *item); } } @@ -844,57 +844,57 @@ void sp_selection_ungroup(Inkscape::Selection *selection, SPDesktop *desktop) for (GSList *item = clones_to_unlink; item; item = item->next) { SPUse *use = static_cast(item->data); - GSList *items_node = g_slist_find(items, item->data); - items_node->data = use->unlink(); + SelContainer::iterator items_node = std::find(items.begin(),items.end(), item->data); + (*items_node) = use->unlink(); } g_slist_free(clones_to_unlink); // do the actual work - for (GSList *item = items; item; item = item->next) { - SPItem *obj = static_cast(item->data); + for (SelContainer::iterator item = items.begin(); item!=items.end(); item++) { + SPItem *obj = static_cast(*item); // ungroup only the groups marked earlier - if (g_slist_find(groups, item->data) != NULL) { - GSList *children = NULL; - sp_item_group_ungroup(dynamic_cast(obj), &children, false); + if (g_slist_find(groups, *item) != NULL) { + SelContainer children; + sp_item_group_ungroup(dynamic_cast(obj), children, false); // add the items resulting from ungrouping to the selection - new_select = g_slist_concat(new_select, children); - item->data = NULL; // zero out the original pointer, which is no longer valid + new_select.splice(new_select.end(),children); + (*item) = NULL; // zero out the original pointer, which is no longer valid } else { // if not a group, keep in the selection - new_select = g_slist_append(new_select, item->data); + new_select.push_back(*item); } } selection->addList(new_select); - g_slist_free(new_select); - g_slist_free(items); + new_select.clear(); + items.clear(); DocumentUndo::done(selection->layers()->getDocument(), SP_VERB_SELECTION_UNGROUP, _("Ungroup")); } /** Replace all groups in the list with their member objects, recursively; returns a new list, frees old */ -GSList * -sp_degroup_list(GSList *items) +SelContainer +sp_degroup_list(SelContainer &items) { - GSList *out = NULL; + SelContainer out; bool has_groups = false; - for (GSList *item = items; item; item = item->next) { - SPGroup *group = dynamic_cast(static_cast(item->data)); + for (SelContainer::const_iterator item=items.begin();item!=items.end();item++) { + SPGroup *group = dynamic_cast(static_cast(*item)); if (!group) { - out = g_slist_prepend(out, item->data); + out.push_front(*item); } else { has_groups = true; - GSList *members = sp_item_group_item_list(group); - for (GSList *member = members; member; member = member->next) { - out = g_slist_prepend(out, member->data); + SelContainer members = sp_item_group_item_list(group); + for (SelContainer::const_iterator member=members.begin();member!=members.end();member++) { + out.push_front(*member); } - g_slist_free(members); + members.clear(); } } - out = g_slist_reverse(out); - g_slist_free(items); + out.reverse(); + items.clear(); if (has_groups) { // recurse if we unwrapped a group - it may have contained others out = sp_degroup_list(out); @@ -906,18 +906,19 @@ sp_degroup_list(GSList *items) /** If items in the list have a common parent, return it, otherwise return NULL */ static SPGroup * -sp_item_list_common_parent_group(GSList const *items) +sp_item_list_common_parent_group(SelContainer const items) { - if (!items) { + if (items.empty()) { return NULL; } - SPObject *parent = SP_OBJECT(items->data)->parent; + SPObject *parent = SP_OBJECT(items.front())->parent; // Strictly speaking this CAN happen, if user selects from Inkscape::XML editor if (!dynamic_cast(parent)) { return NULL; } - for (items = items->next; items; items = items->next) { - if (SP_OBJECT(items->data)->parent != parent) { + for (SelContainer::const_iterator item=items.begin();item!=items.end();item++) { + if((*item)==items.front())continue; + if (SP_OBJECT(*item)->parent != parent) { return NULL; } } @@ -927,13 +928,13 @@ sp_item_list_common_parent_group(GSList const *items) /** Finds out the minimum common bbox of the selected items. */ static Geom::OptRect -enclose_items(GSList const *items) +enclose_items(SelContainer const &items) { - g_assert(items != NULL); + g_assert(!items.empty()); Geom::OptRect r; - for (GSList const *i = items; i; i = i->next) { - r.unionWith(static_cast(i->data)->desktopVisualBounds()); + for (SelContainer::const_iterator i = items.begin();i!=items.end();i++) { + r.unionWith(static_cast(*i)->desktopVisualBounds()); } return r; } @@ -948,11 +949,17 @@ static SPObject *prev_sibling(SPObject *child) return prev; } +int sp_item_repr_compare_position_obj(SPObject const *first, SPObject const *second) +{ + return sp_repr_compare_position(((SPItem*)first)->getRepr(), + ((SPItem*)second)->getRepr())<0; +} + void sp_selection_raise(Inkscape::Selection *selection, SPDesktop *desktop) { - GSList const *items = const_cast(selection->itemList()); - if (!items) { + SelContainer items= selection->itemList(); + if (items.empty()) { selection_display_message(desktop, Inkscape::WARNING_MESSAGE, _("Select object(s) to raise.")); return; } @@ -966,16 +973,16 @@ sp_selection_raise(Inkscape::Selection *selection, SPDesktop *desktop) Inkscape::XML::Node *grepr = const_cast(group->getRepr()); /* Construct reverse-ordered list of selected children. */ - GSList *rev = g_slist_copy(const_cast(items)); - rev = g_slist_sort(rev, (GCompareFunc) sp_item_repr_compare_position); + SelContainer rev(items); + rev.sort(sp_item_repr_compare_position_obj); // Determine the common bbox of the selected items. Geom::OptRect selected = enclose_items(items); // Iterate over all objects in the selection (starting from top). if (selected) { - while (rev) { - SPObject *child = reinterpret_cast(rev->data); + while (!rev.empty()) { + SPObject *child = reinterpret_cast(rev.front()); // for each selected object, find the next sibling for (SPObject *newref = child->next; newref; newref = newref->next) { // if the sibling is an item AND overlaps our selection, @@ -984,7 +991,7 @@ sp_selection_raise(Inkscape::Selection *selection, SPDesktop *desktop) Geom::OptRect newref_bbox = newItem->desktopVisualBounds(); if ( newref_bbox && selected->intersects(*newref_bbox) ) { // AND if it's not one of our selected objects, - if (!g_slist_find(const_cast(items), newref)) { + if ( std::find(items.begin(),items.end(),newref)==items.end()) { // move the selected object after that sibling grepr->changeOrder(child->getRepr(), newref->getRepr()); } @@ -992,10 +999,10 @@ sp_selection_raise(Inkscape::Selection *selection, SPDesktop *desktop) } } } - rev = g_slist_remove(rev, child); + rev.pop_front(); } } else { - g_slist_free(rev); + rev.clear(); } DocumentUndo::done(selection->layers()->getDocument(), SP_VERB_SELECTION_RAISE, @@ -1012,7 +1019,7 @@ void sp_selection_raise_to_top(Inkscape::Selection *selection, SPDesktop *deskto return; } - GSList const *items = const_cast(selection->itemList()); + SelContainer items = selection->itemList(); SPGroup const *group = sp_item_list_common_parent_group(items); if (!group) { @@ -1020,15 +1027,15 @@ void sp_selection_raise_to_top(Inkscape::Selection *selection, SPDesktop *deskto return; } - GSList *rl = g_slist_copy(const_cast(selection->reprList())); - rl = g_slist_sort(rl, (GCompareFunc) sp_repr_compare_position); + SelContainer rl(selection->reprList()); + rl.sort(sp_repr_compare_position_obj); - for (GSList *l = rl; l != NULL; l = l->next) { - Inkscape::XML::Node *repr = static_cast(l->data); + for (SelContainer::iterator l=rl.begin(); l!=rl.end();l++) { + Inkscape::XML::Node *repr = dynamic_cast(*l); repr->setPosition(-1); } - g_slist_free(rl); + rl.clear(); DocumentUndo::done(document, SP_VERB_SELECTION_TO_FRONT, _("Raise to top")); @@ -1036,8 +1043,8 @@ void sp_selection_raise_to_top(Inkscape::Selection *selection, SPDesktop *deskto void sp_selection_lower(Inkscape::Selection *selection, SPDesktop *desktop) { - GSList const *items = const_cast(selection->itemList()); - if (!items) { + SelContainer items = selection->itemList(); + if (items.empty()) { selection_display_message(desktop, Inkscape::WARNING_MESSAGE, _("Select object(s) to lower.")); return; } @@ -1054,14 +1061,14 @@ void sp_selection_lower(Inkscape::Selection *selection, SPDesktop *desktop) Geom::OptRect selected = enclose_items(items); /* Construct direct-ordered list of selected children. */ - GSList *rev = g_slist_copy(const_cast(items)); - rev = g_slist_sort(rev, (GCompareFunc) sp_item_repr_compare_position); - rev = g_slist_reverse(rev); + SelContainer rev(items); + rev.sort(sp_item_repr_compare_position_obj); + rev.reverse(); // Iterate over all objects in the selection (starting from top). if (selected) { - while (rev) { - SPObject *child = reinterpret_cast(rev->data); + while (!rev.empty()) { + SPObject *child = reinterpret_cast(rev.front()); // for each selected object, find the prev sibling for (SPObject *newref = prev_sibling(child); newref; newref = prev_sibling(newref)) { // if the sibling is an item AND overlaps our selection, @@ -1070,7 +1077,7 @@ void sp_selection_lower(Inkscape::Selection *selection, SPDesktop *desktop) Geom::OptRect ref_bbox = newItem->desktopVisualBounds(); if ( ref_bbox && selected->intersects(*ref_bbox) ) { // AND if it's not one of our selected objects, - if (!g_slist_find(const_cast(items), newref)) { + if (items.end()==std::find(items.begin(),items.end(),newref)) { // move the selected object before that sibling SPObject *put_after = prev_sibling(newref); if (put_after) @@ -1082,10 +1089,10 @@ void sp_selection_lower(Inkscape::Selection *selection, SPDesktop *desktop) } } } - rev = g_slist_remove(rev, child); + rev.pop_front(); } } else { - g_slist_free(rev); + rev.clear(); } DocumentUndo::done(selection->layers()->getDocument(), SP_VERB_SELECTION_LOWER, @@ -1102,7 +1109,7 @@ void sp_selection_lower_to_bottom(Inkscape::Selection *selection, SPDesktop *des return; } - GSList const *items = const_cast(selection->itemList()); + SelContainer items =selection->itemList(); SPGroup const *group = sp_item_list_common_parent_group(items); if (!group) { @@ -1110,15 +1117,14 @@ void sp_selection_lower_to_bottom(Inkscape::Selection *selection, SPDesktop *des return; } - GSList *rl; - rl = g_slist_copy(const_cast(selection->reprList())); - rl = g_slist_sort(rl, (GCompareFunc) sp_repr_compare_position); - rl = g_slist_reverse(rl); + SelContainer rl(selection->reprList()); + rl.sort(sp_repr_compare_position_obj); + rl.reverse(); - for (GSList *l = rl; l != NULL; l = l->next) { + for (SelContainer::const_iterator l=rl.begin();l!=rl.end();l++) { gint minpos; SPObject *pp, *pc; - Inkscape::XML::Node *repr = static_cast(l->data); + Inkscape::XML::Node *repr = dynamic_cast(*l); pp = document->getObjectByRepr(repr->parent()); minpos = 0; g_assert(dynamic_cast(pp)); @@ -1130,7 +1136,7 @@ void sp_selection_lower_to_bottom(Inkscape::Selection *selection, SPDesktop *des repr->setPosition(minpos); } - g_slist_free(rl); + rl.clear(); DocumentUndo::done(document, SP_VERB_SELECTION_TO_BACK, _("Lower to bottom")); @@ -1269,9 +1275,9 @@ void sp_selection_remove_livepatheffect(SPDesktop *desktop) desktop->messageStack()->flash(Inkscape::WARNING_MESSAGE, _("Select object(s) to remove live path effects from.")); return; } - - for ( GSList const *itemlist = selection->itemList(); itemlist != NULL; itemlist = g_slist_next(itemlist) ) { - SPItem *item = reinterpret_cast(itemlist->data); + SelContainer list=selection->itemList(); + for ( SelContainer::const_iterator itemlist=list.begin();itemlist!=list.end();itemlist++) { + SPItem *item = reinterpret_cast(*itemlist); sp_selection_remove_livepatheffect_impl(item); @@ -1331,25 +1337,25 @@ void sp_selection_to_next_layer(SPDesktop *dt, bool suppressDone) return; } - GSList const *items = g_slist_copy(const_cast(selection->itemList())); + SelContainer items(selection->itemList()); bool no_more = false; // Set to true, if no more layers above SPObject *next=Inkscape::next_layer(dt->currentRoot(), dt->currentLayer()); if (next) { - GSList *temp_clip = NULL; - sp_selection_copy_impl(items, &temp_clip, dt->doc()->getReprDoc()); + SelContainer temp_clip; + sp_selection_copy_impl(items, temp_clip, dt->doc()->getReprDoc()); sp_selection_delete_impl(items, false, false); next=Inkscape::next_layer(dt->currentRoot(), dt->currentLayer()); // Fixes bug 1482973: crash while moving layers - GSList *copied; + SelContainer copied; if (next) { - copied = sp_selection_paste_impl(dt->getDocument(), next, &temp_clip); + copied = sp_selection_paste_impl(dt->getDocument(), next, temp_clip); } else { - copied = sp_selection_paste_impl(dt->getDocument(), dt->currentLayer(), &temp_clip); + copied = sp_selection_paste_impl(dt->getDocument(), dt->currentLayer(), temp_clip); no_more = true; } - selection->setReprList((GSList const *) copied); - g_slist_free(copied); - if (temp_clip) g_slist_free(temp_clip); + selection->setReprList(copied); + copied.clear(); + if (!temp_clip.empty()) temp_clip.clear(); if (next) dt->setCurrentLayer(next); if ( !suppressDone ) { DocumentUndo::done(dt->getDocument(), SP_VERB_LAYER_MOVE_TO_NEXT, @@ -1363,7 +1369,7 @@ void sp_selection_to_next_layer(SPDesktop *dt, bool suppressDone) dt->messageStack()->flash(Inkscape::WARNING_MESSAGE, _("No more layers above.")); } - g_slist_free(const_cast(items)); + items.clear(); } void sp_selection_to_prev_layer(SPDesktop *dt, bool suppressDone) @@ -1376,25 +1382,25 @@ void sp_selection_to_prev_layer(SPDesktop *dt, bool suppressDone) return; } - GSList const *items = g_slist_copy(const_cast(selection->itemList())); + const SelContainer items(selection->itemList()); bool no_more = false; // Set to true, if no more layers below SPObject *next=Inkscape::previous_layer(dt->currentRoot(), dt->currentLayer()); if (next) { - GSList *temp_clip = NULL; - sp_selection_copy_impl(items, &temp_clip, dt->doc()->getReprDoc()); // we're in the same doc, so no need to copy defs + SelContainer temp_clip; + sp_selection_copy_impl(items, temp_clip, dt->doc()->getReprDoc()); // we're in the same doc, so no need to copy defs sp_selection_delete_impl(items, false, false); next=Inkscape::previous_layer(dt->currentRoot(), dt->currentLayer()); // Fixes bug 1482973: crash while moving layers - GSList *copied; + SelContainer copied; if (next) { - copied = sp_selection_paste_impl(dt->getDocument(), next, &temp_clip); + copied = sp_selection_paste_impl(dt->getDocument(), next, temp_clip); } else { - copied = sp_selection_paste_impl(dt->getDocument(), dt->currentLayer(), &temp_clip); + copied = sp_selection_paste_impl(dt->getDocument(), dt->currentLayer(), temp_clip); no_more = true; } - selection->setReprList((GSList const *) copied); - g_slist_free(copied); - if (temp_clip) g_slist_free(temp_clip); + selection->setReprList( copied); + copied.clear(); + if (!temp_clip.empty()) temp_clip.clear(); if (next) dt->setCurrentLayer(next); if ( !suppressDone ) { DocumentUndo::done(dt->getDocument(), SP_VERB_LAYER_MOVE_TO_PREV, @@ -1407,8 +1413,6 @@ void sp_selection_to_prev_layer(SPDesktop *dt, bool suppressDone) if (no_more) { dt->messageStack()->flash(Inkscape::WARNING_MESSAGE, _("No more layers below.")); } - - g_slist_free(const_cast(items)); } void sp_selection_to_layer(SPDesktop *dt, SPObject *moveto, bool suppressDone) @@ -1421,24 +1425,22 @@ void sp_selection_to_layer(SPDesktop *dt, SPObject *moveto, bool suppressDone) return; } - GSList const *items = g_slist_copy(const_cast(selection->itemList())); + SelContainer items(selection->itemList()); if (moveto) { - GSList *temp_clip = NULL; - sp_selection_copy_impl(items, &temp_clip, dt->doc()->getReprDoc()); // we're in the same doc, so no need to copy defs + SelContainer temp_clip; + sp_selection_copy_impl(items, temp_clip, dt->doc()->getReprDoc()); // we're in the same doc, so no need to copy defs sp_selection_delete_impl(items, false, false); - GSList *copied = sp_selection_paste_impl(dt->getDocument(), moveto, &temp_clip); - selection->setReprList((GSList const *) copied); - g_slist_free(copied); - if (temp_clip) g_slist_free(temp_clip); + SelContainer copied = sp_selection_paste_impl(dt->getDocument(), moveto, temp_clip); + selection->setReprList(copied); + copied.clear(); + if (!temp_clip.empty()) temp_clip.clear(); if (moveto) dt->setCurrentLayer(moveto); if ( !suppressDone ) { DocumentUndo::done(dt->getDocument(), SP_VERB_LAYER_MOVE_TO, _("Move selection to layer")); } } - - g_slist_free(const_cast(items)); } static bool @@ -1473,8 +1475,9 @@ static bool selection_contains_both_clone_and_original(Inkscape::Selection *selection) { bool clone_with_original = false; - for (GSList const *l = selection->itemList(); l != NULL; l = l->next) { - SPItem *item = dynamic_cast(static_cast(l->data)); + SelContainer items = selection->itemList(); + for (SelContainer::const_iterator l=items.begin();l!=items.end() ;l++) { + SPItem *item = dynamic_cast(static_cast(*l)); if (item) { clone_with_original |= selection_contains_original(item, selection); if (clone_with_original) @@ -1517,9 +1520,9 @@ void sp_selection_apply_affine(Inkscape::Selection *selection, Geom::Affine cons persp3d_apply_affine_transformation(transf_persp, affine); } - - for (GSList const *l = selection->itemList(); l != NULL; l = l->next) { - SPItem *item = dynamic_cast(static_cast(l->data)); + SelContainer items = selection->itemList(); + for (SelContainer::const_iterator l=items.begin();l!=items.end() ;l++) { + SPItem *item = dynamic_cast(static_cast(*l)); if( dynamic_cast(item) ) { // An SVG element cannot have a transform. We could change 'x' and 'y' in response @@ -1688,10 +1691,9 @@ void sp_selection_remove_transform(SPDesktop *desktop) Inkscape::Selection *selection = desktop->getSelection(); - GSList const *l = const_cast(selection->reprList()); - while (l != NULL) { - ((Inkscape::XML::Node*)l->data)->setAttribute("transform", NULL, false); - l = l->next; + SelContainer items = selection->itemList(); + for (SelContainer::const_iterator l=items.begin();l!=items.end() ;l++) { + ((Inkscape::XML::Node*)*l)->setAttribute("transform", NULL, false); } DocumentUndo::done(desktop->getDocument(), SP_VERB_OBJECT_FLATTEN, @@ -1789,10 +1791,10 @@ void sp_selection_rotate_90(SPDesktop *desktop, bool ccw) if (selection->isEmpty()) return; - GSList const *l = selection->itemList(); + SelContainer items = selection->itemList(); Geom::Rotate const rot_90(Geom::Point(0, ccw ? 1 : -1)); // pos. or neg. rotation, depending on the value of ccw - for (GSList const *l2 = l ; l2 != NULL ; l2 = l2->next) { - SPItem *item = dynamic_cast(static_cast(l2->data)); + for (SelContainer::const_iterator l=items.begin();l!=items.end() ;l++) { + SPItem *item = dynamic_cast(static_cast(*l)); if (item) { sp_item_rotate_rel(item, rot_90); } else { @@ -1848,15 +1850,15 @@ void sp_select_same_fill_stroke_style(SPDesktop *desktop, gboolean fill, gboolea bool onlyvisible = prefs->getBool("/options/kbselection/onlyvisible", true); bool onlysensitive = prefs->getBool("/options/kbselection/onlysensitive", true); bool ingroups = TRUE; - - GSList *all_list = get_all_items(NULL, desktop->currentRoot(), desktop, onlyvisible, onlysensitive, ingroups, NULL); - GSList *all_matches = NULL; + SelContainer x,y; + SelContainer all_list = get_all_items(x, desktop->currentRoot(), desktop, onlyvisible, onlysensitive, ingroups, y); + SelContainer all_matches; Inkscape::Selection *selection = desktop->getSelection(); - - for (GSList const* sel_iter = selection->itemList(); sel_iter; sel_iter = sel_iter->next) { - SPItem *sel = dynamic_cast(static_cast(sel_iter->data)); - GSList *matches = all_list; + SelContainer items = selection->itemList(); + for (SelContainer::const_iterator sel_iter=items.begin();sel_iter!=items.end();sel_iter++) { + SPItem *sel = dynamic_cast(static_cast(*sel_iter)); + SelContainer matches = all_list; if (fill) { matches = sp_get_same_fill_or_stroke_color(sel, matches, SP_FILL_COLOR); } @@ -1868,19 +1870,12 @@ void sp_select_same_fill_stroke_style(SPDesktop *desktop, gboolean fill, gboolea matches = sp_get_same_stroke_style(sel, matches, SP_STROKE_STYLE_DASHES); matches = sp_get_same_stroke_style(sel, matches, SP_STROKE_STYLE_MARKERS); } - all_matches = g_slist_concat (all_matches, matches); + all_matches.splice(all_matches.end(), matches); } selection->clear(); selection->setList(all_matches); - if (all_matches) { - g_slist_free(all_matches); - } - if (all_list) { - g_slist_free(all_list); - } - } @@ -1901,14 +1896,15 @@ void sp_select_same_object_type(SPDesktop *desktop) bool onlyvisible = prefs->getBool("/options/kbselection/onlyvisible", true); bool onlysensitive = prefs->getBool("/options/kbselection/onlysensitive", true); bool ingroups = TRUE; - - GSList *all_list = get_all_items(NULL, desktop->currentRoot(), desktop, onlyvisible, onlysensitive, ingroups, NULL); - GSList *matches = all_list; + SelContainer x,y; + SelContainer all_list = get_all_items(x, desktop->currentRoot(), desktop, onlyvisible, onlysensitive, ingroups, y); + SelContainer matches = all_list; Inkscape::Selection *selection = desktop->getSelection(); - for (GSList const* sel_iter = selection->itemList(); sel_iter; sel_iter = sel_iter->next) { - SPItem *sel = dynamic_cast(static_cast(sel_iter->data)); + SelContainer items=selection->itemList(); + for (SelContainer::const_iterator sel_iter=items.begin();sel_iter!=items.end();sel_iter++) { + SPItem *sel = dynamic_cast(static_cast(*sel_iter)); if (sel) { matches = sp_get_same_object_type(sel, matches); } else { @@ -1919,12 +1915,6 @@ void sp_select_same_object_type(SPDesktop *desktop) selection->clear(); selection->setList(matches); - if (matches) { - g_slist_free(matches); - } - if (all_list) { - g_slist_free(all_list); - } } /* @@ -1944,13 +1934,14 @@ void sp_select_same_stroke_style(SPDesktop *desktop) bool onlysensitive = prefs->getBool("/options/kbselection/onlysensitive", true); bool ingroups = TRUE; - GSList *all_list = get_all_items(NULL, desktop->currentRoot(), desktop, onlyvisible, onlysensitive, ingroups, NULL); - GSList *matches = all_list; + SelContainer x,y; + SelContainer matches = get_all_items(x, desktop->currentRoot(), desktop, onlyvisible, onlysensitive, ingroups, y); Inkscape::Selection *selection = desktop->getSelection(); + SelContainer items=selection->itemList(); - for (GSList const* sel_iter = selection->itemList(); sel_iter; sel_iter = sel_iter->next) { - SPItem *sel = dynamic_cast(static_cast(sel_iter->data)); + for (SelContainer::const_iterator sel_iter=items.begin();sel_iter!=items.end();sel_iter++) { + SPItem *sel = dynamic_cast(static_cast(*sel_iter)); if (sel) { matches = sp_get_same_stroke_style(sel, matches, SP_STROKE_STYLE_WIDTH); matches = sp_get_same_stroke_style(sel, matches, SP_STROKE_STYLE_DASHES); @@ -1963,27 +1954,21 @@ void sp_select_same_stroke_style(SPDesktop *desktop) selection->clear(); selection->setList(matches); - if (matches) { - g_slist_free(matches); - } - if (all_list) { - g_slist_free(all_list); - } } /* * Find all items in src list that have the same fill or stroke style as sel * Return the list of matching items */ -GSList *sp_get_same_fill_or_stroke_color(SPItem *sel, GSList *src, SPSelectStrokeStyleType type) +SelContainer sp_get_same_fill_or_stroke_color(SPItem *sel, SelContainer &src, SPSelectStrokeStyleType type) { - GSList *matches = NULL; + SelContainer matches ; gboolean match = false; SPIPaint *sel_paint = (type == SP_FILL_COLOR) ? &(sel->style->fill) : &(sel->style->stroke); - for (GSList *i = src; i != NULL; i = i->next) { - SPItem *iter = dynamic_cast(static_cast(i->data)); + for (SelContainer::const_iterator i=src.begin();i!=src.end();i++) { + SPItem *iter = dynamic_cast(static_cast(*i)); if (iter) { SPIPaint *iter_paint = (type == SP_FILL_COLOR) ? &(iter->style->fill) : &(iter->style->stroke); match = false; @@ -2022,7 +2007,7 @@ GSList *sp_get_same_fill_or_stroke_color(SPItem *sel, GSList *src, SPSelectStrok } if (match) { - matches = g_slist_prepend(matches, iter); + matches.push_front(iter); } } else { g_assert_not_reached(); @@ -2073,17 +2058,16 @@ static bool item_type_match (SPItem *i, SPItem *j) * Find all items in src list that have the same object type as sel by type * Return the list of matching items */ -GSList *sp_get_same_object_type(SPItem *sel, GSList *src) +SelContainer sp_get_same_object_type(SPItem *sel, SelContainer &src) { - GSList *matches = NULL; + SelContainer matches; - for (GSList *i = src; i != NULL; i = i->next) { - SPItem *item = dynamic_cast(static_cast(i->data)); + for (SelContainer::const_iterator i=src.begin();i!=src.end();i++) { + SPItem *item = dynamic_cast(static_cast(*i)); if (item && item_type_match(sel, item)) { - matches = g_slist_prepend (matches, item); + matches.push_front(item); } } - return matches; } @@ -2091,9 +2075,9 @@ GSList *sp_get_same_object_type(SPItem *sel, GSList *src) * Find all items in src list that have the same stroke style as sel by type * Return the list of matching items */ -GSList *sp_get_same_stroke_style(SPItem *sel, GSList *src, SPSelectStrokeStyleType type) +SelContainer sp_get_same_stroke_style(SPItem *sel, SelContainer &src, SPSelectStrokeStyleType type) { - GSList *matches = NULL; + SelContainer matches; gboolean match = false; SPStyle *sel_style = sel->style; @@ -2106,16 +2090,15 @@ GSList *sp_get_same_stroke_style(SPItem *sel, GSList *src, SPSelectStrokeStyleTy * Stroke width needs to handle transformations, so call this function * to get the transformed stroke width */ - GSList *objects = NULL; + SelContainer objects; SPStyle *sel_style_for_width = NULL; if (type == SP_STROKE_STYLE_WIDTH) { - objects = g_slist_prepend(objects, sel); + objects.push_front(sel); sel_style_for_width = new SPStyle(SP_ACTIVE_DOCUMENT); objects_query_strokewidth (objects, sel_style_for_width); } - - for (GSList *i = src; i != NULL; i = i->next) { - SPItem *iter = dynamic_cast(static_cast(i->data)); + for (SelContainer::const_iterator i=src.begin();i!=src.end();i++) { + SPItem *iter = dynamic_cast(static_cast(*i)); if (iter) { SPStyle *iter_style = iter->style; match = false; @@ -2123,15 +2106,15 @@ GSList *sp_get_same_stroke_style(SPItem *sel, GSList *src, SPSelectStrokeStyleTy if (type == SP_STROKE_STYLE_WIDTH) { match = (sel_style->stroke_width.set == iter_style->stroke_width.set); if (sel_style->stroke_width.set && iter_style->stroke_width.set) { - GSList *objects = NULL; - objects = g_slist_prepend(objects, iter); + SelContainer objects; + objects.push_front(iter); SPStyle tmp_style(SP_ACTIVE_DOCUMENT); objects_query_strokewidth (objects, &tmp_style); if (sel_style_for_width) { match = (sel_style_for_width->stroke_width.computed == tmp_style.stroke_width.computed); } - g_slist_free(objects); + objects.clear(); } } else if (type == SP_STROKE_STYLE_DASHES ) { @@ -2154,7 +2137,7 @@ GSList *sp_get_same_stroke_style(SPItem *sel, GSList *src, SPSelectStrokeStyleTy } if (match) { - matches = g_slist_prepend(matches, iter); + matches.push_front(iter); } } else { g_assert_not_reached(); @@ -2162,8 +2145,6 @@ GSList *sp_get_same_stroke_style(SPItem *sel, GSList *src, SPSelectStrokeStyleTy } if( sel_style_for_width != NULL ) delete sel_style_for_width; - g_slist_free(objects); - return matches; } @@ -2320,11 +2301,11 @@ sp_selection_move_screen(Inkscape::Selection *selection, gdouble dx, gdouble dy) namespace { template -SPItem *next_item(SPDesktop *desktop, GSList *path, SPObject *root, +SPItem *next_item(SPDesktop *desktop, SelContainer &path, SPObject *root, bool only_in_viewport, PrefsSelectionContext inlayer, bool onlyvisible, bool onlysensitive); template -SPItem *next_item_from_list(SPDesktop *desktop, GSList const *items, SPObject *root, +SPItem *next_item_from_list(SPDesktop *desktop, SelContainer const &items, SPObject *root, bool only_in_viewport, PrefsSelectionContext inlayer, bool onlyvisible, bool onlysensitive); struct Forward { @@ -2618,17 +2599,17 @@ void sp_selection_clone(SPDesktop *desktop) return; } - GSList *reprs = g_slist_copy(const_cast(selection->reprList())); + SelContainer reprs (selection->reprList()); selection->clear(); // sorting items from different parents sorts each parent's subset without possibly mixing them, just what we need - reprs = g_slist_sort(reprs, (GCompareFunc) sp_repr_compare_position); + reprs.sort(sp_repr_compare_position_obj); - GSList *newsel = NULL; + SelContainer newsel; - while (reprs) { - Inkscape::XML::Node *sel_repr = static_cast(reprs->data); + while (!reprs.empty()) { + Inkscape::XML::Node *sel_repr = dynamic_cast(reprs.front()); Inkscape::XML::Node *parent = sel_repr->parent(); Inkscape::XML::Node *clone = xml_doc->createElement("svg:use"); @@ -2644,8 +2625,8 @@ void sp_selection_clone(SPDesktop *desktop) // add the new clone to the top of the original's parent parent->appendChild(clone); - newsel = g_slist_prepend(newsel, clone); - reprs = g_slist_remove(reprs, sel_repr); + newsel.push_front(dynamic_cast(clone)); + reprs.pop_front(); Inkscape::GC::release(clone); } @@ -2653,8 +2634,6 @@ void sp_selection_clone(SPDesktop *desktop) C_("Action", "Clone")); selection->setReprList(newsel); - - g_slist_free(newsel); } void @@ -2680,11 +2659,9 @@ sp_selection_relink(SPDesktop *desktop) // Get a copy of current selection. bool relinked = false; - for (GSList *items = const_cast(selection->itemList()); - items != NULL; - items = items->next) - { - SPItem *item = static_cast(items->data); + SelContainer items=selection->itemList(); + for (SelContainer::const_iterator i=items.begin();i!=items.end();i++){ + SPItem *item = static_cast(*i); if (dynamic_cast(item)) { item->getRepr()->setAttribute("xlink:href", newref); @@ -2718,13 +2695,11 @@ sp_selection_unlink(SPDesktop *desktop) } // Get a copy of current selection. - GSList *new_select = NULL; + SelContainer new_select; bool unlinked = false; - for (GSList *items = g_slist_copy(const_cast(selection->itemList())); - items != NULL; - items = items->next) - { - SPItem *item = static_cast(items->data); + SelContainer items=selection->itemList(); + for (SelContainer::const_iterator i=items.begin();i!=items.end();i++){ + SPItem *item = static_cast(*i); if (dynamic_cast(item)) { SPObject *tspan = sp_tref_convert_to_tspan(item); @@ -2740,7 +2715,7 @@ sp_selection_unlink(SPDesktop *desktop) if (!(dynamic_cast(item) || dynamic_cast(item))) { // keep the non-use item in the new selection - new_select = g_slist_prepend(new_select, item); + new_select.push_front(item); continue; } @@ -2750,7 +2725,7 @@ sp_selection_unlink(SPDesktop *desktop) unlink = use->unlink(); // Unable to unlink use (external or invalid href?) if (!unlink) { - new_select = g_slist_prepend(new_select, item); + new_select.push_front(item); continue; } } else /*if (SP_IS_TREF(use))*/ { @@ -2760,13 +2735,12 @@ sp_selection_unlink(SPDesktop *desktop) unlinked = true; // Add ungrouped items to the new selection. - new_select = g_slist_prepend(new_select, unlink); + new_select.push_front(unlink); } - if (new_select) { // set new selection + if (!new_select.empty()) { // set new selection selection->clear(); selection->setList(new_select); - g_slist_free(new_select); } if (!unlinked) { desktop->messageStack()->flash(Inkscape::ERROR_MESSAGE, _("No clones to unlink in the selection.")); @@ -2789,7 +2763,9 @@ sp_select_clone_original(SPDesktop *desktop) gchar const *error = _("Select a clone to go to its original. Select a linked offset to go to its source. Select a text on path to go to the path. Select a flowed text to go to its frame."); // Check if other than two objects are selected - if (g_slist_length(const_cast(selection->itemList())) != 1 || !item) { + + SelContainer items=selection->itemList(); + if (items.size() != 1 || !item) { desktop->messageStack()->flash(Inkscape::WARNING_MESSAGE, error); return; } @@ -2886,14 +2862,15 @@ void sp_selection_clone_original_path_lpe(SPDesktop *desktop) Inkscape::SVGOStringStream os; SPObject * firstItem = NULL; - for (const GSList * item = selection->itemList(); item != NULL; item = item->next) { - if (SP_IS_SHAPE(item->data) || SP_IS_TEXT(item->data)) { + SelContainer items=selection->itemList(); + for (SelContainer::const_iterator i=items.begin();i!=items.end();i++){ + if (SP_IS_SHAPE(*i) || SP_IS_TEXT(*i)) { if (firstItem) { os << "|"; } else { - firstItem = SP_ITEM(item->data); + firstItem = SP_ITEM(*i); } - os << '#' << SP_ITEM(item->data)->getId() << ",0"; + os << '#' << SP_ITEM(*i)->getId() << ",0"; } } if (firstItem) { @@ -2970,12 +2947,12 @@ void sp_selection_to_marker(SPDesktop *desktop, bool apply) Geom::Point center( *c - corner ); // As defined by rotation center center[Geom::Y] = -center[Geom::Y]; - GSList *items = g_slist_copy(const_cast(selection->itemList())); + SelContainer items(selection->itemList()); //items = g_slist_sort(items, (GCompareFunc) sp_object_compare_position); // Why needed? // bottommost object, after sorting - SPObject *parent = SP_OBJECT(items->data)->parent; + SPObject *parent = SP_OBJECT(items.front())->parent; Geom::Affine parent_transform; { @@ -2988,10 +2965,10 @@ void sp_selection_to_marker(SPDesktop *desktop, bool apply) } // Create a list of duplicates, to be pasted inside marker element. - GSList *repr_copies = NULL; - for (GSList *i = items; i != NULL; i = i->next) { - Inkscape::XML::Node *dup = SP_OBJECT(i->data)->getRepr()->duplicate(xml_doc); - repr_copies = g_slist_prepend(repr_copies, dup); + SelContainer repr_copies; + for (SelContainer::const_iterator i=items.begin();i!=items.end();i++){ + Inkscape::XML::Node *dup = SP_OBJECT(*i)->getRepr()->duplicate(xml_doc); + repr_copies.push_front(dynamic_cast(dup)); } Geom::Rect bbox(desktop->dt2doc(r->min()), desktop->dt2doc(r->max())); @@ -2999,8 +2976,8 @@ void sp_selection_to_marker(SPDesktop *desktop, bool apply) if (apply) { // Delete objects so that their clones don't get alerted; // the objects will be restored inside the marker element. - for (GSList *i = items; i != NULL; i = i->next) { - SPObject *item = reinterpret_cast(i->data); + for (SelContainer::const_iterator i=items.begin();i!=items.end();i++){ + SPObject *item = reinterpret_cast(*i); item->deleteObject(false); } } @@ -3019,7 +2996,6 @@ void sp_selection_to_marker(SPDesktop *desktop, bool apply) prefs->setInt("/options/clonecompensation/value", saved_compensation); - g_slist_free(items); DocumentUndo::done(doc, SP_VERB_EDIT_SELECTION_2_MARKER, _("Objects to marker")); @@ -3028,8 +3004,9 @@ void sp_selection_to_marker(SPDesktop *desktop, bool apply) static void sp_selection_to_guides_recursive(SPItem *item, bool wholegroups) { SPGroup *group = dynamic_cast(item); if (group && !dynamic_cast(item) && !wholegroups) { - for (GSList *i = sp_item_group_item_list(group); i != NULL; i = i->next) { - sp_selection_to_guides_recursive(static_cast(i->data), wholegroups); + SelContainer items=sp_item_group_item_list(group); + for (SelContainer::const_iterator i=items.begin();i!=items.end();i++){ + sp_selection_to_guides_recursive(static_cast(*i), wholegroups); } } else { item->convert_to_guides(); @@ -3044,9 +3021,9 @@ void sp_selection_to_guides(SPDesktop *desktop) SPDocument *doc = desktop->getDocument(); Inkscape::Selection *selection = desktop->getSelection(); // we need to copy the list because it gets reset when objects are deleted - GSList *items = g_slist_copy(const_cast(selection->itemList())); + SelContainer items(selection->itemList()); - if (!items) { + if (items.empty()) { desktop->messageStack()->flash(Inkscape::WARNING_MESSAGE, _("Select object(s) to convert to guides.")); return; } @@ -3059,8 +3036,8 @@ void sp_selection_to_guides(SPDesktop *desktop) // and its entry in the selection list is invalid (crash). // Therefore: first convert all, then delete all. - for (GSList const *i = items; i != NULL; i = i->next) { - sp_selection_to_guides_recursive(static_cast(i->data), wholegroups); + for (SelContainer::const_iterator i=items.begin();i!=items.end();i++){ + sp_selection_to_guides_recursive(static_cast(*i), wholegroups); } if (deleteitems) { @@ -3068,8 +3045,6 @@ void sp_selection_to_guides(SPDesktop *desktop) sp_selection_delete_impl(items); } - g_slist_free(items); - DocumentUndo::done(doc, SP_VERB_EDIT_SELECTION_2_GUIDES, _("Objects to guides")); } @@ -3112,18 +3087,18 @@ void sp_selection_symbol(SPDesktop *desktop, bool /*apply*/ ) doc->ensureUpToDate(); - GSList *items = g_slist_copy(const_cast(selection->list())); + SelContainer items(selection->list()); // Keep track of parent, this is where will be inserted. - Inkscape::XML::Node *the_first_repr = reinterpret_cast( items->data )->getRepr(); + Inkscape::XML::Node *the_first_repr = reinterpret_cast( items.front() )->getRepr(); Inkscape::XML::Node *the_parent_repr = the_first_repr->parent(); // Find out if we have a single group bool single_group = false; SPGroup *the_group = NULL; Geom::Affine transform; - if( g_slist_length( items ) == 1 ) { - SPObject *object = reinterpret_cast( items->data ); + if( items.size() == 1 ) { + SPObject *object = reinterpret_cast( items.front() ); the_group = dynamic_cast(object); if ( the_group ) { single_group = true; @@ -3134,7 +3109,6 @@ void sp_selection_symbol(SPDesktop *desktop, bool /*apply*/ ) if( transform.isTranslation() ) { // Create new list from group children. - g_slist_free(items); items = object->childList(false); // Hack: Temporarily set clone compensation to unmoved, so that we can move clone-originals @@ -3180,8 +3154,8 @@ void sp_selection_symbol(SPDesktop *desktop, bool /*apply*/ ) } // Move selected items to new - for (GSList *i = items; i != NULL; i = i->next) { - Inkscape::XML::Node *repr = SP_OBJECT(i->data)->getRepr(); + for (SelContainer::const_iterator i=items.begin();i!=items.end();i++){ + Inkscape::XML::Node *repr = SP_OBJECT(*i)->getRepr(); repr->parent()->removeChild(repr); symbol_repr->addChild(repr,NULL); } @@ -3207,7 +3181,6 @@ void sp_selection_symbol(SPDesktop *desktop, bool /*apply*/ ) // Clean up Inkscape::GC::release(symbol_repr); - g_slist_free(items); DocumentUndo::done(doc, SP_VERB_EDIT_SYMBOL, _("Group to symbol")); } @@ -3248,26 +3221,25 @@ void sp_selection_unsymbol(SPDesktop *desktop) desktop->currentLayer()->getRepr()->appendChild(group); // Move all children of symbol to group - GSList* children = symbol->childList(false); + SelContainer children = symbol->childList(false); // Converting a group to a symbol inserts a group for non-translational transform. // In converting a symbol back to a group we strip out the inserted group (or any other // group that only adds a transform to the symbol content). - if( g_slist_length( children ) == 1 ) { - SPObject *object = reinterpret_cast( children->data ); + if( children.size() == 1 ) { + SPObject *object = reinterpret_cast( children.front() ); if ( dynamic_cast( object ) ) { if( object->getAttribute("style") == NULL || object->getAttribute("class") == NULL ) { group->setAttribute("transform", object->getAttribute("transform")); - g_slist_free(children); children = object->childList(false); } } } - for (GSList* i = children; i != NULL; i = i->next ) { - Inkscape::XML::Node *repr = SP_OBJECT(i->data)->getRepr(); + for (SelContainer::const_iterator i=children.begin();i!=children.end();i++){ + Inkscape::XML::Node *repr = SP_OBJECT(*i)->getRepr(); repr->parent()->removeChild(repr); group->addChild(repr,NULL); } @@ -3293,7 +3265,6 @@ void sp_selection_unsymbol(SPDesktop *desktop) // Clean up Inkscape::GC::release(group); - g_slist_free(children); DocumentUndo::done(doc, SP_VERB_EDIT_UNSYMBOL, _("Group from symbol")); } @@ -3328,12 +3299,12 @@ sp_selection_tile(SPDesktop *desktop, bool apply) move_p[Geom::Y] = -move_p[Geom::Y]; Geom::Affine move = Geom::Affine(Geom::Translate(move_p)); - GSList *items = g_slist_copy(const_cast(selection->itemList())); + SelContainer items (selection->itemList()); - items = g_slist_sort(items, (GCompareFunc) sp_object_compare_position); + items.sort(sp_object_compare_position); // bottommost object, after sorting - SPObject *parent = SP_OBJECT(items->data)->parent; + SPObject *parent = SP_OBJECT(items.front())->parent; Geom::Affine parent_transform; @@ -3347,23 +3318,23 @@ sp_selection_tile(SPDesktop *desktop, bool apply) } // remember the position of the first item - gint pos = SP_OBJECT(items->data)->getRepr()->position(); + gint pos = SP_OBJECT(items.front())->getRepr()->position(); // create a list of duplicates - GSList *repr_copies = NULL; - for (GSList *i = items; i != NULL; i = i->next) { - Inkscape::XML::Node *dup = SP_OBJECT(i->data)->getRepr()->duplicate(xml_doc); - repr_copies = g_slist_prepend(repr_copies, dup); + SelContainer repr_copies; + for (SelContainer::const_iterator i=items.begin();i!=items.end();i++){ + Inkscape::XML::Node *dup = SP_OBJECT(*i)->getRepr()->duplicate(xml_doc); + repr_copies.push_front(dynamic_cast(dup)); } // restore the z-order after prepends - repr_copies = g_slist_reverse(repr_copies); + repr_copies.reverse(); Geom::Rect bbox(desktop->dt2doc(r->min()), desktop->dt2doc(r->max())); if (apply) { // delete objects so that their clones don't get alerted; this object will be restored shortly - for (GSList *i = items; i != NULL; i = i->next) { - SPObject *item = reinterpret_cast(i->data); + for (SelContainer::const_iterator i=items.begin();i!=items.end();i++){ + SPObject *item = reinterpret_cast(*i); item->deleteObject(false); } } @@ -3409,7 +3380,6 @@ sp_selection_tile(SPDesktop *desktop, bool apply) selection->set(rectangle); } - g_slist_free(items); DocumentUndo::done(doc, SP_VERB_EDIT_TILE, _("Objects to pattern")); @@ -3432,15 +3402,13 @@ void sp_selection_untile(SPDesktop *desktop) return; } - GSList *new_select = NULL; + SelContainer new_select; bool did = false; - for (GSList *items = g_slist_copy(const_cast(selection->itemList())); - items != NULL; - items = items->next) { - - SPItem *item = static_cast(items->data); + SelContainer items(selection->itemList()); + for (SelContainer::const_iterator i=items.begin();i!=items.end();i++){ + SPItem *item = static_cast(*i); SPStyle *style = item->style; @@ -3476,7 +3444,7 @@ void sp_selection_untile(SPDesktop *desktop) Geom::Affine transform( i->transform * pat_transform ); i->doWriteTransform(i->getRepr(), transform); - new_select = g_slist_prepend(new_select, i); + new_select.push_front(i); } else { g_assert_not_reached(); } @@ -3503,18 +3471,14 @@ void sp_selection_get_export_hints(Inkscape::Selection *selection, Glib::ustring return; } - GSList const *reprlst = selection->reprList(); + SelContainer const reprlst = selection->reprList(); bool filename_search = TRUE; bool xdpi_search = TRUE; bool ydpi_search = TRUE; - for (; reprlst != NULL && - filename_search && - xdpi_search && - ydpi_search; - reprlst = reprlst->next) { + for (SelContainer::const_iterator i=reprlst.begin();filename_search&&xdpi_search&&ydpi_search&&i!=reprlst.end();i++){ gchar const *dpi_string; - Inkscape::XML::Node * repr = static_cast(reprlst->data); + Inkscape::XML::Node * repr = dynamic_cast(*i); if (filename_search) { const gchar* tmp = repr->attribute("inkscape:export-filename"); @@ -3600,10 +3564,10 @@ void sp_selection_create_bitmap_copy(SPDesktop *desktop) } // List of the items to show; all others will be hidden - GSList *items = g_slist_copy(const_cast(selection->itemList())); + SelContainer items(selection->itemList()); // Sort items so that the topmost comes last - items = g_slist_sort(items, (GCompareFunc) sp_item_repr_compare_position); + items.sort(sp_item_repr_compare_position_obj); // Generate a random value from the current time (you may create bitmap from the same object(s) // multiple times, and this is done so that they don't clash) @@ -3614,7 +3578,7 @@ void sp_selection_create_bitmap_copy(SPDesktop *desktop) // Create the filename. gchar *const basename = g_strdup_printf("%s-%s-%u.png", document->getName(), - SP_OBJECT(items->data)->getRepr()->attribute("id"), + SP_OBJECT(items.front())->getRepr()->attribute("id"), current); // Imagemagick is known not to handle spaces in filenames, so we replace anything but letters, // digits, and a few other chars, with "_" @@ -3634,8 +3598,8 @@ void sp_selection_create_bitmap_copy(SPDesktop *desktop) //g_print("%s\n", filepath); // Remember parent and z-order of the topmost one - gint pos = SP_OBJECT(g_slist_last(items)->data)->getRepr()->position(); - SPObject *parent_object = SP_OBJECT(g_slist_last(items)->data)->parent; + gint pos = SP_OBJECT(items.back())->getRepr()->position(); + SPObject *parent_object = SP_OBJECT(items.back())->parent; Inkscape::XML::Node *parent = parent_object->getRepr(); // Calculate resolution @@ -3727,8 +3691,6 @@ void sp_selection_create_bitmap_copy(SPDesktop *desktop) true, /*bool force_overwrite,*/ items); - g_slist_free(items); - // Run filter, if any if (run) { g_print("Running external filter: %s\n", run); @@ -3803,22 +3765,22 @@ void sp_selection_set_clipgroup(SPDesktop *desktop) return; } - GSList const *l = const_cast(selection->reprList()); + SelContainer l=selection->reprList(); - GSList *p = g_slist_copy(const_cast(l)); + SelContainer p(l); - p = g_slist_sort(p, (GCompareFunc) sp_repr_compare_position); + p.sort(sp_repr_compare_position_obj); selection->clear(); - gint topmost = (static_cast(g_slist_last(p)->data))->position(); - Inkscape::XML::Node *topmost_parent = (static_cast(g_slist_last(p)->data))->parent(); + gint topmost = (dynamic_cast(p.back()))->position(); + Inkscape::XML::Node *topmost_parent = (dynamic_cast(p.back()))->parent(); Inkscape::XML::Node *inner = xml_doc->createElement("svg:g"); inner->setAttribute("inkscape:label", "Clip"); - while (p) { - Inkscape::XML::Node *current = static_cast(p->data); + while (!p.empty()) { + Inkscape::XML::Node *current = dynamic_cast(p.front()); if (current->parent() == topmost_parent) { Inkscape::XML::Node *spnew = current->duplicate(xml_doc); @@ -3827,7 +3789,7 @@ void sp_selection_set_clipgroup(SPDesktop *desktop) Inkscape::GC::release(spnew); topmost --; // only reduce count for those items deleted from topmost_parent } else { // move it to topmost_parent first - GSList *temp_clip = NULL; + SelContainer temp_clip; // At this point, current may already have no item, due to its being a clone whose original is already moved away // So we copy it artificially calculating the transform from its repr->attr("transform") and the parent transform @@ -3843,15 +3805,14 @@ void sp_selection_set_clipgroup(SPDesktop *desktop) // then, if this is clone, looking up its original in that array and pre-multiplying // it by the inverse of that original's transform diff. - sp_selection_copy_one(current, item_t, &temp_clip, xml_doc); + sp_selection_copy_one(current, item_t, temp_clip, xml_doc); sp_repr_unparent(current); // paste into topmost_parent (temporarily) - GSList *copied = sp_selection_paste_impl(doc, doc->getObjectByRepr(topmost_parent), &temp_clip); - if (temp_clip) g_slist_free(temp_clip); - if (copied) { // if success, + SelContainer copied = sp_selection_paste_impl(doc, doc->getObjectByRepr(topmost_parent), temp_clip); + if (!copied.empty()) { // if success, // take pasted object (now in topmost_parent) - Inkscape::XML::Node *in_topmost = static_cast(copied->data); + Inkscape::XML::Node *in_topmost = dynamic_cast(copied.front()); // make a copy Inkscape::XML::Node *spnew = in_topmost->duplicate(xml_doc); // remove pasted @@ -3859,10 +3820,9 @@ void sp_selection_set_clipgroup(SPDesktop *desktop) // put its copy into group inner->appendChild(spnew); Inkscape::GC::release(spnew); - g_slist_free(copied); } } - p = g_slist_remove(p, current); + p.pop_front(); } Inkscape::XML::Node *outer = xml_doc->createElement("svg:g"); @@ -3920,7 +3880,7 @@ void sp_selection_set_mask(SPDesktop *desktop, bool apply_clip_path, bool apply_ if ( apply_to_layer && is_empty) { desktop->messageStack()->flash(Inkscape::WARNING_MESSAGE, _("Select object(s) to create clippath or mask from.")); return; - } else if (!apply_to_layer && ( is_empty || NULL == selection->itemList()->next )) { + } else if (!apply_to_layer && ( is_empty || selection->itemList().size()==1 )) { desktop->messageStack()->flash(Inkscape::WARNING_MESSAGE, _("Select mask object and object(s) to apply clippath or mask to.")); return; } @@ -3935,9 +3895,9 @@ void sp_selection_set_mask(SPDesktop *desktop, bool apply_clip_path, bool apply_ doc->ensureUpToDate(); - GSList *items = g_slist_copy(const_cast(selection->itemList())); + SelContainer items(selection->itemList()); - items = g_slist_sort(items, (GCompareFunc) sp_object_compare_position); + items.sort(sp_object_compare_position); // See lp bug #542004 selection->clear(); @@ -3946,7 +3906,7 @@ void sp_selection_set_mask(SPDesktop *desktop, bool apply_clip_path, bool apply_ GSList *mask_items = NULL; GSList *apply_to_items = NULL; GSList *items_to_delete = NULL; - GSList *items_to_select = NULL; + SelContainer items_to_select; Inkscape::Preferences *prefs = Inkscape::Preferences::get(); bool topmost = prefs->getBool("/options/maskobject/topmost", true); @@ -3957,38 +3917,38 @@ void sp_selection_set_mask(SPDesktop *desktop, bool apply_clip_path, bool apply_ // all selected items are used for mask, which is applied to a layer apply_to_items = g_slist_prepend(apply_to_items, desktop->currentLayer()); - for (GSList *i = items; i != NULL; i = i->next) { - Inkscape::XML::Node *dup = SP_OBJECT(i->data)->getRepr()->duplicate(xml_doc); + for (SelContainer::const_iterator i=items.begin();i!=items.end();i++) { + Inkscape::XML::Node *dup = SP_OBJECT(*i)->getRepr()->duplicate(xml_doc); mask_items = g_slist_prepend(mask_items, dup); - SPObject *item = reinterpret_cast(i->data); + SPObject *item = reinterpret_cast(*i); if (remove_original) { items_to_delete = g_slist_prepend(items_to_delete, item); } else { - items_to_select = g_slist_prepend(items_to_select, item); + items_to_select.push_front(item); } } } else if (!topmost) { // topmost item is used as a mask, which is applied to other items in a selection - GSList *i = items; - Inkscape::XML::Node *dup = SP_OBJECT(i->data)->getRepr()->duplicate(xml_doc); + Inkscape::XML::Node *dup = SP_OBJECT(items.front())->getRepr()->duplicate(xml_doc); mask_items = g_slist_prepend(mask_items, dup); if (remove_original) { - SPObject *item = reinterpret_cast(i->data); + SPObject *item = reinterpret_cast(items.front()); items_to_delete = g_slist_prepend(items_to_delete, item); } - for (i = i->next; i != NULL; i = i->next) { - apply_to_items = g_slist_prepend(apply_to_items, i->data); - items_to_select = g_slist_prepend(items_to_select, i->data); + for (SelContainer::const_iterator i=items.begin();i!=items.end();i++) { + if(i==items.begin())continue; + apply_to_items = g_slist_prepend(apply_to_items, *i); + items_to_select.push_front(*i); } } else { GSList *i = NULL; - for (i = items; NULL != i->next; i = i->next) { - apply_to_items = g_slist_prepend(apply_to_items, i->data); - items_to_select = g_slist_prepend(items_to_select, i->data); + for (SelContainer::const_iterator i=items.begin();i!=items.end();i++) { + apply_to_items = g_slist_prepend(apply_to_items, *i); + items_to_select.push_front(*i); } Inkscape::XML::Node *dup = SP_OBJECT(i->data)->getRepr()->duplicate(xml_doc); @@ -3999,9 +3959,7 @@ void sp_selection_set_mask(SPDesktop *desktop, bool apply_clip_path, bool apply_ items_to_delete = g_slist_prepend(items_to_delete, item); } } - - g_slist_free(items); - items = NULL; + items.clear(); if (apply_to_items && grouping == PREFS_MASKOBJECT_GROUPING_ALL) { // group all those objects into one group @@ -4011,24 +3969,22 @@ void sp_selection_set_mask(SPDesktop *desktop, bool apply_clip_path, bool apply_ // make a note we should ungroup this when unsetting mask group->setAttribute("inkscape:groupmode", "maskhelper"); - GSList *reprs_to_group = NULL; + SelContainer reprs_to_group; for (GSList *i = apply_to_items ; NULL != i ; i = i->next) { - reprs_to_group = g_slist_prepend(reprs_to_group, SP_OBJECT(i->data)->getRepr()); - items_to_select = g_slist_remove(items_to_select, i->data); + reprs_to_group.push_front(dynamic_cast(SP_OBJECT(i->data)->getRepr())); + items_to_select.remove(static_cast(i->data)); } - reprs_to_group = g_slist_reverse(reprs_to_group); + reprs_to_group.reverse(); sp_selection_group_impl(reprs_to_group, group, xml_doc, doc); - reprs_to_group = NULL; - // apply clip/mask only to newly created group g_slist_free(apply_to_items); apply_to_items = NULL; apply_to_items = g_slist_prepend(apply_to_items, doc->getObjectByRepr(group)); - items_to_select = g_slist_prepend(items_to_select, doc->getObjectByRepr(group)); + items_to_select.push_front(doc->getObjectByRepr(group)); Inkscape::GC::release(group); } @@ -4068,7 +4024,7 @@ void sp_selection_set_mask(SPDesktop *desktop, bool apply_clip_path, bool apply_ Inkscape::XML::Node *spnew = current->duplicate(xml_doc); gint position = current->position(); - items_to_select = g_slist_remove(items_to_select, item); + items_to_select.remove(item); current->parent()->appendChild(group); sp_repr_unparent(current); group->appendChild(spnew); @@ -4077,7 +4033,7 @@ void sp_selection_set_mask(SPDesktop *desktop, bool apply_clip_path, bool apply_ // Apply clip/mask to group instead apply_mask_to = group; - items_to_select = g_slist_prepend(items_to_select, doc->getObjectByRepr(group)); + items_to_select.push_front(doc->getObjectByRepr(group)); Inkscape::GC::release(spnew); Inkscape::GC::release(group); } @@ -4092,14 +4048,13 @@ void sp_selection_set_mask(SPDesktop *desktop, bool apply_clip_path, bool apply_ for (GSList *i = items_to_delete; NULL != i; i = i->next) { SPObject *item = reinterpret_cast(i->data); item->deleteObject(false); - items_to_select = g_slist_remove(items_to_select, item); + items_to_select.remove(item); } g_slist_free(items_to_delete); - items_to_select = g_slist_reverse(items_to_select); + items_to_select.reverse(); selection->addList(items_to_select); - g_slist_free(items_to_select); if (apply_clip_path) { DocumentUndo::done(doc, SP_VERB_OBJECT_SET_CLIPPATH, _("Set clipping path")); @@ -4131,20 +4086,20 @@ void sp_selection_unset_mask(SPDesktop *desktop, bool apply_clip_path) { gchar const *attributeName = apply_clip_path ? "clip-path" : "mask"; std::map referenced_objects; - GSList *items = g_slist_copy(const_cast(selection->itemList())); + SelContainer items(selection->itemList()); selection->clear(); GSList *items_to_ungroup = NULL; - GSList *items_to_select = g_slist_copy(items); - items_to_select = g_slist_reverse(items_to_select); + SelContainer items_to_select(items); + items_to_select.reverse(); // SPObject* refers to a group containing the clipped path or mask itself, // whereas SPItem* refers to the item being clipped or masked - for (GSList const *i = items; NULL != i; i = i->next) { + for (SelContainer::const_iterator i=items.begin();i!=items.end();i++){ if (remove_original) { // remember referenced mask/clippath, so orphaned masks can be moved back to document - SPItem *item = reinterpret_cast(i->data); + SPItem *item = reinterpret_cast(*i); Inkscape::URIReference *uri_ref = NULL; if (apply_clip_path) { @@ -4159,9 +4114,9 @@ void sp_selection_unset_mask(SPDesktop *desktop, bool apply_clip_path) { } } - SP_OBJECT(i->data)->getRepr()->setAttribute(attributeName, "none"); + SP_OBJECT(*i)->getRepr()->setAttribute(attributeName, "none"); - SPGroup *group = dynamic_cast(static_cast(i->data)); + SPGroup *group = dynamic_cast(static_cast(*i)); if (ungroup_masked && group) { // if we had previously enclosed masked object in group, // add it to list so we can ungroup it later @@ -4173,7 +4128,6 @@ void sp_selection_unset_mask(SPDesktop *desktop, bool apply_clip_path) { } } - g_slist_free(items); // restore mask objects into a document for ( std::map::iterator it = referenced_objects.begin() ; it != referenced_objects.end() ; ++it) { @@ -4207,7 +4161,7 @@ void sp_selection_unset_mask(SPDesktop *desktop, bool apply_clip_path) { repr->setPosition((pos + 1) > 0 ? (pos + 1) : 0); SPItem *mask_item = static_cast(desktop->getDocument()->getObjectByRepr(repr)); - items_to_select = g_slist_prepend(items_to_select, mask_item); + items_to_select.push_front(mask_item); // transform mask, so it is moved the same spot where mask was applied Geom::Affine transform(mask_item->transform); @@ -4222,10 +4176,10 @@ void sp_selection_unset_mask(SPDesktop *desktop, bool apply_clip_path) { for (GSList *i = items_to_ungroup ; NULL != i ; i = i->next) { SPGroup *group = dynamic_cast(static_cast(i->data)); if (group) { - items_to_select = g_slist_remove(items_to_select, group); - GSList *children = NULL; - sp_item_group_ungroup(group, &children, false); - items_to_select = g_slist_concat(children, items_to_select); + items_to_select.remove(group); + SelContainer children; + sp_item_group_ungroup(group, children, false); + items_to_select.splice(items_to_select.begin(),children); } else { g_assert_not_reached(); } @@ -4234,9 +4188,8 @@ void sp_selection_unset_mask(SPDesktop *desktop, bool apply_clip_path) { g_slist_free(items_to_ungroup); // rebuild selection - items_to_select = g_slist_reverse(items_to_select); + items_to_select.reverse(); selection->addList(items_to_select); - g_slist_free(items_to_select); if (apply_clip_path) { DocumentUndo::done(doc, SP_VERB_OBJECT_UNSET_CLIPPATH, _("Release clipping path")); diff --git a/src/selection-chemistry.h b/src/selection-chemistry.h index d86906548..bc317d556 100644 --- a/src/selection-chemistry.h +++ b/src/selection-chemistry.h @@ -19,6 +19,7 @@ #include <2geom/forward.h> #include "sp-item.h" +#include "selection.h" class SPCSSAttr; class SPDesktop; @@ -142,9 +143,9 @@ enum SPSelectStrokeStyleType { void sp_select_same_fill_stroke_style(SPDesktop *desktop, gboolean fill, gboolean strok, gboolean style); void sp_select_same_stroke_style(SPDesktop *desktop); void sp_select_same_object_type(SPDesktop *desktop); -GSList *sp_get_same_fill_or_stroke_color(SPItem *sel, GSList *src, SPSelectStrokeStyleType type); -GSList *sp_get_same_stroke_style(SPItem *sel, GSList *src, SPSelectStrokeStyleType type); -GSList *sp_get_same_object_type(SPItem *sel, GSList *src); +SelContainer sp_get_same_fill_or_stroke_color(SPItem *sel, SelContainer &src, SPSelectStrokeStyleType type); +SelContainer sp_get_same_stroke_style(SPItem *sel, SelContainer &src, SPSelectStrokeStyleType type); +SelContainer sp_get_same_object_type(SPItem *sel, SelContainer &src); void scroll_to_show_item(SPDesktop *desktop, SPItem *item); @@ -171,9 +172,9 @@ void unlock_all_in_all_layers(SPDesktop *dt); void unhide_all(SPDesktop *dt); void unhide_all_in_all_layers(SPDesktop *dt); -GSList *get_all_items(GSList *list, SPObject *from, SPDesktop *desktop, bool onlyvisible, bool onlysensitive, bool ingroups, GSList const *exclude); +SelContainer &get_all_items(SelContainer &list, SPObject *from, SPDesktop *desktop, bool onlyvisible, bool onlysensitive, bool ingroups, SelContainer const &exclude); -GSList *sp_degroup_list (GSList *items); +SelContainer sp_degroup_list (SelContainer &items); /* selection cycling */ typedef enum diff --git a/src/selection-describer.cpp b/src/selection-describer.cpp index f7814fd57..0625c4002 100644 --- a/src/selection-describer.cpp +++ b/src/selection-describer.cpp @@ -40,14 +40,14 @@ #include "sp-spiral.h" // Returns a list of terms for the items to be used in the statusbar -char* collect_terms (GSList *items) +char* collect_terms (const SelContainer &items) { GSList *check = NULL; std::stringstream ss; bool first = true; - for (GSList *i = (GSList *)items; i != NULL; i = i->next) { - SPItem *item = dynamic_cast(reinterpret_cast(i->data)); + for ( SelContainer::const_iterator iter=items.begin();iter!=items.end();iter++ ) { + SPItem *item = dynamic_cast(reinterpret_cast(*iter)); if (item) { const char *term = item->displayName(); if (term != NULL && g_slist_find (check, term) == NULL) { @@ -61,12 +61,12 @@ char* collect_terms (GSList *items) } // Returns the number of terms in the list -static int count_terms (GSList *items) +static int count_terms (const SelContainer &items) { GSList *check = NULL; int count=0; - for (GSList *i = (GSList *)items; i != NULL; i = i->next) { - SPItem *item = dynamic_cast(reinterpret_cast(i->data)); + for ( SelContainer::const_iterator iter=items.begin();iter!=items.end();iter++ ) { + SPItem *item = dynamic_cast(reinterpret_cast(*iter)); if (item) { const char *term = item->displayName(); if (term != NULL && g_slist_find (check, term) == NULL) { @@ -79,11 +79,11 @@ static int count_terms (GSList *items) } // Returns the number of filtered items in the list -static int count_filtered (GSList *items) +static int count_filtered (const SelContainer &items) { int count=0; - for (GSList *i = items; i != NULL; i = i->next) { - SPItem *item = dynamic_cast(reinterpret_cast((i->data))); + for ( SelContainer::const_iterator iter=items.begin();iter!=items.end();iter++ ) { + SPItem *item = dynamic_cast(reinterpret_cast((*iter))); if (item) { count += item->isFiltered(); } @@ -122,12 +122,12 @@ void SelectionDescriber::_selectionModified(Inkscape::Selection *selection, guin } void SelectionDescriber::_updateMessageFromSelection(Inkscape::Selection *selection) { - GSList const *items = selection->itemList(); + SelContainer const items = selection->itemList(); - if (!items) { // no items + if (items.empty()) { // no items _context.set(Inkscape::NORMAL_MESSAGE, _when_nothing); } else { - SPItem *item = dynamic_cast(reinterpret_cast(items->data)); + SPItem *item = dynamic_cast(reinterpret_cast(items.front())); g_assert(item != NULL); SPObject *layer = selection->layers()->layerForObject(item); SPObject *root = selection->layers()->currentRoot(); @@ -188,7 +188,7 @@ void SelectionDescriber::_updateMessageFromSelection(Inkscape::Selection *select g_free (layer_name); g_free (parent_name); - if (!items->next) { // one item + if (items.size()==1) { // one item char *item_desc = item->detailedDescription(); bool isUse = dynamic_cast(item) != NULL; @@ -228,9 +228,9 @@ void SelectionDescriber::_updateMessageFromSelection(Inkscape::Selection *select g_free(item_desc); } else { // multiple items - int objcount = g_slist_length((GSList *)items); - char *terms = collect_terms ((GSList *)items); - int n_terms = count_terms((GSList *)items); + int objcount = items.size(); + char *terms = collect_terms (items); + int n_terms = count_terms(items); gchar *objects_str = g_strdup_printf(ngettext( "%i objects selected of type %s", @@ -241,7 +241,7 @@ void SelectionDescriber::_updateMessageFromSelection(Inkscape::Selection *select // indicate all, some, or none filtered gchar *filt_str = NULL; - int n_filt = count_filtered((GSList *)items); //all filtered + int n_filt = count_filtered(items); //all filtered if (n_filt) { filt_str = g_strdup_printf(ngettext("; %d filtered object ", "; %d filtered objects ", n_filt), n_filt); diff --git a/src/selection.cpp b/src/selection.cpp index 81139d044..b509f4272 100644 --- a/src/selection.cpp +++ b/src/selection.cpp @@ -42,9 +42,9 @@ namespace Inkscape { Selection::Selection(LayerModel *layers, SPDesktop *desktop) : - _objs(NULL), - _reprs(NULL), - _items(NULL), + _objs(SelContainer()), + _reprs(SelContainer()), + _items(SelContainer()), _layers(layers), _desktop(desktop), _selection_context(NULL), @@ -121,17 +121,14 @@ Selection::_releaseContext(SPObject *obj) } void Selection::_invalidateCachedLists() { - g_slist_free(_items); - _items = NULL; - - g_slist_free(_reprs); - _reprs = NULL; + _items.clear(); + _reprs.clear(); } void Selection::_clear() { _invalidateCachedLists(); - while (_objs) { - SPObject *obj=reinterpret_cast(_objs->data); + while (!_objs.empty()) { + SPObject *obj=reinterpret_cast(_objs.front()); _remove(obj); } } @@ -148,7 +145,7 @@ bool Selection::includes(SPObject *obj) const { g_return_val_if_fail(SP_IS_OBJECT(obj), FALSE); - return ( g_slist_find(_objs, obj) != NULL ); + return ( find(_objs.begin(),_objs.end(),obj)!=_objs.end() ); } void Selection::add(SPObject *obj, bool persist_selection_context/* = false */) { @@ -180,7 +177,7 @@ void Selection::_add(SPObject *obj) { _removeObjectDescendants(obj); _removeObjectAncestors(obj); - _objs = g_slist_prepend(_objs, obj); + _objs.push_front(obj); add_3D_boxes_recursively(obj); @@ -234,26 +231,26 @@ void Selection::_remove(SPObject *obj) { remove_3D_boxes_recursively(obj); - _objs = g_slist_remove(_objs, obj); + _objs.remove(obj); } -void Selection::setList(GSList const *list) { +void Selection::setList(SelContainer const &list) { // Clear and add, or just clear with emit. - if (list != NULL) { + if (!list.empty()) { _clear(); addList(list); } else clear(); } -void Selection::addList(GSList const *list) { +void Selection::addList(SelContainer const &list) { - if (list == NULL) + if (list.empty()) return; _invalidateCachedLists(); - for ( GSList const *iter = list ; iter != NULL ; iter = iter->next ) { - SPObject *obj = reinterpret_cast(iter->data); + for ( SelContainer::const_iterator iter=list.begin();iter!=list.end();iter++ ) { + SPObject *obj = reinterpret_cast(*iter); if (includes(obj)) continue; _add (obj); } @@ -261,11 +258,11 @@ void Selection::addList(GSList const *list) { _emitChanged(); } -void Selection::setReprList(GSList const *list) { +void Selection::setReprList(SelContainer const &list) { _clear(); - for ( GSList const *iter = list ; iter != NULL ; iter = iter->next ) { - SPObject *obj=_objectForXMLNode(reinterpret_cast(iter->data)); + for ( SelContainer::const_iterator iter=list.begin();iter!=list.end();iter++ ) { + SPObject *obj=_objectForXMLNode(reinterpret_cast(*iter)); if (obj) { _add(obj); } @@ -279,34 +276,34 @@ void Selection::clear() { _emitChanged(); } -GSList const *Selection::list() { +SelContainer const &Selection::list() { return _objs; } -GSList const *Selection::itemList() { - if (_items) { +SelContainer const &Selection::itemList() { + if (!_items.empty()) { return _items; } - for ( GSList const *iter=_objs ; iter != NULL ; iter = iter->next ) { - SPObject *obj=reinterpret_cast(iter->data); + for ( SelContainer::const_iterator iter=_objs.begin();iter!=_objs.end();iter++ ) { + SPObject *obj=reinterpret_cast(*iter); if (SP_IS_ITEM(obj)) { - _items = g_slist_prepend(_items, SP_ITEM(obj)); + _items.push_front(SP_ITEM(obj)); } } - _items = g_slist_reverse(_items); + _items.reverse(); return _items; } -GSList const *Selection::reprList() { - if (_reprs) { return _reprs; } - - for ( GSList const *iter=itemList() ; iter != NULL ; iter = iter->next ) { - SPObject *obj=reinterpret_cast(iter->data); - _reprs = g_slist_prepend(_reprs, obj->getRepr()); +SelContainer const &Selection::reprList() { + if (!_reprs.empty()) { return _reprs; } + SelContainer list = itemList(); + for ( SelContainer::const_iterator iter=list.begin();iter!=list.end();iter++ ) { + SPObject *obj=reinterpret_cast(*iter); + _reprs.push_front(dynamic_cast(obj->getRepr())); } - _reprs = g_slist_reverse(_reprs); + _reprs.reverse(); return _reprs; } @@ -337,17 +334,17 @@ std::list const Selection::box3DList(Persp3D *persp) { } SPObject *Selection::single() { - if ( _objs != NULL && _objs->next == NULL ) { - return reinterpret_cast(_objs->data); + if ( _objs.size() == 1 ) { + return reinterpret_cast(_objs.front()); } else { return NULL; } } SPItem *Selection::singleItem() { - GSList const *items=itemList(); - if ( items != NULL && items->next == NULL ) { - return reinterpret_cast(items->data); + SelContainer const items=itemList(); + if ( !items.size()==1) { + return reinterpret_cast(items.front()); } else { return NULL; } @@ -362,12 +359,12 @@ SPItem *Selection::largestItem(Selection::CompareSize compare) { } SPItem *Selection::_sizeistItem(bool sml, Selection::CompareSize compare) { - GSList const *items = const_cast(this)->itemList(); + SelContainer const items = const_cast(this)->itemList(); gdouble max = sml ? 1e18 : 0; SPItem *ist = NULL; - for ( GSList const *i = items; i != NULL ; i = i->next ) { - Geom::OptRect obox = SP_ITEM(i->data)->desktopPreferredBounds(); + for ( SelContainer::const_iterator i=items.begin();i!=items.end();i++ ) { + Geom::OptRect obox = SP_ITEM(*i)->desktopPreferredBounds(); if (!obox || obox.isEmpty()) continue; Geom::Rect bbox = *obox; @@ -376,7 +373,7 @@ SPItem *Selection::_sizeistItem(bool sml, Selection::CompareSize compare) { size = sml ? size : size * -1; if (size < max) { max = size; - ist = SP_ITEM(i->data); + ist = SP_ITEM(*i); } } return ist; @@ -395,22 +392,22 @@ Geom::OptRect Selection::bounds(SPItem::BBoxType type) const Geom::OptRect Selection::geometricBounds() const { - GSList const *items = const_cast(this)->itemList(); + SelContainer const items = const_cast(this)->itemList(); Geom::OptRect bbox; - for ( GSList const *i = items ; i != NULL ; i = i->next ) { - bbox.unionWith(SP_ITEM(i->data)->desktopGeometricBounds()); + for ( SelContainer::const_iterator iter=items.begin();iter!=items.end();iter++ ) { + bbox.unionWith(SP_ITEM(*iter)->desktopGeometricBounds()); } return bbox; } Geom::OptRect Selection::visualBounds() const { - GSList const *items = const_cast(this)->itemList(); + SelContainer const items = const_cast(this)->itemList(); Geom::OptRect bbox; - for ( GSList const *i = items ; i != NULL ; i = i->next ) { - bbox.unionWith(SP_ITEM(i->data)->desktopVisualBounds()); + for ( SelContainer::const_iterator iter=items.begin();iter!=items.end();iter++ ) { + bbox.unionWith(SP_ITEM(*iter)->desktopVisualBounds()); } return bbox; } @@ -427,11 +424,11 @@ Geom::OptRect Selection::preferredBounds() const Geom::OptRect Selection::documentBounds(SPItem::BBoxType type) const { Geom::OptRect bbox; - GSList const *items = const_cast(this)->itemList(); - if (!items) return bbox; + SelContainer const items = const_cast(this)->itemList(); + if (items.empty()) return bbox; - for ( GSList const *iter=items ; iter != NULL ; iter = iter->next ) { - SPItem *item = SP_ITEM(iter->data); + for ( SelContainer::const_iterator iter=items.begin();iter!=items.end();iter++ ) { + SPItem *item = SP_ITEM(*iter); bbox |= item->documentBounds(type); } @@ -441,9 +438,9 @@ Geom::OptRect Selection::documentBounds(SPItem::BBoxType type) const // If we have a selection of multiple items, then the center of the first item // will be returned; this is also the case in SelTrans::centerRequest() boost::optional Selection::center() const { - GSList *items = (GSList *) const_cast(this)->itemList(); - if (items) { - SPItem *first = reinterpret_cast(g_slist_last(items)->data); // from the first item in selection + SelContainer const items = const_cast(this)->itemList(); + if (!items.empty()) { + SPItem *first = reinterpret_cast(items.back()); // from the first item in selection if (first->isCenterSet()) { // only if set explicitly return first->getCenter(); } @@ -457,13 +454,13 @@ boost::optional Selection::center() const { } std::vector Selection::getSnapPoints(SnapPreferences const *snapprefs) const { - GSList const *items = const_cast(this)->itemList(); + SelContainer const items = const_cast(this)->itemList(); SnapPreferences snapprefs_dummy = *snapprefs; // create a local copy of the snapping prefs snapprefs_dummy.setTargetSnappable(Inkscape::SNAPTARGET_ROTATION_CENTER, false); // locally disable snapping to the item center std::vector p; - for (GSList const *iter = items; iter != NULL; iter = iter->next) { - SPItem *this_item = SP_ITEM(iter->data); + for ( SelContainer::const_iterator iter=items.begin();iter!=items.end();iter++ ) { + SPItem *this_item = SP_ITEM(*iter); this_item->getSnappoints(p, &snapprefs_dummy); //Include the transformation origin for snapping @@ -477,10 +474,8 @@ std::vector Selection::getSnapPoints(SnapPreferenc } void Selection::_removeObjectDescendants(SPObject *obj) { - GSList *iter, *next; - for ( iter = _objs ; iter ; iter = next ) { - next = iter->next; - SPObject *sel_obj=reinterpret_cast(iter->data); + for ( SelContainer::const_iterator iter=_objs.begin();iter!=_objs.end();iter++ ) { + SPObject *sel_obj=reinterpret_cast(*iter); SPObject *parent = sel_obj->parent; while (parent) { if ( parent == obj ) { @@ -511,32 +506,24 @@ SPObject *Selection::_objectForXMLNode(Inkscape::XML::Node *repr) const { return object; } -guint Selection::numberOfLayers() { - GSList const *items = const_cast(this)->itemList(); - GSList *layers = NULL; - for (GSList const *iter = items; iter != NULL; iter = iter->next) { - SPObject *layer = _layers->layerForObject(SP_OBJECT(iter->data)); - if (g_slist_find (layers, layer) == NULL) { - layers = g_slist_prepend (layers, layer); - } +uint Selection::numberOfLayers() { + SelContainer const items = const_cast(this)->itemList(); + std::set layers; + for ( SelContainer::const_iterator iter=items.begin();iter!=items.end();iter++ ) { + SPObject *layer = _layers->layerForObject(SP_OBJECT(*iter)); + layers.insert(layer); } - guint ret = g_slist_length (layers); - g_slist_free (layers); - return ret; + return layers.size(); } guint Selection::numberOfParents() { - GSList const *items = const_cast(this)->itemList(); - GSList *parents = NULL; - for (GSList const *iter = items; iter != NULL; iter = iter->next) { - SPObject *parent = SP_OBJECT(iter->data)->parent; - if (g_slist_find (parents, parent) == NULL) { - parents = g_slist_prepend (parents, parent); - } + SelContainer const items = const_cast(this)->itemList(); + std::set parents; + for ( SelContainer::const_iterator iter=items.begin();iter!=items.end();iter++ ) { + SPObject *parent = SP_OBJECT(*iter)->parent; + parents.insert(parent); } - guint ret = g_slist_length (parents); - g_slist_free (parents); - return ret; + return parents.size(); } } diff --git a/src/selection.h b/src/selection.h index 5964b20e8..7171b8742 100644 --- a/src/selection.h +++ b/src/selection.h @@ -19,6 +19,11 @@ #include #include +#include +#include +#include +#include + #include "gc-managed.h" #include "gc-finalized.h" #include "gc-anchored.h" @@ -26,11 +31,13 @@ #include "sp-item.h" + class SPDesktop; class SPItem; class SPBox3D; class Persp3D; -typedef struct _GSList GSList; + +typedef std::list SelContainer; namespace Inkscape { class LayerModel; @@ -39,6 +46,15 @@ class Node; } } +/*template +const GSList* std_list_to_GS_list(const std::list list) const +{ + gpointer l=NULL; + for(auto x:list){ + + } +}*/ + namespace Inkscape { /** @@ -154,21 +170,21 @@ public: * * @param objs the objects to select */ - void setList(GSList const *objs); + void setList(SelContainer const &objs); /** * Adds the specified objects to selection, without deselecting first. * * @param objs the objects to select */ - void addList(GSList const *objs); + void addList(SelContainer const &objs); /** * Clears the selection and selects the specified objects. * * @param repr a list of xml nodes for the items to select */ - void setReprList(GSList const *reprs); + void setReprList(std::list const &reprs); /** Add items from an STL iterator range to the selection. * \param from the begin iterator @@ -192,7 +208,7 @@ public: /** * Returns true if no items are selected. */ - bool isEmpty() const { return _objs == NULL; } + bool isEmpty() const { return _objs.empty(); } /** * Returns true if the given object is selected. @@ -238,13 +254,13 @@ public: XML::Node *singleRepr(); /** Returns the list of selected objects. */ - GSList const *list(); + std::list const &list(); /** Returns the list of selected SPItems. */ - GSList const *itemList(); + std::list const &itemList(); /** Returns a list of the xml nodes of all selected objects. */ /// \todo only returns reprs of SPItems currently; need a separate /// method for that - GSList const *reprList(); + std::list const &reprList(); /** Returns a list of all perspectives which have a 3D box in the current selection. (these may also be nested in groups) */ @@ -360,9 +376,9 @@ private: /** Releases an active layer object that is being removed. */ void _releaseContext(SPObject *obj); - mutable GSList *_objs; - mutable GSList *_reprs; - mutable GSList *_items; + mutable std::list _objs; + mutable std::list _reprs; + mutable std::list _items; void add_box_perspective(SPBox3D *box); void add_3D_boxes_recursively(SPObject *obj); diff --git a/src/seltrans.cpp b/src/seltrans.cpp index 5e4c0642e..8c06356db 100644 --- a/src/seltrans.cpp +++ b/src/seltrans.cpp @@ -112,7 +112,7 @@ Inkscape::SelTrans::SelTrans(SPDesktop *desktop) : _opposite_for_bboxpoints(Geom::Point(0,0)), _origin_for_specpoints(Geom::Point(0,0)), _origin_for_bboxpoints(Geom::Point(0,0)), - _stamp_cache(NULL), + _stamp_cache(SelContainer()), _message_context(desktop->messageStack()), _bounding_box_prefs_observer(*this) { @@ -239,8 +239,9 @@ void Inkscape::SelTrans::setCenter(Geom::Point const &p) _center_is_set = true; // Write the new center position into all selected items - for (GSList const *l = _desktop->selection->itemList(); l; l = l->next) { - SPItem *it = SP_ITEM(l->data); + SelContainer items=_desktop->selection->itemList(); + for ( SelContainer::const_iterator iter=items.begin();iter!=items.end();iter++ ) { + SPItem *it = SP_ITEM(*iter); it->setCenter(p); // only set the value; updating repr and document_done will be done once, on ungrab } @@ -268,8 +269,9 @@ void Inkscape::SelTrans::grab(Geom::Point const &p, gdouble x, gdouble y, bool s return; } - for (GSList const *l = selection->itemList(); l; l = l->next) { - SPItem *it = reinterpret_cast(sp_object_ref(SP_ITEM(l->data), NULL)); + SelContainer items=_desktop->selection->itemList(); + for ( SelContainer::const_iterator iter=items.begin();iter!=items.end();iter++ ) { + SPItem *it = reinterpret_cast(sp_object_ref(SP_ITEM(*iter), NULL)); _items.push_back(it); _items_const.push_back(it); _items_affines.push_back(it->i2dt_affine()); @@ -370,7 +372,7 @@ void Inkscape::SelTrans::grab(Geom::Point const &p, gdouble x, gdouble y, bool s } _updateHandles(); - g_return_if_fail(_stamp_cache == NULL); + g_return_if_fail(_stamp_cache.empty()); } void Inkscape::SelTrans::transform(Geom::Affine const &rel_affine, Geom::Point const &norm) @@ -433,9 +435,8 @@ void Inkscape::SelTrans::ungrab() sp_canvas_item_hide(_l[i]); } - if (_stamp_cache) { - g_slist_free(_stamp_cache); - _stamp_cache = NULL; + if (!_stamp_cache.empty()) { + _stamp_cache.clear(); } _message_context.clear(); @@ -491,8 +492,9 @@ void Inkscape::SelTrans::ungrab() if (_center_is_set) { // we were dragging center; update reprs and commit undoable action - for (GSList const *l = _desktop->selection->itemList(); l; l = l->next) { - SPItem *it = SP_ITEM(l->data); + SelContainer items=_desktop->selection->itemList(); + for ( SelContainer::const_iterator iter=items.begin();iter!=items.end();iter++ ) { + SPItem *it = SP_ITEM(*iter); it->updateRepr(); } DocumentUndo::done(_desktop->getDocument(), SP_VERB_CONTEXT_SELECT, @@ -515,26 +517,25 @@ void Inkscape::SelTrans::stamp() Inkscape::Selection *selection = _desktop->getSelection(); bool fixup = !_grabbed; - if ( fixup && _stamp_cache ) { + if ( fixup && !_stamp_cache.empty() ) { // TODO - give a proper fix. Simple temporary work-around for the grab() issue - g_slist_free(_stamp_cache); - _stamp_cache = NULL; + _stamp_cache.clear(); } /* stamping mode */ if (!_empty) { - GSList *l; - if (_stamp_cache) { + SelContainer l; + if (!_stamp_cache.empty()) { l = _stamp_cache; } else { /* Build cache */ - l = g_slist_copy((GSList *) selection->itemList()); - l = g_slist_sort(l, (GCompareFunc) sp_object_compare_position); + l = selection->itemList(); + l.sort(sp_object_compare_position); _stamp_cache = l; } - while (l) { - SPItem *original_item = SP_ITEM(l->data); + for(SelContainer::const_iterator x=l.begin();x!=l.end();x++) { + SPItem *original_item = SP_ITEM(*x); Inkscape::XML::Node *original_repr = original_item->getRepr(); // remember the position of the item @@ -568,16 +569,14 @@ void Inkscape::SelTrans::stamp() } Inkscape::GC::release(copy_repr); - l = l->next; } DocumentUndo::done(_desktop->getDocument(), SP_VERB_CONTEXT_SELECT, _("Stamp")); } - if ( fixup && _stamp_cache ) { + if ( fixup && !_stamp_cache.empty() ) { // TODO - give a proper fix. Simple temporary work-around for the grab() issue - g_slist_free(_stamp_cache); - _stamp_cache = NULL; + _stamp_cache.clear(); } } @@ -712,8 +711,9 @@ void Inkscape::SelTrans::handleClick(SPKnot */*knot*/, guint state, SPSelTransHa case HANDLE_CENTER: if (state & GDK_SHIFT_MASK) { // Unset the center position for all selected items - for (GSList const *l = _desktop->selection->itemList(); l; l = l->next) { - SPItem *it = SP_ITEM(l->data); + SelContainer items=_desktop->selection->itemList(); + for ( SelContainer::const_iterator iter=items.begin();iter!=items.end();iter++ ) { + SPItem *it = SP_ITEM(*iter); it->unsetCenter(); it->updateRepr(); _center_is_set = false; // center has changed @@ -1283,7 +1283,7 @@ gboolean Inkscape::SelTrans::centerRequest(Geom::Point &pt, guint state) // items will share a single center. While dragging that single center, it should never snap to the // centers of any of the selected objects. Therefore we will have to pass the list of selected items // to the snapper, to avoid self-snapping of the rotation center - GSList *items = (GSList *) const_cast(_selection)->itemList(); + SelContainer items = const_cast(_selection)->itemList(); SnapManager &m = _desktop->namedview->snap_manager; m.setup(_desktop); m.setRotationCenterSource(items); diff --git a/src/seltrans.h b/src/seltrans.h index d5db1542d..8f9c329ed 100644 --- a/src/seltrans.h +++ b/src/seltrans.h @@ -187,7 +187,7 @@ private: SPCtrlLine *_l[4]; unsigned int _sel_changed_id; unsigned int _sel_modified_id; - GSList *_stamp_cache; + SelContainer _stamp_cache; Geom::Point _origin; ///< position of origin for transforms Geom::Point _point; ///< original position of the knot being used for the current transform diff --git a/src/snap.cpp b/src/snap.cpp index 8138e4546..a7145b834 100644 --- a/src/snap.cpp +++ b/src/snap.cpp @@ -43,7 +43,7 @@ SnapManager::SnapManager(SPNamedView const *v) : object(this, 0), snapprefs(), _named_view(v), - _rotation_center_source_items(NULL), + _rotation_center_source_items(SelContainer()), _guide_to_ignore(NULL), _desktop(NULL), _snapindicator(true), @@ -1013,7 +1013,7 @@ void SnapManager::setup(SPDesktop const *desktop, _snapindicator = snapindicator; _unselected_nodes = unselected_nodes; _guide_to_ignore = guide_to_ignore; - _rotation_center_source_items = NULL; + _rotation_center_source_items.clear(); } void SnapManager::setup(SPDesktop const *desktop, @@ -1031,7 +1031,7 @@ void SnapManager::setup(SPDesktop const *desktop, _snapindicator = snapindicator; _unselected_nodes = unselected_nodes; _guide_to_ignore = guide_to_ignore; - _rotation_center_source_items = NULL; + _rotation_center_source_items.clear(); } /// Setup, taking the list of items to ignore from the desktop's selection. @@ -1049,13 +1049,13 @@ void SnapManager::setupIgnoreSelection(SPDesktop const *desktop, _snapindicator = snapindicator; _unselected_nodes = unselected_nodes; _guide_to_ignore = guide_to_ignore; - _rotation_center_source_items = NULL; + _rotation_center_source_items.clear(); _items_to_ignore.clear(); Inkscape::Selection *sel = _desktop->selection; - GSList const *items = sel->itemList(); - for (GSList *i = const_cast(items); i; i = i->next) { - _items_to_ignore.push_back(static_cast(i->data)); + SelContainer const items = sel->itemList(); + for (SelContainer::const_iterator i=items.begin();i!=items.end();i++) { + _items_to_ignore.push_back(static_cast(*i)); } } diff --git a/src/snap.h b/src/snap.h index 20b2b246f..012eb072b 100644 --- a/src/snap.h +++ b/src/snap.h @@ -136,7 +136,7 @@ public: std::vector *unselected_nodes = NULL, SPGuide *guide_to_ignore = NULL); - void unSetup() {_rotation_center_source_items = NULL; + void unSetup() {_rotation_center_source_items.clear(); _guide_to_ignore = NULL; _desktop = NULL; _unselected_nodes = NULL;} @@ -145,8 +145,8 @@ public: // of this rotation center; this reference is used to make sure that we do not snap a rotation // center to itself // NOTE: Must be called after calling setup(), not before! - void setRotationCenterSource(GSList *items) {_rotation_center_source_items = items;} - GSList const *getRotationCenterSource() {return _rotation_center_source_items;} + void setRotationCenterSource(const SelContainer &items) {_rotation_center_source_items = items;} + SelContainer getRotationCenterSource() {return _rotation_center_source_items;} // freeSnapReturnByRef() is preferred over freeSnap(), because it only returns a // point if snapping has occurred (by overwriting p); otherwise p is untouched @@ -490,7 +490,7 @@ protected: private: std::vector _items_to_ignore; ///< Items that should not be snapped to, for example the items that are currently being dragged. Set using the setup() method - GSList *_rotation_center_source_items; // to avoid snapping a rotation center to itself + SelContainer _rotation_center_source_items; // to avoid snapping a rotation center to itself SPGuide *_guide_to_ignore; ///< A guide that should not be snapped to, e.g. the guide that is currently being dragged SPDesktop const *_desktop; bool _snapindicator; ///< When true, an indicator will be drawn at the position that was being snapped to diff --git a/src/sp-conn-end.cpp b/src/sp-conn-end.cpp index 3e5398ced..bd139277d 100644 --- a/src/sp-conn-end.cpp +++ b/src/sp-conn-end.cpp @@ -50,8 +50,9 @@ static bool try_get_intersect_point_with_item_recursive(Geom::PathVector& conn_p // consider all first-order children double child_pos = 0.0; - for (GSList const* i = sp_item_group_item_list(group); i != NULL; i = i->next) { - SPItem* child_item = SP_ITEM(i->data); + SelContainer g = sp_item_group_item_list(group); + for (SelContainer::const_iterator i = g.begin();i!=g.end();i++) { + SPItem* child_item = SP_ITEM(*i); try_get_intersect_point_with_item_recursive(conn_pv, child_item, item_transform * child_item->transform, child_pos); if (intersect_pos < child_pos) diff --git a/src/sp-defs.cpp b/src/sp-defs.cpp index 334570076..d52fa038a 100644 --- a/src/sp-defs.cpp +++ b/src/sp-defs.cpp @@ -46,11 +46,10 @@ void SPDefs::update(SPCtx *ctx, guint flags) { } flags &= SP_OBJECT_MODIFIED_CASCADE; - - GSList *l = g_slist_reverse(this->childList(true)); - while (l) { - SPObject *child = SP_OBJECT(l->data); - l = g_slist_remove(l, child); + SelContainer l(this->childList(true)); + l.reverse(); + for(SelContainer::const_iterator i=l.begin();i!=l.end();i++){ + SPObject *child = SP_OBJECT(*i); if (flags || (child->uflags & (SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_CHILD_MODIFIED_FLAG))) { child->updateDisplay(ctx, flags); } diff --git a/src/sp-filter.cpp b/src/sp-filter.cpp index 9cb33a6f3..bf8f7a5a4 100644 --- a/src/sp-filter.cpp +++ b/src/sp-filter.cpp @@ -244,11 +244,10 @@ void SPFilter::update(SPCtx *ctx, guint flags) { childflags |= SP_OBJECT_PARENT_MODIFIED_FLAG; } childflags &= SP_OBJECT_MODIFIED_CASCADE; - - GSList *l = g_slist_reverse(this->childList(true, SPObject::ActionUpdate)); - while (l) { - SPObject *child = SP_OBJECT (l->data); - l = g_slist_remove (l, child); + SelContainer l(this->childList(true, SPObject::ActionUpdate)); + l.reverse(); + for(SelContainer::const_iterator i=l.begin();i!=l.end();i++){ + SPObject *child = SP_OBJECT (*i); if( SP_IS_FILTER_PRIMITIVE( child ) ) { child->updateDisplay(ctx, childflags); } diff --git a/src/sp-item-group.cpp b/src/sp-item-group.cpp index b1ba37de2..e6531c6be 100644 --- a/src/sp-item-group.cpp +++ b/src/sp-item-group.cpp @@ -171,11 +171,10 @@ void SPGroup::update(SPCtx *ctx, unsigned int flags) { childflags |= SP_OBJECT_PARENT_MODIFIED_FLAG; } childflags &= SP_OBJECT_MODIFIED_CASCADE; - - GSList *l = g_slist_reverse(this->childList(true, SPObject::ActionUpdate)); - while (l) { - SPObject *child = SP_OBJECT (l->data); - l = g_slist_remove (l, child); + SelContainer l=this->childList(true, SPObject::ActionUpdate); + l.reverse(); + for(SelContainer::const_iterator i=l.begin();i!=l.end();i++){ + SPObject *child = SP_OBJECT (*i); if (childflags || (child->uflags & (SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_CHILD_MODIFIED_FLAG))) { SPItem *item = dynamic_cast(child); @@ -211,20 +210,16 @@ void SPGroup::update(SPCtx *ctx, unsigned int flags) { void SPGroup::modified(guint flags) { // std::cout << "SPGroup::modified(): " << (getId()?getId():"null") << std::endl; SPLPEItem::modified(flags); - - SPObject *child; - if (flags & SP_OBJECT_MODIFIED_FLAG) { flags |= SP_OBJECT_PARENT_MODIFIED_FLAG; } flags &= SP_OBJECT_MODIFIED_CASCADE; - GSList *l = g_slist_reverse(this->childList(true)); - - while (l) { - child = SP_OBJECT (l->data); - l = g_slist_remove (l, child); + SelContainer l=this->childList(true); + l.reverse(); + for(SelContainer::const_iterator i=l.begin();i!=l.end();i++){ + SPObject *child = SP_OBJECT (*i); if (flags || (child->mflags & (SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_CHILD_MODIFIED_FLAG))) { child->emitModified(flags); @@ -296,35 +291,28 @@ Geom::OptRect SPGroup::bbox(Geom::Affine const &transform, SPItem::BBoxType bbox Geom::OptRect bbox; // TODO CPPIFY: replace this const_cast later - GSList *l = const_cast(this)->childList(false, SPObject::ActionBBox); - - while (l) { - SPObject *o = SP_OBJECT (l->data); - + SelContainer l=const_cast(this)->childList(false, SPObject::ActionBBox); + for(SelContainer::const_iterator i=l.begin();i!=l.end();i++){ + SPObject *o = SP_OBJECT (*i); SPItem *item = dynamic_cast(o); if (item && !item->isHidden()) { Geom::Affine const ct(item->transform * transform); bbox |= item->bounds(bboxtype, ct); } - - l = g_slist_remove (l, o); } return bbox; } void SPGroup::print(SPPrintContext *ctx) { - GSList *l = g_slist_reverse(this->childList(false)); - - while (l) { - SPObject *o = SP_OBJECT (l->data); - + SelContainer l=this->childList(false); + l.reverse(); + for(SelContainer::const_iterator i=l.begin();i!=l.end();i++){ + SPObject *o = SP_OBJECT (*i); SPItem *item = dynamic_cast(o); if (item) { item->invoke_print(ctx); } - - l = g_slist_remove (l, o); } } @@ -372,17 +360,15 @@ Inkscape::DrawingItem *SPGroup::show (Inkscape::Drawing &drawing, unsigned int k } void SPGroup::hide (unsigned int key) { - GSList *l = g_slist_reverse(this->childList(false, SPObject::ActionShow)); - - while (l) { - SPObject *o = SP_OBJECT (l->data); + SelContainer l=this->childList(false, SPObject::ActionShow); + l.reverse(); + for(SelContainer::const_iterator i=l.begin();i!=l.end();i++){ + SPObject *o = SP_OBJECT (*i); SPItem *item = dynamic_cast(o); if (item) { item->invoke_hide(key); } - - l = g_slist_remove (l, o); } // SPLPEItem::onHide(key); @@ -401,7 +387,7 @@ void SPGroup::snappoints(std::vector &p, Inkscape: void -sp_item_group_ungroup (SPGroup *group, GSList **children, bool do_done) +sp_item_group_ungroup (SPGroup *group, SelContainer &children, bool do_done) { g_return_if_fail (group != NULL); @@ -560,8 +546,8 @@ sp_item_group_ungroup (SPGroup *group, GSList **children, bool do_done) } Inkscape::GC::release(repr); - if (children && item) { - *children = g_slist_prepend(*children, item); + if (!children.empty() && item) { + children.push_front(dynamic_cast(item)); } items = g_slist_remove (items, items->data); @@ -576,19 +562,18 @@ sp_item_group_ungroup (SPGroup *group, GSList **children, bool do_done) * some API for list aspect of SPGroup */ -GSList *sp_item_group_item_list(SPGroup * group) +SelContainer sp_item_group_item_list(SPGroup * group) { - g_return_val_if_fail(group != NULL, NULL); - - GSList *s = NULL; + SelContainer s; + g_return_val_if_fail(group != NULL, s); for (SPObject *o = group->firstChild() ; o ; o = o->getNext() ) { if ( dynamic_cast(o) ) { - s = g_slist_prepend(s, o); + s.push_front(o); } } - - return g_slist_reverse (s); + s.reverse(); + return s; } SPObject *sp_item_group_get_child_by_name(SPGroup *group, SPObject *ref, const gchar *name) @@ -809,9 +794,10 @@ gint SPGroup::getItemCount() const { void SPGroup::_showChildren (Inkscape::Drawing &drawing, Inkscape::DrawingItem *ai, unsigned int key, unsigned int flags) { Inkscape::DrawingItem *ac = NULL; - GSList *l = g_slist_reverse(this->childList(false, SPObject::ActionShow)); - while (l) { - SPObject *o = SP_OBJECT (l->data); + SelContainer l=this->childList(false, SPObject::ActionShow); + l.reverse(); + for(SelContainer::const_iterator i=l.begin();i!=l.end();i++){ + SPObject *o = SP_OBJECT (*i); SPItem * child = dynamic_cast(o); if (child) { ac = child->invoke_show (drawing, key, flags); @@ -819,7 +805,6 @@ void SPGroup::_showChildren (Inkscape::Drawing &drawing, Inkscape::DrawingItem * ai->appendChild(ac); } } - l = g_slist_remove (l, o); } } @@ -828,10 +813,10 @@ void SPGroup::update_patheffect(bool write) { g_message("sp_group_update_patheffect: %p\n", lpeitem); #endif - GSList const *item_list = sp_item_group_item_list(this); + SelContainer const item_list = sp_item_group_item_list(this); - for ( GSList const *iter = item_list; iter; iter = iter->next ) { - SPObject *subitem = static_cast(iter->data); + for ( SelContainer::const_iterator iter=item_list.begin();iter!=item_list.end();iter++) { + SPObject *subitem = static_cast(*iter); SPLPEItem *lpeItem = dynamic_cast(subitem); if (lpeItem) { @@ -856,10 +841,10 @@ void SPGroup::update_patheffect(bool write) { static void sp_group_perform_patheffect(SPGroup *group, SPGroup *topgroup, bool write) { - GSList const *item_list = sp_item_group_item_list(group); + SelContainer const item_list = sp_item_group_item_list(group); - for ( GSList const *iter = item_list; iter; iter = iter->next ) { - SPObject *subitem = static_cast(iter->data); + for ( SelContainer::const_iterator iter=item_list.begin();iter!=item_list.end();iter++) { + SPObject *subitem = static_cast(*iter); SPGroup *subGroup = dynamic_cast(subitem); if (subGroup) { diff --git a/src/sp-item-group.h b/src/sp-item-group.h index 15bb58f22..9a5ee0161 100644 --- a/src/sp-item-group.h +++ b/src/sp-item-group.h @@ -15,6 +15,7 @@ #include #include "sp-lpe-item.h" +#include "selection.h"//SelContainer #define SP_GROUP(obj) (dynamic_cast((SPObject*)obj)) #define SP_IS_GROUP(obj) (dynamic_cast((SPObject*)obj) != NULL) @@ -95,10 +96,10 @@ public: virtual void update_patheffect(bool write); }; -void sp_item_group_ungroup (SPGroup *group, GSList **children, bool do_done = true); +void sp_item_group_ungroup (SPGroup *group, SelContainer &children, bool do_done = true); -GSList *sp_item_group_item_list (SPGroup *group); +SelContainer sp_item_group_item_list (SPGroup *group); SPObject *sp_item_group_get_child_by_name (SPGroup *group, SPObject *ref, const char *name); #endif diff --git a/src/sp-lpe-item.cpp b/src/sp-lpe-item.cpp index f059ab531..1305efd83 100644 --- a/src/sp-lpe-item.cpp +++ b/src/sp-lpe-item.cpp @@ -353,9 +353,9 @@ sp_lpe_item_create_original_path_recursive(SPLPEItem *lpeitem) sp_lpe_item_create_original_path_recursive(SP_LPE_ITEM(clipPath->firstChild())); } if (SP_IS_GROUP(lpeitem)) { - GSList const *item_list = sp_item_group_item_list(SP_GROUP(lpeitem)); - for ( GSList const *iter = item_list; iter; iter = iter->next ) { - SPObject *subitem = static_cast(iter->data); + SelContainer item_list = sp_item_group_item_list(SP_GROUP(lpeitem)); + for ( SelContainer::const_iterator iter=item_list.begin();iter!=item_list.end();iter++) { + SPObject *subitem = static_cast(*iter); if (SP_IS_LPE_ITEM(subitem)) { sp_lpe_item_create_original_path_recursive(SP_LPE_ITEM(subitem)); } @@ -387,9 +387,9 @@ sp_lpe_item_cleanup_original_path_recursive(SPLPEItem *lpeitem) sp_lpe_item_cleanup_original_path_recursive(SP_LPE_ITEM(clipPath->firstChild())); } } - GSList const *item_list = sp_item_group_item_list(SP_GROUP(lpeitem)); - for ( GSList const *iter = item_list; iter; iter = iter->next ) { - SPObject *subitem = static_cast(iter->data); + SelContainer item_list = sp_item_group_item_list(SP_GROUP(lpeitem)); + for ( SelContainer::const_iterator iter=item_list.begin();iter!=item_list.end();iter++) { + SPObject *subitem = static_cast(*iter); if (SP_IS_LPE_ITEM(subitem)) { sp_lpe_item_cleanup_original_path_recursive(SP_LPE_ITEM(subitem)); } @@ -680,9 +680,9 @@ SPLPEItem::apply_to_clippath(SPItem *item) } } if(SP_IS_GROUP(item)){ - GSList const *item_list = sp_item_group_item_list(SP_GROUP(item)); - for ( GSList const *iter = item_list; iter; iter = iter->next ) { - SPObject *subitem = static_cast(iter->data); + SelContainer item_list = sp_item_group_item_list(SP_GROUP(item)); + for ( SelContainer::const_iterator iter=item_list.begin();iter!=item_list.end();iter++) { + SPObject *subitem = static_cast(*iter); apply_to_clippath(SP_ITEM(subitem)); } } @@ -732,9 +732,9 @@ SPLPEItem::apply_to_mask(SPItem *item) } } if(SP_IS_GROUP(item)){ - GSList const *item_list = sp_item_group_item_list(SP_GROUP(item)); - for ( GSList const *iter = item_list; iter; iter = iter->next ) { - SPObject *subitem = static_cast(iter->data); + SelContainer item_list = sp_item_group_item_list(SP_GROUP(item)); + for ( SelContainer::const_iterator iter=item_list.begin();iter!=item_list.end();iter++) { + SPObject *subitem = static_cast(*iter); apply_to_mask(SP_ITEM(subitem)); } } @@ -746,9 +746,9 @@ SPLPEItem::apply_to_clip_or_mask_group(SPItem *group, SPItem *item) if (!SP_IS_GROUP(group)) { return; } - GSList *item_list = sp_item_group_item_list(SP_GROUP(group)); - for ( GSList *iter = item_list; iter; iter = iter->next ) { - SPObject *subitem = static_cast(iter->data); + SelContainer item_list = sp_item_group_item_list(SP_GROUP(group)); + for ( SelContainer::const_iterator iter=item_list.begin();iter!=item_list.end();iter++) { + SPObject *subitem = static_cast(*iter); if (SP_IS_GROUP(subitem)) { apply_to_clip_or_mask_group(SP_ITEM(subitem), item); } else if (SP_IS_SHAPE(subitem)) { diff --git a/src/sp-marker.cpp b/src/sp-marker.cpp index 371a6c35c..66b445265 100644 --- a/src/sp-marker.cpp +++ b/src/sp-marker.cpp @@ -429,7 +429,7 @@ sp_marker_hide (SPMarker *marker, unsigned int key) } -const gchar *generate_marker(GSList *reprs, Geom::Rect bounds, SPDocument *document, Geom::Point center, Geom::Affine move) +const gchar *generate_marker(SelContainer &reprs, Geom::Rect bounds, SPDocument *document, Geom::Point center, Geom::Affine move) { Inkscape::XML::Document *xml_doc = document->getReprDoc(); Inkscape::XML::Node *defsrepr = document->getDefs()->getRepr(); @@ -452,8 +452,8 @@ const gchar *generate_marker(GSList *reprs, Geom::Rect bounds, SPDocument *docum const gchar *mark_id = repr->attribute("id"); SPObject *mark_object = document->getObjectById(mark_id); - for (GSList *i = reprs; i != NULL; i = i->next) { - Inkscape::XML::Node *node = (Inkscape::XML::Node *)(i->data); + for (SelContainer::const_iterator i=reprs.begin();i!=reprs.end();i++){ + Inkscape::XML::Node *node = (Inkscape::XML::Node *)(*i); SPItem *copy = SP_ITEM(mark_object->appendChildRepr(node)); Geom::Affine dup_transform; diff --git a/src/sp-marker.h b/src/sp-marker.h index e804fd7dc..594c164c5 100644 --- a/src/sp-marker.h +++ b/src/sp-marker.h @@ -101,7 +101,7 @@ Inkscape::DrawingItem *sp_marker_show_instance (SPMarker *marker, Inkscape::Draw unsigned int key, unsigned int pos, Geom::Affine const &base, float linewidth); void sp_marker_hide (SPMarker *marker, unsigned int key); -const char *generate_marker (GSList *reprs, Geom::Rect bounds, SPDocument *document, Geom::Point center, Geom::Affine move); +const char *generate_marker (SelContainer &reprs, Geom::Rect bounds, SPDocument *document, Geom::Point center, Geom::Affine move); SPObject *sp_marker_fork_if_necessary(SPObject *marker); #endif diff --git a/src/sp-object.cpp b/src/sp-object.cpp index 7d24a978e..3ea480f66 100644 --- a/src/sp-object.cpp +++ b/src/sp-object.cpp @@ -382,14 +382,14 @@ void SPObject::changeCSS(SPCSSAttr *css, gchar const *attr) sp_repr_css_change(this->getRepr(), css, attr); } -GSList *SPObject::childList(bool add_ref, Action) { - GSList *l = NULL; +SelContainer SPObject::childList(bool add_ref, Action) { + SelContainer l; for ( SPObject *child = firstChild() ; child; child = child->getNext() ) { if (add_ref) { sp_object_ref (child); } - l = g_slist_prepend (l, child); + l.push_front(child); } return l; diff --git a/src/sp-object.h b/src/sp-object.h index ff80eaefc..858587611 100644 --- a/src/sp-object.h +++ b/src/sp-object.h @@ -47,11 +47,14 @@ class SPObject; #define SP_OBJECT_WRITE_ALL (1 << 2) #define SP_OBJECT_WRITE_NO_CHILDREN (1 << 3) + + #include #include #include #include #include +#include #include "version.h" #include "util/forward-pointer-iterator.h" @@ -60,6 +63,11 @@ class SPCSSAttr; class SPStyle; typedef struct _GSList GSList; +//should be in selection.h +typedef std::list SelContainer; + + + namespace Inkscape { namespace XML { class Node; @@ -330,7 +338,7 @@ public: * Retrieves the children as a GSList object, optionally ref'ing the children * in the process, if add_ref is specified. */ - GSList *childList(bool add_ref, Action action = ActionGeneral); + SelContainer childList(bool add_ref, Action action = ActionGeneral); /** * Append repr as child of this object. diff --git a/src/sp-pattern.cpp b/src/sp-pattern.cpp index 961ab0f84..d5eff9796 100644 --- a/src/sp-pattern.cpp +++ b/src/sp-pattern.cpp @@ -408,7 +408,7 @@ sp_pattern_transform_multiply (SPPattern *pattern, Geom::Affine postmul, bool se g_free(c); } -const gchar *pattern_tile(GSList *reprs, Geom::Rect bounds, SPDocument *document, Geom::Affine transform, Geom::Affine move) +const gchar *pattern_tile(const SelContainer &reprs, Geom::Rect bounds, SPDocument *document, Geom::Affine transform, Geom::Affine move) { Inkscape::XML::Document *xml_doc = document->getReprDoc(); Inkscape::XML::Node *defsrepr = document->getDefs()->getRepr(); @@ -426,8 +426,8 @@ const gchar *pattern_tile(GSList *reprs, Geom::Rect bounds, SPDocument *document const gchar *pat_id = repr->attribute("id"); SPObject *pat_object = document->getObjectById(pat_id); - for (GSList *i = reprs; i != NULL; i = i->next) { - Inkscape::XML::Node *node = (Inkscape::XML::Node *)(i->data); + for (SelContainer::const_iterator i=reprs.begin();i!=reprs.end();i++){ + Inkscape::XML::Node *node = (Inkscape::XML::Node *)(*i); SPItem *copy = SP_ITEM(pat_object->appendChildRepr(node)); Geom::Affine dup_transform; diff --git a/src/sp-pattern.h b/src/sp-pattern.h index f021101e2..0e2b058b5 100644 --- a/src/sp-pattern.h +++ b/src/sp-pattern.h @@ -89,7 +89,7 @@ SPPattern *pattern_chain (SPPattern *pattern); SPPattern *sp_pattern_clone_if_necessary (SPItem *item, SPPattern *pattern, const char *property); void sp_pattern_transform_multiply (SPPattern *pattern, Geom::Affine postmul, bool set); -const char *pattern_tile (GSList *reprs, Geom::Rect bounds, SPDocument *document, Geom::Affine transform, Geom::Affine move); +const char *pattern_tile (const SelContainer &reprs, Geom::Rect bounds, SPDocument *document, Geom::Affine transform, Geom::Affine move); SPPattern *pattern_getroot (SPPattern *pat); diff --git a/src/sp-switch.cpp b/src/sp-switch.cpp index db6db9909..0090f1855 100644 --- a/src/sp-switch.cpp +++ b/src/sp-switch.cpp @@ -55,21 +55,22 @@ SPObject *SPSwitch::_evaluateFirst() { return first; } -GSList *SPSwitch::_childList(bool add_ref, SPObject::Action action) { +SelContainer SPSwitch::_childList(bool add_ref, SPObject::Action action) { if ( action != SPObject::ActionGeneral ) { return this->childList(add_ref, action); } SPObject *child = _evaluateFirst(); + SelContainer x; if (NULL == child) - return NULL; + return x; if (add_ref) { //g_object_ref (G_OBJECT (child)); sp_object_ref(child); } - - return g_slist_prepend (NULL, child); + x.push_front(child); + return x; } const char *SPSwitch::displayName() const { @@ -109,10 +110,9 @@ void SPSwitch::_reevaluate(bool /*add_to_drawing*/) { _releaseLastItem(_cached_item); - for ( GSList *l = _childList(false, SPObject::ActionShow); - NULL != l ; l = g_slist_remove (l, l->data)) - { - SPObject *o = SP_OBJECT (l->data); + SelContainer item_list = _childList(false, SPObject::ActionShow); + for ( SelContainer::const_iterator iter=item_list.begin();iter!=item_list.end();iter++) { + SPObject *o = SP_OBJECT (*iter); if ( !SP_IS_ITEM (o) ) { continue; } @@ -144,10 +144,10 @@ void SPSwitch::_releaseLastItem(SPObject *obj) void SPSwitch::_showChildren (Inkscape::Drawing &drawing, Inkscape::DrawingItem *ai, unsigned int key, unsigned int flags) { SPObject *evaluated_child = this->_evaluateFirst(); - GSList *l = this->_childList(false, SPObject::ActionShow); + SelContainer l = this->_childList(false, SPObject::ActionShow); - while (l) { - SPObject *o = SP_OBJECT (l->data); + for ( SelContainer::const_iterator iter=l.begin();iter!=l.end();iter++) { + SPObject *o = SP_OBJECT (*iter); if (SP_IS_ITEM (o)) { SPItem * child = SP_ITEM(o); @@ -158,8 +158,6 @@ void SPSwitch::_showChildren (Inkscape::Drawing &drawing, Inkscape::DrawingItem ai->appendChild(ac); } } - - l = g_slist_remove (l, o); } } diff --git a/src/sp-switch.h b/src/sp-switch.h index 4fce1f5a6..6a83072e7 100644 --- a/src/sp-switch.h +++ b/src/sp-switch.h @@ -29,7 +29,7 @@ public: void resetChildEvaluated() { _reevaluate(); } - GSList *_childList(bool add_ref, SPObject::Action action); + SelContainer _childList(bool add_ref, SPObject::Action action); virtual void _showChildren (Inkscape::Drawing &drawing, Inkscape::DrawingItem *ai, unsigned int key, unsigned int flags); SPObject *_evaluateFirst(); diff --git a/src/splivarot.cpp b/src/splivarot.cpp index 8bb3e9897..aec7051e0 100644 --- a/src/splivarot.cpp +++ b/src/splivarot.cpp @@ -60,6 +60,11 @@ using Inkscape::DocumentUndo; bool Ancetre(Inkscape::XML::Node *a, Inkscape::XML::Node *who); +//SHOULD DISAPPEAR +bool sp_repr_compare_position_obj(SPObject* &a,SPObject* &b){ + return sp_repr_compare_position(dynamic_cast(a),dynamic_cast(b)); +} + void sp_selected_path_boolop(Inkscape::Selection *selection, SPDesktop *desktop, bool_op bop, const unsigned int verb=SP_VERB_NONE, const Glib::ustring description=""); void sp_selected_path_do_offset(SPDesktop *desktop, bool expand, double prefOffset); void sp_selected_path_create_offset_object(SPDesktop *desktop, int expand, bool updating); @@ -326,21 +331,21 @@ void sp_selected_path_boolop(Inkscape::Selection *selection, SPDesktop *desktop, bool_op bop, const unsigned int verb, const Glib::ustring description) { SPDocument *doc = selection->layers()->getDocument(); - GSList *il = (GSList *) selection->itemList(); + SelContainer il= selection->itemList(); // allow union on a single object for the purpose of removing self overlapse (svn log, revision 13334) - if ( (g_slist_length(il) < 2) && (bop != bool_op_union)) { + if ( (il.size() < 2) && (bop != bool_op_union)) { boolop_display_error_message(desktop, _("Select at least 2 paths to perform a boolean operation.")); return; } - else if ( g_slist_length(il) < 1 ) { + else if ( il.size() < 1 ) { boolop_display_error_message(desktop, _("Select at least 1 path to perform a boolean union.")); return; } - g_assert(il != NULL); + g_assert(!il.empty()); - if (g_slist_length(il) > 2) { + if (il.size() > 2) { if (bop == bool_op_diff || bop == bool_op_cut || bop == bool_op_slice ) { boolop_display_error_message(desktop, _("Select exactly 2 paths to perform difference, division, or path cut.")); return; @@ -354,8 +359,8 @@ sp_selected_path_boolop(Inkscape::Selection *selection, SPDesktop *desktop, bool if (bop == bool_op_diff || bop == bool_op_cut || bop == bool_op_slice) { // check in the tree to find which element of the selection list is topmost (for 2-operand commands only) - Inkscape::XML::Node *a = SP_OBJECT(il->data)->getRepr(); - Inkscape::XML::Node *b = SP_OBJECT(il->next->data)->getRepr(); + Inkscape::XML::Node *a = SP_OBJECT(il.front())->getRepr(); + Inkscape::XML::Node *b = SP_OBJECT(il.back())->getRepr(); if (a == NULL || b == NULL) { boolop_display_error_message(desktop, _("Unable to determine the z-order of the objects selected for difference, XOR, division, or path cut.")); @@ -394,38 +399,36 @@ sp_selected_path_boolop(Inkscape::Selection *selection, SPDesktop *desktop, bool } } - il = g_slist_copy(il); - g_assert(il != NULL); + g_assert(!il.empty()); // first check if all the input objects have shapes // otherwise bail out - for (GSList *l = il; l != NULL; l = l->next) + for (SelContainer::const_iterator l = il.begin(); l != il.end(); l++) { - SPItem *item = SP_ITEM(l->data); + SPItem *item = SP_ITEM(*l); if (!SP_IS_SHAPE(item) && !SP_IS_TEXT(item) && !SP_IS_FLOWTEXT(item)) { boolop_display_error_message(desktop, _("One of the objects is not a path, cannot perform boolean operation.")); - g_slist_free(il); return; } } // extract the livarot Paths from the source objects // also get the winding rule specified in the style - int nbOriginaux = g_slist_length(il); + int nbOriginaux = il.size(); std::vector originaux(nbOriginaux); std::vector origWind(nbOriginaux); int curOrig; { curOrig = 0; - for (GSList *l = il; l != NULL; l = l->next) + for (SelContainer::const_iterator l = il.begin(); l != il.end(); l++) { // apply live path effects prior to performing boolean operation - if (SP_IS_LPE_ITEM(l->data)) { - SP_LPE_ITEM(l->data)->removeAllPathEffects(true); + if (SP_IS_LPE_ITEM(*l)) { + SP_LPE_ITEM(*l)->removeAllPathEffects(true); } - SPCSSAttr *css = sp_repr_css_attr(reinterpret_cast(il->data)->getRepr(), "style"); + SPCSSAttr *css = sp_repr_css_attr(reinterpret_cast(il.front())->getRepr(), "style"); gchar const *val = sp_repr_css_property(css, "fill-rule", NULL); if (val && strcmp(val, "nonzero") == 0) { origWind[curOrig]= fill_nonZero; @@ -435,11 +438,10 @@ sp_selected_path_boolop(Inkscape::Selection *selection, SPDesktop *desktop, bool origWind[curOrig]= fill_nonZero; } - originaux[curOrig] = Path_for_item((SPItem *) l->data, true, true); + originaux[curOrig] = Path_for_item((SPItem *) (*l), true, true); if (originaux[curOrig] == NULL || originaux[curOrig]->descr_cmd.size() <= 1) { for (int i = curOrig; i >= 0; i--) delete originaux[i]; - g_slist_free(il); return; } curOrig++; @@ -472,7 +474,8 @@ sp_selected_path_boolop(Inkscape::Selection *selection, SPDesktop *desktop, bool theShapeA->ConvertToShape(theShape, origWind[0]); curOrig = 1; - for (GSList *l = il->next; l != NULL; l = l->next) { + for (SelContainer::const_iterator l = il.begin(); l != il.end(); l++){ + if(*l==il.front())continue; originaux[curOrig]->ConvertWithBackData(0.1); originaux[curOrig]->Fill(theShape, curOrig); @@ -668,15 +671,13 @@ sp_selected_path_boolop(Inkscape::Selection *selection, SPDesktop *desktop, bool if (res->descr_cmd.size() <= 1) { // only one command, presumably a moveto: it isn't a path - for (GSList *l = il; l != NULL; l = l->next) - { - SP_OBJECT(l->data)->deleteObject(); + for (SelContainer::const_iterator l = il.begin(); l != il.end(); l++){ + SP_OBJECT(*l)->deleteObject(); } DocumentUndo::done(doc, SP_VERB_NONE, description); selection->clear(); delete res; - g_slist_free(il); return; } @@ -684,19 +685,17 @@ sp_selected_path_boolop(Inkscape::Selection *selection, SPDesktop *desktop, bool SPObject *source; if ( bop == bool_op_diff || bop == bool_op_cut || bop == bool_op_slice ) { if (reverseOrderForOp) { - source = SP_OBJECT(il->data); + source = SP_OBJECT(il.front()); } else { - source = SP_OBJECT(il->next->data); + source = SP_OBJECT(il.back()); } } else { // find out the bottom object - GSList *sorted = g_slist_copy((GSList *) selection->reprList()); - - sorted = g_slist_sort(sorted, (GCompareFunc) sp_repr_compare_position); + SelContainer sorted(selection->reprList()); - source = doc->getObjectByRepr((Inkscape::XML::Node *)sorted->data); + sorted.sort(sp_repr_compare_position_obj); - g_slist_free(sorted); + source = doc->getObjectByRepr((Inkscape::XML::Node *)sorted.front()); } // adjust style properties that depend on a possible transform in the source object in order @@ -721,17 +720,16 @@ sp_selected_path_boolop(Inkscape::Selection *selection, SPDesktop *desktop, bool gchar *desc = source->desc(); // remove source paths selection->clear(); - for (GSList *l = il; l != NULL; l = l->next) { + for (SelContainer::const_iterator l = il.begin(); l != il.end(); l++){ // if this is the bottommost object, - if (!strcmp(reinterpret_cast(l->data)->getRepr()->attribute("id"), id)) { + if (!strcmp(reinterpret_cast(*l)->getRepr()->attribute("id"), id)) { // delete it so that its clones don't get alerted; this object will be restored shortly, with the same id - SP_OBJECT(l->data)->deleteObject(false); + SP_OBJECT(*l)->deleteObject(false); } else { // delete the object for real, so that its clones can take appropriate action - SP_OBJECT(l->data)->deleteObject(); + SP_OBJECT(*l)->deleteObject(); } } - g_slist_free(il); // premultiply by the inverse of parent's repr SPItem *parent_item = SP_ITEM(doc->getObjectByRepr(parent)); @@ -1159,12 +1157,9 @@ sp_selected_path_outline(SPDesktop *desktop) } bool did = false; - - for (GSList *items = g_slist_copy((GSList *) selection->itemList()); - items != NULL; - items = items->next) { - - SPItem *item = SP_ITEM(items->data); + SelContainer il(selection->itemList()); + for (SelContainer::const_iterator l = il.begin(); l != il.end(); l++){ + SPItem *item = SP_ITEM(*l); if (!SP_IS_SHAPE(item) && !SP_IS_TEXT(item)) continue; @@ -1774,12 +1769,9 @@ sp_selected_path_do_offset(SPDesktop *desktop, bool expand, double prefOffset) } bool did = false; - - for (GSList *items = g_slist_copy((GSList *) selection->itemList()); - items != NULL; - items = items->next) { - - SPItem *item = SP_ITEM(items->data); + SelContainer il(selection->itemList()); + for (SelContainer::const_iterator l = il.begin(); l != il.end(); l++){ + SPItem *item = SP_ITEM(*l); SPCurve *curve = NULL; if (!SP_IS_SHAPE(item) && !SP_IS_TEXT(item)) @@ -1975,7 +1967,7 @@ sp_selected_path_do_offset(SPDesktop *desktop, bool expand, double prefOffset) static bool sp_selected_path_simplify_items(SPDesktop *desktop, - Inkscape::Selection *selection, GSList *items, + Inkscape::Selection *selection, SelContainer &items, float threshold, bool justCoalesce, float angleLimit, bool breakableAngles, bool modifySelection); @@ -1994,7 +1986,7 @@ sp_selected_path_simplify_item(SPDesktop *desktop, //If this is a group, do the children instead if (SP_IS_GROUP(item)) { - GSList *items = sp_item_group_item_list(SP_GROUP(item)); + SelContainer items = sp_item_group_item_list(SP_GROUP(item)); return sp_selected_path_simplify_items(desktop, selection, items, threshold, justCoalesce, @@ -2119,7 +2111,7 @@ sp_selected_path_simplify_item(SPDesktop *desktop, bool sp_selected_path_simplify_items(SPDesktop *desktop, - Inkscape::Selection *selection, GSList *items, + Inkscape::Selection *selection, SelContainer &items, float threshold, bool justCoalesce, float angleLimit, bool breakableAngles, bool modifySelection) @@ -2145,13 +2137,13 @@ sp_selected_path_simplify_items(SPDesktop *desktop, gdouble simplifySize = selectionSize; int pathsSimplified = 0; - int totalPathCount = g_slist_length(items); + int totalPathCount = items.size(); // set "busy" cursor desktop->setWaitingCursor(); - for (; items != NULL; items = items->next) { - SPItem *item = (SPItem *) items->data; + for (SelContainer::const_iterator l = items.begin(); l != items.end(); l++){ + SPItem *item = SP_ITEM(*l); if (!(SP_IS_GROUP(item) || SP_IS_SHAPE(item) || SP_IS_TEXT(item))) continue; @@ -2199,7 +2191,7 @@ sp_selected_path_simplify_selection(SPDesktop *desktop, float threshold, bool ju return; } - GSList *items = g_slist_copy((GSList *) selection->itemList()); + SelContainer items(selection->itemList()); bool didSomething = sp_selected_path_simplify_items(desktop, selection, items, threshold, diff --git a/src/text-chemistry.cpp b/src/text-chemistry.cpp index 65b59f2ad..391e255a5 100644 --- a/src/text-chemistry.cpp +++ b/src/text-chemistry.cpp @@ -43,11 +43,10 @@ using Inkscape::DocumentUndo; static SPItem * flowtext_in_selection(Inkscape::Selection *selection) { - for (GSList *items = (GSList *) selection->itemList(); - items != NULL; - items = items->next) { - if (SP_IS_FLOWTEXT(items->data)) - return ((SPItem *) items->data); + SelContainer items = selection->itemList(); + for(SelContainer::const_iterator i=items.begin();i!=items.end();i++){ + if (SP_IS_FLOWTEXT(*i)) + return ((SPItem *) *i); } return NULL; } @@ -55,11 +54,10 @@ flowtext_in_selection(Inkscape::Selection *selection) static SPItem * text_or_flowtext_in_selection(Inkscape::Selection *selection) { - for (GSList *items = (GSList *) selection->itemList(); - items != NULL; - items = items->next) { - if (SP_IS_TEXT(items->data) || SP_IS_FLOWTEXT(items->data)) - return ((SPItem *) items->data); + SelContainer items = selection->itemList(); + for(SelContainer::const_iterator i=items.begin();i!=items.end();i++){ + if (SP_IS_TEXT(*i) || SP_IS_FLOWTEXT(*i)) + return ((SPItem *) *i); } return NULL; } @@ -67,11 +65,10 @@ text_or_flowtext_in_selection(Inkscape::Selection *selection) static SPItem * shape_in_selection(Inkscape::Selection *selection) { - for (GSList *items = (GSList *) selection->itemList(); - items != NULL; - items = items->next) { - if (SP_IS_SHAPE(items->data)) - return ((SPItem *) items->data); + SelContainer items = selection->itemList(); + for(SelContainer::const_iterator i=items.begin();i!=items.end();i++){ + if (SP_IS_SHAPE(*i)) + return ((SPItem *) *i); } return NULL; } @@ -90,7 +87,7 @@ text_put_on_path() Inkscape::XML::Document *xml_doc = desktop->doc()->getReprDoc(); - if (!text || !shape || g_slist_length((GSList *) selection->itemList()) != 2) { + if (!text || !shape || selection->itemList().size() != 2) { desktop->getMessageStack()->flash(Inkscape::WARNING_MESSAGE, _("Select a text and a path to put text on path.")); return; } @@ -199,11 +196,9 @@ text_remove_from_path() } bool did = false; - - for (GSList *items = g_slist_copy((GSList *) selection->itemList()); - items != NULL; - items = items->next) { - SPObject *obj = SP_OBJECT(items->data); + SelContainer items(selection->itemList()); + for(SelContainer::const_iterator i=items.begin();i!=items.end();i++){ + SPObject *obj = SP_OBJECT(*i); if (SP_IS_TEXT_TEXTPATH(obj)) { SPObject *tp = obj->firstChild(); @@ -219,7 +214,7 @@ text_remove_from_path() } else { DocumentUndo::done(desktop->getDocument(), SP_VERB_CONTEXT_TEXT, _("Remove text from path")); - selection->setList(g_slist_copy((GSList *) selection->itemList())); // reselect to update statusbar description + selection->setList(selection->itemList()); // reselect to update statusbar description } } @@ -265,10 +260,9 @@ text_remove_all_kerns() bool did = false; - for (GSList *items = g_slist_copy((GSList *) selection->itemList()); - items != NULL; - items = items->next) { - SPObject *obj = SP_OBJECT(items->data); + SelContainer items = selection->itemList(); + for(SelContainer::const_iterator i=items.begin();i!=items.end();i++){ + SPObject *obj = SP_OBJECT(*i); if (!SP_IS_TEXT(obj) && !SP_IS_TSPAN(obj) && !SP_IS_FLOWTEXT(obj)) { continue; @@ -302,7 +296,7 @@ text_flow_into_shape() SPItem *text = text_or_flowtext_in_selection(selection); SPItem *shape = shape_in_selection(selection); - if (!text || !shape || g_slist_length((GSList *) selection->itemList()) < 2) { + if (!text || !shape || selection->itemList().size() < 2) { desktop->getMessageStack()->flash(Inkscape::WARNING_MESSAGE, _("Select a text and one or more paths or shapes to flow text into frame.")); return; } @@ -326,10 +320,9 @@ text_flow_into_shape() g_return_if_fail(SP_IS_FLOWREGION(object)); /* Add clones */ - for (GSList *items = (GSList *) selection->itemList(); - items != NULL; - items = items->next) { - SPItem *item = SP_ITEM(items->data); + SelContainer items = selection->itemList(); + for(SelContainer::const_iterator i=items.begin();i!=items.end();i++){ + SPItem *item = SP_ITEM(*i); if (SP_IS_SHAPE(item)){ Inkscape::XML::Node *clone = xml_doc->createElement("svg:use"); clone->setAttribute("x", "0"); @@ -394,23 +387,22 @@ text_unflow () Inkscape::Selection *selection = desktop->getSelection(); - if (!flowtext_in_selection(selection) || g_slist_length((GSList *) selection->itemList()) < 1) { + if (!flowtext_in_selection(selection) || selection->itemList().size() < 1) { desktop->getMessageStack()->flash(Inkscape::WARNING_MESSAGE, _("Select a flowed text to unflow it.")); return; } - GSList *new_objs = NULL; + SelContainer new_objs; GSList *old_objs = NULL; - for (GSList *items = g_slist_copy((GSList *) selection->itemList()); - items != NULL; - items = items->next) { + SelContainer items = selection->itemList(); + for(SelContainer::const_iterator i=items.begin();i!=items.end();i++){ - if (!SP_IS_FLOWTEXT(SP_OBJECT(items->data))) { + if (!SP_IS_FLOWTEXT(SP_OBJECT(*i))) { continue; } - SPItem *flowtext = SP_ITEM(items->data); + SPItem *flowtext = SP_ITEM(*i); // we discard transform when unflowing, but we must preserve expansion which is visible as // font size multiplier @@ -451,7 +443,7 @@ text_unflow () SPText *text = SP_TEXT(text_object); text->_adjustFontsizeRecursive(text, ex); - new_objs = g_slist_prepend (new_objs, text_object); + new_objs.push_front(text_object); old_objs = g_slist_prepend (old_objs, flowtext); Inkscape::GC::release(rtext); @@ -466,7 +458,6 @@ text_unflow () } g_slist_free (old_objs); - g_slist_free (new_objs); DocumentUndo::done(doc, SP_VERB_CONTEXT_TEXT, _("Unflow flowed text")); @@ -487,11 +478,11 @@ flowtext_to_text() bool did = false; - GSList *reprs = NULL; - GSList *items = g_slist_copy((GSList *) selection->itemList()); - for (; items != NULL; items = items->next) { + SelContainer reprs; + SelContainer items(selection->itemList()); + for(SelContainer::const_iterator i=items.begin();i!=items.end();i++){ - SPItem *item = (SPItem *) items->data; + SPItem *item = (SPItem *) *i; if (!SP_IS_FLOWTEXT(item)) continue; @@ -519,10 +510,9 @@ flowtext_to_text() Inkscape::GC::release(repr); item->deleteObject(); - reprs = g_slist_prepend(reprs, repr); + reprs.push_front(dynamic_cast(repr)); } - g_slist_free(items); if (did) { DocumentUndo::done(desktop->getDocument(), @@ -535,7 +525,6 @@ flowtext_to_text() _("No flowed text(s) to convert in the selection.")); } - g_slist_free(reprs); } diff --git a/src/text-editing.cpp b/src/text-editing.cpp index 4a962ab4c..44d90b4ae 100644 --- a/src/text-editing.cpp +++ b/src/text-editing.cpp @@ -67,12 +67,11 @@ static void te_update_layout_now (SPItem *item) void te_update_layout_now_recursive(SPItem *item) { if (SP_IS_GROUP(item)) { - GSList *item_list = sp_item_group_item_list(SP_GROUP(item)); - for(GSList* elem = item_list; elem; elem = elem->next) { - SPItem* list_item = static_cast(elem->data); + SelContainer item_list = sp_item_group_item_list(SP_GROUP(item)); + for(SelContainer::const_iterator i=item_list.begin();i!=item_list.end();i++){ + SPItem* list_item = static_cast(*i); te_update_layout_now_recursive(list_item); } - g_slist_free(item_list); } else if (SP_IS_TEXT(item)) SP_TEXT(item)->rebuildLayout(); else if (SP_IS_FLOWTEXT (item)) diff --git a/src/trace/trace.cpp b/src/trace/trace.cpp index cc3d000a3..892ecdb87 100644 --- a/src/trace/trace.cpp +++ b/src/trace/trace.cpp @@ -65,7 +65,7 @@ SPImage *Tracer::getSelectedSPImage() if (sioxEnabled) { SPImage *img = NULL; - GSList const *list = sel->itemList(); + SelContainer const list = sel->itemList(); std::vector items; sioxShapes.clear(); @@ -74,13 +74,13 @@ SPImage *Tracer::getSelectedSPImage() them as bottom-to-top so that we can discover the image and any SPItems above it */ - for ( ; list ; list=list->next) + for(SelContainer::const_iterator x=list.begin();x!=list.end();x++){ { - if (!SP_IS_ITEM(list->data)) + if (!SP_IS_ITEM(*x)) { continue; } - SPItem *item = SP_ITEM(list->data); + SPItem *item = SP_ITEM(*x); items.insert(items.begin(), item); } std::vector::iterator iter; diff --git a/src/ui/clipboard.cpp b/src/ui/clipboard.cpp index 94a1eb2dc..20b43af3b 100644 --- a/src/ui/clipboard.cpp +++ b/src/ui/clipboard.cpp @@ -523,8 +523,9 @@ bool ClipboardManagerImpl::pasteSize(SPDesktop *desktop, bool separately, bool a // resize each object in the selection if (separately) { - for (GSList *i = const_cast(selection->itemList()) ; i ; i = i->next) { - SPItem *item = dynamic_cast(static_cast(i->data)); + SelContainer itemlist=selection->itemList(); + for(SelContainer::const_iterator i=itemlist.begin();i!=itemlist.end();i++){ + SPItem *item = SP_ITEM(*i); if (item) { Geom::OptRect obj_size = item->desktopVisualBounds(); if ( obj_size ) { @@ -578,8 +579,9 @@ bool ClipboardManagerImpl::pastePathEffect(SPDesktop *desktop) desktop->doc()->importDefs(tempdoc); // make sure all selected items are converted to paths first (i.e. rectangles) sp_selected_to_lpeitems(desktop); - for (GSList *itemptr = const_cast(selection->itemList()) ; itemptr ; itemptr = itemptr->next) { - SPItem *item = reinterpret_cast(itemptr->data); + SelContainer itemlist=selection->itemList(); + for(SelContainer::const_iterator i=itemlist.begin();i!=itemlist.end();i++){ + SPItem *item = SP_ITEM(*i); _applyPathEffect(item, effectstack); } @@ -659,10 +661,10 @@ Glib::ustring ClipboardManagerImpl::getShapeOrTextObjectId(SPDesktop *desktop) */ void ClipboardManagerImpl::_copySelection(Inkscape::Selection *selection) { - GSList const *items = selection->itemList(); // copy the defs used by all items - for (GSList *i = const_cast(items) ; i != NULL ; i = i->next) { - SPItem *item = dynamic_cast(static_cast(i->data)); + SelContainer itemlist=selection->itemList(); + for(SelContainer::const_iterator i=itemlist.begin();i!=itemlist.end();i++){ + SPItem *item = SP_ITEM(*i); if (item) { _copyUsedDefs(item); } else { @@ -671,11 +673,11 @@ void ClipboardManagerImpl::_copySelection(Inkscape::Selection *selection) } // copy the representation of the items - GSList *sorted_items = g_slist_copy(const_cast(items)); - sorted_items = g_slist_sort(sorted_items, (GCompareFunc) sp_object_compare_position); + SelContainer sorted_items(itemlist); + sorted_items.sort(sp_object_compare_position); - for (GSList *i = sorted_items ; i ; i = i->next) { - SPItem *item = dynamic_cast(static_cast(i->data)); + for(SelContainer::const_iterator i=sorted_items.begin();i!=sorted_items.end();i++){ + SPItem *item = SP_ITEM(*i); if (item) { Inkscape::XML::Node *obj = item->getRepr(); Inkscape::XML::Node *obj_copy = _copyNode(obj, _doc, _root); @@ -695,8 +697,8 @@ void ClipboardManagerImpl::_copySelection(Inkscape::Selection *selection) } // copy style for Paste Style action - if (sorted_items) { - SPObject *object = static_cast(sorted_items->data); + if (!sorted_items.empty()) { + SPObject *object = static_cast(sorted_items.front()); SPItem *item = dynamic_cast(object); if (item) { SPCSSAttr *style = take_style_from_item(item); @@ -719,7 +721,6 @@ void ClipboardManagerImpl::_copySelection(Inkscape::Selection *selection) sp_repr_set_point(_clipnode, "max", size->max()); } - g_slist_free(sorted_items); } @@ -1156,8 +1157,8 @@ void ClipboardManagerImpl::_onGet(Gtk::SelectionData &sel, guint /*info*/) sp_repr_get_double(nv, "inkscape:pageopacity", &opacity); bgcolor |= SP_COLOR_F_TO_U(opacity); } - - sp_export_png_file(_clipboardSPDoc, filename, area, width, height, dpi, dpi, bgcolor, NULL, NULL, true, NULL); + SelContainer x; + sp_export_png_file(_clipboardSPDoc, filename, area, width, height, dpi, dpi, bgcolor, NULL, NULL, true, x); } else { diff --git a/src/ui/dialog/align-and-distribute.cpp b/src/ui/dialog/align-and-distribute.cpp index 65bc94011..562bc28b7 100644 --- a/src/ui/dialog/align-and-distribute.cpp +++ b/src/ui/dialog/align-and-distribute.cpp @@ -98,8 +98,7 @@ void ActionAlign::do_action(SPDesktop *desktop, int index) bool sel_as_group = prefs->getBool("/dialogs/align/sel-as-groups"); using Inkscape::Util::GSListConstIterator; - std::list selected; - selected.insert >(selected.end(), selection->itemList(), NULL); + SelContainer selected(selection->itemList()); if (selected.empty()) return; const Coeffs &a = _allCoeffs[index]; @@ -149,18 +148,19 @@ void ActionAlign::do_action(SPDesktop *desktop, int index) b = selection->preferredBounds(); //Move each item in the selected list separately - for (std::list::iterator it(selected.begin()); + for (SelContainer::iterator it(selected.begin()); it != selected.end(); ++it) { + SPItem* item=static_cast (*it); desktop->getDocument()->ensureUpToDate(); if (!sel_as_group) - b = (*it)->desktopPreferredBounds(); - if (b && (!focus || (*it) != focus)) { + b = (item)->desktopPreferredBounds(); + if (b && (!focus || (item) != focus)) { Geom::Point const sp(a.sx0 * b->min()[Geom::X] + a.sx1 * b->max()[Geom::X], a.sy0 * b->min()[Geom::Y] + a.sy1 * b->max()[Geom::Y]); Geom::Point const mp_rel( mp - sp ); if (LInfty(mp_rel) > 1e-9) { - sp_item_move_rel(*it, Geom::Translate(mp_rel)); + sp_item_move_rel(item, Geom::Translate(mp_rel)); changed = true; } } @@ -251,25 +251,24 @@ private : if (!selection) return; using Inkscape::Util::GSListConstIterator; - std::list selected; - selected.insert >(selected.end(), selection->itemList(), NULL); + SelContainer selected(selection->itemList()); if (selected.empty()) return; //Check 2 or more selected objects - std::list::iterator second(selected.begin()); + SelContainer::iterator second(selected.begin()); ++second; if (second == selected.end()) return; Inkscape::Preferences *prefs = Inkscape::Preferences::get(); int prefs_bbox = prefs->getBool("/tools/bounding_box"); std::vector< BBoxSort > sorted; - for (std::list::iterator it(selected.begin()); + for (SelContainer::iterator it(selected.begin()); it != selected.end(); ++it) - { - Geom::OptRect bbox = !prefs_bbox ? (*it)->desktopVisualBounds() : (*it)->desktopGeometricBounds(); + {SPItem *item=static_cast(*it); + Geom::OptRect bbox = !prefs_bbox ? (item)->desktopVisualBounds() : (item)->desktopGeometricBounds(); if (bbox) { - sorted.push_back(BBoxSort(*it, *bbox, _orientation, _kBegin, _kEnd)); + sorted.push_back(BBoxSort(item, *bbox, _orientation, _kBegin, _kEnd)); } } //sort bbox by anchors @@ -541,6 +540,10 @@ private : return (a->isSiblingOf(b)); } + static bool local_obj_compare(SPObject* a,SPObject* b){ + return ActionExchangePositions::sort_compare(static_cast(a),static_cast(b)); + } + virtual void on_button_click() { SPDesktop *desktop = _dialog.getDesktop(); @@ -550,8 +553,7 @@ private : if (!selection) return; using Inkscape::Util::GSListConstIterator; - std::list selected; - selected.insert >(selected.end(), selection->itemList(), NULL); + SelContainer selected(selection->itemList()); if (selected.empty()) return; //Check 2 or more selected objects @@ -569,20 +571,22 @@ private : } else { // sorting by ZOrder is outomatically done by not setting the center center.reset(); } - selected.sort(ActionExchangePositions::sort_compare); + selected.sort(local_obj_compare); } - std::list::iterator it(selected.begin()); - Geom::Point p1 = (*it)->getCenter(); + SelContainer::iterator it(selected.begin()); + SPItem* item=static_cast(*it); + Geom::Point p1 = (item)->getCenter(); for (++it ;it != selected.end(); ++it) { - Geom::Point p2 = (*it)->getCenter(); + item=static_cast(*it); + Geom::Point p2 = (item)->getCenter(); Geom::Point delta = p1 - p2; - sp_item_move_rel((*it),Geom::Translate(delta[Geom::X],delta[Geom::Y] )); + sp_item_move_rel((item),Geom::Translate(delta[Geom::X],delta[Geom::Y] )); p1 = p2; } - Geom::Point p2 = selected.front()->getCenter(); + Geom::Point p2 = static_cast(selected.front())->getCenter(); Geom::Point delta = p1 - p2; - sp_item_move_rel(selected.front(),Geom::Translate(delta[Geom::X],delta[Geom::Y] )); + sp_item_move_rel(static_cast(selected.front()),Geom::Translate(delta[Geom::X],delta[Geom::Y] )); // restore compensation setting prefs->setInt("/options/clonecompensation/value", saved_compensation); @@ -615,8 +619,8 @@ private : Inkscape::Preferences *prefs = Inkscape::Preferences::get(); int saved_compensation = prefs->getInt("/options/clonecompensation/value", SP_CLONE_COMPENSATION_UNMOVED); prefs->setInt("/options/clonecompensation/value", SP_CLONE_COMPENSATION_UNMOVED); - - unclump ((GSList *) _dialog.getDesktop()->getSelection()->itemList()); + SelContainer x(_dialog.getDesktop()->getSelection()->itemList()); + unclump (x); // restore compensation setting prefs->setInt("/options/clonecompensation/value", saved_compensation); @@ -647,8 +651,7 @@ private : if (!selection) return; using Inkscape::Util::GSListConstIterator; - std::list selected; - selected.insert >(selected.end(), selection->itemList(), NULL); + SelContainer selected(selection->itemList()); if (selected.empty()) return; //Check 2 or more selected objects @@ -672,12 +675,13 @@ private : int saved_compensation = prefs->getInt("/options/clonecompensation/value", SP_CLONE_COMPENSATION_UNMOVED); prefs->setInt("/options/clonecompensation/value", SP_CLONE_COMPENSATION_UNMOVED); - for (std::list::iterator it(selected.begin()); + for (SelContainer::iterator it(selected.begin()); it != selected.end(); ++it) { + SPItem* item=static_cast(*it); desktop->getDocument()->ensureUpToDate(); - Geom::OptRect item_box = !prefs_bbox ? (*it)->desktopVisualBounds() : (*it)->desktopGeometricBounds(); + Geom::OptRect item_box = !prefs_bbox ? (item)->desktopVisualBounds() : (item)->desktopGeometricBounds(); if (item_box) { // find new center, staying within bbox double x = _dialog.randomize_bbox->min()[Geom::X] + (*item_box)[Geom::X].extent() /2 + @@ -686,7 +690,7 @@ private : g_random_double_range (0, (*_dialog.randomize_bbox)[Geom::Y].extent() - (*item_box)[Geom::Y].extent()); // displacement is the new center minus old: Geom::Point t = Geom::Point (x, y) - 0.5*(item_box->max() + item_box->min()); - sp_item_move_rel(*it, Geom::Translate(t)); + sp_item_move_rel(item, Geom::Translate(t)); } } @@ -746,8 +750,7 @@ private : if (!selection) return; using Inkscape::Util::GSListConstIterator; - std::list selected; - selected.insert >(selected.end(), selection->itemList(), NULL); + SelContainer selected(selection->itemList()); if (selected.empty()) return; //Check 2 or more selected objects @@ -758,20 +761,21 @@ private : std::vector sorted; - for (std::list::iterator it(selected.begin()); + for (SelContainer::iterator it(selected.begin()); it != selected.end(); ++it) { - if (SP_IS_TEXT (*it) || SP_IS_FLOWTEXT (*it)) { - Inkscape::Text::Layout const *layout = te_get_layout(*it); + SPItem* item=static_cast(*it); + if (SP_IS_TEXT (item) || SP_IS_FLOWTEXT (item)) { + Inkscape::Text::Layout const *layout = te_get_layout(item); boost::optional pt = layout->baselineAnchorPoint(); if (pt) { - Geom::Point base = *pt * (*it)->i2dt_affine(); + Geom::Point base = *pt * (item)->i2dt_affine(); if (base[Geom::X] < b_min[Geom::X]) b_min[Geom::X] = base[Geom::X]; if (base[Geom::Y] < b_min[Geom::Y]) b_min[Geom::Y] = base[Geom::Y]; if (base[Geom::X] > b_max[Geom::X]) b_max[Geom::X] = base[Geom::X]; if (base[Geom::Y] > b_max[Geom::Y]) b_max[Geom::Y] = base[Geom::Y]; - Baselines b (*it, base, _orientation); + Baselines b (item, base, _orientation); sorted.push_back(b); } } @@ -801,18 +805,19 @@ private : } } else { - for (std::list::iterator it(selected.begin()); + for (SelContainer::iterator it(selected.begin()); it != selected.end(); ++it) { - if (SP_IS_TEXT (*it) || SP_IS_FLOWTEXT (*it)) { - Inkscape::Text::Layout const *layout = te_get_layout(*it); + SPItem* item=static_cast(*it); + if (SP_IS_TEXT (item) || SP_IS_FLOWTEXT (item)) { + Inkscape::Text::Layout const *layout = te_get_layout(item); boost::optional pt = layout->baselineAnchorPoint(); if (pt) { - Geom::Point base = *pt * (*it)->i2dt_affine(); + Geom::Point base = *pt * (item)->i2dt_affine(); Geom::Point t(0.0, 0.0); t[_orientation] = b_min[_orientation] - base[_orientation]; - sp_item_move_rel(*it, Geom::Translate(t)); + sp_item_move_rel(item, Geom::Translate(t)); changed = true; } } diff --git a/src/ui/dialog/clonetiler.cpp b/src/ui/dialog/clonetiler.cpp index fede30b26..abfab8b19 100644 --- a/src/ui/dialog/clonetiler.cpp +++ b/src/ui/dialog/clonetiler.cpp @@ -1359,7 +1359,7 @@ void CloneTiler::clonetiler_change_selection(Inkscape::Selection *selection, Gtk return; } - if (g_slist_length ((GSList *) selection->itemList()) > 1) { + if (selection->itemList().size() > 1) { gtk_widget_set_sensitive (buttons, FALSE); gtk_label_set_markup (GTK_LABEL(status), _("More than one object selected.")); return; @@ -2096,7 +2096,7 @@ void CloneTiler::clonetiler_unclump(GtkWidget */*widget*/, void *) Inkscape::Selection *selection = desktop->getSelection(); // check if something is selected - if (selection->isEmpty() || g_slist_length((GSList *) selection->itemList()) > 1) { + if (selection->isEmpty() || selection->itemList().size() > 1) { desktop->getMessageStack()->flash(Inkscape::WARNING_MESSAGE, _("Select one object whose tiled clones to unclump.")); return; } @@ -2104,11 +2104,11 @@ void CloneTiler::clonetiler_unclump(GtkWidget */*widget*/, void *) SPObject *obj = selection->singleItem(); SPObject *parent = obj->parent; - GSList *to_unclump = NULL; // not including the original + SelContainer to_unclump; // not including the original for (SPObject *child = parent->firstChild(); child != NULL; child = child->next) { if (clonetiler_is_a_clone_of (child, obj)) { - to_unclump = g_slist_prepend (to_unclump, child); + to_unclump.push_front(child); } } @@ -2116,8 +2116,6 @@ void CloneTiler::clonetiler_unclump(GtkWidget */*widget*/, void *) unclump (to_unclump); - g_slist_free (to_unclump); - DocumentUndo::done(desktop->getDocument(), SP_VERB_DIALOG_CLONETILER, _("Unclump tiled clones")); } @@ -2147,7 +2145,7 @@ void CloneTiler::clonetiler_remove(GtkWidget */*widget*/, GtkWidget *dlg, bool d Inkscape::Selection *selection = desktop->getSelection(); // check if something is selected - if (selection->isEmpty() || g_slist_length((GSList *) selection->itemList()) > 1) { + if (selection->isEmpty() || selection->itemList().size() > 1) { desktop->getMessageStack()->flash(Inkscape::WARNING_MESSAGE, _("Select one object whose tiled clones to remove.")); return; } @@ -2225,7 +2223,7 @@ void CloneTiler::clonetiler_apply(GtkWidget */*widget*/, GtkWidget *dlg) } // Check if more than one object is selected. - if (g_slist_length((GSList *) selection->itemList()) > 1) { + if (selection->itemList().size() > 1) { desktop->getMessageStack()->flash(Inkscape::ERROR_MESSAGE, _("If you want to clone several objects, group them and clone the group.")); return; } diff --git a/src/ui/dialog/export.cpp b/src/ui/dialog/export.cpp index 6d90c792e..fc6094c9f 100644 --- a/src/ui/dialog/export.cpp +++ b/src/ui/dialog/export.cpp @@ -605,7 +605,7 @@ void Export::onBatchClicked () void Export::updateCheckbuttons () { - gint num = g_slist_length((GSList *) SP_ACTIVE_DESKTOP->getSelection()->itemList()); + gint num = SP_ACTIVE_DESKTOP->getSelection()->itemList().size(); if (num >= 2) { batch_export.set_sensitive(true); batch_export.set_label(g_strdup_printf (ngettext("B_atch export %d selected object","B_atch export %d selected objects",num), num)); @@ -817,9 +817,9 @@ void Export::onAreaToggled () one that's nice */ if (filename.empty()) { const gchar * id = "object"; - const GSList * reprlst = SP_ACTIVE_DESKTOP->getSelection()->reprList(); - for(; reprlst != NULL; reprlst = reprlst->next) { - Inkscape::XML::Node * repr = (Inkscape::XML::Node *)reprlst->data; + const SelContainer reprlst = SP_ACTIVE_DESKTOP->getSelection()->reprList(); + for(SelContainer::const_iterator i=reprlst.begin(); reprlst.end() != i; i++) { + Inkscape::XML::Node * repr = (Inkscape::XML::Node *)(*i); if (repr->attribute("id")) { id = repr->attribute("id"); break; @@ -1010,7 +1010,7 @@ void Export::onExport () if (batch_export.get_active ()) { // Batch export of selected objects - gint num = g_slist_length(const_cast(desktop->getSelection()->itemList())); + gint num = (desktop->getSelection()->itemList()).size(); gint n = 0; if (num < 1) { @@ -1024,8 +1024,9 @@ void Export::onExport () gint export_count = 0; - for (GSList *i = const_cast(desktop->getSelection()->itemList()); i && !interrupted; i = i->next) { - SPItem *item = reinterpret_cast(i->data); + SelContainer itemlist=desktop->getSelection()->itemList(); + for(SelContainer::const_iterator i = itemlist.begin();i!=itemlist.end() && !interrupted ;i++){ + SPItem *item = reinterpret_cast(*i); prog_dlg->set_data("current", GINT_TO_POINTER(n)); prog_dlg->set_data("total", GINT_TO_POINTER(num)); @@ -1063,13 +1064,13 @@ void Export::onExport () _("Exporting file %s..."), safeFile), desktop); MessageCleaner msgFlashCleanup(desktop->messageStack()->flashF(Inkscape::IMMEDIATE_MESSAGE, _("Exporting file %s..."), safeFile), desktop); - + SelContainer x; if (!sp_export_png_file (doc, path.c_str(), *area, width, height, dpi, dpi, nv->pagecolor, onProgressCallback, (void*)prog_dlg, TRUE, // overwrite without asking - hide ? const_cast(desktop->getSelection()->itemList()) : NULL + hide ? (desktop->getSelection()->itemList()) : x )) { gchar * error = g_strdup_printf(_("Could not export to filename %s.\n"), safeFile); @@ -1153,12 +1154,13 @@ void Export::onExport () prog_dlg->set_data("total", GINT_TO_POINTER(0)); /* Do export */ + SelContainer x; ExportResult status = sp_export_png_file(desktop->getDocument(), path.c_str(), Geom::Rect(Geom::Point(x0, y0), Geom::Point(x1, y1)), width, height, xdpi, ydpi, nv->pagecolor, onProgressCallback, (void*)prog_dlg, FALSE, - hide ? const_cast(desktop->getSelection()->itemList()) : NULL + hide ? (desktop->getSelection()->itemList()) : x ); if (status == EXPORT_ERROR) { gchar * safeFile = Inkscape::IO::sanitizeString(path.c_str()); @@ -1224,7 +1226,7 @@ void Export::onExport () break; } case SELECTION_SELECTION: { - const GSList * reprlst; + SelContainer reprlst; SPDocument * doc = SP_ACTIVE_DOCUMENT; bool modified = false; @@ -1232,8 +1234,8 @@ void Export::onExport () DocumentUndo::setUndoSensitive(doc, false); reprlst = desktop->getSelection()->reprList(); - for(; reprlst != NULL; reprlst = reprlst->next) { - Inkscape::XML::Node * repr = static_cast(reprlst->data); + for(SelContainer::const_iterator i=reprlst.begin(); reprlst.end() != i; i++) { + Inkscape::XML::Node * repr = dynamic_cast(*i); const gchar * temp_string; Glib::ustring dir = Glib::path_get_dirname(filename.c_str()); const gchar* docURI=SP_ACTIVE_DOCUMENT->getURI(); diff --git a/src/ui/dialog/filter-effects-dialog.cpp b/src/ui/dialog/filter-effects-dialog.cpp index 3da0e0043..657d6771b 100644 --- a/src/ui/dialog/filter-effects-dialog.cpp +++ b/src/ui/dialog/filter-effects-dialog.cpp @@ -690,7 +690,7 @@ private: void select_svg_element(){ Inkscape::Selection* sel = _desktop->getSelection(); if (sel->isEmpty()) return; - Inkscape::XML::Node* node = (Inkscape::XML::Node*) g_slist_nth_data((GSList *)sel->reprList(), 0); + Inkscape::XML::Node* node = (Inkscape::XML::Node*) sel->reprList().front(); if (!node || !node->matchAttributeName("id")) return; std::ostringstream xlikhref; @@ -1465,9 +1465,9 @@ void FilterEffectsDialog::FilterModifier::update_selection(Selection *sel) } std::set used; - - for (GSList const *i = sel->itemList(); i != NULL; i = i->next) { - SPObject *obj = SP_OBJECT (i->data); + SelContainer itemlist=sel->itemList(); + for(SelContainer::const_iterator i=itemlist.begin(); itemlist.end() != i; i++) { + SPObject *obj = SP_OBJECT (*i); SPStyle *style = obj->style; if (!style || !SP_IS_ITEM(obj)) { continue; @@ -1545,10 +1545,9 @@ void FilterEffectsDialog::FilterModifier::on_selection_toggled(const Glib::ustri if((*iter)[_columns.sel] == 1) filter = 0; - GSList const *items = sel->itemList(); - - for (GSList const *i = items; i != NULL; i = i->next) { - SPItem * item = SP_ITEM(i->data); + SelContainer itemlist=sel->itemList(); + for(SelContainer::const_iterator i=itemlist.begin(); itemlist.end() != i; i++) { + SPItem * item = SP_ITEM(*i); SPStyle *style = item->style; g_assert(style != NULL); @@ -1650,12 +1649,13 @@ void FilterEffectsDialog::FilterModifier::remove_filter() SPDocument* doc = filter->document; // Delete all references to this filter - GSList *all = get_all_items(NULL, _desktop->currentRoot(), _desktop, false, false, true, NULL); - for (GSList *i = all; i != NULL; i = i->next) { - if (!SP_IS_ITEM(i->data)) { + SelContainer x,y; + SelContainer all = get_all_items(x, _desktop->currentRoot(), _desktop, false, false, true, y); + for(SelContainer::const_iterator i=all.begin(); all.end() != i; i++) { + if (!SP_IS_ITEM(*i)) { continue; } - SPItem *item = SP_ITEM(i->data); + SPItem *item = SP_ITEM(*i); if (!item->style) { continue; } @@ -1668,9 +1668,6 @@ void FilterEffectsDialog::FilterModifier::remove_filter() } } } - if (all) { - g_slist_free(all); - } //XML Tree being used directly here while it shouldn't be. sp_repr_unparent(filter->getRepr()); diff --git a/src/ui/dialog/find.cpp b/src/ui/dialog/find.cpp index 951cb01ea..43ecb60ac 100644 --- a/src/ui/dialog/find.cpp +++ b/src/ui/dialog/find.cpp @@ -549,7 +549,7 @@ bool Find::item_font_match(SPItem *item, const gchar *text, bool exact, bool cas } -GSList *Find::filter_fields (GSList *l, bool exact, bool casematch) +SelContainer Find::filter_fields (SelContainer &l, bool exact, bool casematch) { Glib::ustring tmp = entry_find.getEntry()->get_text(); if (tmp.empty()) { @@ -557,17 +557,17 @@ GSList *Find::filter_fields (GSList *l, bool exact, bool casematch) } gchar* text = g_strdup(tmp.c_str()); - GSList *in = l; - GSList *out = NULL; + SelContainer in = l; + SelContainer out; if (check_searchin_text.get_active()) { - for (GSList *i = in; i != NULL; i = i->next) { - SPObject *obj = reinterpret_cast(i->data); + for(SelContainer::const_iterator i=in.begin(); in.end() != i; i++) { + SPObject *obj = SP_OBJECT (*i); SPItem *item = dynamic_cast(obj); g_assert(item != NULL); if (item_text_match(item, text, exact, casematch)) { - if (!g_slist_find(out, i->data)) { - out = g_slist_prepend (out, i->data); + if (out.end()==find(out.begin(),out.end(), *i)) { + out.push_front(*i); if (_action_replace) { item_text_match(item, text, exact, casematch, _action_replace); } @@ -584,12 +584,12 @@ GSList *Find::filter_fields (GSList *l, bool exact, bool casematch) bool attrvalue = check_attributevalue.get_active(); if (ids) { - for (GSList *i = in; i != NULL; i = i->next) { - SPObject *obj = reinterpret_cast(i->data); + for(SelContainer::const_iterator i=in.begin(); in.end() != i; i++) { + SPObject *obj = SP_OBJECT (*i); SPItem *item = dynamic_cast(obj); if (item_id_match(item, text, exact, casematch)) { - if (!g_slist_find(out, i->data)) { - out = g_slist_prepend (out, i->data); + if (out.end()==find(out.begin(),out.end(), *i)) { + out.push_front(*i); if (_action_replace) { item_id_match(item, text, exact, casematch, _action_replace); } @@ -600,14 +600,13 @@ GSList *Find::filter_fields (GSList *l, bool exact, bool casematch) if (style) { - for (GSList *i = in; i != NULL; i = i->next) { - SPObject *obj = reinterpret_cast(i->data); + for(SelContainer::const_iterator i=in.begin(); in.end() != i; i++) { + SPObject *obj = SP_OBJECT (*i); SPItem *item = dynamic_cast(obj); g_assert(item != NULL); if (item_style_match(item, text, exact, casematch)) { - if (!g_slist_find(out, i->data)) - if (!g_slist_find(out, i->data)) { - out = g_slist_prepend (out, i->data); + if (out.end()==find(out.begin(),out.end(), *i)){ + out.push_front(*i); if (_action_replace) { item_style_match(item, text, exact, casematch, _action_replace); } @@ -618,13 +617,13 @@ GSList *Find::filter_fields (GSList *l, bool exact, bool casematch) if (attrname) { - for (GSList *i = in; i != NULL; i = i->next) { - SPObject *obj = reinterpret_cast(i->data); + for(SelContainer::const_iterator i=in.begin(); in.end() != i; i++) { + SPObject *obj = SP_OBJECT (*i); SPItem *item = dynamic_cast(obj); g_assert(item != NULL); if (item_attr_match(item, text, exact, casematch)) { - if (!g_slist_find(out, i->data)) { - out = g_slist_prepend (out, i->data); + if (out.end()==find(out.begin(),out.end(), *i)) { + out.push_front(*i); if (_action_replace) { item_attr_match(item, text, exact, casematch, _action_replace); } @@ -635,13 +634,13 @@ GSList *Find::filter_fields (GSList *l, bool exact, bool casematch) if (attrvalue) { - for (GSList *i = in; i != NULL; i = i->next) { - SPObject *obj = reinterpret_cast(i->data); + for(SelContainer::const_iterator i=in.begin(); in.end() != i; i++) { + SPObject *obj = SP_OBJECT (*i); SPItem *item = dynamic_cast(obj); g_assert(item != NULL); if (item_attrvalue_match(item, text, exact, casematch)) { - if (!g_slist_find(out, i->data)) { - out = g_slist_prepend (out, i->data); + if (out.end()==find(out.begin(),out.end(), *i)) { + out.push_front(*i); if (_action_replace) { item_attrvalue_match(item, text, exact, casematch, _action_replace); } @@ -652,13 +651,13 @@ GSList *Find::filter_fields (GSList *l, bool exact, bool casematch) if (font) { - for (GSList *i = in; i != NULL; i = i->next) { - SPObject *obj = reinterpret_cast(i->data); + for(SelContainer::const_iterator i=in.begin(); in.end() != i; i++) { + SPObject *obj = SP_OBJECT (*i); SPItem *item = dynamic_cast(obj); g_assert(item != NULL); if (item_font_match(item, text, exact, casematch)) { - if (!g_slist_find(out, i->data)) { - out = g_slist_prepend (out, i->data); + if (out.end()==find(out.begin(),out.end(),*i)) { + out.push_front(*i); if (_action_replace) { item_font_match(item, text, exact, casematch, _action_replace); } @@ -716,29 +715,29 @@ bool Find::item_type_match (SPItem *item) return false; } -GSList *Find::filter_types (GSList *l) +SelContainer Find::filter_types (SelContainer &l) { - GSList *n = NULL; - for (GSList *i = l; i != NULL; i = i->next) { - SPObject *obj = reinterpret_cast(i->data); + SelContainer n; + for(SelContainer::const_iterator i=l.begin(); l.end() != i; i++) { + SPObject *obj = SP_OBJECT (*i); SPItem *item = dynamic_cast(obj); g_assert(item != NULL); if (item_type_match(item)) { - n = g_slist_prepend (n, i->data); + n.push_front(*i); } } return n; } -GSList *Find::filter_list (GSList *l, bool exact, bool casematch) +SelContainer &Find::filter_list (SelContainer &l, bool exact, bool casematch) { l = filter_types (l); l = filter_fields (l, exact, casematch); return l; } -GSList *Find::all_items (SPObject *r, GSList *l, bool hidden, bool locked) +SelContainer &Find::all_items (SPObject *r, SelContainer &l, bool hidden, bool locked) { if (dynamic_cast(r)) { return l; // we're not interested in items in defs @@ -752,7 +751,7 @@ GSList *Find::all_items (SPObject *r, GSList *l, bool hidden, bool locked) SPItem *item = dynamic_cast(child); if (item && !child->cloned && !desktop->isLayer(item)) { if ((hidden || !desktop->itemIsHidden(item)) && (locked || !item->isLocked())) { - l = g_slist_prepend (l, child); + l.push_front(child); } } l = all_items (child, l, hidden, locked); @@ -760,16 +759,17 @@ GSList *Find::all_items (SPObject *r, GSList *l, bool hidden, bool locked) return l; } -GSList *Find::all_selection_items (Inkscape::Selection *s, GSList *l, SPObject *ancestor, bool hidden, bool locked) +SelContainer &Find::all_selection_items (Inkscape::Selection *s, SelContainer &l, SPObject *ancestor, bool hidden, bool locked) { - for (GSList *i = (GSList *) s->itemList(); i != NULL; i = i->next) { - SPObject *obj = reinterpret_cast(i->data); + SelContainer itemlist=s->itemList(); + for(SelContainer::const_iterator i=itemlist.begin(); itemlist.end() != i; i++) { + SPObject *obj = SP_OBJECT (*i); SPItem *item = dynamic_cast(obj); g_assert(item != NULL); if (item && !item->cloned && !desktop->isLayer(item)) { if (!ancestor || ancestor->isAncestorOf(item)) { if ((hidden || !desktop->itemIsHidden(item)) && (locked || !item->isLocked())) { - l = g_slist_prepend (l, i->data); + l.push_back(*i); } } } @@ -817,7 +817,7 @@ void Find::onAction() bool casematch = check_case_sensitive.get_active(); blocked = true; - GSList *l = NULL; + SelContainer l; if (check_scope_selection.get_active()) { if (check_scope_layer.get_active()) { l = all_selection_items (desktop->selection, l, desktop->currentLayer(), hidden, locked); @@ -831,12 +831,12 @@ void Find::onAction() l = all_items(desktop->getDocument()->getRoot(), l, hidden, locked); } } - guint all = g_slist_length (l); + guint all = l.size(); - GSList *n = filter_list (l, exact, casematch); + SelContainer n = filter_list (l, exact, casematch); - if (n != NULL) { - int count = g_slist_length (n); + if (!n.empty()) { + int count = n.size(); desktop->messageStack()->flashF(Inkscape::NORMAL_MESSAGE, // TRANSLATORS: "%s" is replaced with "exact" or "partial" when this string is displayed ngettext("%d object found (out of %d), %s match.", @@ -857,7 +857,7 @@ void Find::onAction() Inkscape::Selection *selection = desktop->getSelection(); selection->clear(); selection->setList(n); - SPObject *obj = reinterpret_cast(n->data); + SPObject *obj = reinterpret_cast(n.front()); SPItem *item = dynamic_cast(obj); g_assert(item != NULL); scroll_to_show_item(desktop, item); diff --git a/src/ui/dialog/find.h b/src/ui/dialog/find.h index c0c635f94..1aded96f2 100644 --- a/src/ui/dialog/find.h +++ b/src/ui/dialog/find.h @@ -16,6 +16,7 @@ # include #endif +#include "selection.h" #include "ui/widget/panel.h" #include "ui/widget/button.h" #include "ui/widget/entry.h" @@ -148,10 +149,10 @@ protected: /** * Function to filter a list of items based on the item type by calling each item_XXX_match function */ - GSList * filter_fields (GSList *l, bool exact, bool casematch); + SelContainer filter_fields (SelContainer &l, bool exact, bool casematch); bool item_type_match (SPItem *item); - GSList * filter_types (GSList *l); - GSList * filter_list (GSList *l, bool exact, bool casematch); + SelContainer filter_types (SelContainer &l); + SelContainer & filter_list (SelContainer &l, bool exact, bool casematch); /** * Find a string within a string and returns true if found with options for exact and casematching @@ -172,12 +173,12 @@ protected: * recursive function to return a list of all the items in the SPObject tree * */ - GSList * all_items (SPObject *r, GSList *l, bool hidden, bool locked); + SelContainer & all_items (SPObject *r, SelContainer &l, bool hidden, bool locked); /** * to return a list of all the selected items * */ - GSList * all_selection_items (Inkscape::Selection *s, GSList *l, SPObject *ancestor, bool hidden, bool locked); + SelContainer & all_selection_items (Inkscape::Selection *s, SelContainer &l, SPObject *ancestor, bool hidden, bool locked); /** * Shrink the dialog size when the expander widget is closed diff --git a/src/ui/dialog/glyphs.cpp b/src/ui/dialog/glyphs.cpp index 2b9053da9..1ef97b996 100644 --- a/src/ui/dialog/glyphs.cpp +++ b/src/ui/dialog/glyphs.cpp @@ -578,9 +578,10 @@ void GlyphsPanel::setTargetDesktop(SPDesktop *desktop) void GlyphsPanel::insertText() { SPItem *textItem = 0; - for (const GSList *item = targetDesktop->selection->itemList(); item; item = item->next ) { - if (SP_IS_TEXT(item->data) || SP_IS_FLOWTEXT(item->data)) { - textItem = SP_ITEM(item->data); + SelContainer itemlist=targetDesktop->selection->itemList(); + for(SelContainer::const_iterator i=itemlist.begin(); itemlist.end() != i; i++) { + if (SP_IS_TEXT(*i) || SP_IS_FLOWTEXT(*i)) { + textItem = SP_ITEM(*i); break; } } @@ -687,8 +688,9 @@ void GlyphsPanel::selectionModifiedCB(guint flags) void GlyphsPanel::calcCanInsert() { int items = 0; - for (const GSList *item = targetDesktop->selection->itemList(); item; item = item->next ) { - if (SP_IS_TEXT(item->data) || SP_IS_FLOWTEXT(item->data)) { + SelContainer itemlist=targetDesktop->selection->itemList(); + for(SelContainer::const_iterator i=itemlist.begin(); itemlist.end() != i; i++) { + if (SP_IS_TEXT(*i) || SP_IS_FLOWTEXT(*i)) { ++items; } } diff --git a/src/ui/interface.cpp b/src/ui/interface.cpp index 28a65e0b4..86cf629c1 100644 --- a/src/ui/interface.cpp +++ b/src/ui/interface.cpp @@ -1906,11 +1906,10 @@ void ContextMenu::ActivateGroup(void) void ContextMenu::ActivateUngroup(void) { - GSList *children = NULL; + SelContainer children; - sp_item_group_ungroup(static_cast(_item), &children); + sp_item_group_ungroup(static_cast(_item), children); _desktop->selection->setList(children); - g_slist_free(children); } void ContextMenu::MakeAnchorMenu(void) @@ -1959,10 +1958,9 @@ void ContextMenu::AnchorLinkFollow(void) void ContextMenu::AnchorLinkRemove(void) { - GSList *children = NULL; - sp_item_group_ungroup(static_cast(_item), &children, false); + SelContainer children; + sp_item_group_ungroup(static_cast(_item), children, false); DocumentUndo::done(_desktop->doc(), SP_VERB_NONE, _("Remove link")); - g_slist_free(children); } void ContextMenu::MakeImageMenu (void) @@ -2051,8 +2049,6 @@ void ContextMenu::ImageEdit(void) _desktop->selection->set(_item); } - GSList const *selected = _desktop->selection->itemList(); - GError* errThing = 0; Glib::ustring cmdline = getImageEditorName(); Glib::ustring name; @@ -2079,8 +2075,9 @@ void ContextMenu::ImageEdit(void) } #endif - for (GSList const *iter = selected; iter != NULL; iter = iter->next) { - Inkscape::XML::Node *ir = SP_ITEM(iter->data)->getRepr(); + SelContainer itemlist=_desktop->selection->itemList(); + for(SelContainer::const_iterator i=itemlist.begin();i!=itemlist.end();i++){ + Inkscape::XML::Node *ir = SP_ITEM(*i)->getRepr(); const gchar *href = ir->attribute("xlink:href"); if (strncmp (href,"file:",5) == 0) { diff --git a/src/unclump.cpp b/src/unclump.cpp index 940369d7a..d1cfc6628 100644 --- a/src/unclump.cpp +++ b/src/unclump.cpp @@ -168,13 +168,12 @@ unclump_dist (SPItem *item1, SPItem *item2) /** Average unclump_dist from item to others */ -static double unclump_average (SPItem *item, GSList *others) +static double unclump_average (SPItem *item, SelContainer &others) { int n = 0; double sum = 0; - - for (GSList *i = others; i != NULL; i = i->next) { - SPItem *other = SP_ITEM (i->data); + for (SelContainer::const_iterator i = others.begin(); i != others.end();i++) { + SPItem *other = SP_ITEM (*i); if (other == item) continue; @@ -192,13 +191,13 @@ static double unclump_average (SPItem *item, GSList *others) /** Closest to item among others */ -static SPItem *unclump_closest (SPItem *item, GSList *others) +static SPItem *unclump_closest (SPItem *item, SelContainer &others) { double min = HUGE_VAL; SPItem *closest = NULL; - for (GSList *i = others; i != NULL; i = i->next) { - SPItem *other = SP_ITEM (i->data); + for (SelContainer::const_iterator i = others.begin(); i != others.end();i++) { + SPItem *other = SP_ITEM (*i); if (other == item) continue; @@ -216,13 +215,12 @@ static SPItem *unclump_closest (SPItem *item, GSList *others) /** Most distant from item among others */ -static SPItem *unclump_farest (SPItem *item, GSList *others) +static SPItem *unclump_farest (SPItem *item, SelContainer &others) { double max = -HUGE_VAL; SPItem *farest = NULL; - - for (GSList *i = others; i != NULL; i = i->next) { - SPItem *other = SP_ITEM (i->data); + for (SelContainer::const_iterator i = others.begin(); i != others.end();i++) { + SPItem *other = SP_ITEM (*i); if (other == item) continue; @@ -242,8 +240,8 @@ Removes from the \a rest list those items that are "behind" \a closest as seen f i.e. those on the other side of the line through \a closest perpendicular to the direction from \a item to \a closest. Returns a newly created list which must be freed. */ -static GSList * -unclump_remove_behind (SPItem *item, SPItem *closest, GSList *rest) +static SelContainer +unclump_remove_behind (SPItem *item, SPItem *closest, SelContainer &rest) { Geom::Point it = unclump_center (item); Geom::Point p1 = unclump_center (closest); @@ -260,10 +258,9 @@ unclump_remove_behind (SPItem *item, SPItem *closest, GSList *rest) // substitute the item into it: double val_item = A * it[Geom::X] + B * it[Geom::Y] + C; - GSList *out = NULL; - - for (GSList *i = rest; i != NULL; i = i->next) { - SPItem *other = SP_ITEM (i->data); + SelContainer out; + for (SelContainer::const_iterator i = rest.begin(); i != rest.end();i++) { + SPItem *other = SP_ITEM (*i); if (other == item) continue; @@ -274,7 +271,7 @@ unclump_remove_behind (SPItem *item, SPItem *closest, GSList *rest) if (val_item * val_other <= 1e-6) { // different signs, which means item and other are on the different sides of p1-p2 line; skip } else { - out = g_slist_prepend (out, other); + out.push_front(other); } } @@ -334,34 +331,32 @@ similar to "engraver dots". The only distribution which is unchanged by unclumpi grid. May be called repeatedly for stronger effect. */ void -unclump (GSList *items) +unclump (SelContainer &items) { c_cache.clear(); wh_cache.clear(); - for (GSList *i = items; i != NULL; i = i->next) { // for each original/clone x: - SPItem *item = SP_ITEM (i->data); + for (SelContainer::const_iterator i = items.begin(); i != items.end();i++) { // for each original/clone x: + SPItem *item = SP_ITEM (*i); - GSList *nei = NULL; + SelContainer nei; - GSList *rest = g_slist_copy (items); - rest = g_slist_remove (rest, item); + SelContainer rest(items); + rest.remove(item); - while (rest != NULL) { + while (!rest.empty()) { SPItem *closest = unclump_closest (item, rest); if (closest) { - nei = g_slist_prepend (nei, closest); - rest = g_slist_remove (rest, closest); - GSList *new_rest = unclump_remove_behind (item, closest, rest); - g_slist_free (rest); + nei.push_front(closest); + rest.remove(closest); + SelContainer new_rest = unclump_remove_behind (item, closest, rest); rest = new_rest; } else { - g_slist_free (rest); break; } } - if (g_slist_length (nei) >= 2) { + if ( (nei.size()) >= 2) { double ave = unclump_average (item, nei); SPItem *closest = unclump_closest (item, nei); diff --git a/src/unclump.h b/src/unclump.h index 2411cb713..54f43ffde 100644 --- a/src/unclump.h +++ b/src/unclump.h @@ -12,8 +12,9 @@ #define SEEN_DIALOGS_UNCLUMP_H typedef struct _GSList GSList; +#include "selection.h" -void unclump(GSList *items); +void unclump(SelContainer &items); #endif /* !UNCLUMP_H_SEEN */ diff --git a/src/vanishing-point.cpp b/src/vanishing-point.cpp index b62aacbc5..98a3eaa67 100644 --- a/src/vanishing-point.cpp +++ b/src/vanishing-point.cpp @@ -256,8 +256,9 @@ VanishingPoint::set_pos(Proj::Pt2 const &pt) { std::list VanishingPoint::selectedBoxes(Inkscape::Selection *sel) { std::list sel_boxes; - for (GSList const* i = sel->itemList(); i != NULL; i = i->next) { - SPItem *item = static_cast(i->data); + SelContainer itemlist=sel->itemList(); + for (SelContainer::const_iterator i=itemlist.begin();i!=itemlist.end();i++) { + SPItem *item = static_cast(*i); SPBox3D *box = dynamic_cast(item); if (box && this->hasBox(box)) { sel_boxes.push_back(box); @@ -395,8 +396,9 @@ VPDragger::VPsOfSelectedBoxes() { VanishingPoint *vp; // FIXME: Should we take the selection from the parent VPDrag? I guess it shouldn't make a difference. Inkscape::Selection *sel = SP_ACTIVE_DESKTOP->getSelection(); - for (GSList const* i = sel->itemList(); i != NULL; i = i->next) { - SPItem *item = static_cast(i->data); + SelContainer itemlist=sel->itemList(); + for (SelContainer::const_iterator i=itemlist.begin();i!=itemlist.end();i++) { + SPItem *item = static_cast(*i); SPBox3D *box = dynamic_cast(item); if (box) { vp = this->findVPWithBox(box); @@ -577,8 +579,9 @@ VPDrag::updateDraggers () g_return_if_fail (this->selection != NULL); - for (GSList const* i = this->selection->itemList(); i != NULL; i = i->next) { - SPItem *item = static_cast(i->data); + SelContainer itemlist=this->selection->itemList(); + for (SelContainer::const_iterator i=itemlist.begin();i!=itemlist.end();i++) { + SPItem *item = static_cast(*i); SPBox3D *box = dynamic_cast(item); if (box) { VanishingPoint vp; @@ -609,8 +612,9 @@ VPDrag::updateLines () g_return_if_fail (this->selection != NULL); - for (GSList const* i = this->selection->itemList(); i != NULL; i = i->next) { - SPItem *item = static_cast(i->data); + SelContainer itemlist=this->selection->itemList(); + for (SelContainer::const_iterator i=itemlist.begin();i!=itemlist.end();i++) { + SPItem *item = static_cast(*i); SPBox3D *box = dynamic_cast(item); if (box) { this->drawLinesForFace (box, Proj::X); @@ -626,11 +630,11 @@ VPDrag::updateBoxHandles () // FIXME: Is there a way to update the knots without accessing the // (previously) statically linked function KnotHolder::update_knots? - GSList *sel = (GSList *) selection->itemList(); - if (!sel) + SelContainer sel = selection->itemList(); + if (sel.empty()) return; // no selection - if (g_slist_length (sel) > 1) { + if (sel.size() > 1) { // Currently we only show handles if a single box is selected return; } diff --git a/src/widgets/arc-toolbar.cpp b/src/widgets/arc-toolbar.cpp index 8a64854be..23c248129 100644 --- a/src/widgets/arc-toolbar.cpp +++ b/src/widgets/arc-toolbar.cpp @@ -97,12 +97,9 @@ sp_arctb_startend_value_changed(GtkAdjustment *adj, GObject *tbl, gchar const *v gchar* namespaced_name = g_strconcat("sodipodi:", value_name, NULL); bool modmade = false; - for (GSList const *items = desktop->getSelection()->itemList(); - items != NULL; - items = items->next) - { - SPItem *item = SP_ITEM(items->data); - + SelContainer itemlist=desktop->getSelection()->itemList(); + for(SelContainer::const_iterator i=itemlist.begin();i!=itemlist.end();i++){ + SPItem *item = SP_ITEM(*i); if (SP_IS_GENERICELLIPSE(item)) { SPGenericEllipse *ge = SP_GENERICELLIPSE(item); @@ -166,11 +163,9 @@ static void sp_arctb_open_state_changed( EgeSelectOneAction *act, GObject *tbl ) bool modmade = false; if ( ege_select_one_action_get_active(act) != 0 ) { - for (GSList const *items = desktop->getSelection()->itemList(); - items != NULL; - items = items->next) - { - SPItem *item = reinterpret_cast(items->data); + SelContainer itemlist=desktop->getSelection()->itemList(); + for(SelContainer::const_iterator i=itemlist.begin();i!=itemlist.end();i++){ + SPItem *item = SP_ITEM(*i); if (SP_IS_GENERICELLIPSE(item)) { Inkscape::XML::Node *repr = item->getRepr(); repr->setAttribute("sodipodi:open", "true"); @@ -179,11 +174,9 @@ static void sp_arctb_open_state_changed( EgeSelectOneAction *act, GObject *tbl ) } } } else { - for (GSList const *items = desktop->getSelection()->itemList(); - items != NULL; - items = items->next) - { - SPItem *item = reinterpret_cast(items->data); + SelContainer itemlist=desktop->getSelection()->itemList(); + for(SelContainer::const_iterator i=itemlist.begin();i!=itemlist.end();i++){ + SPItem *item = SP_ITEM(*i); if (SP_IS_GENERICELLIPSE(item)) { Inkscape::XML::Node *repr = item->getRepr(); repr->setAttribute("sodipodi:open", NULL); @@ -271,11 +264,9 @@ static void sp_arc_toolbox_selection_changed(Inkscape::Selection *selection, GOb purge_repr_listener( tbl, tbl ); - for (GSList const *items = selection->itemList(); - items != NULL; - items = items->next) - { - SPItem *item = reinterpret_cast(items->data); + SelContainer itemlist=selection->itemList(); + for(SelContainer::const_iterator i=itemlist.begin();i!=itemlist.end();i++){ + SPItem *item = SP_ITEM(*i); if (SP_IS_GENERICELLIPSE(item)) { n_selected++; repr = item->getRepr(); diff --git a/src/widgets/connector-toolbar.cpp b/src/widgets/connector-toolbar.cpp index c906f7de4..401ce932a 100644 --- a/src/widgets/connector-toolbar.cpp +++ b/src/widgets/connector-toolbar.cpp @@ -76,7 +76,6 @@ static void sp_connector_path_set_ignore(void) static void sp_connector_orthogonal_toggled( GtkToggleAction* act, GObject *tbl ) { SPDesktop *desktop = static_cast(g_object_get_data( tbl, "desktop" )); - Inkscape::Selection * selection = desktop->getSelection(); SPDocument *doc = desktop->getDocument(); if (!DocumentUndo::getUndoSensitive(doc)) { @@ -98,9 +97,9 @@ static void sp_connector_orthogonal_toggled( GtkToggleAction* act, GObject *tbl gchar *value = is_orthog ? orthog_str : polyline_str ; bool modmade = false; - GSList *l = (GSList *) selection->itemList(); - while (l) { - SPItem *item = SP_ITEM(l->data); + SelContainer itemlist=desktop->getSelection()->itemList(); + for(SelContainer::const_iterator i=itemlist.begin();i!=itemlist.end();i++){ + SPItem *item = SP_ITEM(*i); if (Inkscape::UI::Tools::cc_item_is_connector(item)) { item->setAttribute( "inkscape:connector-type", @@ -108,7 +107,6 @@ static void sp_connector_orthogonal_toggled( GtkToggleAction* act, GObject *tbl item->avoidRef->handleSettingChange(); modmade = true; } - l = l->next; } if (!modmade) { @@ -126,7 +124,6 @@ static void sp_connector_orthogonal_toggled( GtkToggleAction* act, GObject *tbl static void connector_curvature_changed(GtkAdjustment *adj, GObject* tbl) { SPDesktop *desktop = static_cast(g_object_get_data( tbl, "desktop" )); - Inkscape::Selection * selection = desktop->getSelection(); SPDocument *doc = desktop->getDocument(); if (!DocumentUndo::getUndoSensitive(doc)) { @@ -147,9 +144,9 @@ static void connector_curvature_changed(GtkAdjustment *adj, GObject* tbl) g_ascii_dtostr(value, G_ASCII_DTOSTR_BUF_SIZE, newValue); bool modmade = false; - GSList *l = (GSList *) selection->itemList(); - while (l) { - SPItem *item = SP_ITEM(l->data); + SelContainer itemlist=desktop->getSelection()->itemList(); + for(SelContainer::const_iterator i=itemlist.begin();i!=itemlist.end();i++){ + SPItem *item = SP_ITEM(*i); if (Inkscape::UI::Tools::cc_item_is_connector(item)) { item->setAttribute( "inkscape:connector-curvature", @@ -157,7 +154,6 @@ static void connector_curvature_changed(GtkAdjustment *adj, GObject* tbl) item->avoidRef->handleSettingChange(); modmade = true; } - l = l->next; } if (!modmade) { diff --git a/src/widgets/fill-style.cpp b/src/widgets/fill-style.cpp index d60a92b8b..2c298b04d 100644 --- a/src/widgets/fill-style.cpp +++ b/src/widgets/fill-style.cpp @@ -481,7 +481,7 @@ void FillNStroke::updateFromPaint() SPDocument *document = desktop->getDocument(); Inkscape::Selection *selection = desktop->getSelection(); - GSList const *items = selection->itemList(); + SelContainer const items = selection->itemList(); switch (psel->mode) { case SPPaintSelector::MODE_EMPTY: @@ -543,7 +543,7 @@ void FillNStroke::updateFromPaint() case SPPaintSelector::MODE_GRADIENT_LINEAR: case SPPaintSelector::MODE_GRADIENT_RADIAL: case SPPaintSelector::MODE_SWATCH: - if (items) { + if (!items.empty()) { SPGradientType const gradient_type = ( psel->mode != SPPaintSelector::MODE_GRADIENT_RADIAL ? SP_GRADIENT_TYPE_LINEAR : SP_GRADIENT_TYPE_RADIAL ); @@ -561,7 +561,7 @@ void FillNStroke::updateFromPaint() /* No vector in paint selector should mean that we just changed mode */ SPStyle query(desktop->doc()); - int result = objects_query_fillstroke(const_cast(items), &query, kind == FILL); + int result = objects_query_fillstroke(items, &query, kind == FILL); if (result == QUERY_STYLE_MULTIPLE_SAME) { SPIPaint &targPaint = (kind == FILL) ? query.fill : query.stroke; SPColor common; @@ -576,39 +576,39 @@ void FillNStroke::updateFromPaint() } } - for (GSList const *i = items; i != NULL; i = i->next) { + for(SelContainer::const_iterator i=items.begin();i!=items.end();i++){ //FIXME: see above if (kind == FILL) { - sp_repr_css_change_recursive(reinterpret_cast(i->data)->getRepr(), css, "style"); + sp_repr_css_change_recursive(reinterpret_cast(*i)->getRepr(), css, "style"); } if (!vector) { SPGradient *gr = sp_gradient_vector_for_object( document, desktop, - reinterpret_cast(i->data), + reinterpret_cast(*i), (kind == FILL) ? Inkscape::FOR_FILL : Inkscape::FOR_STROKE, createSwatch ); if ( gr && createSwatch ) { gr->setSwatch(); } - sp_item_set_gradient(SP_ITEM(i->data), + sp_item_set_gradient(SP_ITEM(*i), gr, gradient_type, (kind == FILL) ? Inkscape::FOR_FILL : Inkscape::FOR_STROKE); } else { - sp_item_set_gradient(SP_ITEM(i->data), vector, gradient_type, (kind == FILL) ? Inkscape::FOR_FILL : Inkscape::FOR_STROKE); + sp_item_set_gradient(SP_ITEM(*i), vector, gradient_type, (kind == FILL) ? Inkscape::FOR_FILL : Inkscape::FOR_STROKE); } } } else { // We have changed from another gradient type, or modified spread/units within // this gradient type. vector = sp_gradient_ensure_vector_normalized(vector); - for (GSList const *i = items; i != NULL; i = i->next) { + for(SelContainer::const_iterator i=items.begin();i!=items.end();i++){ //FIXME: see above if (kind == FILL) { - sp_repr_css_change_recursive(reinterpret_cast(i->data)->getRepr(), css, "style"); + sp_repr_css_change_recursive(reinterpret_cast(*i)->getRepr(), css, "style"); } - SPGradient *gr = sp_item_set_gradient(SP_ITEM(i->data), vector, gradient_type, (kind == FILL) ? Inkscape::FOR_FILL : Inkscape::FOR_STROKE); + SPGradient *gr = sp_item_set_gradient(SP_ITEM(*i), vector, gradient_type, (kind == FILL) ? Inkscape::FOR_FILL : Inkscape::FOR_STROKE); psel->pushAttrsToGradient( gr ); } } @@ -625,7 +625,7 @@ void FillNStroke::updateFromPaint() case SPPaintSelector::MODE_PATTERN: - if (items) { + if (!items.empty()) { SPPattern *pattern = psel->getPattern(); if (!pattern) { @@ -648,12 +648,12 @@ void FillNStroke::updateFromPaint() // cannot just call sp_desktop_set_style, because we don't want to touch those // objects who already have the same root pattern but through a different href // chain. FIXME: move this to a sp_item_set_pattern - for (GSList const *i = items; i != NULL; i = i->next) { - Inkscape::XML::Node *selrepr = reinterpret_cast(i->data)->getRepr(); + for(SelContainer::const_iterator i=items.begin();i!=items.end();i++){ + Inkscape::XML::Node *selrepr = reinterpret_cast(*i)->getRepr(); if ( (kind == STROKE) && !selrepr) { continue; } - SPObject *selobj = reinterpret_cast(i->data); + SPObject *selobj = reinterpret_cast(*i); SPStyle *style = selobj->style; if (style && ((kind == FILL) ? style->fill : style->stroke).isPaintserver()) { @@ -686,7 +686,7 @@ void FillNStroke::updateFromPaint() break; case SPPaintSelector::MODE_UNSET: - if (items) { + if (!items.empty()) { SPCSSAttr *css = sp_repr_css_attr_new(); if (kind == FILL) { sp_repr_css_unset_property(css, "fill"); diff --git a/src/widgets/gradient-toolbar.cpp b/src/widgets/gradient-toolbar.cpp index 7ce04403b..b9608130b 100644 --- a/src/widgets/gradient-toolbar.cpp +++ b/src/widgets/gradient-toolbar.cpp @@ -116,8 +116,9 @@ void gr_apply_gradient(Inkscape::Selection *selection, GrDrag *drag, SPGradient } // If no drag or no dragger selected, act on selection - for (GSList const* i = selection->itemList(); i != NULL; i = i->next) { - gr_apply_gradient_to_item(SP_ITEM(i->data), gr, initialType, initialMode, initialMode); + SelContainer itemlist=selection->itemList(); + for(SelContainer::const_iterator i=itemlist.begin();i!=itemlist.end();i++){ + gr_apply_gradient_to_item(SP_ITEM(*i), gr, initialType, initialMode, initialMode); } } @@ -217,8 +218,9 @@ void gr_get_dt_selected_gradient(Inkscape::Selection *selection, SPGradient *&gr { SPGradient *gradient = 0; - for (GSList const* i = selection->itemList(); i; i = i->next) { - SPItem *item = SP_ITEM(i->data); // get the items gradient, not the getVector() version + SelContainer itemlist=selection->itemList(); + for(SelContainer::const_iterator i=itemlist.begin();i!=itemlist.end();i++){ + SPItem *item = SP_ITEM(*i);// get the items gradient, not the getVector() version SPStyle *style = item->style; SPPaintServer *server = 0; @@ -284,8 +286,9 @@ void gr_read_selection( Inkscape::Selection *selection, } // If no selected dragger, read desktop selection - for (GSList const* i = selection->itemList(); i; i = i->next) { - SPItem *item = SP_ITEM(i->data); + SelContainer itemlist=selection->itemList(); + for(SelContainer::const_iterator i=itemlist.begin();i!=itemlist.end();i++){ + SPItem *item = SP_ITEM(*i); SPStyle *style = item->style; if (style && (style->fill.isPaintserver())) { diff --git a/src/widgets/mesh-toolbar.cpp b/src/widgets/mesh-toolbar.cpp index 3d549047a..b4176db6f 100644 --- a/src/widgets/mesh-toolbar.cpp +++ b/src/widgets/mesh-toolbar.cpp @@ -87,8 +87,9 @@ void ms_read_selection( Inkscape::Selection *selection, bool first = true; ms_smooth = SP_MESH_SMOOTH_NONE; - for (GSList const* i = selection->itemList(); i; i = i->next) { - SPItem *item = SP_ITEM(i->data); + SelContainer itemlist=selection->itemList(); + for(SelContainer::const_iterator i=itemlist.begin();i!=itemlist.end();i++){ + SPItem *item = SP_ITEM(*i); SPStyle *style = item->style; if (style && (style->fill.isPaintserver())) { @@ -213,8 +214,9 @@ void ms_get_dt_selected_gradient(Inkscape::Selection *selection, SPMeshGradient { SPMeshGradient *gradient = 0; - for (GSList const* i = selection->itemList(); i; i = i->next) { - SPItem *item = SP_ITEM(i->data); // get the items gradient, not the getVector() version + SelContainer itemlist=selection->itemList(); + for(SelContainer::const_iterator i=itemlist.begin();i!=itemlist.end();i++){ + SPItem *item = SP_ITEM(*i);// get the items gradient, not the getVector() version SPStyle *style = item->style; SPPaintServer *server = 0; diff --git a/src/widgets/rect-toolbar.cpp b/src/widgets/rect-toolbar.cpp index 016aa4987..1f19867ee 100644 --- a/src/widgets/rect-toolbar.cpp +++ b/src/widgets/rect-toolbar.cpp @@ -106,12 +106,13 @@ static void sp_rtb_value_changed(GtkAdjustment *adj, GObject *tbl, gchar const * bool modmade = false; Inkscape::Selection *selection = desktop->getSelection(); - for (GSList const *items = selection->itemList(); items != NULL; items = items->next) { - if (SP_IS_RECT(items->data)) { + SelContainer itemlist=selection->itemList(); + for(SelContainer::const_iterator i=itemlist.begin();i!=itemlist.end();i++){ + if (SP_IS_RECT(*i)) { if (gtk_adjustment_get_value(adj) != 0) { - (SP_RECT(items->data)->*setter)(Quantity::convert(gtk_adjustment_get_value(adj), unit, desktop->getNamedView()->svg_units)); + (SP_RECT(*i)->*setter)(Quantity::convert(gtk_adjustment_get_value(adj), unit, desktop->getNamedView()->svg_units)); } else { - SP_OBJECT(items->data)->getRepr()->setAttribute(value_name, NULL); + SP_OBJECT(*i)->getRepr()->setAttribute(value_name, NULL); } modmade = true; } @@ -243,12 +244,11 @@ static void sp_rect_toolbox_selection_changed(Inkscape::Selection *selection, GO } purge_repr_listener( tbl, tbl ); - for (GSList const *items = selection->itemList(); - items != NULL; - items = items->next) { - if (SP_IS_RECT(reinterpret_cast(items->data))) { + SelContainer itemlist=selection->itemList(); + for(SelContainer::const_iterator i=itemlist.begin();i!=itemlist.end();i++){ + if (SP_IS_RECT(reinterpret_cast(*i))) { n_selected++; - item = reinterpret_cast(items->data); + item = reinterpret_cast(*i); repr = item->getRepr(); } } diff --git a/src/widgets/spiral-toolbar.cpp b/src/widgets/spiral-toolbar.cpp index 3fb0015c1..2f4ad481d 100644 --- a/src/widgets/spiral-toolbar.cpp +++ b/src/widgets/spiral-toolbar.cpp @@ -79,11 +79,9 @@ static void sp_spl_tb_value_changed(GtkAdjustment *adj, GObject *tbl, Glib::ustr gchar* namespaced_name = g_strconcat("sodipodi:", value_name.data(), NULL); bool modmade = false; - for (GSList const *items = desktop->getSelection()->itemList(); - items != NULL; - items = items->next) - { - SPItem *item = reinterpret_cast(items->data); + SelContainer itemlist=desktop->getSelection()->itemList(); + for(SelContainer::const_iterator i=itemlist.begin();i!=itemlist.end();i++){ + SPItem *item = SP_ITEM(*i); if (SP_IS_SPIRAL(item)) { Inkscape::XML::Node *repr = item->getRepr(); sp_repr_set_svg_double( repr, namespaced_name, @@ -197,11 +195,9 @@ static void sp_spiral_toolbox_selection_changed(Inkscape::Selection *selection, purge_repr_listener( tbl, tbl ); - for (GSList const *items = selection->itemList(); - items != NULL; - items = items->next) - { - SPItem *item = reinterpret_cast(items->data); + SelContainer itemlist=selection->itemList(); + for(SelContainer::const_iterator i=itemlist.begin();i!=itemlist.end();i++){ + SPItem *item = SP_ITEM(*i); if (SP_IS_SPIRAL(item)) { n_selected++; repr = item->getRepr(); diff --git a/src/widgets/star-toolbar.cpp b/src/widgets/star-toolbar.cpp index cf12391c1..37daf69d0 100644 --- a/src/widgets/star-toolbar.cpp +++ b/src/widgets/star-toolbar.cpp @@ -83,9 +83,9 @@ static void sp_stb_magnitude_value_changed( GtkAdjustment *adj, GObject *dataKlu bool modmade = false; Inkscape::Selection *selection = desktop->getSelection(); - GSList const *items = selection->itemList(); - for (; items != NULL; items = items->next) { - SPItem *item = reinterpret_cast(items->data); + SelContainer itemlist=selection->itemList(); + for(SelContainer::const_iterator i=itemlist.begin();i!=itemlist.end();i++){ + SPItem *item = SP_ITEM(*i); if (SP_IS_STAR(item)) { Inkscape::XML::Node *repr = item->getRepr(); sp_repr_set_int(repr,"sodipodi:sides", @@ -128,9 +128,9 @@ static void sp_stb_proportion_value_changed( GtkAdjustment *adj, GObject *dataKl bool modmade = false; Inkscape::Selection *selection = desktop->getSelection(); - GSList const *items = selection->itemList(); - for (; items != NULL; items = items->next) { - SPItem *item = reinterpret_cast(items->data); + SelContainer itemlist=selection->itemList(); + for(SelContainer::const_iterator i=itemlist.begin();i!=itemlist.end();i++){ + SPItem *item = SP_ITEM(*i); if (SP_IS_STAR(item)) { Inkscape::XML::Node *repr = item->getRepr(); @@ -178,7 +178,6 @@ static void sp_stb_sides_flat_state_changed( EgeSelectOneAction *act, GObject *d g_object_set_data( dataKludge, "freeze", GINT_TO_POINTER(TRUE) ); Inkscape::Selection *selection = desktop->getSelection(); - GSList const *items = selection->itemList(); GtkAction* prop_action = GTK_ACTION( g_object_get_data( dataKludge, "prop_action" ) ); bool modmade = false; @@ -186,8 +185,9 @@ static void sp_stb_sides_flat_state_changed( EgeSelectOneAction *act, GObject *d gtk_action_set_sensitive( prop_action, !flat ); } - for (; items != NULL; items = items->next) { - SPItem *item = reinterpret_cast(items->data); + SelContainer itemlist=selection->itemList(); + for(SelContainer::const_iterator i=itemlist.begin();i!=itemlist.end();i++){ + SPItem *item = SP_ITEM(*i); if (SP_IS_STAR(item)) { Inkscape::XML::Node *repr = item->getRepr(); repr->setAttribute("inkscape:flatsided", flat ? "true" : "false" ); @@ -224,9 +224,9 @@ static void sp_stb_rounded_value_changed( GtkAdjustment *adj, GObject *dataKludg bool modmade = false; Inkscape::Selection *selection = desktop->getSelection(); - GSList const *items = selection->itemList(); - for (; items != NULL; items = items->next) { - SPItem *item = reinterpret_cast(items->data); + SelContainer itemlist=selection->itemList(); + for(SelContainer::const_iterator i=itemlist.begin();i!=itemlist.end();i++){ + SPItem *item = SP_ITEM(*i); if (SP_IS_STAR(item)) { Inkscape::XML::Node *repr = item->getRepr(); sp_repr_set_svg_double(repr, "inkscape:rounded", @@ -264,9 +264,9 @@ static void sp_stb_randomized_value_changed( GtkAdjustment *adj, GObject *dataKl bool modmade = false; Inkscape::Selection *selection = desktop->getSelection(); - GSList const *items = selection->itemList(); - for (; items != NULL; items = items->next) { - SPItem *item = reinterpret_cast(items->data); + SelContainer itemlist=selection->itemList(); + for(SelContainer::const_iterator i=itemlist.begin();i!=itemlist.end();i++){ + SPItem *item = SP_ITEM(*i); if (SP_IS_STAR(item)) { Inkscape::XML::Node *repr = item->getRepr(); sp_repr_set_svg_double(repr, "inkscape:randomized", @@ -367,11 +367,9 @@ sp_star_toolbox_selection_changed(Inkscape::Selection *selection, GObject *tbl) purge_repr_listener( tbl, tbl ); - for (GSList const *items = selection->itemList(); - items != NULL; - items = items->next) - { - SPItem* item = reinterpret_cast(items->data); + SelContainer itemlist=selection->itemList(); + for(SelContainer::const_iterator i=itemlist.begin();i!=itemlist.end();i++){ + SPItem *item = SP_ITEM(*i); if (SP_IS_STAR(item)) { n_selected++; repr = item->getRepr(); diff --git a/src/widgets/stroke-style.cpp b/src/widgets/stroke-style.cpp index 5ca06a795..2599fe537 100644 --- a/src/widgets/stroke-style.cpp +++ b/src/widgets/stroke-style.cpp @@ -475,9 +475,9 @@ void StrokeStyle::markerSelectCB(MarkerComboBox *marker_combo, StrokeStyle *spw, //spw->updateMarkerHist(which); Inkscape::Selection *selection = spw->desktop->getSelection(); - GSList const *items = selection->itemList(); - for (; items != NULL; items = items->next) { - SPItem *item = reinterpret_cast(items->data); + SelContainer itemlist=selection->itemList(); + for(SelContainer::const_iterator i=itemlist.begin();i!=itemlist.end();i++){ + SPItem *item = SP_ITEM(*i); if (!SP_IS_SHAPE(item) || SP_IS_RECT(item)) { // can't set marker to rect, until it's converted to using continue; } @@ -901,8 +901,8 @@ StrokeStyle::updateLine() if (!sel || sel->isEmpty()) return; - GSList const *objects = sel->itemList(); - SPObject * const object = SP_OBJECT(objects->data); + SelContainer const objects = sel->itemList(); + SPObject * const object = SP_OBJECT(objects.front()); SPStyle * const style = object->style; /* Markers */ @@ -957,13 +957,12 @@ StrokeStyle::scaleLine() SPDocument *document = desktop->getDocument(); Inkscape::Selection *selection = desktop->getSelection(); - - GSList const *items = selection->itemList(); + SelContainer items=selection->itemList(); /* TODO: Create some standardized method */ SPCSSAttr *css = sp_repr_css_attr_new(); - if (items) { + if (!items.empty()) { #if WITH_GTKMM_3_0 double width_typed = (*widthAdj)->get_value(); double const miterlimit = (*miterLimitAdj)->get_value(); @@ -978,13 +977,13 @@ StrokeStyle::scaleLine() int ndash; dashSelector->get_dash(&ndash, &dash, &offset); - for (GSList const *i = items; i != NULL; i = i->next) { + for(SelContainer::const_iterator i=items.begin();i!=items.end();i++){ /* Set stroke width */ double width; if (unit->type == Inkscape::Util::UNIT_TYPE_LINEAR) { width = Inkscape::Util::Quantity::convert(width_typed, unit, "px"); } else { // percentage - gdouble old_w = SP_OBJECT(i->data)->style->stroke_width.computed; + gdouble old_w = SP_OBJECT(*i)->style->stroke_width.computed; width = old_w * width_typed / 100; } @@ -1003,7 +1002,7 @@ StrokeStyle::scaleLine() /* Set dash */ setScaledDash(css, ndash, dash, offset, width); - sp_desktop_apply_css_recursive (SP_OBJECT(i->data), css, true); + sp_desktop_apply_css_recursive (SP_OBJECT(*i), css, true); } g_free(dash); @@ -1144,7 +1143,7 @@ StrokeStyle::setCapButtons(Gtk::ToggleButton *active) * that marker. */ void -StrokeStyle::updateAllMarkers(GSList const *objects) +StrokeStyle::updateAllMarkers(SelContainer const &objects) { struct { MarkerComboBox *key; int loc; } const keyloc[] = { { startMarkerCombo, SP_MARKER_LOC_START }, @@ -1153,8 +1152,8 @@ StrokeStyle::updateAllMarkers(GSList const *objects) }; bool all_texts = true; - for (GSList *i = (GSList *) objects; i != NULL; i = i->next) { - if (!SP_IS_TEXT (i->data)) { + for(SelContainer::const_iterator i=objects.begin();i!=objects.end();i++){ + if (!SP_IS_TEXT (*i)) { all_texts = false; } } @@ -1167,7 +1166,7 @@ StrokeStyle::updateAllMarkers(GSList const *objects) // We show markers of the first object in the list only // FIXME: use the first in the list that has the marker of each type, if any - SPObject *object = SP_OBJECT(objects->data); + SPObject *object = SP_OBJECT(objects.front()); for (unsigned i = 0; i < G_N_ELEMENTS(keyloc); ++i) { // For all three marker types, diff --git a/src/widgets/stroke-style.h b/src/widgets/stroke-style.h index 83048cb76..286305ec3 100644 --- a/src/widgets/stroke-style.h +++ b/src/widgets/stroke-style.h @@ -153,7 +153,7 @@ private: }; void updateLine(); - void updateAllMarkers(GSList const *objects); + void updateAllMarkers(SelContainer const &objects); void updateMarkerHist(SPMarkerLoc const which); void setDashSelectorFromStyle(SPDashSelector *dsel, SPStyle *style); void setJoinType (unsigned const jointype); diff --git a/src/widgets/text-toolbar.cpp b/src/widgets/text-toolbar.cpp index 3d2e6eef8..ba7dfc1fd 100644 --- a/src/widgets/text-toolbar.cpp +++ b/src/widgets/text-toolbar.cpp @@ -366,9 +366,10 @@ static void sp_text_align_mode_changed( EgeSelectOneAction *act, GObject *tbl ) // move the x of all texts to preserve the same bbox Inkscape::Selection *selection = desktop->getSelection(); - for (GSList const *items = selection->itemList(); items != NULL; items = items->next) { - if (SP_IS_TEXT(SP_ITEM(items->data))) { - SPItem *item = SP_ITEM(items->data); + SelContainer itemlist=selection->itemList(); + for(SelContainer::const_iterator i=itemlist.begin();i!=itemlist.end();i++){ + if (SP_IS_TEXT(SP_ITEM(*i))) { + SPItem *item = SP_ITEM(*i); unsigned writing_mode = item->style->writing_mode.value; // below, variable names suggest horizontal move, but we check the writing direction @@ -517,11 +518,11 @@ static void sp_text_lineheight_value_changed( GtkAdjustment *adj, GObject *tbl ) // Until deprecated sodipodi:linespacing purged: Inkscape::Selection *selection = desktop->getSelection(); - GSList const *items = selection->itemList(); bool modmade = false; - for (; items != NULL; items = items->next) { - if (SP_IS_TEXT (items->data)) { - SP_OBJECT(items->data)->getRepr()->setAttribute("sodipodi:linespacing", sp_repr_css_property (css, "line-height", NULL)); + SelContainer itemlist=selection->itemList(); + for(SelContainer::const_iterator i=itemlist.begin();i!=itemlist.end();i++){ + if (SP_IS_TEXT (*i)) { + SP_OBJECT(*i)->getRepr()->setAttribute("sodipodi:linespacing", sp_repr_css_property (css, "line-height", NULL)); modmade = true; } } @@ -863,12 +864,11 @@ static void sp_text_toolbox_selection_changed(Inkscape::Selection */*selection*/ // Only flowed text can be justified, only normal text can be kerned... // Find out if we have flowed text now so we can use it several places gboolean isFlow = false; - for (GSList const *items = SP_ACTIVE_DESKTOP->getSelection()->itemList(); - items != NULL; - items = items->next) { + SelContainer itemlist=SP_ACTIVE_DESKTOP->getSelection()->itemList(); + for(SelContainer::const_iterator i=itemlist.begin();i!=itemlist.end();i++){ // const gchar* id = reinterpret_cast(items->data)->getId(); // std::cout << " " << id << std::endl; - if( SP_IS_FLOWTEXT(SP_ITEM(items->data))) { + if( SP_IS_FLOWTEXT(SP_ITEM(*i))) { isFlow = true; // std::cout << " Found flowed text" << std::endl; break; @@ -1153,14 +1153,14 @@ static void sp_text_toolbox_select_cb( GtkEntry* entry, GtkEntryIconPosition /*p //std::cout << "text_toolbox_missing_font_cb: selecting: " << family << std::endl; // Get all items with matching font-family set (not inherited!). - GSList *selectList = NULL; + SelContainer selectList; SPDesktop *desktop = SP_ACTIVE_DESKTOP; SPDocument *document = desktop->getDocument(); - GSList *allList = get_all_items(NULL, document->getRoot(), desktop, false, false, true, NULL); - for (GSList *i = allList; i != NULL; i = i->next) { - - SPItem *item = SP_ITEM(i->data); + SelContainer x,y; + SelContainer allList = get_all_items(x, document->getRoot(), desktop, false, false, true, y); + for(SelContainer::const_iterator i=allList.begin();i!=allList.end();i++){ + SPItem *item = SP_ITEM(*i); SPStyle *style = item->style; if (style) { @@ -1177,7 +1177,7 @@ static void sp_text_toolbox_select_cb( GtkEntry* entry, GtkEntryIconPosition /*p if (family_style.compare( family ) == 0 ) { //std::cout << " found: " << item->getId() << std::endl; - selectList = g_slist_prepend (selectList, item); + selectList.push_front(static_cast(item)); } } } -- cgit v1.2.3 From 193b25a53c51a36fe9538e03203b0054c8cfc355 Mon Sep 17 00:00:00 2001 From: mc <> Date: Wed, 18 Feb 2015 02:02:37 +0100 Subject: Just... some... more... lines... (bzr r13922.1.2) --- src/desktop.cpp | 2 +- src/desktop.h | 2 +- src/document.cpp | 32 ++++++++--------- src/document.h | 9 ++--- src/selection-chemistry.cpp | 13 ++++--- src/splivarot.h | 3 +- src/trace/trace.cpp | 6 ++-- src/ui/dialog/font-substitution.cpp | 24 +++++-------- src/ui/dialog/font-substitution.h | 6 ++-- src/ui/dialog/grid-arrange-tab.cpp | 54 ++++++++++++++++------------- src/ui/dialog/icon-preview.cpp | 8 ++--- src/ui/dialog/objects.cpp | 8 ++--- src/ui/dialog/pixelartdialog.cpp | 8 ++--- src/ui/dialog/polar-arrange-tab.cpp | 14 +++----- src/ui/dialog/print.cpp | 2 +- src/ui/dialog/svg-fonts-dialog.cpp | 4 +-- src/ui/dialog/swatches.cpp | 6 ++-- src/ui/dialog/tags.cpp | 11 +++--- src/ui/dialog/text-edit.cpp | 26 +++++++------- src/ui/dialog/transformation.cpp | 41 ++++++++++++---------- src/ui/tools/connector-tool.cpp | 8 ++--- src/ui/tools/eraser-tool.cpp | 31 +++++++---------- src/ui/tools/gradient-tool.cpp | 43 +++++++++++++---------- src/ui/tools/gradient-tool.h | 3 +- src/ui/tools/lpe-tool.cpp | 8 ++--- src/ui/tools/measure-tool.cpp | 6 ++-- src/ui/tools/mesh-tool.cpp | 34 +++++++++++------- src/ui/tools/node-tool.cpp | 10 +++--- src/ui/tools/select-tool.cpp | 5 ++- src/ui/tools/spray-tool.cpp | 32 +++++++---------- src/ui/tools/text-tool.cpp | 7 ++-- src/ui/tools/tool-base.cpp | 6 ++-- src/ui/tools/tweak-tool.cpp | 25 ++++++------- src/ui/widget/object-composite-settings.cpp | 3 +- src/ui/widget/style-subject.cpp | 34 +++++++++--------- src/ui/widget/style-subject.h | 15 ++++---- 36 files changed, 270 insertions(+), 279 deletions(-) (limited to 'src') diff --git a/src/desktop.cpp b/src/desktop.cpp index cdf8f276c..64353e582 100644 --- a/src/desktop.cpp +++ b/src/desktop.cpp @@ -716,7 +716,7 @@ Inkscape::UI::Widget::Dock* SPDesktop::getDock() { /** * \see SPDocument::getItemFromListAtPointBottom() */ -SPItem *SPDesktop::getItemFromListAtPointBottom(const GSList *list, Geom::Point const &p) const +SPItem *SPDesktop::getItemFromListAtPointBottom(const SelContainer &list, Geom::Point const &p) const { g_return_val_if_fail (doc() != NULL, NULL); return SPDocument::getItemFromListAtPointBottom(dkey, doc()->getRoot(), list, p); diff --git a/src/desktop.h b/src/desktop.h index a0b9592d0..8765fa699 100644 --- a/src/desktop.h +++ b/src/desktop.h @@ -319,7 +319,7 @@ public: //void push_event_context (GType type, const gchar *config, unsigned int key); void set_coordinate_status (Geom::Point p); - SPItem *getItemFromListAtPointBottom(const GSList *list, Geom::Point const &p) const; + SPItem *getItemFromListAtPointBottom(const SelContainer &list, Geom::Point const &p) const; SPItem *getItemAtPoint(Geom::Point const &p, bool into_groups, SPItem *upto = NULL) const; SPItem *getGroupAtPoint(Geom::Point const &p) const; Geom::Point point() const; diff --git a/src/document.cpp b/src/document.cpp index 11971e63d..5c49ff6c3 100644 --- a/src/document.cpp +++ b/src/document.cpp @@ -1235,7 +1235,7 @@ static bool overlaps(Geom::Rect const &area, Geom::Rect const &box) return area.intersects(box); } -static GSList *find_items_in_area(GSList *s, SPGroup *group, unsigned int dkey, Geom::Rect const &area, +static SelContainer &find_items_in_area(SelContainer &s, SPGroup *group, unsigned int dkey, Geom::Rect const &area, bool (*test)(Geom::Rect const &, Geom::Rect const &), bool take_insensitive = false) { g_return_val_if_fail(SP_IS_GROUP(group), s); @@ -1248,7 +1248,7 @@ static GSList *find_items_in_area(GSList *s, SPGroup *group, unsigned int dkey, SPItem *child = SP_ITEM(o); Geom::OptRect box = child->desktopVisualBounds(); if ( box && test(area, *box) && (take_insensitive || child->isVisibleAndUnlocked(dkey))) { - s = g_slist_append(s, child); + s.push_back(child); } } } @@ -1275,7 +1275,7 @@ static bool item_is_in_group(SPItem *item, SPGroup *group) return inGroup; } -SPItem *SPDocument::getItemFromListAtPointBottom(unsigned int dkey, SPGroup *group, GSList const *list,Geom::Point const &p, bool take_insensitive) +SPItem *SPDocument::getItemFromListAtPointBottom(unsigned int dkey, SPGroup *group, SelContainer const &list,Geom::Point const &p, bool take_insensitive) { g_return_val_if_fail(group, NULL); SPItem *bottomMost = 0; @@ -1289,7 +1289,7 @@ SPItem *SPDocument::getItemFromListAtPointBottom(unsigned int dkey, SPGroup *gro Inkscape::DrawingItem *arenaitem = item->get_arenaitem(dkey); if (arenaitem && arenaitem->pick(p, delta, 1) != NULL && (take_insensitive || item->isVisibleAndUnlocked(dkey))) { - if (g_slist_find((GSList *) list, item) != NULL) { + if (find(list.begin(),list.end(),item)==list.end() ) { bottomMost = item; } } @@ -1391,11 +1391,11 @@ static SPItem *find_group_at_point(unsigned int dkey, SPGroup *group, Geom::Poin * Assumes box is normalized (and g_asserts it!) * */ -GSList *SPDocument::getItemsInBox(unsigned int dkey, Geom::Rect const &box) const +SelContainer SPDocument::getItemsInBox(unsigned int dkey, Geom::Rect const &box) const { - g_return_val_if_fail(this->priv != NULL, NULL); - - return find_items_in_area(NULL, SP_GROUP(this->root), dkey, box, is_within); + SelContainer x; + g_return_val_if_fail(this->priv != NULL, x); + return find_items_in_area(x, SP_GROUP(this->root), dkey, box, is_within); } /* @@ -1405,16 +1405,16 @@ GSList *SPDocument::getItemsInBox(unsigned int dkey, Geom::Rect const &box) cons * */ -GSList *SPDocument::getItemsPartiallyInBox(unsigned int dkey, Geom::Rect const &box) const +SelContainer SPDocument::getItemsPartiallyInBox(unsigned int dkey, Geom::Rect const &box) const { - g_return_val_if_fail(this->priv != NULL, NULL); - - return find_items_in_area(NULL, SP_GROUP(this->root), dkey, box, overlaps); + SelContainer x; + g_return_val_if_fail(this->priv != NULL, x); + return find_items_in_area(x, SP_GROUP(this->root), dkey, box, overlaps); } -GSList *SPDocument::getItemsAtPoints(unsigned const key, std::vector points) const +SelContainer SPDocument::getItemsAtPoints(unsigned const key, std::vector points) const { - GSList *items = NULL; + SelContainer items; Inkscape::Preferences *prefs = Inkscape::Preferences::get(); // When picking along the path, we don't want small objects close together @@ -1426,8 +1426,8 @@ GSList *SPDocument::getItemsAtPoints(unsigned const key, std::vector #include #include +#include "selection.h" namespace Avoid { class Router; @@ -232,7 +233,7 @@ public: /** * Returns the bottommost item from the list which is at the point, or NULL if none. */ - static SPItem *getItemFromListAtPointBottom(unsigned int dkey, SPGroup *group, const GSList *list, Geom::Point const &p, bool take_insensitive = false); + static SPItem *getItemFromListAtPointBottom(unsigned int dkey, SPGroup *group, const SelContainer &list, Geom::Point const &p, bool take_insensitive = false); static SPDocument *createDoc(Inkscape::XML::Document *rdoc, char const *uri, char const *base, char const *name, unsigned int keepalive, @@ -256,10 +257,10 @@ public: bool addResource(char const *key, SPObject *object); bool removeResource(char const *key, SPObject *object); const GSList *getResourceList(char const *key) const; - GSList *getItemsInBox(unsigned int dkey, Geom::Rect const &box) const; - GSList *getItemsPartiallyInBox(unsigned int dkey, Geom::Rect const &box) const; + SelContainer getItemsInBox(unsigned int dkey, Geom::Rect const &box) const; + SelContainer getItemsPartiallyInBox(unsigned int dkey, Geom::Rect const &box) const; SPItem *getItemAtPoint(unsigned int key, Geom::Point const &p, bool into_groups, SPItem *upto = NULL) const; - GSList *getItemsAtPoints(unsigned const key, std::vector points) const; + SelContainer getItemsAtPoints(unsigned const key, std::vector points) const; SPItem *getGroupAtPoint(unsigned int key, Geom::Point const &p) const; void changeUriAndHrefs(char const *uri); diff --git a/src/selection-chemistry.cpp b/src/selection-chemistry.cpp index f20df1594..05711e734 100644 --- a/src/selection-chemistry.cpp +++ b/src/selection-chemistry.cpp @@ -442,10 +442,10 @@ static void add_ids_recursive(std::vector &ids, SPObject *obj) } } } - +/* bool sp_repr_compare_position_obj(SPObject* &a,SPObject* &b){ return sp_repr_compare_position(dynamic_cast(a),dynamic_cast(b)); -} +}*/ void sp_selection_duplicate(SPDesktop *desktop, bool suppressDone) { @@ -2301,7 +2301,7 @@ sp_selection_move_screen(Inkscape::Selection *selection, gdouble dx, gdouble dy) namespace { template -SPItem *next_item(SPDesktop *desktop, SelContainer &path, SPObject *root, +SPItem *next_item(SPDesktop *desktop, GSList *path, SPObject *root, bool only_in_viewport, PrefsSelectionContext inlayer, bool onlyvisible, bool onlysensitive); template @@ -2481,19 +2481,18 @@ void sp_selection_edit_clip_or_mask(SPDesktop * /*dt*/, bool /*clip*/) namespace { template -SPItem *next_item_from_list(SPDesktop *desktop, GSList const *items, +SPItem *next_item_from_list(SPDesktop *desktop, SelContainer const items, SPObject *root, bool only_in_viewport, PrefsSelectionContext inlayer, bool onlyvisible, bool onlysensitive) { SPObject *current=root; - while (items) { - SPItem *item = dynamic_cast(static_cast(items->data)); + for(SelContainer::const_iterator i = items.begin();i!=items.end();i++) { + SPItem *item = dynamic_cast(static_cast(*i)); if ( root->isAncestorOf(item) && ( !only_in_viewport || desktop->isWithinViewport(item) ) ) { current = item; break; } - items = items->next; } GSList *path=NULL; diff --git a/src/splivarot.h b/src/splivarot.h index ba314399f..79b9b98a6 100644 --- a/src/splivarot.h +++ b/src/splivarot.h @@ -10,6 +10,7 @@ #include <2geom/forward.h> #include <2geom/path.h> #include "livarot/Path.h" +#include "sp-object.h"//kill it class SPCurve; class SPDesktop; @@ -18,7 +19,7 @@ class SPItem; namespace Inkscape { class Selection; } - +bool sp_repr_compare_position_obj(SPObject* &a,SPObject* &b);//kill it with fire // boolean operations // work on the current selection // selection has 2 contain exactly 2 items diff --git a/src/trace/trace.cpp b/src/trace/trace.cpp index 892ecdb87..2becca5cc 100644 --- a/src/trace/trace.cpp +++ b/src/trace/trace.cpp @@ -74,13 +74,13 @@ SPImage *Tracer::getSelectedSPImage() them as bottom-to-top so that we can discover the image and any SPItems above it */ - for(SelContainer::const_iterator x=list.begin();x!=list.end();x++){ + for (SelContainer::const_iterator i=list.begin() ; list.end()!=i ; i++) { - if (!SP_IS_ITEM(*x)) + if (!SP_IS_ITEM(*i)) { continue; } - SPItem *item = SP_ITEM(*x); + SPItem *item = SP_ITEM(*i); items.insert(items.begin(), item); } std::vector::iterator iter; diff --git a/src/ui/dialog/font-substitution.cpp b/src/ui/dialog/font-substitution.cpp index ae03bdf0e..625ed99b9 100644 --- a/src/ui/dialog/font-substitution.cpp +++ b/src/ui/dialog/font-substitution.cpp @@ -70,19 +70,15 @@ FontSubstitution::checkFontSubstitutions(SPDocument* doc) int show_dlg = prefs->getInt("/options/font/substitutedlg", 0); if (show_dlg) { Glib::ustring out; - GSList *l = getFontReplacedItems(doc, &out); + SelContainer l = getFontReplacedItems(doc, &out); if (out.length() > 0) { show(out, l); } - if (l) { - g_slist_free(l); - l = NULL; - } } } void -FontSubstitution::show(Glib::ustring out, GSList *l) +FontSubstitution::show(Glib::ustring out, SelContainer &l) { Gtk::MessageDialog warning(_("\nSome fonts are not available and have been substituted."), false, Gtk::MESSAGE_INFO, Gtk::BUTTONS_OK, true); @@ -152,20 +148,18 @@ FontSubstitution::show(Glib::ustring out, GSList *l) * b. Build up a list of the objects rendered fonts - taken for the objects layout/spans * If there are fonts in a. that are not in b. then those fonts have been substituted. */ -GSList * FontSubstitution::getFontReplacedItems(SPDocument* doc, Glib::ustring *out) +SelContainer FontSubstitution::getFontReplacedItems(SPDocument* doc, Glib::ustring *out) { SPDesktop *desktop = SP_ACTIVE_DESKTOP; - GSList *allList = NULL; - GSList *outList = NULL; + SelContainer allList; + SelContainer outList,x,y; std::set setErrors; std::set setFontSpans; std::map mapFontStyles; - allList = get_all_items(NULL, doc->getRoot(), desktop, false, false, true, NULL); - - for (GSList *i = allList; i != NULL; i = i->next) { - - SPItem *item = SP_ITEM(i->data); + allList = get_all_items(x, doc->getRoot(), desktop, false, false, true, y); + for(SelContainer::const_iterator i = allList.begin();i!=allList.end();i++){ + SPItem *item = SP_ITEM(*i); SPStyle *style = item->style; Glib::ustring family = ""; @@ -254,7 +248,7 @@ GSList * FontSubstitution::getFontReplacedItems(SPDocument* doc, Glib::ustring * Glib::ustring err = Glib::ustring::compose( _("Font '%1' substituted with '%2'"), fonts.c_str(), subName.c_str()); setErrors.insert(err); - outList = g_slist_prepend (outList, item); + outList.push_front(item); } } diff --git a/src/ui/dialog/font-substitution.h b/src/ui/dialog/font-substitution.h index 1c445081b..eed7adcf2 100644 --- a/src/ui/dialog/font-substitution.h +++ b/src/ui/dialog/font-substitution.h @@ -13,7 +13,7 @@ #define INKSCAPE_UI_FONT_SUBSTITUTION_H #include - +#include "selection.h" class SPDocument; namespace Inkscape { @@ -25,13 +25,13 @@ public: FontSubstitution(); virtual ~FontSubstitution(); void checkFontSubstitutions(SPDocument* doc); - void show(Glib::ustring out, GSList *l); + void show(Glib::ustring out, SelContainer &l); static FontSubstitution &getInstance() { return *new FontSubstitution(); } Glib::ustring getSubstituteFontName (Glib::ustring font); protected: - GSList *getFontReplacedItems(SPDocument* doc, Glib::ustring *out); + SelContainer getFontReplacedItems(SPDocument* doc, Glib::ustring *out); private: FontSubstitution(FontSubstitution const &d); diff --git a/src/ui/dialog/grid-arrange-tab.cpp b/src/ui/dialog/grid-arrange-tab.cpp index d3ccb9bde..ba8616d9b 100644 --- a/src/ui/dialog/grid-arrange-tab.cpp +++ b/src/ui/dialog/grid-arrange-tab.cpp @@ -109,6 +109,13 @@ static int sp_compare_y_position(SPItem *first, SPItem *second) return 0; } +static bool sp_compare_y_position_obj(SPObject *first, SPObject *second){ + return sp_compare_y_position(static_cast(first),static_cast(second))<0; +} +static bool sp_compare_x_position_obj(SPObject *first, SPObject *second){ + return sp_compare_x_position(static_cast(first),static_cast(second))<0; +} + namespace Inkscape { namespace UI { @@ -168,10 +175,10 @@ void GridArrangeTab::arrange() desktop->getDocument()->ensureUpToDate(); Inkscape::Selection *selection = desktop->getSelection(); - const GSList *items = selection ? selection->itemList() : 0; + const SelContainer items = selection ? selection->itemList() : SelContainer(); cnt=0; - for (; items != NULL; items = items->next) { - SPItem *item = SP_ITEM(items->data); + for(SelContainer::const_iterator i = items.begin();i!=items.end();i++){ + SPItem *item = SP_ITEM(*i); Geom::OptRect b = item->documentVisualBounds(); if (!b) { continue; @@ -198,20 +205,19 @@ void GridArrangeTab::arrange() // require the sorting done before we can calculate row heights etc. g_return_if_fail(selection); - const GSList *items2 = selection->itemList(); - GSList *rev = g_slist_copy(const_cast(items2)); - GSList *sorted = NULL; - rev = g_slist_sort(rev, (GCompareFunc) sp_compare_y_position); - sorted = g_slist_sort(rev, (GCompareFunc) sp_compare_x_position); + SelContainer rev(selection->itemList()); + rev.sort(sp_compare_y_position_obj); + SelContainer sorted(rev); + sorted.sort(sp_compare_x_position_obj); // Calculate individual Row and Column sizes if necessary cnt=0; - const GSList *sizes = sorted; - for (; sizes != NULL; sizes = sizes->next) { - SPItem *item = SP_ITEM(sizes->data); + const SelContainer sizes(sorted); + for (SelContainer::const_iterator i = sizes.begin();i!=sizes.end();i++) { + SPItem *item = SP_ITEM(*i); Geom::OptRect b = item->documentVisualBounds(); if (b) { width = b->dimensions()[Geom::X]; @@ -308,12 +314,14 @@ g_print("\n row = %f col = %f selection x= %f selection y = %f", total_row_h } cnt=0; - for (row_cnt=0; ((sorted != NULL) && (row_cntdata); - sorted = sorted->next; + col_cnt = 0; + for(;it!=sorted.end()&&colnext) { @@ -374,8 +382,8 @@ void GridArrangeTab::on_row_spinbutton_changed() Inkscape::Selection *selection = desktop ? desktop->selection : 0; g_return_if_fail( selection ); - GSList const *items = selection->itemList(); - int selcount = g_slist_length((GSList *)items); + SelContainer const items = selection->itemList(); + int selcount = items.size(); double PerCol = ceil(selcount / NoOfColsSpinner.get_value()); NoOfRowsSpinner.set_value(PerCol); @@ -400,8 +408,7 @@ void GridArrangeTab::on_col_spinbutton_changed() Inkscape::Selection *selection = desktop ? desktop->selection : 0; g_return_if_fail(selection); - GSList const *items = selection->itemList(); - int selcount = g_slist_length((GSList *)items); + int selcount = selection->itemList().size(); double PerRow = ceil(selcount / NoOfRowsSpinner.get_value()); NoOfColsSpinner.set_value(PerRow); @@ -538,10 +545,10 @@ void GridArrangeTab::updateSelection() updating = true; SPDesktop *desktop = Parent->getDesktop(); Inkscape::Selection *selection = desktop ? desktop->selection : 0; - GSList const *items = selection ? selection->itemList() : 0; + SelContainer const items = selection ? selection->itemList() : SelContainer(); - if (items) { - int selcount = g_slist_length((GSList *)items); + if (!items.empty()) { + int selcount = items.size(); if (NoOfColsSpinner.get_value() > 1 && NoOfRowsSpinner.get_value() > 1){ // Update the number of rows assuming number of columns wanted remains same. @@ -609,8 +616,7 @@ GridArrangeTab::GridArrangeTab(ArrangeDialog *parent) g_return_if_fail( selection ); int selcount = 1; if (!selection->isEmpty()) { - GSList const *items = selection->itemList(); - selcount = g_slist_length((GSList *)items); + selcount = selection->itemList().size(); } diff --git a/src/ui/dialog/icon-preview.cpp b/src/ui/dialog/icon-preview.cpp index b908a90cb..79e5b556d 100644 --- a/src/ui/dialog/icon-preview.cpp +++ b/src/ui/dialog/icon-preview.cpp @@ -366,16 +366,14 @@ void IconPreviewPanel::refreshPreview() if ( sel ) { //g_message("found a selection to play with"); - GSList const *items = sel->itemList(); - while ( items && !target ) { - SPItem* item = SP_ITEM( items->data ); + SelContainer const items = sel->itemList(); + for(SelContainer::const_iterator i=items.begin();!target && i!=items.end();i++){ + SPItem* item = SP_ITEM( *i); gchar const *id = item->getId(); if ( id ) { targetId = id; target = item; } - - items = g_slist_next(items); } } } diff --git a/src/ui/dialog/objects.cpp b/src/ui/dialog/objects.cpp index c95529a56..0ae3027c7 100644 --- a/src/ui/dialog/objects.cpp +++ b/src/ui/dialog/objects.cpp @@ -479,15 +479,15 @@ void ObjectsPanel::_objectsSelected( Selection *sel ) { _selectedConnection.block(); _tree.get_selection()->unselect_all(); SPItem *item = NULL; - for (const GSList * iter = sel->itemList(); iter != NULL; iter = iter->next) - { - item = reinterpret_cast(iter->data); + SelContainer const items = sel->itemList(); + for(SelContainer::const_iterator i=items.begin(); i!=items.end();i++){ + item = reinterpret_cast(*i); if (setOpacity) { _setCompositingValues(item); setOpacity = false; } - _store->foreach(sigc::bind( sigc::mem_fun(*this, &ObjectsPanel::_checkForSelected), item, iter->next == NULL)); + _store->foreach(sigc::bind( sigc::mem_fun(*this, &ObjectsPanel::_checkForSelected), item, (*i)==items.back())); } if (!item) { if (_desktop->currentLayer() && SP_IS_ITEM(_desktop->currentLayer())) { diff --git a/src/ui/dialog/pixelartdialog.cpp b/src/ui/dialog/pixelartdialog.cpp index 5113f172a..273a378e5 100644 --- a/src/ui/dialog/pixelartdialog.cpp +++ b/src/ui/dialog/pixelartdialog.cpp @@ -372,12 +372,12 @@ void PixelArtDialogImpl::vectorize() return; } - for ( GSList const *list = desktop->selection->itemList() ; list - ; list = list->next ) { - if ( !SP_IS_IMAGE(list->data) ) + SelContainer const items = desktop->selection->itemList(); + for(SelContainer::const_iterator i=items.begin(); i!=items.end();i++){ + if ( !SP_IS_IMAGE(*i) ) continue; - SPImage *img = SP_IMAGE(list->data); + SPImage *img = SP_IMAGE(*i); Input input; input.pixbuf = Glib::wrap(img->pixbuf->getPixbufRaw(), true); input.x = img->x; diff --git a/src/ui/dialog/polar-arrange-tab.cpp b/src/ui/dialog/polar-arrange-tab.cpp index 281958998..8a382fc93 100644 --- a/src/ui/dialog/polar-arrange-tab.cpp +++ b/src/ui/dialog/polar-arrange-tab.cpp @@ -297,19 +297,18 @@ static void moveToPoint(int anchor, SPItem *item, Geom::Point p) void PolarArrangeTab::arrange() { Inkscape::Selection *selection = parent->getDesktop()->getSelection(); - const GSList *items, *tmp; - tmp = items = selection->itemList(); + const SelContainer tmp(selection->itemList()); SPGenericEllipse *referenceEllipse = NULL; // Last ellipse in selection bool arrangeOnEllipse = !arrangeOnParametersRadio.get_active(); bool arrangeOnFirstEllipse = arrangeOnEllipse && arrangeOnFirstCircleRadio.get_active(); int count = 0; - while(tmp) + for(SelContainer::const_iterator i=tmp.begin();i!=tmp.end();i++) { if(arrangeOnEllipse) { - SPItem *item = SP_ITEM(tmp->data); + SPItem *item = SP_ITEM(*i); if(arrangeOnFirstEllipse) { @@ -322,7 +321,6 @@ void PolarArrangeTab::arrange() referenceEllipse = SP_GENERICELLIPSE(item); } } - tmp = tmp->next; ++count; } @@ -374,11 +372,10 @@ void PolarArrangeTab::arrange() Geom::Point realCenter = Geom::Point(cx, cy) * transformation; - tmp = items; int i = 0; - while(tmp) + for(SelContainer::const_iterator it=tmp.begin();it!=tmp.end();it++) { - SPItem *item = SP_ITEM(tmp->data); + SPItem *item = SP_ITEM(*it); // Ignore the reference ellipse if any if(item != referenceEllipse) @@ -396,7 +393,6 @@ void PolarArrangeTab::arrange() ++i; } - tmp = tmp->next; } DocumentUndo::done(parent->getDesktop()->getDocument(), SP_VERB_SELECTION_ARRANGE, diff --git a/src/ui/dialog/print.cpp b/src/ui/dialog/print.cpp index a015d28f9..dc98b6032 100644 --- a/src/ui/dialog/print.cpp +++ b/src/ui/dialog/print.cpp @@ -81,7 +81,7 @@ static void draw_page( width, height, (unsigned long)(Inkscape::Util::Quantity::convert(width, "px", "in") * dpi), (unsigned long)(Inkscape::Util::Quantity::convert(height, "px", "in") * dpi), - dpi, dpi, bgcolor, NULL, NULL, true, NULL); + dpi, dpi, bgcolor, NULL, NULL, true, SelContainer()); // This doesn't seem to work: //context->set_cairo_context ( Cairo::Context::create (Cairo::ImageSurface::create_from_png (tmp_png) ), dpi, dpi ); diff --git a/src/ui/dialog/svg-fonts-dialog.cpp b/src/ui/dialog/svg-fonts-dialog.cpp index bc228633d..8f5601e3a 100644 --- a/src/ui/dialog/svg-fonts-dialog.cpp +++ b/src/ui/dialog/svg-fonts-dialog.cpp @@ -524,7 +524,7 @@ void SvgFontsDialog::set_glyph_description_from_selected_path(){ return; } - Inkscape::XML::Node* node = (Inkscape::XML::Node*) g_slist_nth_data((GSList *)sel->reprList(), 0); + Inkscape::XML::Node* node = (Inkscape::XML::Node*)(sel->reprList().front()); if (!node) return;//TODO: should this be an assert? if (!node->matchAttributeName("d") || !node->attribute("d")){ char *msg = _("The selected object does not have a path description."); @@ -566,7 +566,7 @@ void SvgFontsDialog::missing_glyph_description_from_selected_path(){ return; } - Inkscape::XML::Node* node = (Inkscape::XML::Node*) g_slist_nth_data((GSList *)sel->reprList(), 0); + Inkscape::XML::Node* node = (Inkscape::XML::Node*)(sel->reprList().front()); if (!node) return;//TODO: should this be an assert? if (!node->matchAttributeName("d") || !node->attribute("d")){ char *msg = _("The selected object does not have a path description."); diff --git a/src/ui/dialog/swatches.cpp b/src/ui/dialog/swatches.cpp index 8759039c3..da24ad605 100644 --- a/src/ui/dialog/swatches.cpp +++ b/src/ui/dialog/swatches.cpp @@ -123,10 +123,10 @@ static void editGradientImpl( SPDesktop* desktop, SPGradient* gr ) bool shown = false; if ( desktop && desktop->doc() ) { Inkscape::Selection *selection = desktop->getSelection(); - GSList const *items = selection->itemList(); - if (items) { + SelContainer const items = selection->itemList(); + if (!items.empty()) { SPStyle query( desktop->doc() ); - int result = objects_query_fillstroke(const_cast(items), &query, true); + int result = objects_query_fillstroke((items), &query, true); if ( (result == QUERY_STYLE_MULTIPLE_SAME) || (result == QUERY_STYLE_SINGLE) ) { // could be pertinent if (query.fill.isPaintserver()) { diff --git a/src/ui/dialog/tags.cpp b/src/ui/dialog/tags.cpp index 8a104d137..ba3a6b914 100644 --- a/src/ui/dialog/tags.cpp +++ b/src/ui/dialog/tags.cpp @@ -371,9 +371,10 @@ void TagsPanel::_objectsSelected( Selection *sel ) { _selectedConnection.block(); _tree.get_selection()->unselect_all(); - for (const GSList * iter = sel->list(); iter != NULL; iter = iter->next) + SelContainer tmp=sel->list(); + for(SelContainer::const_iterator i=tmp.begin();i!=tmp.end();i++) { - SPObject *obj = reinterpret_cast(iter->data); + SPObject *obj = reinterpret_cast(*i); _store->foreach(sigc::bind( sigc::mem_fun(*this, &TagsPanel::_checkForSelected), obj)); } _selectedConnection.unblock(); @@ -668,9 +669,9 @@ bool TagsPanel::_handleButtonEvent(GdkEventButton* event) if (col == _tree.get_column(COL_ADD - 1) && down_at_add) { if (SP_IS_TAG(obj)) { bool wasadded = false; - for (const GSList * iter = _desktop->selection->itemList(); iter != NULL; iter = iter->next) - { - SPObject *newobj = reinterpret_cast(iter->data); + SelContainer items=_desktop->selection->itemList(); + for(SelContainer::const_iterator i=items.begin();i!=items.end();i++){ + SPObject *newobj = reinterpret_cast(*i); bool addchild = true; for ( SPObject *child = obj->children; child != NULL; child = child->next) { if (SP_IS_TAG_USE(child) && SP_TAG_USE(child)->ref->getObject() == newobj) { diff --git a/src/ui/dialog/text-edit.cpp b/src/ui/dialog/text-edit.cpp index a8be8b543..593261ec5 100644 --- a/src/ui/dialog/text-edit.cpp +++ b/src/ui/dialog/text-edit.cpp @@ -418,12 +418,11 @@ SPItem *TextEdit::getSelectedTextItem (void) if (!SP_ACTIVE_DESKTOP) return NULL; - for (const GSList *item = SP_ACTIVE_DESKTOP->getSelection()->itemList(); - item != NULL; - item = item->next) + SelContainer tmp=SP_ACTIVE_DESKTOP->getSelection()->itemList(); + for(SelContainer::const_iterator i=tmp.begin();i!=tmp.end();i++) { - if (SP_IS_TEXT(item->data) || SP_IS_FLOWTEXT(item->data)) - return SP_ITEM (item->data); + if (SP_IS_TEXT(*i) || SP_IS_FLOWTEXT(*i)) + return SP_ITEM (*i); } return NULL; @@ -437,11 +436,10 @@ unsigned TextEdit::getSelectedTextCount (void) unsigned int items = 0; - for (const GSList *item = SP_ACTIVE_DESKTOP->getSelection()->itemList(); - item != NULL; - item = item->next) + SelContainer tmp=SP_ACTIVE_DESKTOP->getSelection()->itemList(); + for(SelContainer::const_iterator i=tmp.begin();i!=tmp.end();i++) { - if (SP_IS_TEXT(item->data) || SP_IS_FLOWTEXT(item->data)) + if (SP_IS_TEXT(*i) || SP_IS_FLOWTEXT(*i)) ++items; } @@ -542,20 +540,20 @@ void TextEdit::onApply() SPDesktop *desktop = SP_ACTIVE_DESKTOP; unsigned items = 0; - const GSList *item_list = desktop->getSelection()->itemList(); + const SelContainer item_list = desktop->getSelection()->itemList(); SPCSSAttr *css = fillTextStyle (); sp_desktop_set_style(desktop, css, true); - for (; item_list != NULL; item_list = item_list->next) { + for(SelContainer::const_iterator i=item_list.begin();i!=item_list.end();i++){ // apply style to the reprs of all text objects in the selection - if (SP_IS_TEXT (item_list->data)) { + if (SP_IS_TEXT (*i)) { // backwards compatibility: - reinterpret_cast(item_list->data)->getRepr()->setAttribute("sodipodi:linespacing", sp_repr_css_property (css, "line-height", NULL)); + reinterpret_cast(*i)->getRepr()->setAttribute("sodipodi:linespacing", sp_repr_css_property (css, "line-height", NULL)); ++items; } - else if (SP_IS_FLOWTEXT (item_list->data)) + else if (SP_IS_FLOWTEXT (*i)) // no need to set sodipodi:linespacing, because Inkscape never supported it on flowtext ++items; } diff --git a/src/ui/dialog/transformation.cpp b/src/ui/dialog/transformation.cpp index 233d99750..8c52144e0 100644 --- a/src/ui/dialog/transformation.cpp +++ b/src/ui/dialog/transformation.cpp @@ -655,7 +655,7 @@ void Transformation::updatePageTransform(Inkscape::Selection *selection) { if (selection && !selection->isEmpty()) { if (_check_replace_matrix.get_active()) { - Geom::Affine current (SP_ITEM(selection->itemList()->data)->transform); // take from the first item in selection + Geom::Affine current (SP_ITEM(selection->itemList().front())->transform); // take from the first item in selection Geom::Affine new_displayed = current; @@ -741,19 +741,19 @@ void Transformation::applyPageMove(Inkscape::Selection *selection) if (_check_move_relative.get_active()) { // shift each object relatively to the previous one using Inkscape::Util::GSListConstIterator; - std::list selected; - selected.insert >(selected.end(), selection->itemList(), NULL); + SelContainer selected(selection->itemList()); if (selected.empty()) return; if (fabs(x) > 1e-6) { std::vector< BBoxSort > sorted; - for (std::list::iterator it(selected.begin()); + for (SelContainer::iterator it(selected.begin()); it != selected.end(); ++it) { - Geom::OptRect bbox = (*it)->desktopPreferredBounds(); + SPItem* item=static_cast(*it); + Geom::OptRect bbox = (item)->desktopPreferredBounds(); if (bbox) { - sorted.push_back(BBoxSort(*it, *bbox, Geom::X, x > 0? 1. : 0., x > 0? 0. : 1.)); + sorted.push_back(BBoxSort(item, *bbox, Geom::X, x > 0? 1. : 0., x > 0? 0. : 1.)); } } //sort bbox by anchors @@ -771,13 +771,14 @@ void Transformation::applyPageMove(Inkscape::Selection *selection) } if (fabs(y) > 1e-6) { std::vector< BBoxSort > sorted; - for (std::list::iterator it(selected.begin()); + for (SelContainer::iterator it(selected.begin()); it != selected.end(); ++it) { - Geom::OptRect bbox = (*it)->desktopPreferredBounds(); + SPItem* item=static_cast(*it); + Geom::OptRect bbox = (item)->desktopPreferredBounds(); if (bbox) { - sorted.push_back(BBoxSort(*it, *bbox, Geom::Y, y > 0? 1. : 0., y > 0? 0. : 1.)); + sorted.push_back(BBoxSort(item, *bbox, Geom::Y, y > 0? 1. : 0., y > 0? 0. : 1.)); } } //sort bbox by anchors @@ -815,8 +816,9 @@ void Transformation::applyPageScale(Inkscape::Selection *selection) bool transform_stroke = prefs->getBool("/options/transform/stroke", true); bool preserve = prefs->getBool("/options/preservetransform/value", false); if (prefs->getBool("/dialogs/transformation/applyseparately")) { - for (GSList const *l = selection->itemList(); l != NULL; l = l->next) { - SPItem *item = SP_ITEM(l->data); + SelContainer tmp=selection->itemList(); + for(SelContainer::const_iterator i=tmp.begin();i!=tmp.end();i++){ + SPItem *item = SP_ITEM(*i); Geom::OptRect bbox_pref = item->desktopPreferredBounds(); Geom::OptRect bbox_geom = item->desktopGeometricBounds(); if (bbox_pref && bbox_geom) { @@ -878,8 +880,9 @@ void Transformation::applyPageRotate(Inkscape::Selection *selection) } if (prefs->getBool("/dialogs/transformation/applyseparately")) { - for (GSList const *l = selection->itemList(); l != NULL; l = l->next) { - SPItem *item = SP_ITEM(l->data); + SelContainer tmp=selection->itemList(); + for(SelContainer::const_iterator i=tmp.begin();i!=tmp.end();i++){ + SPItem *item = SP_ITEM(*i); sp_item_rotate_rel(item, Geom::Rotate (angle*M_PI/180.0)); } } else { @@ -897,8 +900,9 @@ void Transformation::applyPageSkew(Inkscape::Selection *selection) { Inkscape::Preferences *prefs = Inkscape::Preferences::get(); if (prefs->getBool("/dialogs/transformation/applyseparately")) { - for (GSList const *l = selection->itemList(); l != NULL; l = l->next) { - SPItem *item = SP_ITEM(l->data); + SelContainer items=selection->itemList(); + for(SelContainer::const_iterator i = items.begin();i!=items.end();i++){ + SPItem *item = SP_ITEM(*i); if (!_units_skew.isAbsolute()) { // percentage double skewX = _scalar_skew_horizontal.getValue("%"); @@ -998,8 +1002,9 @@ void Transformation::applyPageTransform(Inkscape::Selection *selection) } if (_check_replace_matrix.get_active()) { - for (GSList const *l = selection->itemList(); l != NULL; l = l->next) { - SPItem *item = SP_ITEM(l->data); + SelContainer tmp=selection->itemList(); + for(SelContainer::const_iterator i=tmp.begin();i!=tmp.end();i++){ + SPItem *item = SP_ITEM(*i); item->set_item_transform(displayed); SP_OBJECT(item)->updateRepr(); } @@ -1150,7 +1155,7 @@ void Transformation::onReplaceMatrixToggled() double f = _scalar_transform_f.getValue(); Geom::Affine displayed (a, b, c, d, e, f); - Geom::Affine current = SP_ITEM(selection->itemList()->data)->transform; // take from the first item in selection + Geom::Affine current = SP_ITEM(selection->itemList().front())->transform; // take from the first item in selection Geom::Affine new_displayed; if (_check_replace_matrix.get_active()) { diff --git a/src/ui/tools/connector-tool.cpp b/src/ui/tools/connector-tool.cpp index 26a4eadd5..fc40c20e7 100644 --- a/src/ui/tools/connector-tool.cpp +++ b/src/ui/tools/connector-tool.cpp @@ -1313,12 +1313,12 @@ void cc_selection_set_avoid(bool const set_avoid) Inkscape::Selection *selection = desktop->getSelection(); - GSList *l = const_cast(selection->itemList()); int changes = 0; - while (l) { - SPItem *item = SP_ITEM(l->data); + SelContainer l = selection->itemList(); + for(SelContainer::const_iterator i=l.begin();i!=l.end();i++) { + SPItem *item = SP_ITEM(*i); char const *value = (set_avoid) ? "true" : NULL; @@ -1327,8 +1327,6 @@ void cc_selection_set_avoid(bool const set_avoid) item->avoidRef->handleSettingChange(); changes++; } - - l = l->next; } if (changes == 0) { diff --git a/src/ui/tools/eraser-tool.cpp b/src/ui/tools/eraser-tool.cpp index 1b4dcfe25..3526e015a 100644 --- a/src/ui/tools/eraser-tool.cpp +++ b/src/ui/tools/eraser-tool.cpp @@ -676,7 +676,7 @@ void EraserTool::set_to_accumulated() { Geom::OptRect eraserBbox = acid->visualBounds(); Geom::Rect bounds = (*eraserBbox) * desktop->doc2dt(); std::vector remainingItems; - GSList* toWorkOn = 0; + SelContainer toWorkOn; if (selection->isEmpty()) { if ( eraserMode ) { @@ -686,16 +686,16 @@ void EraserTool::set_to_accumulated() { toWorkOn = desktop->getDocument()->getItemsAtPoints(desktop->dkey, r->getPoints()); } - toWorkOn = g_slist_remove( toWorkOn, acid ); + toWorkOn.remove(static_cast(acid) ); } else { - toWorkOn = g_slist_copy(const_cast(selection->itemList())); + toWorkOn = selection->itemList(); wasSelection = true; } - if ( g_slist_length(toWorkOn) > 0 ) { + if ( !toWorkOn.empty() ) { if ( eraserMode ) { - for (GSList *i = toWorkOn ; i ; i = i->next ) { - SPItem *item = SP_ITEM(i->data); + for (SelContainer::const_iterator i = toWorkOn.begin();i!=toWorkOn.end();i++) { + SPItem *item = SP_ITEM(*i); if ( eraserMode ) { Geom::OptRect bbox = item->visualBounds(); @@ -712,13 +712,10 @@ void EraserTool::set_to_accumulated() { if ( !selection->isEmpty() ) { // If the item was not completely erased, track the new remainder. - GSList *nowSel = g_slist_copy(const_cast(selection->itemList())); - - for (GSList const *i2 = nowSel ; i2 ; i2 = i2->next ) { - remainingItems.push_back(SP_ITEM(i2->data)); + SelContainer nowSel(selection->itemList()); + for (SelContainer::const_iterator i2 = nowSel.begin();i!=nowSel.end();i++) { + remainingItems.push_back(SP_ITEM(*i2)); } - - g_slist_free(nowSel); } } else { remainingItems.push_back(item); @@ -726,20 +723,18 @@ void EraserTool::set_to_accumulated() { } } } else { - for (GSList *i = toWorkOn ; i ; i = i->next ) { - sp_object_ref( SP_ITEM(i->data), 0 ); + for (SelContainer::const_iterator i = toWorkOn.begin();i!=toWorkOn.end();i++) { + sp_object_ref( SP_ITEM(*i), 0 ); } - for (GSList *i = toWorkOn ; i ; i = i->next ) { - SPItem *item = SP_ITEM(i->data); + for (SelContainer::const_iterator i = toWorkOn.begin();i!=toWorkOn.end();i++) { + SPItem *item = SP_ITEM(*i); item->deleteObject(true); sp_object_unref(item); workDone = true; } } - g_slist_free(toWorkOn); - if ( !eraserMode ) { //sp_selection_delete(desktop); remainingItems.clear(); diff --git a/src/ui/tools/gradient-tool.cpp b/src/ui/tools/gradient-tool.cpp index 5da30da7b..d1db5fb93 100644 --- a/src/ui/tools/gradient-tool.cpp +++ b/src/ui/tools/gradient-tool.cpp @@ -116,7 +116,7 @@ void GradientTool::selection_changed(Inkscape::Selection*) { if (selection == NULL) { return; } - guint n_obj = g_slist_length((GSList *) selection->itemList()); + guint n_obj = selection->itemList().size(); if (!drag->isNonEmpty() || selection->isEmpty()) return; @@ -502,10 +502,11 @@ bool GradientTool::root_handler(GdkEvent* event) { if (over_line) { // we take the first item in selection, because with doubleclick, the first click // always resets selection to the single object under cursor - sp_gradient_context_add_stop_near_point(this, SP_ITEM(selection->itemList()->data), this->mousepoint_doc, event->button.time); + sp_gradient_context_add_stop_near_point(this, SP_ITEM(selection->itemList().front()), this->mousepoint_doc, event->button.time); } else { - for (GSList const* i = selection->itemList(); i != NULL; i = i->next) { - SPItem *item = SP_ITEM(i->data); + SelContainer items=selection->itemList(); + for (SelContainer::const_iterator i = items.begin();i!=items.end();i++) { + SPItem *item = SP_ITEM(*i); SPGradientType new_type = (SPGradientType) prefs->getInt("/tools/gradient/newgradient", SP_GRADIENT_TYPE_LINEAR); Inkscape::PaintTarget fsmode = (prefs->getInt("/tools/gradient/newfillorstroke", 1) != 0) ? Inkscape::FOR_FILL : Inkscape::FOR_STROKE; @@ -889,6 +890,12 @@ bool GradientTool::root_handler(GdkEvent* event) { return ret; } +int sp_item_repr_compare_position_obj(SPObject const *first, SPObject const *second) +{ + return sp_repr_compare_position(((SPItem*)first)->getRepr(), + ((SPItem*)second)->getRepr())<0; +} + static void sp_gradient_drag(GradientTool &rc, Geom::Point const pt, guint /*state*/, guint32 etime) { SPDesktop *desktop = SP_EVENT_CONTEXT(&rc)->desktop; @@ -908,32 +915,32 @@ static void sp_gradient_drag(GradientTool &rc, Geom::Point const pt, guint /*sta } else { // Starting from empty space: // Sort items so that the topmost comes last - GSList *items = g_slist_copy ((GSList *) selection->itemList()); - items = g_slist_sort(items, (GCompareFunc) sp_item_repr_compare_position); + SelContainer items(selection->itemList()); + items.sort(sp_item_repr_compare_position_obj); // take topmost - vector = sp_gradient_vector_for_object(document, desktop, SP_ITEM(g_slist_last(items)->data), fill_or_stroke); - g_slist_free (items); + vector = sp_gradient_vector_for_object(document, desktop, SP_ITEM(items.back()), fill_or_stroke); } // HACK: reset fill-opacity - that 0.75 is annoying; BUT remove this when we have an opacity slider for all tabs SPCSSAttr *css = sp_repr_css_attr_new(); sp_repr_css_set_property(css, "fill-opacity", "1.0"); - for (GSList const *i = selection->itemList(); i != NULL; i = i->next) { + SelContainer itemlist = selection->itemList(); + for (SelContainer::const_iterator i = itemlist.begin();i!=itemlist.end();i++) { //FIXME: see above - sp_repr_css_change_recursive(SP_OBJECT(i->data)->getRepr(), css, "style"); + sp_repr_css_change_recursive(SP_OBJECT(*i)->getRepr(), css, "style"); - sp_item_set_gradient(SP_ITEM(i->data), vector, (SPGradientType) type, fill_or_stroke); + sp_item_set_gradient(SP_ITEM(*i), vector, (SPGradientType) type, fill_or_stroke); if (type == SP_GRADIENT_TYPE_LINEAR) { - sp_item_gradient_set_coords (SP_ITEM(i->data), POINT_LG_BEGIN, 0, rc.origin, fill_or_stroke, true, false); - sp_item_gradient_set_coords (SP_ITEM(i->data), POINT_LG_END, 0, pt, fill_or_stroke, true, false); + sp_item_gradient_set_coords (SP_ITEM(*i), POINT_LG_BEGIN, 0, rc.origin, fill_or_stroke, true, false); + sp_item_gradient_set_coords (SP_ITEM(*i), POINT_LG_END, 0, pt, fill_or_stroke, true, false); } else if (type == SP_GRADIENT_TYPE_RADIAL) { - sp_item_gradient_set_coords (SP_ITEM(i->data), POINT_RG_CENTER, 0, rc.origin, fill_or_stroke, true, false); - sp_item_gradient_set_coords (SP_ITEM(i->data), POINT_RG_R1, 0, pt, fill_or_stroke, true, false); + sp_item_gradient_set_coords (SP_ITEM(*i), POINT_RG_CENTER, 0, rc.origin, fill_or_stroke, true, false); + sp_item_gradient_set_coords (SP_ITEM(*i), POINT_RG_R1, 0, pt, fill_or_stroke, true, false); } - SP_OBJECT(i->data)->requestModified(SP_OBJECT_MODIFIED_FLAG); + SP_OBJECT(*i)->requestModified(SP_OBJECT_MODIFIED_FLAG); } if (ec->_grdrag) { ec->_grdrag->updateDraggers(); @@ -942,7 +949,7 @@ static void sp_gradient_drag(GradientTool &rc, Geom::Point const pt, guint /*sta ec->_grdrag->local_change = true; // give the grab out-of-bounds values of xp/yp because we're already dragging // and therefore are already out of tolerance - ec->_grdrag->grabKnot (SP_ITEM(selection->itemList()->data), + ec->_grdrag->grabKnot (SP_ITEM(selection->itemList().front()), type == SP_GRADIENT_TYPE_LINEAR? POINT_LG_END : POINT_RG_R1, -1, // ignore number (though it is always 1) fill_or_stroke, 99999, 99999, etime); @@ -951,7 +958,7 @@ static void sp_gradient_drag(GradientTool &rc, Geom::Point const pt, guint /*sta // status text; we do not track coords because this branch is run once, not all the time // during drag - int n_objects = g_slist_length((GSList *) selection->itemList()); + int n_objects = selection->itemList().size(); rc.message_context->setF(Inkscape::NORMAL_MESSAGE, ngettext("Gradient for %d object; with Ctrl to snap angle", "Gradient for %d objects; with Ctrl to snap angle", n_objects), diff --git a/src/ui/tools/gradient-tool.h b/src/ui/tools/gradient-tool.h index 6fe3bca9f..786aed372 100644 --- a/src/ui/tools/gradient-tool.h +++ b/src/ui/tools/gradient-tool.h @@ -18,6 +18,7 @@ #include #include #include "ui/tools/tool-base.h" +class SPObject;//kill it #define SP_GRADIENT_CONTEXT(obj) (dynamic_cast((Inkscape::UI::Tools::ToolBase*)obj)) #define SP_IS_GRADIENT_CONTEXT(obj) (dynamic_cast((const Inkscape::UI::Tools::ToolBase*)obj) != NULL) @@ -25,12 +26,12 @@ namespace Inkscape { namespace UI { namespace Tools { +int sp_item_repr_compare_position_obj(SPObject const *first, SPObject const *second);//kill it class GradientTool : public ToolBase { public: GradientTool(); virtual ~GradientTool(); - Geom::Point origin; bool cursor_addnode; diff --git a/src/ui/tools/lpe-tool.cpp b/src/ui/tools/lpe-tool.cpp index c9b656397..ce0ad7a9a 100644 --- a/src/ui/tools/lpe-tool.cpp +++ b/src/ui/tools/lpe-tool.cpp @@ -407,10 +407,10 @@ lpetool_create_measuring_items(LpeTool *lc, Inkscape::Selection *selection) SPCanvasGroup *tmpgrp = lc->desktop->getTempGroup(); gchar *arc_length; double lengthval; - - for (GSList const *i = selection->itemList(); i != NULL; i = i->next) { - if (SP_IS_PATH(i->data)) { - path = SP_PATH(i->data); + SelContainer items=selection->itemList(); + for(SelContainer::const_iterator i=items.begin();i!=items.end();i++){ + if (SP_IS_PATH(*i)) { + path = SP_PATH(*i); curve = path->getCurve(); Geom::Piecewise > pwd2 = paths_to_pw(curve->get_pathvector()); canvas_text = (SPCanvasText *) sp_canvastext_new(tmpgrp, lc->desktop, Geom::Point(0,0), ""); diff --git a/src/ui/tools/measure-tool.cpp b/src/ui/tools/measure-tool.cpp index b7e54b9c8..8d52210ff 100644 --- a/src/ui/tools/measure-tool.cpp +++ b/src/ui/tools/measure-tool.cpp @@ -441,10 +441,10 @@ bool MeasureTool::root_handler(GdkEvent* event) { // TODO switch to a different variable name. The single letter 'l' is easy to misread. //select elements crossed by line segment: - GSList *items = desktop->getDocument()->getItemsAtPoints(desktop->dkey, points); + SelContainer items = desktop->getDocument()->getItemsAtPoints(desktop->dkey, points); std::vector intersection_times; - for (GSList *l = items; l != NULL; l = l->next) { - SPItem *item = static_cast(l->data); + for (SelContainer::const_iterator i=items.begin();i!=items.end();i++) { + SPItem *item = static_cast(*i); if (SP_IS_SHAPE(item)) { calculate_intersections(desktop, item, lineseg, SP_SHAPE(item)->getCurve(), intersection_times); diff --git a/src/ui/tools/mesh-tool.cpp b/src/ui/tools/mesh-tool.cpp index d333b932e..1cc06a5b9 100644 --- a/src/ui/tools/mesh-tool.cpp +++ b/src/ui/tools/mesh-tool.cpp @@ -48,6 +48,7 @@ // Mesh specific #include "ui/tools/mesh-tool.h" +#include "ui/tools/gradient-tool.h"//not needed #include "sp-mesh-gradient.h" #include "display/sp-ctrlcurve.h" @@ -113,7 +114,7 @@ void MeshTool::selection_changed(Inkscape::Selection* /*sel*/) { return; } - guint n_obj = g_slist_length((GSList *) selection->itemList()); + guint n_obj = selection->itemList().size(); if (!drag->isNonEmpty() || selection->isEmpty()) { return; @@ -477,11 +478,12 @@ bool MeshTool::root_handler(GdkEvent* event) { if (over_line) { // We take the first item in selection, because with doubleclick, the first click // always resets selection to the single object under cursor - sp_mesh_context_split_near_point(this, SP_ITEM(selection->itemList()->data), this->mousepoint_doc, event->button.time); + sp_mesh_context_split_near_point(this, SP_ITEM(selection->itemList().front()), this->mousepoint_doc, event->button.time); } else { // Create a new gradient with default coordinates. - for (GSList const* i = selection->itemList(); i != NULL; i = i->next) { - SPItem *item = SP_ITEM(i->data); + SelContainer items=selection->itemList(); + for(SelContainer::const_iterator i=items.begin();i!=items.end();i++){ + SPItem *item = SP_ITEM(*i); SPGradientType new_type = SP_GRADIENT_TYPE_MESH; Inkscape::PaintTarget fsmode = (prefs->getInt("/tools/gradient/newfillorstroke", 1) != 0) ? Inkscape::FOR_FILL : Inkscape::FOR_STROKE; @@ -930,6 +932,12 @@ bool MeshTool::root_handler(GdkEvent* event) { return ret; } +/* +int sp_item_repr_compare_position_obj(SPObject const *first, SPObject const *second) +{ + return sp_repr_compare_position(((SPItem*)first)->getRepr(), + ((SPItem*)second)->getRepr())<0; +}*/ static void sp_mesh_drag(MeshTool &rc, Geom::Point const /*pt*/, guint /*state*/, guint32 /*etime*/) { SPDesktop *desktop = SP_EVENT_CONTEXT(&rc)->desktop; @@ -950,27 +958,27 @@ static void sp_mesh_drag(MeshTool &rc, Geom::Point const /*pt*/, guint /*state*/ } else { // Starting from empty space: // Sort items so that the topmost comes last - GSList *items = g_slist_copy ((GSList *) selection->itemList()); - items = g_slist_sort(items, (GCompareFunc) sp_item_repr_compare_position); + SelContainer items(selection->itemList()); + items.sort(sp_item_repr_compare_position_obj); // take topmost - vector = sp_gradient_vector_for_object(document, desktop, SP_ITEM(g_slist_last(items)->data), fill_or_stroke); - g_slist_free (items); + vector = sp_gradient_vector_for_object(document, desktop, SP_ITEM(items.back()), fill_or_stroke); } // HACK: reset fill-opacity - that 0.75 is annoying; BUT remove this when we have an opacity slider for all tabs SPCSSAttr *css = sp_repr_css_attr_new(); sp_repr_css_set_property(css, "fill-opacity", "1.0"); - for (GSList const *i = selection->itemList(); i != NULL; i = i->next) { + SelContainer items=selection->itemList(); + for(SelContainer::const_iterator i=items.begin();i!=items.end();i++){ //FIXME: see above - sp_repr_css_change_recursive(SP_OBJECT(i->data)->getRepr(), css, "style"); + sp_repr_css_change_recursive(SP_OBJECT(*i)->getRepr(), css, "style"); - sp_item_set_gradient(SP_ITEM(i->data), vector, (SPGradientType) type, fill_or_stroke); + sp_item_set_gradient(SP_ITEM(*i), vector, (SPGradientType) type, fill_or_stroke); // We don't need to do anything. Mesh is already sized appropriately. - SP_OBJECT(i->data)->requestModified(SP_OBJECT_MODIFIED_FLAG); + SP_OBJECT(*i)->requestModified(SP_OBJECT_MODIFIED_FLAG); } // if (ec->_grdrag) { // ec->_grdrag->updateDraggers(); @@ -988,7 +996,7 @@ static void sp_mesh_drag(MeshTool &rc, Geom::Point const /*pt*/, guint /*state*/ // status text; we do not track coords because this branch is run once, not all the time // during drag - int n_objects = g_slist_length((GSList *) selection->itemList()); + int n_objects = selection->itemList().size(); rc.message_context->setF(Inkscape::NORMAL_MESSAGE, ngettext("Gradient for %d object; with Ctrl to snap angle", "Gradient for %d objects; with Ctrl to snap angle", n_objects), diff --git a/src/ui/tools/node-tool.cpp b/src/ui/tools/node-tool.cpp index caec901a6..46c978c84 100644 --- a/src/ui/tools/node-tool.cpp +++ b/src/ui/tools/node-tool.cpp @@ -420,10 +420,9 @@ void NodeTool::selection_changed(Inkscape::Selection *sel) { std::set shapes; - GSList const *ilist = sel->itemList(); - - for (GSList *i = const_cast(ilist); i; i = i->next) { - SPObject *obj = static_cast(i->data); + SelContainer items=sel->itemList(); + for(SelContainer::const_iterator i=items.begin();i!=items.end();i++){ + SPObject *obj = static_cast(*i); if (SP_IS_ITEM(obj)) { gather_items(this, NULL, static_cast(obj), SHAPE_ROLE_NORMAL, shapes); @@ -668,9 +667,8 @@ void NodeTool::select_area(Geom::Rect const &sel, GdkEventButton *event) { if (this->_multipath->empty()) { // if multipath is empty, select rubberbanded items rather than nodes Inkscape::Selection *selection = this->desktop->selection; - GSList *items = this->desktop->getDocument()->getItemsInBox(this->desktop->dkey, sel); + SelContainer items = this->desktop->getDocument()->getItemsInBox(this->desktop->dkey, sel); selection->setList(items); - g_slist_free(items); } else { if (!held_shift(*event)) { this->_selected_nodes->clear(); diff --git a/src/ui/tools/select-tool.cpp b/src/ui/tools/select-tool.cpp index 939b1a0b3..f84170631 100644 --- a/src/ui/tools/select-tool.cpp +++ b/src/ui/tools/select-tool.cpp @@ -481,7 +481,7 @@ bool SelectTool::root_handler(GdkEvent* event) { case GDK_2BUTTON_PRESS: if (event->button.button == 1) { if (!selection->isEmpty()) { - SPItem *clicked_item = static_cast(selection->itemList()->data); + SPItem *clicked_item = static_cast(selection->itemList().front()); if (dynamic_cast(clicked_item) && !dynamic_cast(clicked_item)) { // enter group if it's not a 3D box desktop->setCurrentLayer(clicked_item); @@ -718,7 +718,7 @@ bool SelectTool::root_handler(GdkEvent* event) { if (r->is_started() && !within_tolerance) { // this was a rubberband drag - GSList *items = NULL; + SelContainer items; if (r->getMode() == RUBBERBAND_MODE_RECT) { Geom::OptRect const b = r->getRectangle(); @@ -739,7 +739,6 @@ bool SelectTool::root_handler(GdkEvent* event) { selection->setList (items); } - g_slist_free (items); } else { // it was just a click, or a too small rubberband r->stop(); diff --git a/src/ui/tools/spray-tool.cpp b/src/ui/tools/spray-tool.cpp index a01c5c55b..d339f6d19 100644 --- a/src/ui/tools/spray-tool.cpp +++ b/src/ui/tools/spray-tool.cpp @@ -188,7 +188,7 @@ void SprayTool::update_cursor(bool /*with_shift*/) { gchar *sel_message = NULL; if (!desktop->selection->isEmpty()) { - num = g_slist_length(const_cast(desktop->selection->itemList())); + num = desktop->selection->itemList().size(); sel_message = g_strdup_printf(ngettext("%i object selected","%i objects selected",num), num); } else { sel_message = g_strdup_printf("%s", _("Nothing selected")); @@ -436,11 +436,9 @@ static bool sp_spray_recursive(SPDesktop *desktop, SPItem *unionResult = NULL; // Previous union int i=1; - for (GSList *items = g_slist_copy(const_cast(selection->itemList())); - items != NULL; - items = items->next) { - - SPItem *item1 = dynamic_cast(static_cast(items->data)); + SelContainer items=selection->itemList(); + for(SelContainer::const_iterator it=items.begin();it!=items.end();it++){ + SPItem *item1 = dynamic_cast(static_cast(*it)); if (i == 1) { parent_item = item1; } @@ -552,20 +550,16 @@ static bool sp_spray_dilate(SprayTool *tc, Geom::Point /*event_p*/, Geom::Point double move_standard_deviation = get_move_standard_deviation(tc); { - GSList *const original_selection = g_slist_copy(const_cast(selection->itemList())); + SelContainer const items(selection->itemList()); - for (GSList *items = original_selection; - items != NULL; - items = items->next) { - SPItem *item = dynamic_cast(static_cast(items->data)); + for(SelContainer::const_iterator i=items.begin();i!=items.end();i++){ + SPItem *item = dynamic_cast(static_cast(*i)); g_assert(item != NULL); sp_object_ref(item); } - for (GSList *items = original_selection; - items != NULL; - items = items->next) { - SPItem *item = dynamic_cast(static_cast(items->data)); + for(SelContainer::const_iterator i=items.begin();i!=items.end();i++){ + SPItem *item = dynamic_cast(static_cast(*i)); g_assert(item != NULL); if (is_transform_modes(tc->mode)) { @@ -579,10 +573,8 @@ static bool sp_spray_dilate(SprayTool *tc, Geom::Point /*event_p*/, Geom::Point } } - for (GSList *items = original_selection; - items != NULL; - items = items->next) { - SPItem *item = dynamic_cast(static_cast(items->data)); + for(SelContainer::const_iterator i=items.begin();i!=items.end();i++){ + SPItem *item = dynamic_cast(static_cast(*i)); g_assert(item != NULL); sp_object_unref(item); } @@ -658,7 +650,7 @@ bool SprayTool::root_handler(GdkEvent* event) { guint num = 0; if (!desktop->selection->isEmpty()) { - num = g_slist_length(const_cast(desktop->selection->itemList())); + num = desktop->selection->itemList().size(); } if (num == 0) { this->message_context->flash(Inkscape::ERROR_MESSAGE, _("Nothing selected! Select objects to spray.")); diff --git a/src/ui/tools/text-tool.cpp b/src/ui/tools/text-tool.cpp index df0583d67..a4370256d 100644 --- a/src/ui/tools/text-tool.cpp +++ b/src/ui/tools/text-tool.cpp @@ -1470,7 +1470,7 @@ int TextTool::_styleQueried(SPStyle *style, int property) } sp_text_context_validate_cursor_iterators(this); - GSList *styles_list = NULL; + SelContainer styles_list; Inkscape::Text::Layout::iterator begin_it, end_it; if (this->text_sel_start < this->text_sel_end) { @@ -1486,7 +1486,7 @@ int TextTool::_styleQueried(SPStyle *style, int property) } } for (Inkscape::Text::Layout::iterator it = begin_it ; it < end_it ; it.nextStartOfSpan()) { - SPObject const *pos_obj = 0; + SPObject *pos_obj = 0; void *rawptr = 0; layout->getSourceOfCharacter(it, &rawptr); if (!rawptr || !SP_IS_OBJECT(rawptr)) { @@ -1496,12 +1496,11 @@ int TextTool::_styleQueried(SPStyle *style, int property) while (SP_IS_STRING(pos_obj) && pos_obj->parent) { pos_obj = pos_obj->parent; // SPStrings don't have style } - styles_list = g_slist_prepend(styles_list, (gpointer)pos_obj); + styles_list.push_front(pos_obj); } int result = sp_desktop_query_style_from_list (styles_list, style, property); - g_slist_free(styles_list); return result; } diff --git a/src/ui/tools/tool-base.cpp b/src/ui/tools/tool-base.cpp index a07f2fb86..cc05f9775 100644 --- a/src/ui/tools/tool-base.cpp +++ b/src/ui/tools/tool-base.cpp @@ -1178,11 +1178,9 @@ SPItem *sp_event_context_find_item(SPDesktop *desktop, Geom::Point const &p, SPItem * sp_event_context_over_item(SPDesktop *desktop, SPItem *item, Geom::Point const &p) { - GSList *temp = NULL; - temp = g_slist_prepend(temp, item); + SelContainer temp; + temp.push_front(static_cast(item)); SPItem *item_at_point = desktop->getItemFromListAtPointBottom(temp, p); - g_slist_free(temp); - return item_at_point; } diff --git a/src/ui/tools/tweak-tool.cpp b/src/ui/tools/tweak-tool.cpp index 5e53fdb93..9342127ce 100644 --- a/src/ui/tools/tweak-tool.cpp +++ b/src/ui/tools/tweak-tool.cpp @@ -163,7 +163,7 @@ void TweakTool::update_cursor (bool with_shift) { gchar *sel_message = NULL; if (!desktop->selection->isEmpty()) { - num = g_slist_length(const_cast(desktop->selection->itemList())); + num = desktop->selection->itemList().size(); sel_message = g_strdup_printf(ngettext("%i object selected","%i objects selected",num), num); } else { sel_message = g_strdup_printf("%s", _("Nothing selected")); @@ -382,14 +382,13 @@ sp_tweak_dilate_recursive (Inkscape::Selection *selection, SPItem *item, Geom::P } if (dynamic_cast(item) || dynamic_cast(item)) { - GSList *items = g_slist_prepend (NULL, item); - GSList *selected = NULL; - GSList *to_select = NULL; + SelContainer items; + items.push_back(item); + SelContainer selected; + SelContainer to_select; SPDocument *doc = item->document; - sp_item_list_to_curves (items, &selected, &to_select); - g_slist_free (items); - SPObject* newObj = doc->getObjectByRepr(static_cast(to_select->data)); - g_slist_free (to_select); + sp_item_list_to_curves (items, selected, to_select); + SPObject* newObj = doc->getObjectByRepr(dynamic_cast(to_select.front())); item = dynamic_cast(newObj); g_assert(item != NULL); selection->add(item); @@ -1088,11 +1087,9 @@ sp_tweak_dilate (TweakTool *tc, Geom::Point event_p, Geom::Point p, Geom::Point double move_force = get_move_force(tc); double color_force = MIN(sqrt(path_force)/20.0, 1); - for (GSList *items = g_slist_copy(const_cast(selection->itemList())); - items != NULL; - items = items->next) { - - SPItem *item = dynamic_cast(static_cast(items->data)); + SelContainer items=selection->itemList(); + for(SelContainer::const_iterator i=items.begin();i!=items.end();i++){ + SPItem *item = dynamic_cast(static_cast(*i)); if (is_color_mode (tc->mode)) { if (do_fill || do_stroke || do_opacity) { @@ -1199,7 +1196,7 @@ bool TweakTool::root_handler(GdkEvent* event) { guint num = 0; if (!desktop->selection->isEmpty()) { - num = g_slist_length(const_cast(desktop->selection->itemList())); + num = desktop->selection->itemList().size(); } if (num == 0) { this->message_context->flash(Inkscape::ERROR_MESSAGE, _("Nothing selected! Select objects to tweak.")); diff --git a/src/ui/widget/object-composite-settings.cpp b/src/ui/widget/object-composite-settings.cpp index 00a74c4fe..ddf67fb5b 100644 --- a/src/ui/widget/object-composite-settings.cpp +++ b/src/ui/widget/object-composite-settings.cpp @@ -125,7 +125,8 @@ ObjectCompositeSettings::_blendBlurValueChanged() const Glib::ustring blendmode = _fe_cb.get_blend_mode(); //apply created filter to every selected item - for (StyleSubject::iterator i = _subject->begin() ; i != _subject->end() ; ++i ) { + SelContainer sel=_subject->getDesktop()->getSelection()->itemList(); + for (SelContainer::const_iterator i = sel.begin() ; i != sel.end() ; ++i ) { if (!SP_IS_ITEM(*i)) { continue; } diff --git a/src/ui/widget/style-subject.cpp b/src/ui/widget/style-subject.cpp index a48370d9b..9d09e67d3 100644 --- a/src/ui/widget/style-subject.cpp +++ b/src/ui/widget/style-subject.cpp @@ -54,7 +54,7 @@ Inkscape::Selection *StyleSubject::Selection::_getSelection() const { return NULL; } } - +/* StyleSubject::iterator StyleSubject::Selection::begin() { Inkscape::Selection *selection = _getSelection(); if (selection) { @@ -62,7 +62,7 @@ StyleSubject::iterator StyleSubject::Selection::begin() { } else { return iterator(NULL); } -} +}*/ Geom::OptRect StyleSubject::Selection::getBounds(SPItem::BBoxType type) { Inkscape::Selection *selection = _getSelection(); @@ -104,8 +104,7 @@ void StyleSubject::Selection::setCSS(SPCSSAttr *css) { } StyleSubject::CurrentLayer::CurrentLayer() { - _element.data = NULL; - _element.next = NULL; + _element = NULL; } StyleSubject::CurrentLayer::~CurrentLayer() { @@ -114,10 +113,10 @@ StyleSubject::CurrentLayer::~CurrentLayer() { void StyleSubject::CurrentLayer::_setLayer(SPObject *layer) { _layer_release.disconnect(); _layer_modified.disconnect(); - if (_element.data) { - sp_object_unref(static_cast(_element.data), NULL); + if (_element) { + sp_object_unref(static_cast(_element), NULL); } - _element.data = layer; + _element = layer; if (layer) { sp_object_ref(layer, NULL); _layer_release = layer->connectRelease(sigc::hide(sigc::bind(sigc::mem_fun(*this, &CurrentLayer::_setLayer), (SPObject *)NULL))); @@ -127,20 +126,17 @@ void StyleSubject::CurrentLayer::_setLayer(SPObject *layer) { } SPObject *StyleSubject::CurrentLayer::_getLayer() const { - return static_cast(_element.data); + return static_cast(_element); } -GSList *StyleSubject::CurrentLayer::_getLayerSList() const { - if (_element.data) { - return &_element; - } else { - return NULL; - } -} +SPObject *StyleSubject::CurrentLayer::_getLayerSList() const { + return _element; +} +/* StyleSubject::iterator StyleSubject::CurrentLayer::begin() { return iterator(_getLayerSList()); -} +}*/ Geom::OptRect StyleSubject::CurrentLayer::getBounds(SPItem::BBoxType type) { SPObject *layer = _getLayer(); @@ -152,8 +148,10 @@ Geom::OptRect StyleSubject::CurrentLayer::getBounds(SPItem::BBoxType type) { } int StyleSubject::CurrentLayer::queryStyle(SPStyle *query, int property) { - GSList *list = _getLayerSList(); - if (list) { + SelContainer list; + SPObject* i=_getLayerSList(); + if (i) { + list.push_back(i); return sp_desktop_query_style_from_list(list, query, property); } else { return QUERY_STYLE_NOTHING; diff --git a/src/ui/widget/style-subject.h b/src/ui/widget/style-subject.h index 47da91732..60f979eb0 100644 --- a/src/ui/widget/style-subject.h +++ b/src/ui/widget/style-subject.h @@ -35,7 +35,8 @@ public: class Selection; class CurrentLayer; - typedef Util::GSListConstIterator iterator; + //typedef Util::GSListConstIterator iterator; + typedef std::list::iterator iterator; StyleSubject(); virtual ~StyleSubject(); @@ -43,8 +44,8 @@ public: void setDesktop(SPDesktop *desktop); SPDesktop *getDesktop() const { return _desktop; } - virtual iterator begin() = 0; - virtual iterator end() { return iterator(NULL); } +// virtual iterator begin() = 0; +// virtual iterator end() { return iterator(NULL); } virtual Geom::OptRect getBounds(SPItem::BBoxType type) = 0; virtual int queryStyle(SPStyle *query, int property) = 0; virtual void setCSS(SPCSSAttr *css) = 0; @@ -67,7 +68,7 @@ public: Selection(); ~Selection(); - virtual iterator begin(); +// virtual iterator begin(); virtual Geom::OptRect getBounds(SPItem::BBoxType type); virtual int queryStyle(SPStyle *query, int property); virtual void setCSS(SPCSSAttr *css); @@ -88,7 +89,7 @@ public: CurrentLayer(); ~CurrentLayer(); - virtual iterator begin(); +// virtual iterator begin(); virtual Geom::OptRect getBounds(SPItem::BBoxType type); virtual int queryStyle(SPStyle *query, int property); virtual void setCSS(SPCSSAttr *css); @@ -99,12 +100,12 @@ protected: private: SPObject *_getLayer() const; void _setLayer(SPObject *layer); - GSList *_getLayerSList() const; + SPObject *_getLayerSList() const; sigc::connection _layer_switched; sigc::connection _layer_release; sigc::connection _layer_modified; - mutable GSList _element; + mutable SPObject* _element; }; } -- cgit v1.2.3 From cc22d3551937d17c596e4dd209060b16a714d463 Mon Sep 17 00:00:00 2001 From: Mc <> Date: Wed, 18 Feb 2015 02:17:25 +0100 Subject: OMG IT'S COMPILING. IT'S REALLY COMPILING ! (Of course it segfaults (what did you expect ?)) (bzr r13922.1.3) --- src/selection-chemistry.cpp | 174 +++++++++++++++++++++----------------------- 1 file changed, 83 insertions(+), 91 deletions(-) (limited to 'src') diff --git a/src/selection-chemistry.cpp b/src/selection-chemistry.cpp index 05711e734..c213e76e4 100644 --- a/src/selection-chemistry.cpp +++ b/src/selection-chemistry.cpp @@ -2298,17 +2298,9 @@ sp_selection_move_screen(Inkscape::Selection *selection, gdouble dx, gdouble dy) } } -namespace { -template -SPItem *next_item(SPDesktop *desktop, GSList *path, SPObject *root, - bool only_in_viewport, PrefsSelectionContext inlayer, bool onlyvisible, bool onlysensitive); - -template -SPItem *next_item_from_list(SPDesktop *desktop, SelContainer const &items, SPObject *root, - bool only_in_viewport, PrefsSelectionContext inlayer, bool onlyvisible, bool onlysensitive); -struct Forward { +typedef struct Forward { typedef SPObject *Iterator; static Iterator children(SPObject *o) { return o->firstChild(); } @@ -2317,9 +2309,9 @@ struct Forward { static SPObject *object(Iterator i) { return i; } static Iterator next(Iterator i) { return i->getNext(); } -}; +} Forward; -struct ListReverse { +typedef struct ListReverse { typedef GSList *Iterator; static Iterator children(SPObject *o) { @@ -2350,8 +2342,87 @@ private: } return list; } -}; +} ListReverse; + + + +template +SPItem *next_item(SPDesktop *desktop, GSList *path, SPObject *root, + bool only_in_viewport, PrefsSelectionContext inlayer, bool onlyvisible, bool onlysensitive) +{ + typename D::Iterator children; + typename D::Iterator iter; + + SPItem *found=NULL; + + if (path) { + SPObject *object=reinterpret_cast(path->data); + g_assert(object->parent == root); + if (desktop->isLayer(object)) { + found = next_item(desktop, path->next, object, only_in_viewport, inlayer, onlyvisible, onlysensitive); + } + iter = children = D::siblings_after(object); + } else { + iter = children = D::children(root); + } + + while ( iter && !found ) { + SPObject *object=D::object(iter); + if (desktop->isLayer(object)) { + if (PREFS_SELECTION_LAYER != inlayer) { // recurse into sublayers + found = next_item(desktop, NULL, object, only_in_viewport, inlayer, onlyvisible, onlysensitive); + } + } else { + SPItem *item = dynamic_cast(object); + if ( item && + ( !only_in_viewport || desktop->isWithinViewport(item) ) && + ( !onlyvisible || !desktop->itemIsHidden(item)) && + ( !onlysensitive || !item->isLocked()) && + !desktop->isLayer(item) ) + { + found = item; + } + } + iter = D::next(iter); + } + + D::dispose(children); + return found; +} + + +template +SPItem *next_item_from_list(SPDesktop *desktop, SelContainer const items, + SPObject *root, bool only_in_viewport, PrefsSelectionContext inlayer, bool onlyvisible, bool onlysensitive) +{ + SPObject *current=root; + for(SelContainer::const_iterator i = items.begin();i!=items.end();i++) { + SPItem *item = dynamic_cast(static_cast(*i)); + if ( root->isAncestorOf(item) && + ( !only_in_viewport || desktop->isWithinViewport(item) ) ) + { + current = item; + break; + } + } + + GSList *path=NULL; + while ( current != root ) { + path = g_slist_prepend(path, current); + current = current->parent; + } + + SPItem *next; + // first, try from the current object + next = next_item(desktop, path, root, only_in_viewport, inlayer, onlyvisible, onlysensitive); + g_slist_free(path); + + if (!next) { // if we ran out of objects, start over at the root + next = next_item(desktop, NULL, root, only_in_viewport, inlayer, onlyvisible, onlysensitive); + } + + return next; } void @@ -2478,87 +2549,8 @@ void sp_selection_edit_clip_or_mask(SPDesktop * /*dt*/, bool /*clip*/) } -namespace { -template -SPItem *next_item_from_list(SPDesktop *desktop, SelContainer const items, - SPObject *root, bool only_in_viewport, PrefsSelectionContext inlayer, bool onlyvisible, bool onlysensitive) -{ - SPObject *current=root; - for(SelContainer::const_iterator i = items.begin();i!=items.end();i++) { - SPItem *item = dynamic_cast(static_cast(*i)); - if ( root->isAncestorOf(item) && - ( !only_in_viewport || desktop->isWithinViewport(item) ) ) - { - current = item; - break; - } - } - GSList *path=NULL; - while ( current != root ) { - path = g_slist_prepend(path, current); - current = current->parent; - } - - SPItem *next; - // first, try from the current object - next = next_item(desktop, path, root, only_in_viewport, inlayer, onlyvisible, onlysensitive); - g_slist_free(path); - - if (!next) { // if we ran out of objects, start over at the root - next = next_item(desktop, NULL, root, only_in_viewport, inlayer, onlyvisible, onlysensitive); - } - - return next; -} - -template -SPItem *next_item(SPDesktop *desktop, GSList *path, SPObject *root, - bool only_in_viewport, PrefsSelectionContext inlayer, bool onlyvisible, bool onlysensitive) -{ - typename D::Iterator children; - typename D::Iterator iter; - - SPItem *found=NULL; - - if (path) { - SPObject *object=reinterpret_cast(path->data); - g_assert(object->parent == root); - if (desktop->isLayer(object)) { - found = next_item(desktop, path->next, object, only_in_viewport, inlayer, onlyvisible, onlysensitive); - } - iter = children = D::siblings_after(object); - } else { - iter = children = D::children(root); - } - - while ( iter && !found ) { - SPObject *object=D::object(iter); - if (desktop->isLayer(object)) { - if (PREFS_SELECTION_LAYER != inlayer) { // recurse into sublayers - found = next_item(desktop, NULL, object, only_in_viewport, inlayer, onlyvisible, onlysensitive); - } - } else { - SPItem *item = dynamic_cast(object); - if ( item && - ( !only_in_viewport || desktop->isWithinViewport(item) ) && - ( !onlyvisible || !desktop->itemIsHidden(item)) && - ( !onlysensitive || !item->isLocked()) && - !desktop->isLayer(item) ) - { - found = item; - } - } - iter = D::next(iter); - } - - D::dispose(children); - - return found; -} - -} /** * If \a item is not entirely visible then adjust visible area to centre on the centre on of -- cgit v1.2.3 From 9e21d00fb1053897420f80d05a9815c5b2bbf312 Mon Sep 17 00:00:00 2001 From: mc <> Date: Wed, 18 Feb 2015 11:25:23 +0100 Subject: I can't really understand why, but i can now launch inkscape without it segfaulting. That's an improvement. Next thing: code cleaning, replacing containers with vectors (bzr r13922.1.4) --- src/selection-chemistry.cpp | 82 ++++++++++++++------------------- src/selection.cpp | 10 ++-- src/selection.h | 4 +- src/splivarot.cpp | 6 +-- src/ui/dialog/export.cpp | 12 ++--- src/ui/dialog/filter-effects-dialog.cpp | 2 +- src/ui/dialog/svg-fonts-dialog.cpp | 4 +- 7 files changed, 53 insertions(+), 67 deletions(-) (limited to 'src') diff --git a/src/selection-chemistry.cpp b/src/selection-chemistry.cpp index c213e76e4..9f27ca22e 100644 --- a/src/selection-chemistry.cpp +++ b/src/selection-chemistry.cpp @@ -462,13 +462,13 @@ void sp_selection_duplicate(SPDesktop *desktop, bool suppressDone) desktop->messageStack()->flash(Inkscape::WARNING_MESSAGE, _("Select object(s) to duplicate.")); return; } - SelContainer reprs(selection->reprList()); + std::vector reprs(selection->reprList()); selection->clear(); // sorting items from different parents sorts each parent's subset without possibly mixing // them, just what we need - reprs.sort(sp_repr_compare_position_obj); + sort(reprs.begin(),reprs.end(),sp_repr_compare_position); SelContainer newsel; @@ -478,8 +478,8 @@ void sp_selection_duplicate(SPDesktop *desktop, bool suppressDone) bool relink_clones = prefs->getBool("/options/relinkclonesonduplicate/value"); const bool fork_livepatheffects = prefs->getBool("/options/forklpeonduplicate/value", true); - while (!reprs.empty()) { - Inkscape::XML::Node *old_repr = dynamic_cast(reprs.front()); + for(std::vector::const_iterator i=reprs.begin();i!=reprs.end();i++){ + Inkscape::XML::Node *old_repr = (*i); Inkscape::XML::Node *parent = old_repr->parent(); Inkscape::XML::Node *copy = old_repr->duplicate(xml_doc); @@ -501,7 +501,6 @@ void sp_selection_duplicate(SPDesktop *desktop, bool suppressDone) } newsel.push_front(dynamic_cast(copy)); - reprs.pop_front(); Inkscape::GC::release(copy); } @@ -692,16 +691,16 @@ void sp_edit_invert_in_all_layers(SPDesktop *desktop) sp_edit_select_all_full(desktop, true, true); } -static void sp_selection_group_impl(SelContainer p, Inkscape::XML::Node *group, Inkscape::XML::Document *xml_doc, SPDocument *doc) { +static void sp_selection_group_impl(std::vector p, Inkscape::XML::Node *group, Inkscape::XML::Document *xml_doc, SPDocument *doc) { - p.sort(sp_repr_compare_position_obj); + sort(p.begin(),p.end(),sp_repr_compare_position); // Remember the position and parent of the topmost object. gint topmost = (dynamic_cast(p.back()))->position(); Inkscape::XML::Node *topmost_parent = (dynamic_cast(p.back()))->parent(); - while (!p.empty()) { - Inkscape::XML::Node *current = dynamic_cast(p.front()); + for(std::vector::const_iterator i=p.begin();i!=p.end();i++){ + Inkscape::XML::Node *current = (*i); if (current->parent() == topmost_parent) { Inkscape::XML::Node *spnew = current->duplicate(xml_doc); @@ -745,7 +744,6 @@ static void sp_selection_group_impl(SelContainer p, Inkscape::XML::Node *group, copied.clear(); } } - p.pop_front(); } // Add the new group to the topmost members' parent @@ -766,7 +764,7 @@ void sp_selection_group(Inkscape::Selection *selection, SPDesktop *desktop) return; } - SelContainer p (selection->reprList()); + std::vector p (selection->reprList()); selection->clear(); @@ -1027,16 +1025,14 @@ void sp_selection_raise_to_top(Inkscape::Selection *selection, SPDesktop *deskto return; } - SelContainer rl(selection->reprList()); - rl.sort(sp_repr_compare_position_obj); + std::vector rl(selection->reprList()); + sort(rl.begin(),rl.end(),sp_repr_compare_position); - for (SelContainer::iterator l=rl.begin(); l!=rl.end();l++) { - Inkscape::XML::Node *repr = dynamic_cast(*l); + for (std::vector::const_iterator l=rl.begin(); l!=rl.end();l++) { + Inkscape::XML::Node *repr =(*l); repr->setPosition(-1); } - rl.clear(); - DocumentUndo::done(document, SP_VERB_SELECTION_TO_FRONT, _("Raise to top")); } @@ -1117,14 +1113,13 @@ void sp_selection_lower_to_bottom(Inkscape::Selection *selection, SPDesktop *des return; } - SelContainer rl(selection->reprList()); - rl.sort(sp_repr_compare_position_obj); - rl.reverse(); + std::vector rl(selection->reprList()); + sort(rl.begin(),rl.end(),sp_repr_compare_position); - for (SelContainer::const_iterator l=rl.begin();l!=rl.end();l++) { + for (std::vector::const_reverse_iterator l=rl.rbegin();l!=rl.rend();l++) { gint minpos; SPObject *pp, *pc; - Inkscape::XML::Node *repr = dynamic_cast(*l); + Inkscape::XML::Node *repr = (*l); pp = document->getObjectByRepr(repr->parent()); minpos = 0; g_assert(dynamic_cast(pp)); @@ -1136,8 +1131,6 @@ void sp_selection_lower_to_bottom(Inkscape::Selection *selection, SPDesktop *des repr->setPosition(minpos); } - rl.clear(); - DocumentUndo::done(document, SP_VERB_SELECTION_TO_BACK, _("Lower to bottom")); } @@ -1691,9 +1684,9 @@ void sp_selection_remove_transform(SPDesktop *desktop) Inkscape::Selection *selection = desktop->getSelection(); - SelContainer items = selection->itemList(); - for (SelContainer::const_iterator l=items.begin();l!=items.end() ;l++) { - ((Inkscape::XML::Node*)*l)->setAttribute("transform", NULL, false); + std::vector items = selection->reprList(); + for (std::vector::const_iterator l=items.begin();l!=items.end() ;l++) { + (*l)->setAttribute("transform", NULL, false); } DocumentUndo::done(desktop->getDocument(), SP_VERB_OBJECT_FLATTEN, @@ -2590,17 +2583,17 @@ void sp_selection_clone(SPDesktop *desktop) return; } - SelContainer reprs (selection->reprList()); + std::vector reprs (selection->reprList()); selection->clear(); // sorting items from different parents sorts each parent's subset without possibly mixing them, just what we need - reprs.sort(sp_repr_compare_position_obj); + sort(reprs.begin(),reprs.end(),sp_repr_compare_position); SelContainer newsel; - while (!reprs.empty()) { - Inkscape::XML::Node *sel_repr = dynamic_cast(reprs.front()); + for(std::vector::const_iterator i=reprs.begin();i!=reprs.end();i++){ + Inkscape::XML::Node *sel_repr = *i; Inkscape::XML::Node *parent = sel_repr->parent(); Inkscape::XML::Node *clone = xml_doc->createElement("svg:use"); @@ -2617,7 +2610,6 @@ void sp_selection_clone(SPDesktop *desktop) parent->appendChild(clone); newsel.push_front(dynamic_cast(clone)); - reprs.pop_front(); Inkscape::GC::release(clone); } @@ -3462,14 +3454,14 @@ void sp_selection_get_export_hints(Inkscape::Selection *selection, Glib::ustring return; } - SelContainer const reprlst = selection->reprList(); + std::vector const reprlst = selection->reprList(); bool filename_search = TRUE; bool xdpi_search = TRUE; bool ydpi_search = TRUE; - for (SelContainer::const_iterator i=reprlst.begin();filename_search&&xdpi_search&&ydpi_search&&i!=reprlst.end();i++){ + for (std::vector::const_iterator i=reprlst.begin();filename_search&&xdpi_search&&ydpi_search&&i!=reprlst.end();i++){ gchar const *dpi_string; - Inkscape::XML::Node * repr = dynamic_cast(*i); + Inkscape::XML::Node * repr = (*i); if (filename_search) { const gchar* tmp = repr->attribute("inkscape:export-filename"); @@ -3756,22 +3748,20 @@ void sp_selection_set_clipgroup(SPDesktop *desktop) return; } - SelContainer l=selection->reprList(); - - SelContainer p(l); + std::vector p(selection->reprList()); - p.sort(sp_repr_compare_position_obj); + sort(p.begin(),p.end(),sp_repr_compare_position); selection->clear(); - gint topmost = (dynamic_cast(p.back()))->position(); - Inkscape::XML::Node *topmost_parent = (dynamic_cast(p.back()))->parent(); + int topmost = (p.back())->position(); + Inkscape::XML::Node *topmost_parent = (p.back())->parent(); Inkscape::XML::Node *inner = xml_doc->createElement("svg:g"); inner->setAttribute("inkscape:label", "Clip"); - while (!p.empty()) { - Inkscape::XML::Node *current = dynamic_cast(p.front()); + for(std::vector::const_iterator i=p.begin();i!=p.end();i++){ + Inkscape::XML::Node *current = *i; if (current->parent() == topmost_parent) { Inkscape::XML::Node *spnew = current->duplicate(xml_doc); @@ -3813,7 +3803,6 @@ void sp_selection_set_clipgroup(SPDesktop *desktop) Inkscape::GC::release(spnew); } } - p.pop_front(); } Inkscape::XML::Node *outer = xml_doc->createElement("svg:g"); @@ -3960,13 +3949,12 @@ void sp_selection_set_mask(SPDesktop *desktop, bool apply_clip_path, bool apply_ // make a note we should ungroup this when unsetting mask group->setAttribute("inkscape:groupmode", "maskhelper"); - SelContainer reprs_to_group; + std::vector reprs_to_group; for (GSList *i = apply_to_items ; NULL != i ; i = i->next) { - reprs_to_group.push_front(dynamic_cast(SP_OBJECT(i->data)->getRepr())); + reprs_to_group.push_back(static_cast(i->data)->getRepr()); items_to_select.remove(static_cast(i->data)); } - reprs_to_group.reverse(); sp_selection_group_impl(reprs_to_group, group, xml_doc, doc); diff --git a/src/selection.cpp b/src/selection.cpp index b509f4272..cbde9a799 100644 --- a/src/selection.cpp +++ b/src/selection.cpp @@ -43,7 +43,7 @@ namespace Inkscape { Selection::Selection(LayerModel *layers, SPDesktop *desktop) : _objs(SelContainer()), - _reprs(SelContainer()), + _reprs(std::vector()), _items(SelContainer()), _layers(layers), _desktop(desktop), @@ -296,15 +296,13 @@ SelContainer const &Selection::itemList() { return _items; } -SelContainer const &Selection::reprList() { +std::vector const &Selection::reprList() { if (!_reprs.empty()) { return _reprs; } SelContainer list = itemList(); for ( SelContainer::const_iterator iter=list.begin();iter!=list.end();iter++ ) { SPObject *obj=reinterpret_cast(*iter); - _reprs.push_front(dynamic_cast(obj->getRepr())); + _reprs.push_back(obj->getRepr()); } - _reprs.reverse(); - return _reprs; } @@ -343,7 +341,7 @@ SPObject *Selection::single() { SPItem *Selection::singleItem() { SelContainer const items=itemList(); - if ( !items.size()==1) { + if ( items.size()==1) { return reinterpret_cast(items.front()); } else { return NULL; diff --git a/src/selection.h b/src/selection.h index 7171b8742..f85c6346b 100644 --- a/src/selection.h +++ b/src/selection.h @@ -260,7 +260,7 @@ public: /** Returns a list of the xml nodes of all selected objects. */ /// \todo only returns reprs of SPItems currently; need a separate /// method for that - std::list const &reprList(); + std::vector const &reprList(); /** Returns a list of all perspectives which have a 3D box in the current selection. (these may also be nested in groups) */ @@ -377,7 +377,7 @@ private: void _releaseContext(SPObject *obj); mutable std::list _objs; - mutable std::list _reprs; + mutable std::vector _reprs; mutable std::list _items; void add_box_perspective(SPBox3D *box); diff --git a/src/splivarot.cpp b/src/splivarot.cpp index aec7051e0..107dfc629 100644 --- a/src/splivarot.cpp +++ b/src/splivarot.cpp @@ -691,11 +691,11 @@ sp_selected_path_boolop(Inkscape::Selection *selection, SPDesktop *desktop, bool } } else { // find out the bottom object - SelContainer sorted(selection->reprList()); + std::vector sorted(selection->reprList()); - sorted.sort(sp_repr_compare_position_obj); + sort(sorted.begin(),sorted.end(),sp_repr_compare_position); - source = doc->getObjectByRepr((Inkscape::XML::Node *)sorted.front()); + source = doc->getObjectByRepr(sorted.front()); } // adjust style properties that depend on a possible transform in the source object in order diff --git a/src/ui/dialog/export.cpp b/src/ui/dialog/export.cpp index fc6094c9f..0667ba721 100644 --- a/src/ui/dialog/export.cpp +++ b/src/ui/dialog/export.cpp @@ -817,9 +817,9 @@ void Export::onAreaToggled () one that's nice */ if (filename.empty()) { const gchar * id = "object"; - const SelContainer reprlst = SP_ACTIVE_DESKTOP->getSelection()->reprList(); - for(SelContainer::const_iterator i=reprlst.begin(); reprlst.end() != i; i++) { - Inkscape::XML::Node * repr = (Inkscape::XML::Node *)(*i); + const std::vector reprlst = SP_ACTIVE_DESKTOP->getSelection()->reprList(); + for(std::vector::const_iterator i=reprlst.begin(); reprlst.end() != i; i++) { + Inkscape::XML::Node * repr = (*i); if (repr->attribute("id")) { id = repr->attribute("id"); break; @@ -1226,7 +1226,7 @@ void Export::onExport () break; } case SELECTION_SELECTION: { - SelContainer reprlst; + std::vector reprlst; SPDocument * doc = SP_ACTIVE_DOCUMENT; bool modified = false; @@ -1234,8 +1234,8 @@ void Export::onExport () DocumentUndo::setUndoSensitive(doc, false); reprlst = desktop->getSelection()->reprList(); - for(SelContainer::const_iterator i=reprlst.begin(); reprlst.end() != i; i++) { - Inkscape::XML::Node * repr = dynamic_cast(*i); + for(std::vector::const_iterator i=reprlst.begin(); reprlst.end() != i; i++) { + Inkscape::XML::Node * repr = *i; const gchar * temp_string; Glib::ustring dir = Glib::path_get_dirname(filename.c_str()); const gchar* docURI=SP_ACTIVE_DOCUMENT->getURI(); diff --git a/src/ui/dialog/filter-effects-dialog.cpp b/src/ui/dialog/filter-effects-dialog.cpp index 657d6771b..f67c1d173 100644 --- a/src/ui/dialog/filter-effects-dialog.cpp +++ b/src/ui/dialog/filter-effects-dialog.cpp @@ -690,7 +690,7 @@ private: void select_svg_element(){ Inkscape::Selection* sel = _desktop->getSelection(); if (sel->isEmpty()) return; - Inkscape::XML::Node* node = (Inkscape::XML::Node*) sel->reprList().front(); + Inkscape::XML::Node* node = sel->reprList().front(); if (!node || !node->matchAttributeName("id")) return; std::ostringstream xlikhref; diff --git a/src/ui/dialog/svg-fonts-dialog.cpp b/src/ui/dialog/svg-fonts-dialog.cpp index 8f5601e3a..12b423602 100644 --- a/src/ui/dialog/svg-fonts-dialog.cpp +++ b/src/ui/dialog/svg-fonts-dialog.cpp @@ -524,7 +524,7 @@ void SvgFontsDialog::set_glyph_description_from_selected_path(){ return; } - Inkscape::XML::Node* node = (Inkscape::XML::Node*)(sel->reprList().front()); + Inkscape::XML::Node* node = sel->reprList().front(); if (!node) return;//TODO: should this be an assert? if (!node->matchAttributeName("d") || !node->attribute("d")){ char *msg = _("The selected object does not have a path description."); @@ -566,7 +566,7 @@ void SvgFontsDialog::missing_glyph_description_from_selected_path(){ return; } - Inkscape::XML::Node* node = (Inkscape::XML::Node*)(sel->reprList().front()); + Inkscape::XML::Node* node = sel->reprList().front(); if (!node) return;//TODO: should this be an assert? if (!node->matchAttributeName("d") || !node->attribute("d")){ char *msg = _("The selected object does not have a path description."); -- cgit v1.2.3 From 5fd00cab14d48beaf2279a2b8f3ad5b02b76c87b Mon Sep 17 00:00:00 2001 From: Marc Jeanmougin Date: Thu, 19 Feb 2015 04:25:21 +0100 Subject: Put a few std::vector (bzr r13922.1.5) --- src/conn-avoid-ref.cpp | 4 +- src/desktop-style.cpp | 66 ++--- src/desktop-style.h | 24 +- src/desktop.cpp | 2 +- src/desktop.h | 2 +- src/document.cpp | 20 +- src/document.h | 8 +- src/extension/execution-env.cpp | 4 +- src/extension/implementation/implementation.cpp | 2 +- src/extension/implementation/script.cpp | 4 +- src/extension/internal/bitmap/imagemagick.cpp | 6 +- src/extension/internal/bluredge.cpp | 4 +- src/extension/internal/filter/filter.cpp | 4 +- src/extension/internal/grid.cpp | 2 +- src/file.cpp | 4 +- src/gradient-chemistry.cpp | 8 +- src/gradient-drag.cpp | 12 +- src/graphlayout.cpp | 6 +- src/graphlayout.h | 4 +- src/helper/png-write.cpp | 6 +- src/helper/png-write.h | 4 +- src/live_effects/lpe-knot.cpp | 4 +- src/main.cpp | 12 +- src/object-snapper.cpp | 4 +- src/path-chemistry.cpp | 73 ++--- src/path-chemistry.h | 2 +- src/removeoverlap.cpp | 6 +- src/removeoverlap.h | 2 +- src/selcue.cpp | 14 +- src/selection-chemistry.cpp | 373 ++++++++++++------------ src/selection-chemistry.h | 10 +- src/selection-describer.cpp | 14 +- src/selection.cpp | 56 ++-- src/selection.h | 10 +- src/seltrans.cpp | 26 +- src/seltrans.h | 2 +- src/snap.cpp | 6 +- src/snap.h | 6 +- src/sp-conn-end.cpp | 4 +- src/sp-item-group.cpp | 19 +- src/sp-item-group.h | 4 +- src/sp-lpe-item.cpp | 20 +- src/sp-marker.cpp | 6 +- src/sp-marker.h | 2 +- src/sp-pattern.cpp | 4 +- src/sp-pattern.h | 2 +- src/splivarot.cpp | 30 +- src/text-chemistry.cpp | 40 +-- src/text-editing.cpp | 4 +- src/trace/trace.cpp | 4 +- src/ui/clipboard.cpp | 20 +- src/ui/dialog/align-and-distribute.cpp | 32 +- src/ui/dialog/clonetiler.cpp | 7 +- src/ui/dialog/export.cpp | 8 +- src/ui/dialog/filter-effects-dialog.cpp | 14 +- src/ui/dialog/find.cpp | 54 ++-- src/ui/dialog/find.h | 10 +- src/ui/dialog/font-substitution.cpp | 18 +- src/ui/dialog/font-substitution.h | 4 +- src/ui/dialog/glyphs.cpp | 8 +- src/ui/dialog/grid-arrange-tab.cpp | 21 +- src/ui/dialog/icon-preview.cpp | 4 +- src/ui/dialog/objects.cpp | 4 +- src/ui/dialog/pixelartdialog.cpp | 4 +- src/ui/dialog/polar-arrange-tab.cpp | 6 +- src/ui/dialog/print.cpp | 2 +- src/ui/dialog/swatches.cpp | 2 +- src/ui/dialog/tags.cpp | 4 +- src/ui/dialog/text-edit.cpp | 12 +- src/ui/dialog/transformation.cpp | 22 +- src/ui/interface.cpp | 8 +- src/ui/tools/connector-tool.cpp | 4 +- src/ui/tools/eraser-tool.cpp | 18 +- src/ui/tools/gradient-tool.cpp | 12 +- src/ui/tools/lpe-tool.cpp | 4 +- src/ui/tools/measure-tool.cpp | 4 +- src/ui/tools/mesh-tool.cpp | 12 +- src/ui/tools/node-tool.cpp | 6 +- src/ui/tools/select-tool.cpp | 2 +- src/ui/tools/spray-tool.cpp | 14 +- src/ui/tools/text-tool.cpp | 4 +- src/ui/tools/tool-base.cpp | 4 +- src/ui/tools/tweak-tool.cpp | 12 +- src/ui/widget/object-composite-settings.cpp | 4 +- src/ui/widget/style-subject.cpp | 4 +- src/unclump.cpp | 36 +-- src/unclump.h | 2 +- src/vanishing-point.cpp | 18 +- src/widgets/arc-toolbar.cpp | 16 +- src/widgets/connector-toolbar.cpp | 8 +- src/widgets/fill-style.cpp | 8 +- src/widgets/gradient-toolbar.cpp | 12 +- src/widgets/mesh-toolbar.cpp | 8 +- src/widgets/rect-toolbar.cpp | 8 +- src/widgets/spiral-toolbar.cpp | 8 +- src/widgets/star-toolbar.cpp | 24 +- src/widgets/stroke-style.cpp | 14 +- src/widgets/stroke-style.h | 2 +- src/widgets/text-toolbar.cpp | 22 +- 99 files changed, 744 insertions(+), 765 deletions(-) (limited to 'src') diff --git a/src/conn-avoid-ref.cpp b/src/conn-avoid-ref.cpp index f2cde352c..fb9fbd935 100644 --- a/src/conn-avoid-ref.cpp +++ b/src/conn-avoid-ref.cpp @@ -252,8 +252,8 @@ static std::vector approxItemWithPoints(SPItem const *item, const G { SPGroup* group = SP_GROUP(item); // consider all first-order children - SelContainer itemlist = sp_item_group_item_list(group); - for (SelContainer::const_iterator i=itemlist.begin();i!=itemlist.end();i++) { + std::vector itemlist = sp_item_group_item_list(group); + for (std::vector::const_iterator i=itemlist.begin();i!=itemlist.end();i++) { SPItem* child_item = SP_ITEM(*i); std::vector child_points = approxItemWithPoints(child_item, item_transform * child_item->transform); poly_points.insert(poly_points.end(), child_points.begin(), child_points.end()); diff --git a/src/desktop-style.cpp b/src/desktop-style.cpp index 39dfad44b..0c661ebfb 100644 --- a/src/desktop-style.cpp +++ b/src/desktop-style.cpp @@ -194,8 +194,8 @@ sp_desktop_set_style(SPDesktop *desktop, SPCSSAttr *css, bool change, bool write sp_repr_css_merge(css_write, css); sp_css_attr_unset_uris(css_write); prefs->mergeStyle("/desktop/style", css_write); - SelContainer const itemlist = desktop->selection->itemList(); - for (SelContainer::const_iterator i=itemlist.begin();i!=itemlist.end();i++) { + std::vector const itemlist = desktop->selection->itemList(); + for (std::vector::const_iterator i=itemlist.begin();i!=itemlist.end();i++) { /* last used styles for 3D box faces are stored separately */ SPObject *obj = reinterpret_cast(*i); // TODO unsafe until Selection is refactored. Box3DSide *side = dynamic_cast(obj); @@ -234,8 +234,8 @@ sp_desktop_set_style(SPDesktop *desktop, SPCSSAttr *css, bool change, bool write sp_repr_css_merge(css_no_text, css); css_no_text = sp_css_attr_unset_text(css_no_text); - SelContainer const itemlist = desktop->selection->itemList(); - for (SelContainer::const_iterator i=itemlist.begin();i!=itemlist.end();i++) { + std::vector const itemlist = desktop->selection->itemList(); + for (std::vector::const_iterator i=itemlist.begin();i!=itemlist.end();i++) { SPItem *item = reinterpret_cast(*i); // If not text, don't apply text attributes (can a group have text attributes? Yes! FIXME) @@ -439,7 +439,7 @@ sp_desktop_get_font_size_tool(SPDesktop *desktop) /** Determine average stroke width, simple method */ // see TODO in dialogs/stroke-style.cpp on how to get rid of this eventually gdouble -stroke_average_width (const SelContainer &objects) +stroke_average_width (const std::vector &objects) { if (objects.empty()) return Geom::infinity(); @@ -447,7 +447,7 @@ stroke_average_width (const SelContainer &objects) gdouble avgwidth = 0.0; bool notstroked = true; int n_notstroked = 0; - for (SelContainer::const_iterator i=objects.begin();i!=objects.end();i++) { + for (std::vector::const_iterator i=objects.begin();i!=objects.end();i++) { SPObject *obj = reinterpret_cast(*i); SPItem *item = dynamic_cast(obj); if (!item) { @@ -492,7 +492,7 @@ static bool vectorsClose( std::vector const &lhs, std::vector co * Write to style_res the average fill or stroke of list of objects, if applicable. */ int -objects_query_fillstroke (const SelContainer &objects, SPStyle *style_res, bool const isfill) +objects_query_fillstroke (const std::vector &objects, SPStyle *style_res, bool const isfill) { if (objects.empty()) { /* No objects, set empty */ @@ -514,7 +514,7 @@ objects_query_fillstroke (const SelContainer &objects, SPStyle *style_res, bool prev[0] = prev[1] = prev[2] = 0.0; bool same_color = true; - for (SelContainer::const_iterator i=objects.begin();i!=objects.end();i++) { + for (std::vector::const_iterator i=objects.begin();i!=objects.end();i++) { SPObject *obj = reinterpret_cast(*i); if (!obj) { continue; @@ -685,7 +685,7 @@ objects_query_fillstroke (const SelContainer &objects, SPStyle *style_res, bool * Write to style_res the average opacity of a list of objects. */ int -objects_query_opacity (const SelContainer &objects, SPStyle *style_res) +objects_query_opacity (const std::vector &objects, SPStyle *style_res) { if (objects.empty()) { /* No objects, set empty */ @@ -698,7 +698,7 @@ objects_query_opacity (const SelContainer &objects, SPStyle *style_res) guint opacity_items = 0; - for (SelContainer::const_iterator i=objects.begin();i!=objects.end();i++) { + for (std::vector::const_iterator i=objects.begin();i!=objects.end();i++) { SPObject *obj = reinterpret_cast(*i); if (!obj) { continue; @@ -739,7 +739,7 @@ objects_query_opacity (const SelContainer &objects, SPStyle *style_res) * Write to style_res the average stroke width of a list of objects. */ int -objects_query_strokewidth (const SelContainer &objects, SPStyle *style_res) +objects_query_strokewidth (const std::vector &objects, SPStyle *style_res) { if (objects.empty()) { /* No objects, set empty */ @@ -754,7 +754,7 @@ objects_query_strokewidth (const SelContainer &objects, SPStyle *style_res) int n_stroked = 0; - for (SelContainer::const_iterator i=objects.begin();i!=objects.end();i++) { + for (std::vector::const_iterator i=objects.begin();i!=objects.end();i++) { SPObject *obj = reinterpret_cast(*i); if (!obj) { continue; @@ -815,7 +815,7 @@ objects_query_strokewidth (const SelContainer &objects, SPStyle *style_res) * Write to style_res the average miter limit of a list of objects. */ int -objects_query_miterlimit (const SelContainer &objects, SPStyle *style_res) +objects_query_miterlimit (const std::vector &objects, SPStyle *style_res) { if (objects.empty()) { /* No objects, set empty */ @@ -828,7 +828,7 @@ objects_query_miterlimit (const SelContainer &objects, SPStyle *style_res) gdouble prev_ml = -1; bool same_ml = true; - for (SelContainer::const_iterator i=objects.begin();i!=objects.end();i++) { + for (std::vector::const_iterator i=objects.begin();i!=objects.end();i++) { SPObject *obj = reinterpret_cast(*i); if (!dynamic_cast(obj)) { continue; @@ -875,7 +875,7 @@ objects_query_miterlimit (const SelContainer &objects, SPStyle *style_res) * Write to style_res the stroke cap of a list of objects. */ int -objects_query_strokecap (const SelContainer &objects, SPStyle *style_res) +objects_query_strokecap (const std::vector &objects, SPStyle *style_res) { if (objects.empty()) { /* No objects, set empty */ @@ -887,7 +887,7 @@ objects_query_strokecap (const SelContainer &objects, SPStyle *style_res) bool same_cap = true; int n_stroked = 0; - for (SelContainer::const_iterator i=objects.begin();i!=objects.end();i++) { + for (std::vector::const_iterator i=objects.begin();i!=objects.end();i++) { SPObject *obj = reinterpret_cast(*i); if (!dynamic_cast(obj)) { continue; @@ -929,7 +929,7 @@ objects_query_strokecap (const SelContainer &objects, SPStyle *style_res) * Write to style_res the stroke join of a list of objects. */ int -objects_query_strokejoin (const SelContainer &objects, SPStyle *style_res) +objects_query_strokejoin (const std::vector &objects, SPStyle *style_res) { if (objects.empty()) { /* No objects, set empty */ @@ -941,7 +941,7 @@ objects_query_strokejoin (const SelContainer &objects, SPStyle *style_res) bool same_join = true; int n_stroked = 0; - for (SelContainer::const_iterator i=objects.begin();i!=objects.end();i++) { + for (std::vector::const_iterator i=objects.begin();i!=objects.end();i++) { SPObject *obj = reinterpret_cast(*i); if (!dynamic_cast(obj)) { continue; @@ -984,7 +984,7 @@ objects_query_strokejoin (const SelContainer &objects, SPStyle *style_res) * Write to style_res the average font size and spacing of objects. */ int -objects_query_fontnumbers (const SelContainer &objects, SPStyle *style_res) +objects_query_fontnumbers (const std::vector &objects, SPStyle *style_res) { bool different = false; @@ -1004,7 +1004,7 @@ objects_query_fontnumbers (const SelContainer &objects, SPStyle *style_res) int texts = 0; int no_size = 0; - for (SelContainer::const_iterator i=objects.begin();i!=objects.end();i++) { + for (std::vector::const_iterator i=objects.begin();i!=objects.end();i++) { SPObject *obj = reinterpret_cast(*i); if (!isTextualItem(obj)) { @@ -1116,14 +1116,14 @@ objects_query_fontnumbers (const SelContainer &objects, SPStyle *style_res) * Write to style_res the average font style of objects. */ int -objects_query_fontstyle (const SelContainer &objects, SPStyle *style_res) +objects_query_fontstyle (const std::vector &objects, SPStyle *style_res) { bool different = false; bool set = false; int texts = 0; - for (SelContainer::const_iterator i=objects.begin();i!=objects.end();i++) { + for (std::vector::const_iterator i=objects.begin();i!=objects.end();i++) { SPObject *obj = reinterpret_cast(*i); if (!isTextualItem(obj)) { @@ -1173,7 +1173,7 @@ objects_query_fontstyle (const SelContainer &objects, SPStyle *style_res) * Write to style_res the baseline numbers. */ static int -objects_query_baselines (const SelContainer &objects, SPStyle *style_res) +objects_query_baselines (const std::vector &objects, SPStyle *style_res) { bool different = false; @@ -1192,7 +1192,7 @@ objects_query_baselines (const SelContainer &objects, SPStyle *style_res) int texts = 0; - for (SelContainer::const_iterator i=objects.begin();i!=objects.end();i++) { + for (std::vector::const_iterator i=objects.begin();i!=objects.end();i++) { SPObject *obj = reinterpret_cast(*i); if (!isTextualItem(obj)) { @@ -1269,7 +1269,7 @@ objects_query_baselines (const SelContainer &objects, SPStyle *style_res) * Write to style_res the average font family of objects. */ int -objects_query_fontfamily (const SelContainer &objects, SPStyle *style_res) +objects_query_fontfamily (const std::vector &objects, SPStyle *style_res) { bool different = false; int texts = 0; @@ -1280,7 +1280,7 @@ objects_query_fontfamily (const SelContainer &objects, SPStyle *style_res) } style_res->font_family.set = FALSE; - for (SelContainer::const_iterator i=objects.begin();i!=objects.end();i++) { + for (std::vector::const_iterator i=objects.begin();i!=objects.end();i++) { SPObject *obj = reinterpret_cast(*i); // std::cout << " " << reinterpret_cast(i->data)->getId() << std::endl; @@ -1325,7 +1325,7 @@ objects_query_fontfamily (const SelContainer &objects, SPStyle *style_res) } static int -objects_query_fontspecification (const SelContainer &objects, SPStyle *style_res) +objects_query_fontspecification (const std::vector &objects, SPStyle *style_res) { bool different = false; int texts = 0; @@ -1336,7 +1336,7 @@ objects_query_fontspecification (const SelContainer &objects, SPStyle *style_res } style_res->font_specification.set = FALSE; - for (SelContainer::const_iterator i=objects.begin();i!=objects.end();i++) { + for (std::vector::const_iterator i=objects.begin();i!=objects.end();i++) { SPObject *obj = reinterpret_cast(*i); // std::cout << " " << reinterpret_cast(i->data)->getId() << std::endl; @@ -1385,7 +1385,7 @@ objects_query_fontspecification (const SelContainer &objects, SPStyle *style_res } static int -objects_query_blend (const SelContainer &objects, SPStyle *style_res) +objects_query_blend (const std::vector &objects, SPStyle *style_res) { const int empty_prev = -2; const int complex_filter = 5; @@ -1394,7 +1394,7 @@ objects_query_blend (const SelContainer &objects, SPStyle *style_res) bool same_blend = true; guint items = 0; - for (SelContainer::const_iterator i=objects.begin();i!=objects.end();i++) { + for (std::vector::const_iterator i=objects.begin();i!=objects.end();i++) { SPObject *obj = reinterpret_cast(*i); if (!obj) { continue; @@ -1471,7 +1471,7 @@ objects_query_blend (const SelContainer &objects, SPStyle *style_res) * Write to style_res the average blurring of a list of objects. */ int -objects_query_blur (const SelContainer &objects, SPStyle *style_res) +objects_query_blur (const std::vector &objects, SPStyle *style_res) { if (objects.empty()) { /* No objects, set empty */ @@ -1484,7 +1484,7 @@ objects_query_blur (const SelContainer &objects, SPStyle *style_res) guint blur_items = 0; guint items = 0; - for (SelContainer::const_iterator i=objects.begin();i!=objects.end();i++) { + for (std::vector::const_iterator i=objects.begin();i!=objects.end();i++) { SPObject *obj = reinterpret_cast(*i); if (!obj) { continue; @@ -1553,7 +1553,7 @@ objects_query_blur (const SelContainer &objects, SPStyle *style_res) * the result to style, return appropriate flag. */ int -sp_desktop_query_style_from_list (const SelContainer &list, SPStyle *style, int property) +sp_desktop_query_style_from_list (const std::vector &list, SPStyle *style, int property) { if (property == QUERY_STYLE_PROPERTY_FILL) { return objects_query_fillstroke (list, style, true); diff --git a/src/desktop-style.h b/src/desktop-style.h index 0e40a2652..7ca25b9ae 100644 --- a/src/desktop-style.h +++ b/src/desktop-style.h @@ -65,21 +65,21 @@ guint32 sp_desktop_get_color_tool(SPDesktop *desktop, Glib::ustring const &tool, double sp_desktop_get_font_size_tool (SPDesktop *desktop); void sp_desktop_apply_style_tool(SPDesktop *desktop, Inkscape::XML::Node *repr, Glib::ustring const &tool, bool with_text); -gdouble stroke_average_width (const SelContainer &objects); +gdouble stroke_average_width (const std::vector &objects); -int objects_query_fillstroke (const SelContainer &objects, SPStyle *style_res, bool const isfill); -int objects_query_fontnumbers (const SelContainer &objects, SPStyle *style_res); -int objects_query_fontstyle (const SelContainer &objects, SPStyle *style_res); -int objects_query_fontfamily (const SelContainer &objects, SPStyle *style_res); -int objects_query_opacity (const SelContainer &objects, SPStyle *style_res); -int objects_query_strokewidth (const SelContainer &objects, SPStyle *style_res); -int objects_query_miterlimit (const SelContainer &objects, SPStyle *style_res); -int objects_query_strokecap (const SelContainer &objects, SPStyle *style_res); -int objects_query_strokejoin (const SelContainer &objects, SPStyle *style_res); +int objects_query_fillstroke (const std::vector &objects, SPStyle *style_res, bool const isfill); +int objects_query_fontnumbers (const std::vector &objects, SPStyle *style_res); +int objects_query_fontstyle (const std::vector &objects, SPStyle *style_res); +int objects_query_fontfamily (const std::vector &objects, SPStyle *style_res); +int objects_query_opacity (const std::vector &objects, SPStyle *style_res); +int objects_query_strokewidth (const std::vector &objects, SPStyle *style_res); +int objects_query_miterlimit (const std::vector &objects, SPStyle *style_res); +int objects_query_strokecap (const std::vector &objects, SPStyle *style_res); +int objects_query_strokejoin (const std::vector &objects, SPStyle *style_res); -int objects_query_blur (const SelContainer &objects, SPStyle *style_res); +int objects_query_blur (const std::vector &objects, SPStyle *style_res); -int sp_desktop_query_style_from_list (const SelContainer &list, SPStyle *style, int property); +int sp_desktop_query_style_from_list (const std::vector &list, SPStyle *style, int property); int sp_desktop_query_style(SPDesktop *desktop, SPStyle *style, int property); bool sp_desktop_query_style_all (SPDesktop *desktop, SPStyle *query); diff --git a/src/desktop.cpp b/src/desktop.cpp index 64353e582..0cf0a3872 100644 --- a/src/desktop.cpp +++ b/src/desktop.cpp @@ -716,7 +716,7 @@ Inkscape::UI::Widget::Dock* SPDesktop::getDock() { /** * \see SPDocument::getItemFromListAtPointBottom() */ -SPItem *SPDesktop::getItemFromListAtPointBottom(const SelContainer &list, Geom::Point const &p) const +SPItem *SPDesktop::getItemFromListAtPointBottom(const std::vector &list, Geom::Point const &p) const { g_return_val_if_fail (doc() != NULL, NULL); return SPDocument::getItemFromListAtPointBottom(dkey, doc()->getRoot(), list, p); diff --git a/src/desktop.h b/src/desktop.h index 8765fa699..754e09766 100644 --- a/src/desktop.h +++ b/src/desktop.h @@ -319,7 +319,7 @@ public: //void push_event_context (GType type, const gchar *config, unsigned int key); void set_coordinate_status (Geom::Point p); - SPItem *getItemFromListAtPointBottom(const SelContainer &list, Geom::Point const &p) const; + SPItem *getItemFromListAtPointBottom(const std::vector &list, Geom::Point const &p) const; SPItem *getItemAtPoint(Geom::Point const &p, bool into_groups, SPItem *upto = NULL) const; SPItem *getGroupAtPoint(Geom::Point const &p) const; Geom::Point point() const; diff --git a/src/document.cpp b/src/document.cpp index 5c49ff6c3..07ad10505 100644 --- a/src/document.cpp +++ b/src/document.cpp @@ -1235,7 +1235,7 @@ static bool overlaps(Geom::Rect const &area, Geom::Rect const &box) return area.intersects(box); } -static SelContainer &find_items_in_area(SelContainer &s, SPGroup *group, unsigned int dkey, Geom::Rect const &area, +static std::vector &find_items_in_area(std::vector &s, SPGroup *group, unsigned int dkey, Geom::Rect const &area, bool (*test)(Geom::Rect const &, Geom::Rect const &), bool take_insensitive = false) { g_return_val_if_fail(SP_IS_GROUP(group), s); @@ -1275,7 +1275,7 @@ static bool item_is_in_group(SPItem *item, SPGroup *group) return inGroup; } -SPItem *SPDocument::getItemFromListAtPointBottom(unsigned int dkey, SPGroup *group, SelContainer const &list,Geom::Point const &p, bool take_insensitive) +SPItem *SPDocument::getItemFromListAtPointBottom(unsigned int dkey, SPGroup *group, std::vector const &list,Geom::Point const &p, bool take_insensitive) { g_return_val_if_fail(group, NULL); SPItem *bottomMost = 0; @@ -1391,9 +1391,9 @@ static SPItem *find_group_at_point(unsigned int dkey, SPGroup *group, Geom::Poin * Assumes box is normalized (and g_asserts it!) * */ -SelContainer SPDocument::getItemsInBox(unsigned int dkey, Geom::Rect const &box) const +std::vector SPDocument::getItemsInBox(unsigned int dkey, Geom::Rect const &box) const { - SelContainer x; + std::vector x; g_return_val_if_fail(this->priv != NULL, x); return find_items_in_area(x, SP_GROUP(this->root), dkey, box, is_within); } @@ -1405,16 +1405,16 @@ SelContainer SPDocument::getItemsInBox(unsigned int dkey, Geom::Rect const &box) * */ -SelContainer SPDocument::getItemsPartiallyInBox(unsigned int dkey, Geom::Rect const &box) const +std::vector SPDocument::getItemsPartiallyInBox(unsigned int dkey, Geom::Rect const &box) const { - SelContainer x; + std::vector x; g_return_val_if_fail(this->priv != NULL, x); return find_items_in_area(x, SP_GROUP(this->root), dkey, box, overlaps); } -SelContainer SPDocument::getItemsAtPoints(unsigned const key, std::vector points) const +std::vector SPDocument::getItemsAtPoints(unsigned const key, std::vector points) const { - SelContainer items; + std::vector items; Inkscape::Preferences *prefs = Inkscape::Preferences::get(); // When picking along the path, we don't want small objects close together @@ -1423,11 +1423,11 @@ SelContainer SPDocument::getItemsAtPoints(unsigned const key, std::vectorgetDouble("/options/cursortolerance/value", 1.0); prefs->setDouble("/options/cursortolerance/value", 0.25); - for(unsigned int i = 0; i < points.size(); i++) { + for(int i = points.size()-1;i>=0; i--) { SPItem *item = getItemAtPoint(key, points[i], false, NULL); if (item && items.end()==find(items.begin(),items.end(), item)) - items.push_front(item); + items.push_back(item); } // and now we restore it back diff --git a/src/document.h b/src/document.h index 87262a079..57ff7643c 100644 --- a/src/document.h +++ b/src/document.h @@ -233,7 +233,7 @@ public: /** * Returns the bottommost item from the list which is at the point, or NULL if none. */ - static SPItem *getItemFromListAtPointBottom(unsigned int dkey, SPGroup *group, const SelContainer &list, Geom::Point const &p, bool take_insensitive = false); + static SPItem *getItemFromListAtPointBottom(unsigned int dkey, SPGroup *group, const std::vector &list, Geom::Point const &p, bool take_insensitive = false); static SPDocument *createDoc(Inkscape::XML::Document *rdoc, char const *uri, char const *base, char const *name, unsigned int keepalive, @@ -257,10 +257,10 @@ public: bool addResource(char const *key, SPObject *object); bool removeResource(char const *key, SPObject *object); const GSList *getResourceList(char const *key) const; - SelContainer getItemsInBox(unsigned int dkey, Geom::Rect const &box) const; - SelContainer getItemsPartiallyInBox(unsigned int dkey, Geom::Rect const &box) const; + std::vector getItemsInBox(unsigned int dkey, Geom::Rect const &box) const; + std::vector getItemsPartiallyInBox(unsigned int dkey, Geom::Rect const &box) const; SPItem *getItemAtPoint(unsigned int key, Geom::Point const &p, bool into_groups, SPItem *upto = NULL) const; - SelContainer getItemsAtPoints(unsigned const key, std::vector points) const; + std::vector getItemsAtPoints(unsigned const key, std::vector points) const; SPItem *getGroupAtPoint(unsigned int key, Geom::Point const &p) const; void changeUriAndHrefs(char const *uri); diff --git a/src/extension/execution-env.cpp b/src/extension/execution-env.cpp index 66a8c4358..90a7810e6 100644 --- a/src/extension/execution-env.cpp +++ b/src/extension/execution-env.cpp @@ -64,8 +64,8 @@ ExecutionEnv::ExecutionEnv (Effect * effect, Inkscape::UI::View::View * doc, Imp sp_namedview_document_from_window(desktop); if (desktop != NULL) { - SelContainer selected = desktop->getSelection()->itemList(); - for(SelContainer::const_iterator x=selected.begin();x!=selected.end();x++){ + std::vector selected = desktop->getSelection()->itemList(); + for(std::vector::const_iterator x=selected.begin();x!=selected.end();x++){ Glib::ustring selected_id; selected_id = (*x)->getId(); _selected.insert(_selected.end(), selected_id); diff --git a/src/extension/implementation/implementation.cpp b/src/extension/implementation/implementation.cpp index 6eff3ede3..cea6d139f 100644 --- a/src/extension/implementation/implementation.cpp +++ b/src/extension/implementation/implementation.cpp @@ -48,7 +48,7 @@ Gtk::Widget *Implementation::prefs_effect(Inkscape::Extension::Effect *module, I SPDocument * current_document = view->doc(); using Inkscape::Util::GSListConstIterator; - SelContainer selected = ((SPDesktop *)view)->getSelection()->itemList(); + std::vector selected = ((SPDesktop *)view)->getSelection()->itemList(); Inkscape::XML::Node const* first_select = NULL; if (!selected.empty()) { const SPItem * item = SP_ITEM(selected.front()); diff --git a/src/extension/implementation/script.cpp b/src/extension/implementation/script.cpp index f396e9848..95d5c7edc 100644 --- a/src/extension/implementation/script.cpp +++ b/src/extension/implementation/script.cpp @@ -689,9 +689,9 @@ void Script::effect(Inkscape::Extension::Effect *module, return; } - SelContainer selected = + std::vector selected = desktop->getSelection()->itemList(); //desktop should not be NULL since doc was checked and desktop is a casted pointer - for(SelContainer::const_iterator x=selected.begin();x!=selected.end();x++){ + for(std::vector::const_iterator x=selected.begin();x!=selected.end();x++){ Glib::ustring selected_id; selected_id += "--id="; selected_id += (*x)->getId(); diff --git a/src/extension/internal/bitmap/imagemagick.cpp b/src/extension/internal/bitmap/imagemagick.cpp index 87ef30887..64abd6c4d 100644 --- a/src/extension/internal/bitmap/imagemagick.cpp +++ b/src/extension/internal/bitmap/imagemagick.cpp @@ -70,7 +70,7 @@ ImageMagickDocCache::ImageMagickDocCache(Inkscape::UI::View::View * view) : _imageItems(NULL) { SPDesktop *desktop = (SPDesktop*)view; - const SelContainer selectedItemList = desktop->selection->itemList(); + const std::vector selectedItemList = desktop->selection->itemList(); int selectCount = selectedItemList.size(); // Init the data-holders @@ -83,7 +83,7 @@ ImageMagickDocCache::ImageMagickDocCache(Inkscape::UI::View::View * view) : _imageItems = new SPItem*[selectCount]; // Loop through selected items - for (SelContainer::const_iterator i=selectedItemList.begin();i!=selectedItemList.end();i++) { + for (std::vector::const_iterator i=selectedItemList.begin();i!=selectedItemList.end();i++) { SPItem *item = static_cast(*i); Inkscape::XML::Node *node = reinterpret_cast(item->getRepr()); if (!strcmp(node->name(), "image") || !strcmp(node->name(), "svg:image")) @@ -242,7 +242,7 @@ ImageMagick::prefs_effect(Inkscape::Extension::Effect *module, Inkscape::UI::Vie using Inkscape::Util::GSListConstIterator; - SelContainer selected = ((SPDesktop *)view)->getSelection()->itemList(); + std::vector selected = ((SPDesktop *)view)->getSelection()->itemList(); Inkscape::XML::Node * first_select = NULL; if (!selected.empty()) { first_select = (selected.front())->getRepr(); diff --git a/src/extension/internal/bluredge.cpp b/src/extension/internal/bluredge.cpp index 138172715..257cac161 100644 --- a/src/extension/internal/bluredge.cpp +++ b/src/extension/internal/bluredge.cpp @@ -65,10 +65,10 @@ BlurEdge::effect (Inkscape::Extension::Effect *module, Inkscape::UI::View::View using Inkscape::Util::GSListConstIterator; // TODO need to properly refcount the items, at least - SelContainer items(selection->itemList()); + std::vector items(selection->itemList()); selection->clear(); - for(SelContainer::iterator item = items.begin(); + for(std::vector::iterator item = items.begin(); item != items.end(); ++item) { SPItem * spitem = static_cast(*item); diff --git a/src/extension/internal/filter/filter.cpp b/src/extension/internal/filter/filter.cpp index 821c023ac..a5eb7de60 100644 --- a/src/extension/internal/filter/filter.cpp +++ b/src/extension/internal/filter/filter.cpp @@ -126,12 +126,12 @@ void Filter::effect(Inkscape::Extension::Effect *module, Inkscape::UI::View::Vie Inkscape::Selection * selection = ((SPDesktop *)document)->selection; // TODO need to properly refcount the items, at least - SelContainer items(selection->itemList()); + std::vector items(selection->itemList()); Inkscape::XML::Document * xmldoc = document->doc()->getReprDoc(); Inkscape::XML::Node * defsrepr = document->doc()->getDefs()->getRepr(); - for(SelContainer::iterator item = items.begin(); + for(std::vector::iterator item = items.begin(); item != items.end(); ++item) { SPItem * spitem = static_cast(*item); Inkscape::XML::Node * node = spitem->getRepr(); diff --git a/src/extension/internal/grid.cpp b/src/extension/internal/grid.cpp index 4c12f629c..440c6b822 100644 --- a/src/extension/internal/grid.cpp +++ b/src/extension/internal/grid.cpp @@ -192,7 +192,7 @@ Grid::prefs_effect(Inkscape::Extension::Effect *module, Inkscape::UI::View::View using Inkscape::Util::GSListConstIterator; - SelContainer selected = ((SPDesktop *)view)->getSelection()->itemList(); + std::vector selected = ((SPDesktop *)view)->getSelection()->itemList(); Inkscape::XML::Node * first_select = NULL; if (!selected.empty()) { first_select = (selected.front())->getRepr(); diff --git a/src/file.cpp b/src/file.cpp index 4325c838b..f9dbe00a7 100644 --- a/src/file.cpp +++ b/src/file.cpp @@ -1063,7 +1063,7 @@ void sp_import_document(SPDesktop *desktop, SPDocument *clipdoc, bool in_place) desktop->doc()->importDefs(clipdoc); // copy objects - std::list pasted_objects; + std::vector pasted_objects; for (Inkscape::XML::Node *obj = root->firstChild() ; obj ; obj = obj->next()) { // Don't copy metadata, defs, named views and internal clipboard contents to the document if (!strcmp(obj->name(), "svg:defs")) { @@ -1082,7 +1082,7 @@ void sp_import_document(SPDesktop *desktop, SPDocument *clipdoc, bool in_place) target_parent->appendChild(obj_copy); Inkscape::GC::release(obj_copy); - pasted_objects.push_front(dynamic_cast(obj_copy)); + pasted_objects.push_back((obj_copy)); } // Change the selection to the freshly pasted objects diff --git a/src/gradient-chemistry.cpp b/src/gradient-chemistry.cpp index 5f1da6cf1..a72423bbb 100644 --- a/src/gradient-chemistry.cpp +++ b/src/gradient-chemistry.cpp @@ -1570,8 +1570,8 @@ void sp_gradient_invert_selected_gradients(SPDesktop *desktop, Inkscape::PaintTa { Inkscape::Selection *selection = desktop->getSelection(); - const SelContainer list=selection->itemList(); - for (SelContainer::const_iterator i=list.begin();i!=list.end();i++) { + const std::vector list=selection->itemList(); + for (std::vector::const_iterator i=list.begin();i!=list.end();i++) { sp_item_gradient_invert_vector_color(SP_ITEM(*i), fill_or_stroke); } @@ -1595,8 +1595,8 @@ void sp_gradient_reverse_selected_gradients(SPDesktop *desktop) if (drag && drag->selected) { drag->selected_reverse_vector(); } else { // If no drag or no dragger selected, act on selection (both fill and stroke gradients) - const SelContainer list=selection->itemList(); - for (SelContainer::const_iterator i=list.begin();i!=list.end();i++) { + const std::vector list=selection->itemList(); + for (std::vector::const_iterator i=list.begin();i!=list.end();i++) { sp_item_gradient_reverse_vector(SP_ITEM(*i), Inkscape::FOR_FILL); sp_item_gradient_reverse_vector(SP_ITEM(*i), Inkscape::FOR_STROKE); } diff --git a/src/gradient-drag.cpp b/src/gradient-drag.cpp index 649928060..525fc074f 100644 --- a/src/gradient-drag.cpp +++ b/src/gradient-drag.cpp @@ -2082,8 +2082,8 @@ void GrDrag::updateDraggers() this->draggers = NULL; g_return_if_fail(this->selection != NULL); - SelContainer list = this->selection->itemList(); - for (SelContainer::const_iterator i=list.begin();i!=list.end();i++) { + std::vector list = this->selection->itemList(); + for (std::vector::const_iterator i=list.begin();i!=list.end();i++) { SPItem *item = SP_ITEM(*i); SPStyle *style = item->style; @@ -2151,8 +2151,8 @@ void GrDrag::updateLines() g_return_if_fail(this->selection != NULL); - SelContainer list = this->selection->itemList(); - for (SelContainer::const_iterator i=list.begin();i!=list.end();i++) { + std::vector list = this->selection->itemList(); + for (std::vector::const_iterator i=list.begin();i!=list.end();i++) { SPItem *item = SP_ITEM(*i); SPStyle *style = item->style; @@ -2295,8 +2295,8 @@ void GrDrag::updateLevels() g_return_if_fail (this->selection != NULL); - SelContainer list = this->selection->itemList(); - for (SelContainer::const_iterator i=list.begin();i!=list.end();i++) { + std::vector list = this->selection->itemList(); + for (std::vector::const_iterator i=list.begin();i!=list.end();i++) { SPItem *item = SP_ITEM(*i); Geom::OptRect rect = item->desktopVisualBounds(); if (rect) { diff --git a/src/graphlayout.cpp b/src/graphlayout.cpp index 613440269..4d590173a 100644 --- a/src/graphlayout.cpp +++ b/src/graphlayout.cpp @@ -88,8 +88,8 @@ struct CheckProgress : TestConvergence { * Scans the items list and places those items that are * not connectors in filtered */ -void filterConnectors(SelContainer const &items, list &filtered) { - for(SelContainer::const_iterator i=items.begin();i!=items.end();i++){ +void filterConnectors(std::vector const &items, list &filtered) { + for(std::vector::const_iterator i=items.begin();i!=items.end();i++){ SPItem *item = SP_ITEM(*i); if(!isConnector(item)) { filtered.push_back(item); @@ -101,7 +101,7 @@ void filterConnectors(SelContainer const &items, list &filtered) { * connectors between them, and uses graph layout techniques to find * a nice layout */ -void graphlayout(SelContainer const &items) { +void graphlayout(std::vector const &items) { if(items.empty()) { return; } diff --git a/src/graphlayout.h b/src/graphlayout.h index c38f9471c..9794dd6b5 100644 --- a/src/graphlayout.h +++ b/src/graphlayout.h @@ -19,10 +19,10 @@ typedef struct _GSList GSList; class SPItem; -void graphlayout(SelContainer const &items); +void graphlayout(std::vector const &items); bool isConnector(SPItem const *const item); -void filterConnectors(SelContainer const &items, std::list &filtered); +void filterConnectors(std::vector const &items, std::list &filtered); #endif // SEEN_GRAPHLAYOUT_H diff --git a/src/helper/png-write.cpp b/src/helper/png-write.cpp index 55fef5a4c..fc365c435 100644 --- a/src/helper/png-write.cpp +++ b/src/helper/png-write.cpp @@ -361,7 +361,7 @@ sp_export_get_rows(guchar const **rows, void **to_free, int row, int num_rows, v /** * Hide all items that are not listed in list, recursively, skipping groups and defs. */ -static void hide_other_items_recursively(SPObject *o, const SelContainer &list, unsigned dkey) +static void hide_other_items_recursively(SPObject *o, const std::vector &list, unsigned dkey) { if ( SP_IS_ITEM(o) && !SP_IS_DEFS(o) @@ -387,7 +387,7 @@ ExportResult sp_export_png_file(SPDocument *doc, gchar const *filename, unsigned long bgcolor, unsigned int (*status) (float, void *), void *data, bool force_overwrite, - const SelContainer &items_only) + const std::vector &items_only) { return sp_export_png_file(doc, filename, Geom::Rect(Geom::Point(x0,y0),Geom::Point(x1,y1)), width, height, xdpi, ydpi, bgcolor, status, data, force_overwrite, items_only); @@ -399,7 +399,7 @@ ExportResult sp_export_png_file(SPDocument *doc, gchar const *filename, unsigned long bgcolor, unsigned (*status)(float, void *), void *data, bool force_overwrite, - const SelContainer &items_only) + const std::vector &items_only) { g_return_val_if_fail(doc != NULL, EXPORT_ERROR); g_return_val_if_fail(filename != NULL, EXPORT_ERROR); diff --git a/src/helper/png-write.h b/src/helper/png-write.h index 47fad1b41..04ca85cd6 100644 --- a/src/helper/png-write.h +++ b/src/helper/png-write.h @@ -38,12 +38,12 @@ ExportResult sp_export_png_file(SPDocument *doc, gchar const *filename, double x0, double y0, double x1, double y1, unsigned long int width, unsigned long int height, double xdpi, double ydpi, unsigned long bgcolor, - unsigned int (*status) (float, void *), void *data, bool force_overwrite = false, const SelContainer &items_only = SelContainer()); + unsigned int (*status) (float, void *), void *data, bool force_overwrite = false, const std::vector &items_only = std::vector()); ExportResult sp_export_png_file(SPDocument *doc, gchar const *filename, Geom::Rect const &area, unsigned long int width, unsigned long int height, double xdpi, double ydpi, unsigned long bgcolor, - unsigned int (*status) (float, void *), void *data, bool force_overwrite = false, const SelContainer &items_only = SelContainer()); + unsigned int (*status) (float, void *), void *data, bool force_overwrite = false, const std::vector &items_only = std::vector()); #endif // SEEN_SP_PNG_WRITE_H diff --git a/src/live_effects/lpe-knot.cpp b/src/live_effects/lpe-knot.cpp index 95a6b16dd..6cdf09180 100644 --- a/src/live_effects/lpe-knot.cpp +++ b/src/live_effects/lpe-knot.cpp @@ -505,8 +505,8 @@ LPEKnot::doEffect_path (std::vector const &path_in) static void collectPathsAndWidths (SPLPEItem const *lpeitem, std::vector &paths, std::vector &stroke_widths){ if (SP_IS_GROUP(lpeitem)) { - SelContainer item_list = sp_item_group_item_list(SP_GROUP(lpeitem)); - for ( SelContainer::const_iterator iter=item_list.begin();iter!=item_list.end();iter++) { + std::vector item_list = sp_item_group_item_list(SP_GROUP(lpeitem)); + for ( std::vector::const_iterator iter=item_list.begin();iter!=item_list.end();iter++) { SPObject *subitem = static_cast(*iter); if (SP_IS_LPE_ITEM(subitem)) { collectPathsAndWidths(SP_LPE_ITEM(subitem), paths, stroke_widths); diff --git a/src/main.cpp b/src/main.cpp index 25dc91f14..c62b9cd25 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1156,7 +1156,7 @@ static int sp_process_file_list(GSList *fl) } if (sp_export_svg) { if (sp_export_text_to_path) { - SelContainer items; + std::vector items; SPRoot *root = doc->getRoot(); doc->ensureUpToDate(); for ( SPObject *iter = root->firstChild(); iter ; iter = iter->getNext()) { @@ -1169,8 +1169,8 @@ static int sp_process_file_list(GSList *fl) items.push_back(item); } - SelContainer selected; - SelContainer to_select; + std::vector selected; + std::vector to_select; sp_item_list_to_curves(items, selected, to_select); @@ -1435,7 +1435,7 @@ static int sp_do_export_png(SPDocument *doc) g_warning ("--export-use-hints can only be used with --export-id or --export-area-drawing; ignored."); } - SelContainer items; + std::vector items; Geom::Rect area; if (sp_export_id || sp_export_area_drawing) { @@ -1459,7 +1459,7 @@ static int sp_do_export_png(SPDocument *doc) return 1; } - items.push_front(SP_ITEM(o)); + items.push_back(SP_ITEM(o)); if (sp_export_id_only) { g_print("Exporting only object with id=\"%s\"; all other objects hidden\n", sp_export_id); @@ -1647,7 +1647,7 @@ static int sp_do_export_png(SPDocument *doc) if ((width >= 1) && (height >= 1) && (width <= PNG_UINT_31_MAX) && (height <= PNG_UINT_31_MAX)) { if( sp_export_png_file(doc, path.c_str(), area, width, height, dpi, - dpi, bgcolor, NULL, NULL, true, sp_export_id_only ? items : SelContainer()) == 1 ) { + dpi, bgcolor, NULL, NULL, true, sp_export_id_only ? items : std::vector()) == 1 ) { g_print("Bitmap saved as: %s\n", filename.c_str()); } else { g_warning("Bitmap failed to save to: %s", filename.c_str()); diff --git a/src/object-snapper.cpp b/src/object-snapper.cpp index 960b5087b..830c3c1db 100644 --- a/src/object-snapper.cpp +++ b/src/object-snapper.cpp @@ -237,8 +237,8 @@ void Inkscape::ObjectSnapper::_collectNodes(SnapSourceType const &t, // current selection (see the comment in SelTrans::centerRequest()) bool old_pref2 = _snapmanager->snapprefs.isTargetSnappable(SNAPTARGET_ROTATION_CENTER); if (old_pref2) { - SelContainer rotationSource=_snapmanager->getRotationCenterSource(); - for ( SelContainer::const_iterator itemlist=rotationSource.begin();itemlist!=rotationSource.end();itemlist++) { + std::vector rotationSource=_snapmanager->getRotationCenterSource(); + for ( std::vector::const_iterator itemlist=rotationSource.begin();itemlist!=rotationSource.end();itemlist++) { if ((*i).item == reinterpret_cast(*itemlist)) { // don't snap to this item's rotation center _snapmanager->snapprefs.setTargetSnappable(SNAPTARGET_ROTATION_CENTER, false); diff --git a/src/path-chemistry.cpp b/src/path-chemistry.cpp index a5e71b720..ae1e0064f 100644 --- a/src/path-chemistry.cpp +++ b/src/path-chemistry.cpp @@ -51,13 +51,19 @@ inline bool less_than_objects(SPObject const *first, SPObject const *second) second->getRepr())<0; } +inline bool less_than_items(SPItem const *first, SPItem const *second) +{ + return sp_repr_compare_position(first->getRepr(), + second->getRepr())<0; +} + void sp_selected_path_combine(SPDesktop *desktop) { Inkscape::Selection *selection = desktop->getSelection(); SPDocument *doc = desktop->getDocument(); - SelContainer items(selection->itemList()); + std::vector items(selection->itemList()); if (items.size() < 1) { desktop->getMessageStack()->flash(Inkscape::WARNING_MESSAGE, _("Select object(s) to combine.")); @@ -70,23 +76,22 @@ sp_selected_path_combine(SPDesktop *desktop) items = sp_degroup_list (items); // descend into any groups in selection - SelContainer to_paths; - for (SelContainer::const_iterator i=items.begin();i!=items.end();i++) { + std::vector to_paths; + for (std::vector::const_reverse_iterator i=items.rbegin();i!=items.rend();i++) { SPItem *item = (SPItem *) (*i); if (!dynamic_cast(item) && !dynamic_cast(item)) { - to_paths.push_front(item); + to_paths.push_back(item); } } - SelContainer converted; + std::vector converted; bool did = sp_item_list_to_curves(to_paths, items, converted); to_paths.clear(); - for (SelContainer::const_iterator i=converted.begin();i!=converted.end();i++) - items.push_front(doc->getObjectByRepr((Inkscape::XML::Node*)(*i))); + for (std::vector::const_iterator i=converted.begin();i!=converted.end();i++) + items.push_back((SPItem*)doc->getObjectByRepr((Inkscape::XML::Node*)(*i))); items = sp_degroup_list (items); // converting to path may have added more groups, descend again - items.sort(less_than_objects); - items.reverse(); + sort(items.begin(),items.end(),less_than_objects); assert(!items.empty()); // cannot be NULL because of list length check at top of function // remember the position, id, transform and style of the topmost path, they will be assigned to the combined one @@ -104,7 +109,7 @@ sp_selected_path_combine(SPDesktop *desktop) selection->clear(); } - for (SelContainer::const_iterator i=items.begin();i!=items.end();i++){ + for (std::vector::const_reverse_iterator i=items.rbegin();i!=items.rend();i++){ SPItem *item = (SPItem *) (*i); SPPath *path = dynamic_cast(item); @@ -206,8 +211,8 @@ sp_selected_path_break_apart(SPDesktop *desktop) bool did = false; - SelContainer itemlist(selection->itemList()); - for (SelContainer::const_iterator i=itemlist.begin();i!=itemlist.end();i++){ + std::vector itemlist(selection->itemList()); + for (std::vector::const_iterator i=itemlist.begin();i!=itemlist.end();i++){ SPItem *item = (SPItem *) (*i); @@ -246,7 +251,7 @@ sp_selected_path_break_apart(SPDesktop *desktop) curve->unref(); - SelContainer reprs; + std::vector reprs; for (GSList *l = list; l != NULL; l = l->next) { curve = (SPCurve *) l->data; @@ -272,14 +277,13 @@ sp_selected_path_break_apart(SPDesktop *desktop) if (l == list) repr->setAttribute("id", id); - reprs.push_front(dynamic_cast(repr)); + reprs.push_back(repr); Inkscape::GC::release(repr); } - + //reverse selection->setReprList(reprs); - reprs.clear(); g_slist_free(list); g_free(style); g_free(path_effect); @@ -312,10 +316,10 @@ sp_selected_path_to_curves(Inkscape::Selection *selection, SPDesktop *desktop, b desktop->setWaitingCursor(); } - SelContainer selected(selection->itemList()); - SelContainer to_select; + std::vector selected(selection->itemList()); + std::vector to_select; selection->clear(); - SelContainer items(selected); + std::vector items(selected); did = sp_item_list_to_curves(items, selected, to_select); @@ -346,27 +350,24 @@ void sp_selected_to_lpeitems(SPDesktop *desktop) return; } - SelContainer selected(selection->itemList()); - SelContainer to_select; + std::vector selected(selection->itemList()); + std::vector to_select; selection->clear(); - SelContainer items(selected); + std::vector items(selected); sp_item_list_to_curves(items, selected, to_select, true); - items.clear(); selection->setReprList(to_select); selection->addList(selected); - to_select.clear(); - selected.clear(); } bool -sp_item_list_to_curves(const SelContainer &items, SelContainer& selected, SelContainer &to_select, bool skip_all_lpeitems) +sp_item_list_to_curves(const std::vector &items, std::vector& selected, std::vector &to_select, bool skip_all_lpeitems) { bool did = false; - for (SelContainer::const_iterator i=items.begin();i!=items.end();i++){ + for (std::vector::const_iterator i=items.begin();i!=items.end();i++){ SPItem *item = dynamic_cast(static_cast(*i)); g_assert(item != NULL); @@ -399,9 +400,9 @@ sp_item_list_to_curves(const SelContainer &items, SelContainer& selected, SelCon Inkscape::XML::Node *repr = box3d_convert_to_group(box)->getRepr(); if (repr) { - to_select.push_front(dynamic_cast(repr)); + to_select.push_back(repr); did = true; - selected.remove(item); + selected.erase(find(selected.begin(),selected.end(),item)); } continue; @@ -409,10 +410,10 @@ sp_item_list_to_curves(const SelContainer &items, SelContainer& selected, SelCon if (group) { group->removeAllPathEffects(true); - SelContainer item_list = sp_item_group_item_list(group); + std::vector item_list = sp_item_group_item_list(group); - SelContainer item_to_select; - SelContainer item_selected; + std::vector item_to_select; + std::vector item_selected; if (sp_item_list_to_curves(item_list, item_selected, item_to_select)) did = true; @@ -429,7 +430,7 @@ sp_item_list_to_curves(const SelContainer &items, SelContainer& selected, SelCon continue; did = true; - selected.remove(item); + selected.erase(find(selected.begin(),selected.end(),item)); // remember the position of the item gint pos = item->getRepr()->position(); @@ -471,7 +472,7 @@ sp_item_list_to_curves(const SelContainer &items, SelContainer& selected, SelCon /* Buglet: We don't re-add the (new version of the) object to the selection of any other * desktops where it was previously selected. */ - to_select.push_front(dynamic_cast(repr)); + to_select.push_back(repr); Inkscape::GC::release(repr); } @@ -613,7 +614,7 @@ void sp_selected_path_reverse(SPDesktop *desktop) { Inkscape::Selection *selection = desktop->getSelection(); - SelContainer items = selection->itemList(); + std::vector items = selection->itemList(); if (items.empty()) { desktop->getMessageStack()->flash(Inkscape::WARNING_MESSAGE, _("Select path(s) to reverse.")); @@ -627,7 +628,7 @@ sp_selected_path_reverse(SPDesktop *desktop) bool did = false; desktop->messageStack()->flash(Inkscape::IMMEDIATE_MESSAGE, _("Reversing paths...")); - for (SelContainer::const_iterator i=items.begin();i!=items.end();i++){ + for (std::vector::const_iterator i=items.begin();i!=items.end();i++){ SPPath *path = dynamic_cast(static_cast(*i)); if (!path) { diff --git a/src/path-chemistry.h b/src/path-chemistry.h index 388268af4..f454167a9 100644 --- a/src/path-chemistry.h +++ b/src/path-chemistry.h @@ -33,7 +33,7 @@ void sp_selected_path_to_curves (Inkscape::Selection *selection, SPDesktop *desk void sp_selected_to_lpeitems(SPDesktop *desktop); Inkscape::XML::Node *sp_selected_item_to_curved_repr(SPItem *item, guint32 text_grouping_policy); void sp_selected_path_reverse (SPDesktop *desktop); -bool sp_item_list_to_curves(const SelContainer &items, SelContainer &selected, SelContainer &to_select, bool skip_all_lpeitems = false); +bool sp_item_list_to_curves(const std::vector &items, std::vector &selected, std::vector &to_select, bool skip_all_lpeitems = false); #endif // SEEN_PATH_CHEMISTRY_H diff --git a/src/removeoverlap.cpp b/src/removeoverlap.cpp index 9009de5e9..7cb1694e3 100644 --- a/src/removeoverlap.cpp +++ b/src/removeoverlap.cpp @@ -38,14 +38,14 @@ namespace { * such that rectangular bounding boxes are separated by at least xGap * horizontally and yGap vertically */ -void removeoverlap(SelContainer const &items, double const xGap, double const yGap) { +void removeoverlap(std::vector const &items, double const xGap, double const yGap) { using Inkscape::Util::GSListConstIterator; - SelContainer selected(items); + std::vector selected(items); std::vector records; std::vector rs; Geom::Point const gap(xGap, yGap); - for (SelContainer::iterator it(selected.begin()); + for (std::vector::iterator it(selected.begin()); it != selected.end(); ++it) { diff --git a/src/removeoverlap.h b/src/removeoverlap.h index d050ca9ef..d873663d1 100644 --- a/src/removeoverlap.h +++ b/src/removeoverlap.h @@ -15,6 +15,6 @@ typedef struct _GSList GSList; -void removeoverlap(SelContainer const &items, double xGap, double yGap); +void removeoverlap(std::vector const &items, double xGap, double yGap); #endif // SEEN_REMOVEOVERLAP_H diff --git a/src/selcue.cpp b/src/selcue.cpp index 0fab6e5a8..f48378cdc 100644 --- a/src/selcue.cpp +++ b/src/selcue.cpp @@ -96,15 +96,15 @@ void Inkscape::SelCue::_updateItemBboxes(Inkscape::Preferences *prefs) void Inkscape::SelCue::_updateItemBboxes(gint mode, int prefs_bbox) { - const SelContainer items = _selection->itemList(); + const std::vector items = _selection->itemList(); if (_item_bboxes.size() != items.size()) { _newItemBboxes(); return; } int bcount = 0; - SelContainer ll=_selection->itemList(); - for (SelContainer::const_iterator l=ll.begin();l!=ll.end();l++) { + std::vector ll=_selection->itemList(); + for (std::vector::const_iterator l=ll.begin();l!=ll.end();l++) { SPItem *item = static_cast(*l); SPCanvasItem* box = _item_bboxes[bcount ++]; @@ -146,8 +146,8 @@ void Inkscape::SelCue::_newItemBboxes() int prefs_bbox = prefs->getBool("/tools/bounding_box"); - SelContainer ll=_selection->itemList(); - for (SelContainer::const_iterator l=ll.begin();l!=ll.end();l++) { + std::vector ll=_selection->itemList(); + for (std::vector::const_iterator l=ll.begin();l!=ll.end();l++) { SPItem *item = static_cast(*l); Geom::OptRect const b = (prefs_bbox == 0) ? @@ -201,8 +201,8 @@ void Inkscape::SelCue::_newTextBaselines() } _text_baselines.clear(); - SelContainer ll=_selection->itemList(); - for (SelContainer::const_iterator l=ll.begin();l!=ll.end();l++) { + std::vector ll=_selection->itemList(); + for (std::vector::const_iterator l=ll.begin();l!=ll.end();l++) { SPItem *item = static_cast(*l); SPCanvasItem* baseline_point = NULL; diff --git a/src/selection-chemistry.cpp b/src/selection-chemistry.cpp index 9f27ca22e..f1c96b6b8 100644 --- a/src/selection-chemistry.cpp +++ b/src/selection-chemistry.cpp @@ -279,23 +279,21 @@ void SelectionHelper::fixSelection(SPDesktop *dt) Inkscape::Selection *selection = dt->getSelection(); - SelContainer items ; + std::vector items ; - SelContainer const selList = selection->itemList(); + std::vector const selList = selection->itemList(); - for( SelContainer::const_iterator i=selList.begin();i!=selList.end();i++ ) { + for( std::vector::const_reverse_iterator i=selList.rbegin();i!=selList.rend();i++ ) { SPItem *item = dynamic_cast(static_cast(*i)); if( item && !dt->isLayer(item) && (!item->isLocked())) { - items.push_front(item); + items.push_back(item); } } selection->setList(items); - - items.clear(); } } // namespace Inkscape @@ -305,7 +303,7 @@ void SelectionHelper::fixSelection(SPDesktop *dt) * Copies repr and its inherited css style elements, along with the accumulated transform 'full_t', * then prepends the copy to 'clip'. */ -static void sp_selection_copy_one(Inkscape::XML::Node *repr, Geom::Affine full_t, SelContainer &clip, Inkscape::XML::Document* xml_doc) +static void sp_selection_copy_one(Inkscape::XML::Node *repr, Geom::Affine full_t, std::vector &clip, Inkscape::XML::Document* xml_doc) { Inkscape::XML::Node *copy = repr->duplicate(xml_doc); @@ -321,17 +319,17 @@ static void sp_selection_copy_one(Inkscape::XML::Node *repr, Geom::Affine full_t copy->setAttribute("transform", affinestr); g_free(affinestr); - clip.push_front(dynamic_cast(copy)); + clip.insert(clip.begin(),dynamic_cast(copy)); } -static void sp_selection_copy_impl(SelContainer const &items, SelContainer &clip, Inkscape::XML::Document* xml_doc) +static void sp_selection_copy_impl(std::vector const &items, std::vector &clip, Inkscape::XML::Document* xml_doc) { // Sort items: - SelContainer sorted_items(items); - sorted_items.sort(sp_object_compare_position); + std::vector sorted_items(items); + sort(sorted_items.begin(),sorted_items.end(),sp_object_compare_position); // Copy item reprs: - for (SelContainer::const_iterator i = sorted_items.begin();i!=sorted_items.end();i++) { + for (std::vector::const_iterator i = sorted_items.begin();i!=sorted_items.end();i++) { SPItem *item = dynamic_cast(SP_OBJECT(*i)); if (item) { sp_selection_copy_one(item->getRepr(), item->i2doc_affine(), clip, xml_doc); @@ -339,22 +337,22 @@ static void sp_selection_copy_impl(SelContainer const &items, SelContainer &clip g_assert_not_reached(); } } - - clip.reverse(); + std::vector tmp(clip); + for(int i=0;i sp_selection_paste_impl(SPDocument *doc, SPObject *parent, std::vector &clip) { Inkscape::XML::Document *xml_doc = doc->getReprDoc(); SPItem *parentItem = dynamic_cast(parent); g_assert(parentItem != NULL); - SelContainer copied; + std::vector copied; // add objects to document - for (SelContainer::const_iterator l=clip.begin();l!=clip.end();l++) { + for (std::vector::const_iterator l=clip.begin();l!=clip.end();l++) { Inkscape::XML::Node *repr = dynamic_cast(*l); Inkscape::XML::Node *copy = repr->duplicate(xml_doc); @@ -373,18 +371,18 @@ static SelContainer sp_selection_paste_impl(SPDocument *doc, SPObject *parent, S } parent->appendChildRepr(copy); - copied.push_front(dynamic_cast(copy)); + copied.push_back(copy); Inkscape::GC::release(copy); } return copied; } -static void sp_selection_delete_impl(SelContainer const &items, bool propagate = true, bool propagate_descendants = true) +static void sp_selection_delete_impl(std::vector const &items, bool propagate = true, bool propagate_descendants = true) { - for (SelContainer::const_iterator i=items.begin();i!=items.end();i++) { + for (std::vector::const_iterator i=items.begin();i!=items.end();i++) { sp_object_ref(static_cast(*i), NULL); } - for (SelContainer::const_iterator i=items.begin();i!=items.end();i++) { + for (std::vector::const_iterator i=items.begin();i!=items.end();i++) { SPItem *item = static_cast(*i); item->deleteObject(propagate, propagate_descendants); sp_object_unref(item, NULL); @@ -412,7 +410,7 @@ void sp_selection_delete(SPDesktop *desktop) desktop->messageStack()->flash(Inkscape::WARNING_MESSAGE, _("Nothing was deleted.")); return; } - SelContainer selected(selection->itemList()); + std::vector selected(selection->itemList()); selection->clear(); sp_selection_delete_impl(selected); selected.clear(); @@ -470,7 +468,7 @@ void sp_selection_duplicate(SPDesktop *desktop, bool suppressDone) // them, just what we need sort(reprs.begin(),reprs.end(),sp_repr_compare_position); - SelContainer newsel; + std::vector newsel; std::vector old_ids; std::vector new_ids; @@ -500,7 +498,7 @@ void sp_selection_duplicate(SPDesktop *desktop, bool suppressDone) } } - newsel.push_front(dynamic_cast(copy)); + newsel.push_back(copy); Inkscape::GC::release(copy); } @@ -546,8 +544,6 @@ void sp_selection_duplicate(SPDesktop *desktop, bool suppressDone) } selection->setReprList(newsel); - - newsel.clear(); } void sp_edit_clear_all(Inkscape::Selection *selection) @@ -560,11 +556,10 @@ void sp_edit_clear_all(Inkscape::Selection *selection) SPGroup *group = dynamic_cast(selection->layers()->currentLayer()); g_return_if_fail(group != NULL); - SelContainer items = sp_item_group_item_list(group); + std::vector items = sp_item_group_item_list(group); - while (!items.empty()) { - reinterpret_cast(items.front())->deleteObject(); - items.pop_front(); + for(int i=0;i(items[i])->deleteObject(); } DocumentUndo::done(doc, SP_VERB_EDIT_CLEAR_ALL, @@ -581,7 +576,7 @@ void sp_edit_clear_all(Inkscape::Selection *selection) * onlysensitive - TRUE includes only non-locked items * ingroups - TRUE to recursively get grouped items children */ -SelContainer &get_all_items(SelContainer &list, SPObject *from, SPDesktop *desktop, bool onlyvisible, bool onlysensitive, bool ingroups, SelContainer const &exclude) +std::vector &get_all_items(std::vector &list, SPObject *from, SPDesktop *desktop, bool onlyvisible, bool onlysensitive, bool ingroups, std::vector const &exclude) { for ( SPObject *child = from->firstChild() ; child; child = child->getNext() ) { SPItem *item = dynamic_cast(child); @@ -592,7 +587,7 @@ SelContainer &get_all_items(SelContainer &list, SPObject *from, SPDesktop *deskt (exclude.empty() || exclude.end() == std::find(exclude.begin(),exclude.end(),child)) ) { - list.push_front(item); + list.insert(list.begin(),item); } if (ingroups || (item && desktop->isLayer(item))) { @@ -617,9 +612,9 @@ static void sp_edit_select_all_full(SPDesktop *dt, bool force_all_layers, bool i bool onlyvisible = prefs->getBool("/options/kbselection/onlyvisible", true); bool onlysensitive = prefs->getBool("/options/kbselection/onlysensitive", true); - SelContainer items ; + std::vector items ; - SelContainer exclude; + std::vector exclude; if (invert) { exclude = selection->itemList(); } @@ -633,16 +628,16 @@ static void sp_edit_select_all_full(SPDesktop *dt, bool force_all_layers, bool i (onlyvisible && dt->itemIsHidden(dynamic_cast(dt->currentLayer()))) ) return; - SelContainer all_items = sp_item_group_item_list(dynamic_cast(dt->currentLayer())); + std::vector all_items = sp_item_group_item_list(dynamic_cast(dt->currentLayer())); - for (SelContainer::const_iterator i=all_items.begin();i!=all_items.end();i++) { + for (std::vector::const_reverse_iterator i=all_items.rbegin();i!=all_items.rend();i++) { SPItem *item = dynamic_cast(static_cast(*i)); if (item && (!onlysensitive || !item->isLocked())) { if (!onlyvisible || !dt->itemIsHidden(item)) { if (!dt->isLayer(item)) { if (!invert || exclude.end() == std::find(exclude.begin(),exclude.end(),item)) { - items.push_front(item); // leave it in the list + items.push_back(item); // leave it in the list } } } @@ -653,12 +648,12 @@ static void sp_edit_select_all_full(SPDesktop *dt, bool force_all_layers, bool i break; } case PREFS_SELECTION_LAYER_RECURSIVE: { - SelContainer x; + std::vector x; items = get_all_items(x, dt->currentLayer(), dt, onlyvisible, onlysensitive, FALSE, exclude); break; } default: { - SelContainer x; + std::vector x; items = get_all_items(x, dt->currentRoot(), dt, onlyvisible, onlysensitive, FALSE, exclude); break; } @@ -709,7 +704,7 @@ static void sp_selection_group_impl(std::vector p, Inkscap Inkscape::GC::release(spnew); topmost --; // only reduce count for those items deleted from topmost_parent } else { // move it to topmost_parent first - SelContainer temp_clip; + std::vector temp_clip; // At this point, current may already have no item, due to its being a clone whose original is already moved away // So we copy it artificially calculating the transform from its repr->attr("transform") and the parent transform @@ -729,11 +724,11 @@ static void sp_selection_group_impl(std::vector p, Inkscap sp_repr_unparent(current); // paste into topmost_parent (temporarily) - SelContainer copied = sp_selection_paste_impl(doc, doc->getObjectByRepr(topmost_parent), temp_clip); + std::vector copied = sp_selection_paste_impl(doc, doc->getObjectByRepr(topmost_parent), temp_clip); if (!temp_clip.empty())temp_clip.clear() ; if (!copied.empty()) { // if success, // take pasted object (now in topmost_parent) - Inkscape::XML::Node *in_topmost = dynamic_cast(copied.front()); + Inkscape::XML::Node *in_topmost = copied.back(); // make a copy Inkscape::XML::Node *spnew = in_topmost->duplicate(xml_doc); // remove pasted @@ -800,10 +795,10 @@ void sp_selection_ungroup(Inkscape::Selection *selection, SPDesktop *desktop) } // first check whether there is anything to ungroup - SelContainer old_select = selection->itemList(); - SelContainer new_select; + std::vector old_select = selection->itemList(); + std::vector new_select; GSList *groups = NULL; - for (SelContainer::const_iterator item = old_select.begin(); item!=old_select.end(); item++) { + for (std::vector::const_iterator item = old_select.begin(); item!=old_select.end(); item++) { SPItem *obj = static_cast(*item); if (dynamic_cast(obj)) { groups = g_slist_prepend(groups, obj); @@ -816,13 +811,13 @@ void sp_selection_ungroup(Inkscape::Selection *selection, SPDesktop *desktop) return; } - SelContainer items(old_select); + std::vector items(old_select); selection->clear(); // If any of the clones refer to the groups, unlink them and replace them with successors // in the items list. GSList *clones_to_unlink = NULL; - for (SelContainer::const_iterator item = items.begin(); item!=items.end(); item++) { + for (std::vector::const_iterator item = items.begin(); item!=items.end(); item++) { SPUse *use = dynamic_cast(static_cast(*item)); SPItem *original = use; @@ -842,21 +837,21 @@ void sp_selection_ungroup(Inkscape::Selection *selection, SPDesktop *desktop) for (GSList *item = clones_to_unlink; item; item = item->next) { SPUse *use = static_cast(item->data); - SelContainer::iterator items_node = std::find(items.begin(),items.end(), item->data); + std::vector::iterator items_node = std::find(items.begin(),items.end(), item->data); (*items_node) = use->unlink(); } g_slist_free(clones_to_unlink); // do the actual work - for (SelContainer::iterator item = items.begin(); item!=items.end(); item++) { + for (std::vector::iterator item = items.begin(); item!=items.end(); item++) { SPItem *obj = static_cast(*item); // ungroup only the groups marked earlier if (g_slist_find(groups, *item) != NULL) { - SelContainer children; + std::vector children; sp_item_group_ungroup(dynamic_cast(obj), children, false); // add the items resulting from ungrouping to the selection - new_select.splice(new_select.end(),children); + new_select.insert(new_select.end(),children.begin(),children.end()); (*item) = NULL; // zero out the original pointer, which is no longer valid } else { // if not a group, keep in the selection @@ -873,25 +868,24 @@ void sp_selection_ungroup(Inkscape::Selection *selection, SPDesktop *desktop) } /** Replace all groups in the list with their member objects, recursively; returns a new list, frees old */ -SelContainer -sp_degroup_list(SelContainer &items) +std::vector +sp_degroup_list(std::vector &items) { - SelContainer out; + std::vector out; bool has_groups = false; - for (SelContainer::const_iterator item=items.begin();item!=items.end();item++) { + for (std::vector::const_iterator item=items.begin();item!=items.end();item++) { SPGroup *group = dynamic_cast(static_cast(*item)); if (!group) { - out.push_front(*item); + out.push_back(*item); } else { has_groups = true; - SelContainer members = sp_item_group_item_list(group); - for (SelContainer::const_iterator member=members.begin();member!=members.end();member++) { - out.push_front(*member); + std::vector members = sp_item_group_item_list(group); + for (std::vector::const_iterator member=members.begin();member!=members.end();member++) { + out.push_back(*member); } members.clear(); } } - out.reverse(); items.clear(); if (has_groups) { // recurse if we unwrapped a group - it may have contained others @@ -904,7 +898,7 @@ sp_degroup_list(SelContainer &items) /** If items in the list have a common parent, return it, otherwise return NULL */ static SPGroup * -sp_item_list_common_parent_group(SelContainer const items) +sp_item_list_common_parent_group(std::vector const items) { if (items.empty()) { return NULL; @@ -914,7 +908,7 @@ sp_item_list_common_parent_group(SelContainer const items) if (!dynamic_cast(parent)) { return NULL; } - for (SelContainer::const_iterator item=items.begin();item!=items.end();item++) { + for (std::vector::const_iterator item=items.begin();item!=items.end();item++) { if((*item)==items.front())continue; if (SP_OBJECT(*item)->parent != parent) { return NULL; @@ -926,12 +920,12 @@ sp_item_list_common_parent_group(SelContainer const items) /** Finds out the minimum common bbox of the selected items. */ static Geom::OptRect -enclose_items(SelContainer const &items) +enclose_items(std::vector const &items) { g_assert(!items.empty()); Geom::OptRect r; - for (SelContainer::const_iterator i = items.begin();i!=items.end();i++) { + for (std::vector::const_iterator i = items.begin();i!=items.end();i++) { r.unionWith(static_cast(*i)->desktopVisualBounds()); } return r; @@ -956,7 +950,7 @@ int sp_item_repr_compare_position_obj(SPObject const *first, SPObject const *sec void sp_selection_raise(Inkscape::Selection *selection, SPDesktop *desktop) { - SelContainer items= selection->itemList(); + std::vector items= selection->itemList(); if (items.empty()) { selection_display_message(desktop, Inkscape::WARNING_MESSAGE, _("Select object(s) to raise.")); return; @@ -971,16 +965,16 @@ sp_selection_raise(Inkscape::Selection *selection, SPDesktop *desktop) Inkscape::XML::Node *grepr = const_cast(group->getRepr()); /* Construct reverse-ordered list of selected children. */ - SelContainer rev(items); - rev.sort(sp_item_repr_compare_position_obj); + std::vector rev(items); + sort(rev.begin(),rev.end(),sp_item_repr_compare_position); // Determine the common bbox of the selected items. Geom::OptRect selected = enclose_items(items); // Iterate over all objects in the selection (starting from top). if (selected) { - while (!rev.empty()) { - SPObject *child = reinterpret_cast(rev.front()); + for (std::vector::const_iterator item=rev.begin();item!=rev.end();item++) { + SPObject *child = reinterpret_cast(*item); // for each selected object, find the next sibling for (SPObject *newref = child->next; newref; newref = newref->next) { // if the sibling is an item AND overlaps our selection, @@ -997,7 +991,6 @@ sp_selection_raise(Inkscape::Selection *selection, SPDesktop *desktop) } } } - rev.pop_front(); } } else { rev.clear(); @@ -1017,7 +1010,7 @@ void sp_selection_raise_to_top(Inkscape::Selection *selection, SPDesktop *deskto return; } - SelContainer items = selection->itemList(); + std::vector items = selection->itemList(); SPGroup const *group = sp_item_list_common_parent_group(items); if (!group) { @@ -1039,7 +1032,7 @@ void sp_selection_raise_to_top(Inkscape::Selection *selection, SPDesktop *deskto void sp_selection_lower(Inkscape::Selection *selection, SPDesktop *desktop) { - SelContainer items = selection->itemList(); + std::vector items = selection->itemList(); if (items.empty()) { selection_display_message(desktop, Inkscape::WARNING_MESSAGE, _("Select object(s) to lower.")); return; @@ -1057,14 +1050,13 @@ void sp_selection_lower(Inkscape::Selection *selection, SPDesktop *desktop) Geom::OptRect selected = enclose_items(items); /* Construct direct-ordered list of selected children. */ - SelContainer rev(items); - rev.sort(sp_item_repr_compare_position_obj); - rev.reverse(); + std::vector rev(items); + sort(rev.begin(),rev.end(),sp_item_repr_compare_position); // Iterate over all objects in the selection (starting from top). if (selected) { - while (!rev.empty()) { - SPObject *child = reinterpret_cast(rev.front()); + for (std::vector::const_reverse_iterator item=rev.rbegin();item!=rev.rend();item++) { + SPObject *child = reinterpret_cast(*item); // for each selected object, find the prev sibling for (SPObject *newref = prev_sibling(child); newref; newref = prev_sibling(newref)) { // if the sibling is an item AND overlaps our selection, @@ -1085,7 +1077,6 @@ void sp_selection_lower(Inkscape::Selection *selection, SPDesktop *desktop) } } } - rev.pop_front(); } } else { rev.clear(); @@ -1105,7 +1096,7 @@ void sp_selection_lower_to_bottom(Inkscape::Selection *selection, SPDesktop *des return; } - SelContainer items =selection->itemList(); + std::vector items =selection->itemList(); SPGroup const *group = sp_item_list_common_parent_group(items); if (!group) { @@ -1268,8 +1259,8 @@ void sp_selection_remove_livepatheffect(SPDesktop *desktop) desktop->messageStack()->flash(Inkscape::WARNING_MESSAGE, _("Select object(s) to remove live path effects from.")); return; } - SelContainer list=selection->itemList(); - for ( SelContainer::const_iterator itemlist=list.begin();itemlist!=list.end();itemlist++) { + std::vector list=selection->itemList(); + for ( std::vector::const_iterator itemlist=list.begin();itemlist!=list.end();itemlist++) { SPItem *item = reinterpret_cast(*itemlist); sp_selection_remove_livepatheffect_impl(item); @@ -1330,16 +1321,16 @@ void sp_selection_to_next_layer(SPDesktop *dt, bool suppressDone) return; } - SelContainer items(selection->itemList()); + std::vector items(selection->itemList()); bool no_more = false; // Set to true, if no more layers above SPObject *next=Inkscape::next_layer(dt->currentRoot(), dt->currentLayer()); if (next) { - SelContainer temp_clip; + std::vector temp_clip; sp_selection_copy_impl(items, temp_clip, dt->doc()->getReprDoc()); sp_selection_delete_impl(items, false, false); next=Inkscape::next_layer(dt->currentRoot(), dt->currentLayer()); // Fixes bug 1482973: crash while moving layers - SelContainer copied; + std::vector copied; if (next) { copied = sp_selection_paste_impl(dt->getDocument(), next, temp_clip); } else { @@ -1375,16 +1366,16 @@ void sp_selection_to_prev_layer(SPDesktop *dt, bool suppressDone) return; } - const SelContainer items(selection->itemList()); + const std::vector items(selection->itemList()); bool no_more = false; // Set to true, if no more layers below SPObject *next=Inkscape::previous_layer(dt->currentRoot(), dt->currentLayer()); if (next) { - SelContainer temp_clip; + std::vector temp_clip; sp_selection_copy_impl(items, temp_clip, dt->doc()->getReprDoc()); // we're in the same doc, so no need to copy defs sp_selection_delete_impl(items, false, false); next=Inkscape::previous_layer(dt->currentRoot(), dt->currentLayer()); // Fixes bug 1482973: crash while moving layers - SelContainer copied; + std::vector copied; if (next) { copied = sp_selection_paste_impl(dt->getDocument(), next, temp_clip); } else { @@ -1418,13 +1409,13 @@ void sp_selection_to_layer(SPDesktop *dt, SPObject *moveto, bool suppressDone) return; } - SelContainer items(selection->itemList()); + std::vector items(selection->itemList()); if (moveto) { - SelContainer temp_clip; + std::vector temp_clip; sp_selection_copy_impl(items, temp_clip, dt->doc()->getReprDoc()); // we're in the same doc, so no need to copy defs sp_selection_delete_impl(items, false, false); - SelContainer copied = sp_selection_paste_impl(dt->getDocument(), moveto, temp_clip); + std::vector copied = sp_selection_paste_impl(dt->getDocument(), moveto, temp_clip); selection->setReprList(copied); copied.clear(); if (!temp_clip.empty()) temp_clip.clear(); @@ -1468,8 +1459,8 @@ static bool selection_contains_both_clone_and_original(Inkscape::Selection *selection) { bool clone_with_original = false; - SelContainer items = selection->itemList(); - for (SelContainer::const_iterator l=items.begin();l!=items.end() ;l++) { + std::vector items = selection->itemList(); + for (std::vector::const_iterator l=items.begin();l!=items.end() ;l++) { SPItem *item = dynamic_cast(static_cast(*l)); if (item) { clone_with_original |= selection_contains_original(item, selection); @@ -1513,8 +1504,8 @@ void sp_selection_apply_affine(Inkscape::Selection *selection, Geom::Affine cons persp3d_apply_affine_transformation(transf_persp, affine); } - SelContainer items = selection->itemList(); - for (SelContainer::const_iterator l=items.begin();l!=items.end() ;l++) { + std::vector items = selection->itemList(); + for (std::vector::const_iterator l=items.begin();l!=items.end() ;l++) { SPItem *item = dynamic_cast(static_cast(*l)); if( dynamic_cast(item) ) { @@ -1784,9 +1775,9 @@ void sp_selection_rotate_90(SPDesktop *desktop, bool ccw) if (selection->isEmpty()) return; - SelContainer items = selection->itemList(); + std::vector items = selection->itemList(); Geom::Rotate const rot_90(Geom::Point(0, ccw ? 1 : -1)); // pos. or neg. rotation, depending on the value of ccw - for (SelContainer::const_iterator l=items.begin();l!=items.end() ;l++) { + for (std::vector::const_iterator l=items.begin();l!=items.end() ;l++) { SPItem *item = dynamic_cast(static_cast(*l)); if (item) { sp_item_rotate_rel(item, rot_90); @@ -1843,15 +1834,15 @@ void sp_select_same_fill_stroke_style(SPDesktop *desktop, gboolean fill, gboolea bool onlyvisible = prefs->getBool("/options/kbselection/onlyvisible", true); bool onlysensitive = prefs->getBool("/options/kbselection/onlysensitive", true); bool ingroups = TRUE; - SelContainer x,y; - SelContainer all_list = get_all_items(x, desktop->currentRoot(), desktop, onlyvisible, onlysensitive, ingroups, y); - SelContainer all_matches; + std::vector x,y; + std::vector all_list = get_all_items(x, desktop->currentRoot(), desktop, onlyvisible, onlysensitive, ingroups, y); + std::vector all_matches; Inkscape::Selection *selection = desktop->getSelection(); - SelContainer items = selection->itemList(); - for (SelContainer::const_iterator sel_iter=items.begin();sel_iter!=items.end();sel_iter++) { + std::vector items = selection->itemList(); + for (std::vector::const_iterator sel_iter=items.begin();sel_iter!=items.end();sel_iter++) { SPItem *sel = dynamic_cast(static_cast(*sel_iter)); - SelContainer matches = all_list; + std::vector matches = all_list; if (fill) { matches = sp_get_same_fill_or_stroke_color(sel, matches, SP_FILL_COLOR); } @@ -1863,7 +1854,7 @@ void sp_select_same_fill_stroke_style(SPDesktop *desktop, gboolean fill, gboolea matches = sp_get_same_stroke_style(sel, matches, SP_STROKE_STYLE_DASHES); matches = sp_get_same_stroke_style(sel, matches, SP_STROKE_STYLE_MARKERS); } - all_matches.splice(all_matches.end(), matches); + all_matches.insert(all_matches.end(), matches.begin(),matches.end()); } selection->clear(); @@ -1889,14 +1880,14 @@ void sp_select_same_object_type(SPDesktop *desktop) bool onlyvisible = prefs->getBool("/options/kbselection/onlyvisible", true); bool onlysensitive = prefs->getBool("/options/kbselection/onlysensitive", true); bool ingroups = TRUE; - SelContainer x,y; - SelContainer all_list = get_all_items(x, desktop->currentRoot(), desktop, onlyvisible, onlysensitive, ingroups, y); - SelContainer matches = all_list; + std::vector x,y; + std::vector all_list = get_all_items(x, desktop->currentRoot(), desktop, onlyvisible, onlysensitive, ingroups, y); + std::vector matches = all_list; Inkscape::Selection *selection = desktop->getSelection(); - SelContainer items=selection->itemList(); - for (SelContainer::const_iterator sel_iter=items.begin();sel_iter!=items.end();sel_iter++) { + std::vector items=selection->itemList(); + for (std::vector::const_iterator sel_iter=items.begin();sel_iter!=items.end();sel_iter++) { SPItem *sel = dynamic_cast(static_cast(*sel_iter)); if (sel) { matches = sp_get_same_object_type(sel, matches); @@ -1927,13 +1918,13 @@ void sp_select_same_stroke_style(SPDesktop *desktop) bool onlysensitive = prefs->getBool("/options/kbselection/onlysensitive", true); bool ingroups = TRUE; - SelContainer x,y; - SelContainer matches = get_all_items(x, desktop->currentRoot(), desktop, onlyvisible, onlysensitive, ingroups, y); + std::vector x,y; + std::vector matches = get_all_items(x, desktop->currentRoot(), desktop, onlyvisible, onlysensitive, ingroups, y); Inkscape::Selection *selection = desktop->getSelection(); - SelContainer items=selection->itemList(); + std::vector items=selection->itemList(); - for (SelContainer::const_iterator sel_iter=items.begin();sel_iter!=items.end();sel_iter++) { + for (std::vector::const_iterator sel_iter=items.begin();sel_iter!=items.end();sel_iter++) { SPItem *sel = dynamic_cast(static_cast(*sel_iter)); if (sel) { matches = sp_get_same_stroke_style(sel, matches, SP_STROKE_STYLE_WIDTH); @@ -1953,14 +1944,14 @@ void sp_select_same_stroke_style(SPDesktop *desktop) * Find all items in src list that have the same fill or stroke style as sel * Return the list of matching items */ -SelContainer sp_get_same_fill_or_stroke_color(SPItem *sel, SelContainer &src, SPSelectStrokeStyleType type) +std::vector sp_get_same_fill_or_stroke_color(SPItem *sel, std::vector &src, SPSelectStrokeStyleType type) { - SelContainer matches ; + std::vector matches ; gboolean match = false; SPIPaint *sel_paint = (type == SP_FILL_COLOR) ? &(sel->style->fill) : &(sel->style->stroke); - for (SelContainer::const_iterator i=src.begin();i!=src.end();i++) { + for (std::vector::const_reverse_iterator i=src.rbegin();i!=src.rend();i++) { SPItem *iter = dynamic_cast(static_cast(*i)); if (iter) { SPIPaint *iter_paint = (type == SP_FILL_COLOR) ? &(iter->style->fill) : &(iter->style->stroke); @@ -2000,7 +1991,7 @@ SelContainer sp_get_same_fill_or_stroke_color(SPItem *sel, SelContainer &src, SP } if (match) { - matches.push_front(iter); + matches.push_back(iter); } } else { g_assert_not_reached(); @@ -2051,14 +2042,14 @@ static bool item_type_match (SPItem *i, SPItem *j) * Find all items in src list that have the same object type as sel by type * Return the list of matching items */ -SelContainer sp_get_same_object_type(SPItem *sel, SelContainer &src) +std::vector sp_get_same_object_type(SPItem *sel, std::vector &src) { - SelContainer matches; + std::vector matches; - for (SelContainer::const_iterator i=src.begin();i!=src.end();i++) { + for (std::vector::const_reverse_iterator i=src.rbegin();i!=src.rend();i++) { SPItem *item = dynamic_cast(static_cast(*i)); if (item && item_type_match(sel, item)) { - matches.push_front(item); + matches.push_back(item); } } return matches; @@ -2068,9 +2059,9 @@ SelContainer sp_get_same_object_type(SPItem *sel, SelContainer &src) * Find all items in src list that have the same stroke style as sel by type * Return the list of matching items */ -SelContainer sp_get_same_stroke_style(SPItem *sel, SelContainer &src, SPSelectStrokeStyleType type) +std::vector sp_get_same_stroke_style(SPItem *sel, std::vector &src, SPSelectStrokeStyleType type) { - SelContainer matches; + std::vector matches; gboolean match = false; SPStyle *sel_style = sel->style; @@ -2083,14 +2074,14 @@ SelContainer sp_get_same_stroke_style(SPItem *sel, SelContainer &src, SPSelectSt * Stroke width needs to handle transformations, so call this function * to get the transformed stroke width */ - SelContainer objects; + std::vector objects; SPStyle *sel_style_for_width = NULL; if (type == SP_STROKE_STYLE_WIDTH) { - objects.push_front(sel); + objects.push_back(sel); sel_style_for_width = new SPStyle(SP_ACTIVE_DOCUMENT); objects_query_strokewidth (objects, sel_style_for_width); } - for (SelContainer::const_iterator i=src.begin();i!=src.end();i++) { + for (std::vector::const_iterator i=src.begin();i!=src.end();i++) { SPItem *iter = dynamic_cast(static_cast(*i)); if (iter) { SPStyle *iter_style = iter->style; @@ -2099,8 +2090,8 @@ SelContainer sp_get_same_stroke_style(SPItem *sel, SelContainer &src, SPSelectSt if (type == SP_STROKE_STYLE_WIDTH) { match = (sel_style->stroke_width.set == iter_style->stroke_width.set); if (sel_style->stroke_width.set && iter_style->stroke_width.set) { - SelContainer objects; - objects.push_front(iter); + std::vector objects; + objects.insert(objects.begin(),iter); SPStyle tmp_style(SP_ACTIVE_DOCUMENT); objects_query_strokewidth (objects, &tmp_style); @@ -2130,7 +2121,7 @@ SelContainer sp_get_same_stroke_style(SPItem *sel, SelContainer &src, SPSelectSt } if (match) { - matches.push_front(iter); + matches.insert(matches.begin(),iter); } } else { g_assert_not_reached(); @@ -2386,11 +2377,11 @@ SPItem *next_item(SPDesktop *desktop, GSList *path, SPObject *root, template -SPItem *next_item_from_list(SPDesktop *desktop, SelContainer const items, +SPItem *next_item_from_list(SPDesktop *desktop, std::vector const items, SPObject *root, bool only_in_viewport, PrefsSelectionContext inlayer, bool onlyvisible, bool onlysensitive) { SPObject *current=root; - for(SelContainer::const_iterator i = items.begin();i!=items.end();i++) { + for(std::vector::const_iterator i = items.begin();i!=items.end();i++) { SPItem *item = dynamic_cast(static_cast(*i)); if ( root->isAncestorOf(item) && ( !only_in_viewport || desktop->isWithinViewport(item) ) ) @@ -2590,7 +2581,7 @@ void sp_selection_clone(SPDesktop *desktop) // sorting items from different parents sorts each parent's subset without possibly mixing them, just what we need sort(reprs.begin(),reprs.end(),sp_repr_compare_position); - SelContainer newsel; + std::vector newsel; for(std::vector::const_iterator i=reprs.begin();i!=reprs.end();i++){ Inkscape::XML::Node *sel_repr = *i; @@ -2609,7 +2600,7 @@ void sp_selection_clone(SPDesktop *desktop) // add the new clone to the top of the original's parent parent->appendChild(clone); - newsel.push_front(dynamic_cast(clone)); + newsel.push_back(clone); Inkscape::GC::release(clone); } @@ -2642,8 +2633,8 @@ sp_selection_relink(SPDesktop *desktop) // Get a copy of current selection. bool relinked = false; - SelContainer items=selection->itemList(); - for (SelContainer::const_iterator i=items.begin();i!=items.end();i++){ + std::vector items=selection->itemList(); + for (std::vector::const_iterator i=items.begin();i!=items.end();i++){ SPItem *item = static_cast(*i); if (dynamic_cast(item)) { @@ -2678,10 +2669,10 @@ sp_selection_unlink(SPDesktop *desktop) } // Get a copy of current selection. - SelContainer new_select; + std::vector new_select; bool unlinked = false; - SelContainer items=selection->itemList(); - for (SelContainer::const_iterator i=items.begin();i!=items.end();i++){ + std::vector items=selection->itemList(); + for (std::vector::const_reverse_iterator i=items.rbegin();i!=items.rend();i++){ SPItem *item = static_cast(*i); if (dynamic_cast(item)) { @@ -2698,7 +2689,7 @@ sp_selection_unlink(SPDesktop *desktop) if (!(dynamic_cast(item) || dynamic_cast(item))) { // keep the non-use item in the new selection - new_select.push_front(item); + new_select.push_back(item); continue; } @@ -2708,7 +2699,7 @@ sp_selection_unlink(SPDesktop *desktop) unlink = use->unlink(); // Unable to unlink use (external or invalid href?) if (!unlink) { - new_select.push_front(item); + new_select.push_back(item); continue; } } else /*if (SP_IS_TREF(use))*/ { @@ -2718,7 +2709,7 @@ sp_selection_unlink(SPDesktop *desktop) unlinked = true; // Add ungrouped items to the new selection. - new_select.push_front(unlink); + new_select.push_back(unlink); } if (!new_select.empty()) { // set new selection @@ -2747,7 +2738,7 @@ sp_select_clone_original(SPDesktop *desktop) // Check if other than two objects are selected - SelContainer items=selection->itemList(); + std::vector items=selection->itemList(); if (items.size() != 1 || !item) { desktop->messageStack()->flash(Inkscape::WARNING_MESSAGE, error); return; @@ -2845,8 +2836,8 @@ void sp_selection_clone_original_path_lpe(SPDesktop *desktop) Inkscape::SVGOStringStream os; SPObject * firstItem = NULL; - SelContainer items=selection->itemList(); - for (SelContainer::const_iterator i=items.begin();i!=items.end();i++){ + std::vector items=selection->itemList(); + for (std::vector::const_iterator i=items.begin();i!=items.end();i++){ if (SP_IS_SHAPE(*i) || SP_IS_TEXT(*i)) { if (firstItem) { os << "|"; @@ -2930,7 +2921,7 @@ void sp_selection_to_marker(SPDesktop *desktop, bool apply) Geom::Point center( *c - corner ); // As defined by rotation center center[Geom::Y] = -center[Geom::Y]; - SelContainer items(selection->itemList()); + std::vector items(selection->itemList()); //items = g_slist_sort(items, (GCompareFunc) sp_object_compare_position); // Why needed? @@ -2948,10 +2939,10 @@ void sp_selection_to_marker(SPDesktop *desktop, bool apply) } // Create a list of duplicates, to be pasted inside marker element. - SelContainer repr_copies; - for (SelContainer::const_iterator i=items.begin();i!=items.end();i++){ + std::vector repr_copies; + for (std::vector::const_reverse_iterator i=items.rbegin();i!=items.rend();i++){ Inkscape::XML::Node *dup = SP_OBJECT(*i)->getRepr()->duplicate(xml_doc); - repr_copies.push_front(dynamic_cast(dup)); + repr_copies.push_back(dup); } Geom::Rect bbox(desktop->dt2doc(r->min()), desktop->dt2doc(r->max())); @@ -2959,7 +2950,7 @@ void sp_selection_to_marker(SPDesktop *desktop, bool apply) if (apply) { // Delete objects so that their clones don't get alerted; // the objects will be restored inside the marker element. - for (SelContainer::const_iterator i=items.begin();i!=items.end();i++){ + for (std::vector::const_iterator i=items.begin();i!=items.end();i++){ SPObject *item = reinterpret_cast(*i); item->deleteObject(false); } @@ -2987,8 +2978,8 @@ void sp_selection_to_marker(SPDesktop *desktop, bool apply) static void sp_selection_to_guides_recursive(SPItem *item, bool wholegroups) { SPGroup *group = dynamic_cast(item); if (group && !dynamic_cast(item) && !wholegroups) { - SelContainer items=sp_item_group_item_list(group); - for (SelContainer::const_iterator i=items.begin();i!=items.end();i++){ + std::vector items=sp_item_group_item_list(group); + for (std::vector::const_iterator i=items.begin();i!=items.end();i++){ sp_selection_to_guides_recursive(static_cast(*i), wholegroups); } } else { @@ -3004,7 +2995,7 @@ void sp_selection_to_guides(SPDesktop *desktop) SPDocument *doc = desktop->getDocument(); Inkscape::Selection *selection = desktop->getSelection(); // we need to copy the list because it gets reset when objects are deleted - SelContainer items(selection->itemList()); + std::vector items(selection->itemList()); if (items.empty()) { desktop->messageStack()->flash(Inkscape::WARNING_MESSAGE, _("Select object(s) to convert to guides.")); @@ -3019,7 +3010,7 @@ void sp_selection_to_guides(SPDesktop *desktop) // and its entry in the selection list is invalid (crash). // Therefore: first convert all, then delete all. - for (SelContainer::const_iterator i=items.begin();i!=items.end();i++){ + for (std::vector::const_iterator i=items.begin();i!=items.end();i++){ sp_selection_to_guides_recursive(static_cast(*i), wholegroups); } @@ -3282,9 +3273,9 @@ sp_selection_tile(SPDesktop *desktop, bool apply) move_p[Geom::Y] = -move_p[Geom::Y]; Geom::Affine move = Geom::Affine(Geom::Translate(move_p)); - SelContainer items (selection->itemList()); + std::vector items (selection->itemList()); - items.sort(sp_object_compare_position); + sort(items.begin(),items.end(),sp_object_compare_position); // bottommost object, after sorting SPObject *parent = SP_OBJECT(items.front())->parent; @@ -3304,19 +3295,17 @@ sp_selection_tile(SPDesktop *desktop, bool apply) gint pos = SP_OBJECT(items.front())->getRepr()->position(); // create a list of duplicates - SelContainer repr_copies; - for (SelContainer::const_iterator i=items.begin();i!=items.end();i++){ + std::vector repr_copies; + for (std::vector::const_iterator i=items.begin();i!=items.end();i++){ Inkscape::XML::Node *dup = SP_OBJECT(*i)->getRepr()->duplicate(xml_doc); - repr_copies.push_front(dynamic_cast(dup)); + repr_copies.push_back(dup); } - // restore the z-order after prepends - repr_copies.reverse(); Geom::Rect bbox(desktop->dt2doc(r->min()), desktop->dt2doc(r->max())); if (apply) { // delete objects so that their clones don't get alerted; this object will be restored shortly - for (SelContainer::const_iterator i=items.begin();i!=items.end();i++){ + for (std::vector::const_iterator i=items.begin();i!=items.end();i++){ SPObject *item = reinterpret_cast(*i); item->deleteObject(false); } @@ -3385,12 +3374,12 @@ void sp_selection_untile(SPDesktop *desktop) return; } - SelContainer new_select; + std::vector new_select; bool did = false; - SelContainer items(selection->itemList()); - for (SelContainer::const_iterator i=items.begin();i!=items.end();i++){ + std::vector items(selection->itemList()); + for (std::vector::const_reverse_iterator i=items.rbegin();i!=items.rend();i++){ SPItem *item = static_cast(*i); SPStyle *style = item->style; @@ -3427,7 +3416,7 @@ void sp_selection_untile(SPDesktop *desktop) Geom::Affine transform( i->transform * pat_transform ); i->doWriteTransform(i->getRepr(), transform); - new_select.push_front(i); + new_select.push_back(i); } else { g_assert_not_reached(); } @@ -3547,10 +3536,10 @@ void sp_selection_create_bitmap_copy(SPDesktop *desktop) } // List of the items to show; all others will be hidden - SelContainer items(selection->itemList()); + std::vector items(selection->itemList()); // Sort items so that the topmost comes last - items.sort(sp_item_repr_compare_position_obj); + sort(items.begin(),items.end(),sp_item_repr_compare_position); // Generate a random value from the current time (you may create bitmap from the same object(s) // multiple times, and this is done so that they don't clash) @@ -3770,7 +3759,7 @@ void sp_selection_set_clipgroup(SPDesktop *desktop) Inkscape::GC::release(spnew); topmost --; // only reduce count for those items deleted from topmost_parent } else { // move it to topmost_parent first - SelContainer temp_clip; + std::vector temp_clip; // At this point, current may already have no item, due to its being a clone whose original is already moved away // So we copy it artificially calculating the transform from its repr->attr("transform") and the parent transform @@ -3790,10 +3779,10 @@ void sp_selection_set_clipgroup(SPDesktop *desktop) sp_repr_unparent(current); // paste into topmost_parent (temporarily) - SelContainer copied = sp_selection_paste_impl(doc, doc->getObjectByRepr(topmost_parent), temp_clip); + std::vector copied = sp_selection_paste_impl(doc, doc->getObjectByRepr(topmost_parent), temp_clip); if (!copied.empty()) { // if success, // take pasted object (now in topmost_parent) - Inkscape::XML::Node *in_topmost = dynamic_cast(copied.front()); + Inkscape::XML::Node *in_topmost = copied.back(); // make a copy Inkscape::XML::Node *spnew = in_topmost->duplicate(xml_doc); // remove pasted @@ -3875,9 +3864,9 @@ void sp_selection_set_mask(SPDesktop *desktop, bool apply_clip_path, bool apply_ doc->ensureUpToDate(); - SelContainer items(selection->itemList()); + std::vector items(selection->itemList()); - items.sort(sp_object_compare_position); + sort(items.begin(),items.end(),sp_object_compare_position); // See lp bug #542004 selection->clear(); @@ -3886,7 +3875,7 @@ void sp_selection_set_mask(SPDesktop *desktop, bool apply_clip_path, bool apply_ GSList *mask_items = NULL; GSList *apply_to_items = NULL; GSList *items_to_delete = NULL; - SelContainer items_to_select; + std::vector items_to_select; Inkscape::Preferences *prefs = Inkscape::Preferences::get(); bool topmost = prefs->getBool("/options/maskobject/topmost", true); @@ -3897,7 +3886,7 @@ void sp_selection_set_mask(SPDesktop *desktop, bool apply_clip_path, bool apply_ // all selected items are used for mask, which is applied to a layer apply_to_items = g_slist_prepend(apply_to_items, desktop->currentLayer()); - for (SelContainer::const_iterator i=items.begin();i!=items.end();i++) { + for (std::vector::const_iterator i=items.begin();i!=items.end();i++) { Inkscape::XML::Node *dup = SP_OBJECT(*i)->getRepr()->duplicate(xml_doc); mask_items = g_slist_prepend(mask_items, dup); @@ -3906,7 +3895,7 @@ void sp_selection_set_mask(SPDesktop *desktop, bool apply_clip_path, bool apply_ items_to_delete = g_slist_prepend(items_to_delete, item); } else { - items_to_select.push_front(item); + items_to_select.push_back((SPItem*)item); } } } else if (!topmost) { @@ -3919,16 +3908,16 @@ void sp_selection_set_mask(SPDesktop *desktop, bool apply_clip_path, bool apply_ items_to_delete = g_slist_prepend(items_to_delete, item); } - for (SelContainer::const_iterator i=items.begin();i!=items.end();i++) { + for (std::vector::const_iterator i=items.begin();i!=items.end();i++) { if(i==items.begin())continue; apply_to_items = g_slist_prepend(apply_to_items, *i); - items_to_select.push_front(*i); + items_to_select.push_back(*i); } } else { GSList *i = NULL; - for (SelContainer::const_iterator i=items.begin();i!=items.end();i++) { + for (std::vector::const_iterator i=items.begin();i!=items.end();i++) { apply_to_items = g_slist_prepend(apply_to_items, *i); - items_to_select.push_front(*i); + items_to_select.push_back(*i); } Inkscape::XML::Node *dup = SP_OBJECT(i->data)->getRepr()->duplicate(xml_doc); @@ -3953,7 +3942,7 @@ void sp_selection_set_mask(SPDesktop *desktop, bool apply_clip_path, bool apply_ for (GSList *i = apply_to_items ; NULL != i ; i = i->next) { reprs_to_group.push_back(static_cast(i->data)->getRepr()); - items_to_select.remove(static_cast(i->data)); + items_to_select.erase(find(items_to_select.begin(),items_to_select.end(),static_cast(i->data))); } sp_selection_group_impl(reprs_to_group, group, xml_doc, doc); @@ -3963,7 +3952,7 @@ void sp_selection_set_mask(SPDesktop *desktop, bool apply_clip_path, bool apply_ apply_to_items = NULL; apply_to_items = g_slist_prepend(apply_to_items, doc->getObjectByRepr(group)); - items_to_select.push_front(doc->getObjectByRepr(group)); + items_to_select.push_back((SPItem*)(doc->getObjectByRepr(group))); Inkscape::GC::release(group); } @@ -4003,7 +3992,7 @@ void sp_selection_set_mask(SPDesktop *desktop, bool apply_clip_path, bool apply_ Inkscape::XML::Node *spnew = current->duplicate(xml_doc); gint position = current->position(); - items_to_select.remove(item); + items_to_select.erase(find(items_to_select.begin(),items_to_select.end(),item)); current->parent()->appendChild(group); sp_repr_unparent(current); group->appendChild(spnew); @@ -4012,7 +4001,7 @@ void sp_selection_set_mask(SPDesktop *desktop, bool apply_clip_path, bool apply_ // Apply clip/mask to group instead apply_mask_to = group; - items_to_select.push_front(doc->getObjectByRepr(group)); + items_to_select.push_back((SPItem*)(doc->getObjectByRepr(group))); Inkscape::GC::release(spnew); Inkscape::GC::release(group); } @@ -4027,12 +4016,10 @@ void sp_selection_set_mask(SPDesktop *desktop, bool apply_clip_path, bool apply_ for (GSList *i = items_to_delete; NULL != i; i = i->next) { SPObject *item = reinterpret_cast(i->data); item->deleteObject(false); - items_to_select.remove(item); + items_to_select.erase(find(items_to_select.begin(),items_to_select.end(),item)); } g_slist_free(items_to_delete); - items_to_select.reverse(); - selection->addList(items_to_select); if (apply_clip_path) { @@ -4065,17 +4052,16 @@ void sp_selection_unset_mask(SPDesktop *desktop, bool apply_clip_path) { gchar const *attributeName = apply_clip_path ? "clip-path" : "mask"; std::map referenced_objects; - SelContainer items(selection->itemList()); + std::vector items(selection->itemList()); selection->clear(); GSList *items_to_ungroup = NULL; - SelContainer items_to_select(items); - items_to_select.reverse(); + std::vector items_to_select(items); // SPObject* refers to a group containing the clipped path or mask itself, // whereas SPItem* refers to the item being clipped or masked - for (SelContainer::const_iterator i=items.begin();i!=items.end();i++){ + for (std::vector::const_iterator i=items.begin();i!=items.end();i++){ if (remove_original) { // remember referenced mask/clippath, so orphaned masks can be moved back to document SPItem *item = reinterpret_cast(*i); @@ -4140,7 +4126,7 @@ void sp_selection_unset_mask(SPDesktop *desktop, bool apply_clip_path) { repr->setPosition((pos + 1) > 0 ? (pos + 1) : 0); SPItem *mask_item = static_cast(desktop->getDocument()->getObjectByRepr(repr)); - items_to_select.push_front(mask_item); + items_to_select.push_back(mask_item); // transform mask, so it is moved the same spot where mask was applied Geom::Affine transform(mask_item->transform); @@ -4155,10 +4141,10 @@ void sp_selection_unset_mask(SPDesktop *desktop, bool apply_clip_path) { for (GSList *i = items_to_ungroup ; NULL != i ; i = i->next) { SPGroup *group = dynamic_cast(static_cast(i->data)); if (group) { - items_to_select.remove(group); - SelContainer children; + items_to_select.erase(find(items_to_select.begin(),items_to_select.end(),group)); + std::vector children; sp_item_group_ungroup(group, children, false); - items_to_select.splice(items_to_select.begin(),children); + items_to_select.insert(items_to_select.end(),children.rbegin(),children.rend()); } else { g_assert_not_reached(); } @@ -4167,7 +4153,6 @@ void sp_selection_unset_mask(SPDesktop *desktop, bool apply_clip_path) { g_slist_free(items_to_ungroup); // rebuild selection - items_to_select.reverse(); selection->addList(items_to_select); if (apply_clip_path) { diff --git a/src/selection-chemistry.h b/src/selection-chemistry.h index bc317d556..2acd62c02 100644 --- a/src/selection-chemistry.h +++ b/src/selection-chemistry.h @@ -143,9 +143,9 @@ enum SPSelectStrokeStyleType { void sp_select_same_fill_stroke_style(SPDesktop *desktop, gboolean fill, gboolean strok, gboolean style); void sp_select_same_stroke_style(SPDesktop *desktop); void sp_select_same_object_type(SPDesktop *desktop); -SelContainer sp_get_same_fill_or_stroke_color(SPItem *sel, SelContainer &src, SPSelectStrokeStyleType type); -SelContainer sp_get_same_stroke_style(SPItem *sel, SelContainer &src, SPSelectStrokeStyleType type); -SelContainer sp_get_same_object_type(SPItem *sel, SelContainer &src); +std::vector sp_get_same_fill_or_stroke_color(SPItem *sel, std::vector &src, SPSelectStrokeStyleType type); +std::vector sp_get_same_stroke_style(SPItem *sel, std::vector &src, SPSelectStrokeStyleType type); +std::vector sp_get_same_object_type(SPItem *sel, std::vector &src); void scroll_to_show_item(SPDesktop *desktop, SPItem *item); @@ -172,9 +172,9 @@ void unlock_all_in_all_layers(SPDesktop *dt); void unhide_all(SPDesktop *dt); void unhide_all_in_all_layers(SPDesktop *dt); -SelContainer &get_all_items(SelContainer &list, SPObject *from, SPDesktop *desktop, bool onlyvisible, bool onlysensitive, bool ingroups, SelContainer const &exclude); +std::vector &get_all_items(std::vector &list, SPObject *from, SPDesktop *desktop, bool onlyvisible, bool onlysensitive, bool ingroups, std::vector const &exclude); -SelContainer sp_degroup_list (SelContainer &items); +std::vector sp_degroup_list (std::vector &items); /* selection cycling */ typedef enum diff --git a/src/selection-describer.cpp b/src/selection-describer.cpp index 0625c4002..d86cfa700 100644 --- a/src/selection-describer.cpp +++ b/src/selection-describer.cpp @@ -40,13 +40,13 @@ #include "sp-spiral.h" // Returns a list of terms for the items to be used in the statusbar -char* collect_terms (const SelContainer &items) +char* collect_terms (const std::vector &items) { GSList *check = NULL; std::stringstream ss; bool first = true; - for ( SelContainer::const_iterator iter=items.begin();iter!=items.end();iter++ ) { + for ( std::vector::const_iterator iter=items.begin();iter!=items.end();iter++ ) { SPItem *item = dynamic_cast(reinterpret_cast(*iter)); if (item) { const char *term = item->displayName(); @@ -61,11 +61,11 @@ char* collect_terms (const SelContainer &items) } // Returns the number of terms in the list -static int count_terms (const SelContainer &items) +static int count_terms (const std::vector &items) { GSList *check = NULL; int count=0; - for ( SelContainer::const_iterator iter=items.begin();iter!=items.end();iter++ ) { + for ( std::vector::const_iterator iter=items.begin();iter!=items.end();iter++ ) { SPItem *item = dynamic_cast(reinterpret_cast(*iter)); if (item) { const char *term = item->displayName(); @@ -79,10 +79,10 @@ static int count_terms (const SelContainer &items) } // Returns the number of filtered items in the list -static int count_filtered (const SelContainer &items) +static int count_filtered (const std::vector &items) { int count=0; - for ( SelContainer::const_iterator iter=items.begin();iter!=items.end();iter++ ) { + for ( std::vector::const_iterator iter=items.begin();iter!=items.end();iter++ ) { SPItem *item = dynamic_cast(reinterpret_cast((*iter))); if (item) { count += item->isFiltered(); @@ -122,7 +122,7 @@ void SelectionDescriber::_selectionModified(Inkscape::Selection *selection, guin } void SelectionDescriber::_updateMessageFromSelection(Inkscape::Selection *selection) { - SelContainer const items = selection->itemList(); + std::vector const items = selection->itemList(); if (items.empty()) { // no items _context.set(Inkscape::NORMAL_MESSAGE, _when_nothing); diff --git a/src/selection.cpp b/src/selection.cpp index cbde9a799..2e8251048 100644 --- a/src/selection.cpp +++ b/src/selection.cpp @@ -44,7 +44,7 @@ namespace Inkscape { Selection::Selection(LayerModel *layers, SPDesktop *desktop) : _objs(SelContainer()), _reprs(std::vector()), - _items(SelContainer()), + _items(std::vector()), _layers(layers), _desktop(desktop), _selection_context(NULL), @@ -234,7 +234,7 @@ void Selection::_remove(SPObject *obj) { _objs.remove(obj); } -void Selection::setList(SelContainer const &list) { +void Selection::setList(std::vector const &list) { // Clear and add, or just clear with emit. if (!list.empty()) { _clear(); @@ -242,14 +242,14 @@ void Selection::setList(SelContainer const &list) { } else clear(); } -void Selection::addList(SelContainer const &list) { +void Selection::addList(std::vector const &list) { if (list.empty()) return; _invalidateCachedLists(); - for ( SelContainer::const_iterator iter=list.begin();iter!=list.end();iter++ ) { + for ( std::vector::const_iterator iter=list.begin();iter!=list.end();iter++ ) { SPObject *obj = reinterpret_cast(*iter); if (includes(obj)) continue; _add (obj); @@ -258,11 +258,11 @@ void Selection::addList(SelContainer const &list) { _emitChanged(); } -void Selection::setReprList(SelContainer const &list) { +void Selection::setReprList(std::vector const &list) { _clear(); - for ( SelContainer::const_iterator iter=list.begin();iter!=list.end();iter++ ) { - SPObject *obj=_objectForXMLNode(reinterpret_cast(*iter)); + for ( std::vector::const_reverse_iterator iter=list.rbegin();iter!=list.rend();iter++ ) { + SPObject *obj=_objectForXMLNode(*iter); if (obj) { _add(obj); } @@ -280,7 +280,7 @@ SelContainer const &Selection::list() { return _objs; } -SelContainer const &Selection::itemList() { +std::vector const &Selection::itemList() { if (!_items.empty()) { return _items; } @@ -288,18 +288,16 @@ SelContainer const &Selection::itemList() { for ( SelContainer::const_iterator iter=_objs.begin();iter!=_objs.end();iter++ ) { SPObject *obj=reinterpret_cast(*iter); if (SP_IS_ITEM(obj)) { - _items.push_front(SP_ITEM(obj)); + _items.push_back(SP_ITEM(obj)); } } - _items.reverse(); - return _items; } std::vector const &Selection::reprList() { if (!_reprs.empty()) { return _reprs; } - SelContainer list = itemList(); - for ( SelContainer::const_iterator iter=list.begin();iter!=list.end();iter++ ) { + std::vector list = itemList(); + for ( std::vector::const_iterator iter=list.begin();iter!=list.end();iter++ ) { SPObject *obj=reinterpret_cast(*iter); _reprs.push_back(obj->getRepr()); } @@ -340,7 +338,7 @@ SPObject *Selection::single() { } SPItem *Selection::singleItem() { - SelContainer const items=itemList(); + std::vector const items=itemList(); if ( items.size()==1) { return reinterpret_cast(items.front()); } else { @@ -357,11 +355,11 @@ SPItem *Selection::largestItem(Selection::CompareSize compare) { } SPItem *Selection::_sizeistItem(bool sml, Selection::CompareSize compare) { - SelContainer const items = const_cast(this)->itemList(); + std::vector const items = const_cast(this)->itemList(); gdouble max = sml ? 1e18 : 0; SPItem *ist = NULL; - for ( SelContainer::const_iterator i=items.begin();i!=items.end();i++ ) { + for ( std::vector::const_iterator i=items.begin();i!=items.end();i++ ) { Geom::OptRect obox = SP_ITEM(*i)->desktopPreferredBounds(); if (!obox || obox.isEmpty()) continue; Geom::Rect bbox = *obox; @@ -390,10 +388,10 @@ Geom::OptRect Selection::bounds(SPItem::BBoxType type) const Geom::OptRect Selection::geometricBounds() const { - SelContainer const items = const_cast(this)->itemList(); + std::vector const items = const_cast(this)->itemList(); Geom::OptRect bbox; - for ( SelContainer::const_iterator iter=items.begin();iter!=items.end();iter++ ) { + for ( std::vector::const_iterator iter=items.begin();iter!=items.end();iter++ ) { bbox.unionWith(SP_ITEM(*iter)->desktopGeometricBounds()); } return bbox; @@ -401,10 +399,10 @@ Geom::OptRect Selection::geometricBounds() const Geom::OptRect Selection::visualBounds() const { - SelContainer const items = const_cast(this)->itemList(); + std::vector const items = const_cast(this)->itemList(); Geom::OptRect bbox; - for ( SelContainer::const_iterator iter=items.begin();iter!=items.end();iter++ ) { + for ( std::vector::const_iterator iter=items.begin();iter!=items.end();iter++ ) { bbox.unionWith(SP_ITEM(*iter)->desktopVisualBounds()); } return bbox; @@ -422,10 +420,10 @@ Geom::OptRect Selection::preferredBounds() const Geom::OptRect Selection::documentBounds(SPItem::BBoxType type) const { Geom::OptRect bbox; - SelContainer const items = const_cast(this)->itemList(); + std::vector const items = const_cast(this)->itemList(); if (items.empty()) return bbox; - for ( SelContainer::const_iterator iter=items.begin();iter!=items.end();iter++ ) { + for ( std::vector::const_iterator iter=items.begin();iter!=items.end();iter++ ) { SPItem *item = SP_ITEM(*iter); bbox |= item->documentBounds(type); } @@ -436,7 +434,7 @@ Geom::OptRect Selection::documentBounds(SPItem::BBoxType type) const // If we have a selection of multiple items, then the center of the first item // will be returned; this is also the case in SelTrans::centerRequest() boost::optional Selection::center() const { - SelContainer const items = const_cast(this)->itemList(); + std::vector const items = const_cast(this)->itemList(); if (!items.empty()) { SPItem *first = reinterpret_cast(items.back()); // from the first item in selection if (first->isCenterSet()) { // only if set explicitly @@ -452,12 +450,12 @@ boost::optional Selection::center() const { } std::vector Selection::getSnapPoints(SnapPreferences const *snapprefs) const { - SelContainer const items = const_cast(this)->itemList(); + std::vector const items = const_cast(this)->itemList(); SnapPreferences snapprefs_dummy = *snapprefs; // create a local copy of the snapping prefs snapprefs_dummy.setTargetSnappable(Inkscape::SNAPTARGET_ROTATION_CENTER, false); // locally disable snapping to the item center std::vector p; - for ( SelContainer::const_iterator iter=items.begin();iter!=items.end();iter++ ) { + for ( std::vector::const_iterator iter=items.begin();iter!=items.end();iter++ ) { SPItem *this_item = SP_ITEM(*iter); this_item->getSnappoints(p, &snapprefs_dummy); @@ -505,9 +503,9 @@ SPObject *Selection::_objectForXMLNode(Inkscape::XML::Node *repr) const { } uint Selection::numberOfLayers() { - SelContainer const items = const_cast(this)->itemList(); + std::vector const items = const_cast(this)->itemList(); std::set layers; - for ( SelContainer::const_iterator iter=items.begin();iter!=items.end();iter++ ) { + for ( std::vector::const_iterator iter=items.begin();iter!=items.end();iter++ ) { SPObject *layer = _layers->layerForObject(SP_OBJECT(*iter)); layers.insert(layer); } @@ -515,9 +513,9 @@ uint Selection::numberOfLayers() { } guint Selection::numberOfParents() { - SelContainer const items = const_cast(this)->itemList(); + std::vector const items = const_cast(this)->itemList(); std::set parents; - for ( SelContainer::const_iterator iter=items.begin();iter!=items.end();iter++ ) { + for ( std::vector::const_iterator iter=items.begin();iter!=items.end();iter++ ) { SPObject *parent = SP_OBJECT(*iter)->parent; parents.insert(parent); } diff --git a/src/selection.h b/src/selection.h index f85c6346b..2d5e7c34a 100644 --- a/src/selection.h +++ b/src/selection.h @@ -170,21 +170,21 @@ public: * * @param objs the objects to select */ - void setList(SelContainer const &objs); + void setList(std::vector const &objs); /** * Adds the specified objects to selection, without deselecting first. * * @param objs the objects to select */ - void addList(SelContainer const &objs); + void addList(std::vector const &objs); /** * Clears the selection and selects the specified objects. * * @param repr a list of xml nodes for the items to select */ - void setReprList(std::list const &reprs); + void setReprList(std::vector const &reprs); /** Add items from an STL iterator range to the selection. * \param from the begin iterator @@ -256,7 +256,7 @@ public: /** Returns the list of selected objects. */ std::list const &list(); /** Returns the list of selected SPItems. */ - std::list const &itemList(); + std::vector const &itemList(); /** Returns a list of the xml nodes of all selected objects. */ /// \todo only returns reprs of SPItems currently; need a separate /// method for that @@ -378,7 +378,7 @@ private: mutable std::list _objs; mutable std::vector _reprs; - mutable std::list _items; + mutable std::vector _items; void add_box_perspective(SPBox3D *box); void add_3D_boxes_recursively(SPObject *obj); diff --git a/src/seltrans.cpp b/src/seltrans.cpp index 8c06356db..0a428edf2 100644 --- a/src/seltrans.cpp +++ b/src/seltrans.cpp @@ -112,7 +112,7 @@ Inkscape::SelTrans::SelTrans(SPDesktop *desktop) : _opposite_for_bboxpoints(Geom::Point(0,0)), _origin_for_specpoints(Geom::Point(0,0)), _origin_for_bboxpoints(Geom::Point(0,0)), - _stamp_cache(SelContainer()), + _stamp_cache(std::vector()), _message_context(desktop->messageStack()), _bounding_box_prefs_observer(*this) { @@ -239,8 +239,8 @@ void Inkscape::SelTrans::setCenter(Geom::Point const &p) _center_is_set = true; // Write the new center position into all selected items - SelContainer items=_desktop->selection->itemList(); - for ( SelContainer::const_iterator iter=items.begin();iter!=items.end();iter++ ) { + std::vector items=_desktop->selection->itemList(); + for ( std::vector::const_iterator iter=items.begin();iter!=items.end();iter++ ) { SPItem *it = SP_ITEM(*iter); it->setCenter(p); // only set the value; updating repr and document_done will be done once, on ungrab @@ -269,8 +269,8 @@ void Inkscape::SelTrans::grab(Geom::Point const &p, gdouble x, gdouble y, bool s return; } - SelContainer items=_desktop->selection->itemList(); - for ( SelContainer::const_iterator iter=items.begin();iter!=items.end();iter++ ) { + std::vector items=_desktop->selection->itemList(); + for ( std::vector::const_iterator iter=items.begin();iter!=items.end();iter++ ) { SPItem *it = reinterpret_cast(sp_object_ref(SP_ITEM(*iter), NULL)); _items.push_back(it); _items_const.push_back(it); @@ -492,8 +492,8 @@ void Inkscape::SelTrans::ungrab() if (_center_is_set) { // we were dragging center; update reprs and commit undoable action - SelContainer items=_desktop->selection->itemList(); - for ( SelContainer::const_iterator iter=items.begin();iter!=items.end();iter++ ) { + std::vector items=_desktop->selection->itemList(); + for ( std::vector::const_iterator iter=items.begin();iter!=items.end();iter++ ) { SPItem *it = SP_ITEM(*iter); it->updateRepr(); } @@ -524,17 +524,17 @@ void Inkscape::SelTrans::stamp() /* stamping mode */ if (!_empty) { - SelContainer l; + std::vector l; if (!_stamp_cache.empty()) { l = _stamp_cache; } else { /* Build cache */ l = selection->itemList(); - l.sort(sp_object_compare_position); + sort(l.begin(),l.end(),sp_object_compare_position); _stamp_cache = l; } - for(SelContainer::const_iterator x=l.begin();x!=l.end();x++) { + for(std::vector::const_iterator x=l.begin();x!=l.end();x++) { SPItem *original_item = SP_ITEM(*x); Inkscape::XML::Node *original_repr = original_item->getRepr(); @@ -711,8 +711,8 @@ void Inkscape::SelTrans::handleClick(SPKnot */*knot*/, guint state, SPSelTransHa case HANDLE_CENTER: if (state & GDK_SHIFT_MASK) { // Unset the center position for all selected items - SelContainer items=_desktop->selection->itemList(); - for ( SelContainer::const_iterator iter=items.begin();iter!=items.end();iter++ ) { + std::vector items=_desktop->selection->itemList(); + for ( std::vector::const_iterator iter=items.begin();iter!=items.end();iter++ ) { SPItem *it = SP_ITEM(*iter); it->unsetCenter(); it->updateRepr(); @@ -1283,7 +1283,7 @@ gboolean Inkscape::SelTrans::centerRequest(Geom::Point &pt, guint state) // items will share a single center. While dragging that single center, it should never snap to the // centers of any of the selected objects. Therefore we will have to pass the list of selected items // to the snapper, to avoid self-snapping of the rotation center - SelContainer items = const_cast(_selection)->itemList(); + std::vector items = const_cast(_selection)->itemList(); SnapManager &m = _desktop->namedview->snap_manager; m.setup(_desktop); m.setRotationCenterSource(items); diff --git a/src/seltrans.h b/src/seltrans.h index 8f9c329ed..26c2e9cd9 100644 --- a/src/seltrans.h +++ b/src/seltrans.h @@ -187,7 +187,7 @@ private: SPCtrlLine *_l[4]; unsigned int _sel_changed_id; unsigned int _sel_modified_id; - SelContainer _stamp_cache; + std::vector _stamp_cache; Geom::Point _origin; ///< position of origin for transforms Geom::Point _point; ///< original position of the knot being used for the current transform diff --git a/src/snap.cpp b/src/snap.cpp index a7145b834..c711874d7 100644 --- a/src/snap.cpp +++ b/src/snap.cpp @@ -43,7 +43,7 @@ SnapManager::SnapManager(SPNamedView const *v) : object(this, 0), snapprefs(), _named_view(v), - _rotation_center_source_items(SelContainer()), + _rotation_center_source_items(std::vector()), _guide_to_ignore(NULL), _desktop(NULL), _snapindicator(true), @@ -1053,8 +1053,8 @@ void SnapManager::setupIgnoreSelection(SPDesktop const *desktop, _items_to_ignore.clear(); Inkscape::Selection *sel = _desktop->selection; - SelContainer const items = sel->itemList(); - for (SelContainer::const_iterator i=items.begin();i!=items.end();i++) { + std::vector const items = sel->itemList(); + for (std::vector::const_iterator i=items.begin();i!=items.end();i++) { _items_to_ignore.push_back(static_cast(*i)); } } diff --git a/src/snap.h b/src/snap.h index 012eb072b..49bdbfa7c 100644 --- a/src/snap.h +++ b/src/snap.h @@ -145,8 +145,8 @@ public: // of this rotation center; this reference is used to make sure that we do not snap a rotation // center to itself // NOTE: Must be called after calling setup(), not before! - void setRotationCenterSource(const SelContainer &items) {_rotation_center_source_items = items;} - SelContainer getRotationCenterSource() {return _rotation_center_source_items;} + void setRotationCenterSource(const std::vector &items) {_rotation_center_source_items = items;} + const std::vector &getRotationCenterSource() {return _rotation_center_source_items;} // freeSnapReturnByRef() is preferred over freeSnap(), because it only returns a // point if snapping has occurred (by overwriting p); otherwise p is untouched @@ -490,7 +490,7 @@ protected: private: std::vector _items_to_ignore; ///< Items that should not be snapped to, for example the items that are currently being dragged. Set using the setup() method - SelContainer _rotation_center_source_items; // to avoid snapping a rotation center to itself + std::vector _rotation_center_source_items; // to avoid snapping a rotation center to itself SPGuide *_guide_to_ignore; ///< A guide that should not be snapped to, e.g. the guide that is currently being dragged SPDesktop const *_desktop; bool _snapindicator; ///< When true, an indicator will be drawn at the position that was being snapped to diff --git a/src/sp-conn-end.cpp b/src/sp-conn-end.cpp index bd139277d..d09699f41 100644 --- a/src/sp-conn-end.cpp +++ b/src/sp-conn-end.cpp @@ -50,8 +50,8 @@ static bool try_get_intersect_point_with_item_recursive(Geom::PathVector& conn_p // consider all first-order children double child_pos = 0.0; - SelContainer g = sp_item_group_item_list(group); - for (SelContainer::const_iterator i = g.begin();i!=g.end();i++) { + std::vector g = sp_item_group_item_list(group); + for (std::vector::const_iterator i = g.begin();i!=g.end();i++) { SPItem* child_item = SP_ITEM(*i); try_get_intersect_point_with_item_recursive(conn_pv, child_item, item_transform * child_item->transform, child_pos); diff --git a/src/sp-item-group.cpp b/src/sp-item-group.cpp index e6531c6be..f09a4ee47 100644 --- a/src/sp-item-group.cpp +++ b/src/sp-item-group.cpp @@ -387,7 +387,7 @@ void SPGroup::snappoints(std::vector &p, Inkscape: void -sp_item_group_ungroup (SPGroup *group, SelContainer &children, bool do_done) +sp_item_group_ungroup (SPGroup *group, std::vector &children, bool do_done) { g_return_if_fail (group != NULL); @@ -547,7 +547,7 @@ sp_item_group_ungroup (SPGroup *group, SelContainer &children, bool do_done) Inkscape::GC::release(repr); if (!children.empty() && item) { - children.push_front(dynamic_cast(item)); + children.insert(children.begin(),item); } items = g_slist_remove (items, items->data); @@ -562,17 +562,16 @@ sp_item_group_ungroup (SPGroup *group, SelContainer &children, bool do_done) * some API for list aspect of SPGroup */ -SelContainer sp_item_group_item_list(SPGroup * group) +std::vector sp_item_group_item_list(SPGroup * group) { - SelContainer s; + std::vector s; g_return_val_if_fail(group != NULL, s); for (SPObject *o = group->firstChild() ; o ; o = o->getNext() ) { if ( dynamic_cast(o) ) { - s.push_front(o); + s.push_back((SPItem*)o); } } - s.reverse(); return s; } @@ -813,9 +812,9 @@ void SPGroup::update_patheffect(bool write) { g_message("sp_group_update_patheffect: %p\n", lpeitem); #endif - SelContainer const item_list = sp_item_group_item_list(this); + std::vector const item_list = sp_item_group_item_list(this); - for ( SelContainer::const_iterator iter=item_list.begin();iter!=item_list.end();iter++) { + for ( std::vector::const_iterator iter=item_list.begin();iter!=item_list.end();iter++) { SPObject *subitem = static_cast(*iter); SPLPEItem *lpeItem = dynamic_cast(subitem); @@ -841,9 +840,9 @@ void SPGroup::update_patheffect(bool write) { static void sp_group_perform_patheffect(SPGroup *group, SPGroup *topgroup, bool write) { - SelContainer const item_list = sp_item_group_item_list(group); + std::vector const item_list = sp_item_group_item_list(group); - for ( SelContainer::const_iterator iter=item_list.begin();iter!=item_list.end();iter++) { + for ( std::vector::const_iterator iter=item_list.begin();iter!=item_list.end();iter++) { SPObject *subitem = static_cast(*iter); SPGroup *subGroup = dynamic_cast(subitem); diff --git a/src/sp-item-group.h b/src/sp-item-group.h index 9a5ee0161..dcabea78c 100644 --- a/src/sp-item-group.h +++ b/src/sp-item-group.h @@ -96,10 +96,10 @@ public: virtual void update_patheffect(bool write); }; -void sp_item_group_ungroup (SPGroup *group, SelContainer &children, bool do_done = true); +void sp_item_group_ungroup (SPGroup *group, std::vector &children, bool do_done = true); -SelContainer sp_item_group_item_list (SPGroup *group); +std::vector sp_item_group_item_list (SPGroup *group); SPObject *sp_item_group_get_child_by_name (SPGroup *group, SPObject *ref, const char *name); #endif diff --git a/src/sp-lpe-item.cpp b/src/sp-lpe-item.cpp index 1305efd83..1f4704e22 100644 --- a/src/sp-lpe-item.cpp +++ b/src/sp-lpe-item.cpp @@ -353,8 +353,8 @@ sp_lpe_item_create_original_path_recursive(SPLPEItem *lpeitem) sp_lpe_item_create_original_path_recursive(SP_LPE_ITEM(clipPath->firstChild())); } if (SP_IS_GROUP(lpeitem)) { - SelContainer item_list = sp_item_group_item_list(SP_GROUP(lpeitem)); - for ( SelContainer::const_iterator iter=item_list.begin();iter!=item_list.end();iter++) { + std::vector item_list = sp_item_group_item_list(SP_GROUP(lpeitem)); + for ( std::vector::const_iterator iter=item_list.begin();iter!=item_list.end();iter++) { SPObject *subitem = static_cast(*iter); if (SP_IS_LPE_ITEM(subitem)) { sp_lpe_item_create_original_path_recursive(SP_LPE_ITEM(subitem)); @@ -387,8 +387,8 @@ sp_lpe_item_cleanup_original_path_recursive(SPLPEItem *lpeitem) sp_lpe_item_cleanup_original_path_recursive(SP_LPE_ITEM(clipPath->firstChild())); } } - SelContainer item_list = sp_item_group_item_list(SP_GROUP(lpeitem)); - for ( SelContainer::const_iterator iter=item_list.begin();iter!=item_list.end();iter++) { + std::vector item_list = sp_item_group_item_list(SP_GROUP(lpeitem)); + for ( std::vector::const_iterator iter=item_list.begin();iter!=item_list.end();iter++) { SPObject *subitem = static_cast(*iter); if (SP_IS_LPE_ITEM(subitem)) { sp_lpe_item_cleanup_original_path_recursive(SP_LPE_ITEM(subitem)); @@ -680,8 +680,8 @@ SPLPEItem::apply_to_clippath(SPItem *item) } } if(SP_IS_GROUP(item)){ - SelContainer item_list = sp_item_group_item_list(SP_GROUP(item)); - for ( SelContainer::const_iterator iter=item_list.begin();iter!=item_list.end();iter++) { + std::vector item_list = sp_item_group_item_list(SP_GROUP(item)); + for ( std::vector::const_iterator iter=item_list.begin();iter!=item_list.end();iter++) { SPObject *subitem = static_cast(*iter); apply_to_clippath(SP_ITEM(subitem)); } @@ -732,8 +732,8 @@ SPLPEItem::apply_to_mask(SPItem *item) } } if(SP_IS_GROUP(item)){ - SelContainer item_list = sp_item_group_item_list(SP_GROUP(item)); - for ( SelContainer::const_iterator iter=item_list.begin();iter!=item_list.end();iter++) { + std::vector item_list = sp_item_group_item_list(SP_GROUP(item)); + for ( std::vector::const_iterator iter=item_list.begin();iter!=item_list.end();iter++) { SPObject *subitem = static_cast(*iter); apply_to_mask(SP_ITEM(subitem)); } @@ -746,8 +746,8 @@ SPLPEItem::apply_to_clip_or_mask_group(SPItem *group, SPItem *item) if (!SP_IS_GROUP(group)) { return; } - SelContainer item_list = sp_item_group_item_list(SP_GROUP(group)); - for ( SelContainer::const_iterator iter=item_list.begin();iter!=item_list.end();iter++) { + std::vector item_list = sp_item_group_item_list(SP_GROUP(group)); + for ( std::vector::const_iterator iter=item_list.begin();iter!=item_list.end();iter++) { SPObject *subitem = static_cast(*iter); if (SP_IS_GROUP(subitem)) { apply_to_clip_or_mask_group(SP_ITEM(subitem), item); diff --git a/src/sp-marker.cpp b/src/sp-marker.cpp index 66b445265..5bb80bd39 100644 --- a/src/sp-marker.cpp +++ b/src/sp-marker.cpp @@ -429,7 +429,7 @@ sp_marker_hide (SPMarker *marker, unsigned int key) } -const gchar *generate_marker(SelContainer &reprs, Geom::Rect bounds, SPDocument *document, Geom::Point center, Geom::Affine move) +const gchar *generate_marker(std::vector &reprs, Geom::Rect bounds, SPDocument *document, Geom::Point center, Geom::Affine move) { Inkscape::XML::Document *xml_doc = document->getReprDoc(); Inkscape::XML::Node *defsrepr = document->getDefs()->getRepr(); @@ -452,8 +452,8 @@ const gchar *generate_marker(SelContainer &reprs, Geom::Rect bounds, SPDocument const gchar *mark_id = repr->attribute("id"); SPObject *mark_object = document->getObjectById(mark_id); - for (SelContainer::const_iterator i=reprs.begin();i!=reprs.end();i++){ - Inkscape::XML::Node *node = (Inkscape::XML::Node *)(*i); + for (std::vector::const_iterator i=reprs.begin();i!=reprs.end();i++){ + Inkscape::XML::Node *node = (*i); SPItem *copy = SP_ITEM(mark_object->appendChildRepr(node)); Geom::Affine dup_transform; diff --git a/src/sp-marker.h b/src/sp-marker.h index 594c164c5..56cbaf94f 100644 --- a/src/sp-marker.h +++ b/src/sp-marker.h @@ -101,7 +101,7 @@ Inkscape::DrawingItem *sp_marker_show_instance (SPMarker *marker, Inkscape::Draw unsigned int key, unsigned int pos, Geom::Affine const &base, float linewidth); void sp_marker_hide (SPMarker *marker, unsigned int key); -const char *generate_marker (SelContainer &reprs, Geom::Rect bounds, SPDocument *document, Geom::Point center, Geom::Affine move); +const char *generate_marker (std::vector &reprs, Geom::Rect bounds, SPDocument *document, Geom::Point center, Geom::Affine move); SPObject *sp_marker_fork_if_necessary(SPObject *marker); #endif diff --git a/src/sp-pattern.cpp b/src/sp-pattern.cpp index d5eff9796..33d66c5dc 100644 --- a/src/sp-pattern.cpp +++ b/src/sp-pattern.cpp @@ -408,7 +408,7 @@ sp_pattern_transform_multiply (SPPattern *pattern, Geom::Affine postmul, bool se g_free(c); } -const gchar *pattern_tile(const SelContainer &reprs, Geom::Rect bounds, SPDocument *document, Geom::Affine transform, Geom::Affine move) +const gchar *pattern_tile(const std::vector &reprs, Geom::Rect bounds, SPDocument *document, Geom::Affine transform, Geom::Affine move) { Inkscape::XML::Document *xml_doc = document->getReprDoc(); Inkscape::XML::Node *defsrepr = document->getDefs()->getRepr(); @@ -426,7 +426,7 @@ const gchar *pattern_tile(const SelContainer &reprs, Geom::Rect bounds, SPDocume const gchar *pat_id = repr->attribute("id"); SPObject *pat_object = document->getObjectById(pat_id); - for (SelContainer::const_iterator i=reprs.begin();i!=reprs.end();i++){ + for (std::vector::const_iterator i=reprs.begin();i!=reprs.end();i++){ Inkscape::XML::Node *node = (Inkscape::XML::Node *)(*i); SPItem *copy = SP_ITEM(pat_object->appendChildRepr(node)); diff --git a/src/sp-pattern.h b/src/sp-pattern.h index 0e2b058b5..34dd5a05b 100644 --- a/src/sp-pattern.h +++ b/src/sp-pattern.h @@ -89,7 +89,7 @@ SPPattern *pattern_chain (SPPattern *pattern); SPPattern *sp_pattern_clone_if_necessary (SPItem *item, SPPattern *pattern, const char *property); void sp_pattern_transform_multiply (SPPattern *pattern, Geom::Affine postmul, bool set); -const char *pattern_tile (const SelContainer &reprs, Geom::Rect bounds, SPDocument *document, Geom::Affine transform, Geom::Affine move); +const char *pattern_tile (const std::vector &reprs, Geom::Rect bounds, SPDocument *document, Geom::Affine transform, Geom::Affine move); SPPattern *pattern_getroot (SPPattern *pat); diff --git a/src/splivarot.cpp b/src/splivarot.cpp index 107dfc629..6e47dfff3 100644 --- a/src/splivarot.cpp +++ b/src/splivarot.cpp @@ -331,7 +331,7 @@ void sp_selected_path_boolop(Inkscape::Selection *selection, SPDesktop *desktop, bool_op bop, const unsigned int verb, const Glib::ustring description) { SPDocument *doc = selection->layers()->getDocument(); - SelContainer il= selection->itemList(); + std::vector il= selection->itemList(); // allow union on a single object for the purpose of removing self overlapse (svn log, revision 13334) if ( (il.size() < 2) && (bop != bool_op_union)) { @@ -403,7 +403,7 @@ sp_selected_path_boolop(Inkscape::Selection *selection, SPDesktop *desktop, bool // first check if all the input objects have shapes // otherwise bail out - for (SelContainer::const_iterator l = il.begin(); l != il.end(); l++) + for (std::vector::const_iterator l = il.begin(); l != il.end(); l++) { SPItem *item = SP_ITEM(*l); if (!SP_IS_SHAPE(item) && !SP_IS_TEXT(item) && !SP_IS_FLOWTEXT(item)) @@ -421,7 +421,7 @@ sp_selected_path_boolop(Inkscape::Selection *selection, SPDesktop *desktop, bool int curOrig; { curOrig = 0; - for (SelContainer::const_iterator l = il.begin(); l != il.end(); l++) + for (std::vector::const_iterator l = il.begin(); l != il.end(); l++) { // apply live path effects prior to performing boolean operation if (SP_IS_LPE_ITEM(*l)) { @@ -474,7 +474,7 @@ sp_selected_path_boolop(Inkscape::Selection *selection, SPDesktop *desktop, bool theShapeA->ConvertToShape(theShape, origWind[0]); curOrig = 1; - for (SelContainer::const_iterator l = il.begin(); l != il.end(); l++){ + for (std::vector::const_iterator l = il.begin(); l != il.end(); l++){ if(*l==il.front())continue; originaux[curOrig]->ConvertWithBackData(0.1); @@ -671,7 +671,7 @@ sp_selected_path_boolop(Inkscape::Selection *selection, SPDesktop *desktop, bool if (res->descr_cmd.size() <= 1) { // only one command, presumably a moveto: it isn't a path - for (SelContainer::const_iterator l = il.begin(); l != il.end(); l++){ + for (std::vector::const_iterator l = il.begin(); l != il.end(); l++){ SP_OBJECT(*l)->deleteObject(); } DocumentUndo::done(doc, SP_VERB_NONE, description); @@ -720,7 +720,7 @@ sp_selected_path_boolop(Inkscape::Selection *selection, SPDesktop *desktop, bool gchar *desc = source->desc(); // remove source paths selection->clear(); - for (SelContainer::const_iterator l = il.begin(); l != il.end(); l++){ + for (std::vector::const_iterator l = il.begin(); l != il.end(); l++){ // if this is the bottommost object, if (!strcmp(reinterpret_cast(*l)->getRepr()->attribute("id"), id)) { // delete it so that its clones don't get alerted; this object will be restored shortly, with the same id @@ -1157,8 +1157,8 @@ sp_selected_path_outline(SPDesktop *desktop) } bool did = false; - SelContainer il(selection->itemList()); - for (SelContainer::const_iterator l = il.begin(); l != il.end(); l++){ + std::vector il(selection->itemList()); + for (std::vector::const_iterator l = il.begin(); l != il.end(); l++){ SPItem *item = SP_ITEM(*l); if (!SP_IS_SHAPE(item) && !SP_IS_TEXT(item)) @@ -1769,8 +1769,8 @@ sp_selected_path_do_offset(SPDesktop *desktop, bool expand, double prefOffset) } bool did = false; - SelContainer il(selection->itemList()); - for (SelContainer::const_iterator l = il.begin(); l != il.end(); l++){ + std::vector il(selection->itemList()); + for (std::vector::const_iterator l = il.begin(); l != il.end(); l++){ SPItem *item = SP_ITEM(*l); SPCurve *curve = NULL; @@ -1967,7 +1967,7 @@ sp_selected_path_do_offset(SPDesktop *desktop, bool expand, double prefOffset) static bool sp_selected_path_simplify_items(SPDesktop *desktop, - Inkscape::Selection *selection, SelContainer &items, + Inkscape::Selection *selection, std::vector &items, float threshold, bool justCoalesce, float angleLimit, bool breakableAngles, bool modifySelection); @@ -1986,7 +1986,7 @@ sp_selected_path_simplify_item(SPDesktop *desktop, //If this is a group, do the children instead if (SP_IS_GROUP(item)) { - SelContainer items = sp_item_group_item_list(SP_GROUP(item)); + std::vector items = sp_item_group_item_list(SP_GROUP(item)); return sp_selected_path_simplify_items(desktop, selection, items, threshold, justCoalesce, @@ -2111,7 +2111,7 @@ sp_selected_path_simplify_item(SPDesktop *desktop, bool sp_selected_path_simplify_items(SPDesktop *desktop, - Inkscape::Selection *selection, SelContainer &items, + Inkscape::Selection *selection, std::vector &items, float threshold, bool justCoalesce, float angleLimit, bool breakableAngles, bool modifySelection) @@ -2142,7 +2142,7 @@ sp_selected_path_simplify_items(SPDesktop *desktop, // set "busy" cursor desktop->setWaitingCursor(); - for (SelContainer::const_iterator l = items.begin(); l != items.end(); l++){ + for (std::vector::const_iterator l = items.begin(); l != items.end(); l++){ SPItem *item = SP_ITEM(*l); if (!(SP_IS_GROUP(item) || SP_IS_SHAPE(item) || SP_IS_TEXT(item))) @@ -2191,7 +2191,7 @@ sp_selected_path_simplify_selection(SPDesktop *desktop, float threshold, bool ju return; } - SelContainer items(selection->itemList()); + std::vector items(selection->itemList()); bool didSomething = sp_selected_path_simplify_items(desktop, selection, items, threshold, diff --git a/src/text-chemistry.cpp b/src/text-chemistry.cpp index 391e255a5..33192a330 100644 --- a/src/text-chemistry.cpp +++ b/src/text-chemistry.cpp @@ -43,8 +43,8 @@ using Inkscape::DocumentUndo; static SPItem * flowtext_in_selection(Inkscape::Selection *selection) { - SelContainer items = selection->itemList(); - for(SelContainer::const_iterator i=items.begin();i!=items.end();i++){ + std::vector items = selection->itemList(); + for(std::vector::const_iterator i=items.begin();i!=items.end();i++){ if (SP_IS_FLOWTEXT(*i)) return ((SPItem *) *i); } @@ -54,8 +54,8 @@ flowtext_in_selection(Inkscape::Selection *selection) static SPItem * text_or_flowtext_in_selection(Inkscape::Selection *selection) { - SelContainer items = selection->itemList(); - for(SelContainer::const_iterator i=items.begin();i!=items.end();i++){ + std::vector items = selection->itemList(); + for(std::vector::const_iterator i=items.begin();i!=items.end();i++){ if (SP_IS_TEXT(*i) || SP_IS_FLOWTEXT(*i)) return ((SPItem *) *i); } @@ -65,8 +65,8 @@ text_or_flowtext_in_selection(Inkscape::Selection *selection) static SPItem * shape_in_selection(Inkscape::Selection *selection) { - SelContainer items = selection->itemList(); - for(SelContainer::const_iterator i=items.begin();i!=items.end();i++){ + std::vector items = selection->itemList(); + for(std::vector::const_iterator i=items.begin();i!=items.end();i++){ if (SP_IS_SHAPE(*i)) return ((SPItem *) *i); } @@ -196,8 +196,8 @@ text_remove_from_path() } bool did = false; - SelContainer items(selection->itemList()); - for(SelContainer::const_iterator i=items.begin();i!=items.end();i++){ + std::vector items(selection->itemList()); + for(std::vector::const_iterator i=items.begin();i!=items.end();i++){ SPObject *obj = SP_OBJECT(*i); if (SP_IS_TEXT_TEXTPATH(obj)) { @@ -260,8 +260,8 @@ text_remove_all_kerns() bool did = false; - SelContainer items = selection->itemList(); - for(SelContainer::const_iterator i=items.begin();i!=items.end();i++){ + std::vector items = selection->itemList(); + for(std::vector::const_iterator i=items.begin();i!=items.end();i++){ SPObject *obj = SP_OBJECT(*i); if (!SP_IS_TEXT(obj) && !SP_IS_TSPAN(obj) && !SP_IS_FLOWTEXT(obj)) { @@ -320,8 +320,8 @@ text_flow_into_shape() g_return_if_fail(SP_IS_FLOWREGION(object)); /* Add clones */ - SelContainer items = selection->itemList(); - for(SelContainer::const_iterator i=items.begin();i!=items.end();i++){ + std::vector items = selection->itemList(); + for(std::vector::const_iterator i=items.begin();i!=items.end();i++){ SPItem *item = SP_ITEM(*i); if (SP_IS_SHAPE(item)){ Inkscape::XML::Node *clone = xml_doc->createElement("svg:use"); @@ -392,11 +392,11 @@ text_unflow () return; } - SelContainer new_objs; + std::vector new_objs; GSList *old_objs = NULL; - SelContainer items = selection->itemList(); - for(SelContainer::const_iterator i=items.begin();i!=items.end();i++){ + std::vector items = selection->itemList(); + for(std::vector::const_reverse_iterator i=items.rbegin();i!=items.rend();i++){ if (!SP_IS_FLOWTEXT(SP_OBJECT(*i))) { continue; @@ -443,7 +443,7 @@ text_unflow () SPText *text = SP_TEXT(text_object); text->_adjustFontsizeRecursive(text, ex); - new_objs.push_front(text_object); + new_objs.push_back((SPItem*)text_object); old_objs = g_slist_prepend (old_objs, flowtext); Inkscape::GC::release(rtext); @@ -478,9 +478,9 @@ flowtext_to_text() bool did = false; - SelContainer reprs; - SelContainer items(selection->itemList()); - for(SelContainer::const_iterator i=items.begin();i!=items.end();i++){ + std::vector reprs; + std::vector items(selection->itemList()); + for(std::vector::const_iterator i=items.begin();i!=items.end();i++){ SPItem *item = (SPItem *) *i; @@ -510,7 +510,7 @@ flowtext_to_text() Inkscape::GC::release(repr); item->deleteObject(); - reprs.push_front(dynamic_cast(repr)); + reprs.push_back(repr); } diff --git a/src/text-editing.cpp b/src/text-editing.cpp index 44d90b4ae..88210dc0b 100644 --- a/src/text-editing.cpp +++ b/src/text-editing.cpp @@ -67,8 +67,8 @@ static void te_update_layout_now (SPItem *item) void te_update_layout_now_recursive(SPItem *item) { if (SP_IS_GROUP(item)) { - SelContainer item_list = sp_item_group_item_list(SP_GROUP(item)); - for(SelContainer::const_iterator i=item_list.begin();i!=item_list.end();i++){ + std::vector item_list = sp_item_group_item_list(SP_GROUP(item)); + for(std::vector::const_iterator i=item_list.begin();i!=item_list.end();i++){ SPItem* list_item = static_cast(*i); te_update_layout_now_recursive(list_item); } diff --git a/src/trace/trace.cpp b/src/trace/trace.cpp index 2becca5cc..4853f127c 100644 --- a/src/trace/trace.cpp +++ b/src/trace/trace.cpp @@ -65,7 +65,7 @@ SPImage *Tracer::getSelectedSPImage() if (sioxEnabled) { SPImage *img = NULL; - SelContainer const list = sel->itemList(); + std::vector const list = sel->itemList(); std::vector items; sioxShapes.clear(); @@ -74,7 +74,7 @@ SPImage *Tracer::getSelectedSPImage() them as bottom-to-top so that we can discover the image and any SPItems above it */ - for (SelContainer::const_iterator i=list.begin() ; list.end()!=i ; i++) + for (std::vector::const_iterator i=list.begin() ; list.end()!=i ; i++) { if (!SP_IS_ITEM(*i)) { diff --git a/src/ui/clipboard.cpp b/src/ui/clipboard.cpp index 20b43af3b..6c15121c2 100644 --- a/src/ui/clipboard.cpp +++ b/src/ui/clipboard.cpp @@ -523,8 +523,8 @@ bool ClipboardManagerImpl::pasteSize(SPDesktop *desktop, bool separately, bool a // resize each object in the selection if (separately) { - SelContainer itemlist=selection->itemList(); - for(SelContainer::const_iterator i=itemlist.begin();i!=itemlist.end();i++){ + std::vector itemlist=selection->itemList(); + for(std::vector::const_iterator i=itemlist.begin();i!=itemlist.end();i++){ SPItem *item = SP_ITEM(*i); if (item) { Geom::OptRect obj_size = item->desktopVisualBounds(); @@ -579,8 +579,8 @@ bool ClipboardManagerImpl::pastePathEffect(SPDesktop *desktop) desktop->doc()->importDefs(tempdoc); // make sure all selected items are converted to paths first (i.e. rectangles) sp_selected_to_lpeitems(desktop); - SelContainer itemlist=selection->itemList(); - for(SelContainer::const_iterator i=itemlist.begin();i!=itemlist.end();i++){ + std::vector itemlist=selection->itemList(); + for(std::vector::const_iterator i=itemlist.begin();i!=itemlist.end();i++){ SPItem *item = SP_ITEM(*i); _applyPathEffect(item, effectstack); } @@ -662,8 +662,8 @@ Glib::ustring ClipboardManagerImpl::getShapeOrTextObjectId(SPDesktop *desktop) void ClipboardManagerImpl::_copySelection(Inkscape::Selection *selection) { // copy the defs used by all items - SelContainer itemlist=selection->itemList(); - for(SelContainer::const_iterator i=itemlist.begin();i!=itemlist.end();i++){ + std::vector itemlist=selection->itemList(); + for(std::vector::const_iterator i=itemlist.begin();i!=itemlist.end();i++){ SPItem *item = SP_ITEM(*i); if (item) { _copyUsedDefs(item); @@ -673,10 +673,10 @@ void ClipboardManagerImpl::_copySelection(Inkscape::Selection *selection) } // copy the representation of the items - SelContainer sorted_items(itemlist); - sorted_items.sort(sp_object_compare_position); + std::vector sorted_items(itemlist); + sort(sorted_items.begin(),sorted_items.end(),sp_object_compare_position); - for(SelContainer::const_iterator i=sorted_items.begin();i!=sorted_items.end();i++){ + for(std::vector::const_iterator i=sorted_items.begin();i!=sorted_items.end();i++){ SPItem *item = SP_ITEM(*i); if (item) { Inkscape::XML::Node *obj = item->getRepr(); @@ -1157,7 +1157,7 @@ void ClipboardManagerImpl::_onGet(Gtk::SelectionData &sel, guint /*info*/) sp_repr_get_double(nv, "inkscape:pageopacity", &opacity); bgcolor |= SP_COLOR_F_TO_U(opacity); } - SelContainer x; + std::vector x; sp_export_png_file(_clipboardSPDoc, filename, area, width, height, dpi, dpi, bgcolor, NULL, NULL, true, x); } else diff --git a/src/ui/dialog/align-and-distribute.cpp b/src/ui/dialog/align-and-distribute.cpp index 562bc28b7..34dbd150b 100644 --- a/src/ui/dialog/align-and-distribute.cpp +++ b/src/ui/dialog/align-and-distribute.cpp @@ -98,7 +98,7 @@ void ActionAlign::do_action(SPDesktop *desktop, int index) bool sel_as_group = prefs->getBool("/dialogs/align/sel-as-groups"); using Inkscape::Util::GSListConstIterator; - SelContainer selected(selection->itemList()); + std::vector selected(selection->itemList()); if (selected.empty()) return; const Coeffs &a = _allCoeffs[index]; @@ -148,7 +148,7 @@ void ActionAlign::do_action(SPDesktop *desktop, int index) b = selection->preferredBounds(); //Move each item in the selected list separately - for (SelContainer::iterator it(selected.begin()); + for (std::vector::iterator it(selected.begin()); it != selected.end(); ++it) { SPItem* item=static_cast (*it); @@ -251,18 +251,18 @@ private : if (!selection) return; using Inkscape::Util::GSListConstIterator; - SelContainer selected(selection->itemList()); + std::vector selected(selection->itemList()); if (selected.empty()) return; //Check 2 or more selected objects - SelContainer::iterator second(selected.begin()); + std::vector::iterator second(selected.begin()); ++second; if (second == selected.end()) return; Inkscape::Preferences *prefs = Inkscape::Preferences::get(); int prefs_bbox = prefs->getBool("/tools/bounding_box"); std::vector< BBoxSort > sorted; - for (SelContainer::iterator it(selected.begin()); + for (std::vector::iterator it(selected.begin()); it != selected.end(); ++it) {SPItem *item=static_cast(*it); @@ -540,10 +540,6 @@ private : return (a->isSiblingOf(b)); } - static bool local_obj_compare(SPObject* a,SPObject* b){ - return ActionExchangePositions::sort_compare(static_cast(a),static_cast(b)); - } - virtual void on_button_click() { SPDesktop *desktop = _dialog.getDesktop(); @@ -553,7 +549,7 @@ private : if (!selection) return; using Inkscape::Util::GSListConstIterator; - SelContainer selected(selection->itemList()); + std::vector selected(selection->itemList()); if (selected.empty()) return; //Check 2 or more selected objects @@ -571,9 +567,9 @@ private : } else { // sorting by ZOrder is outomatically done by not setting the center center.reset(); } - selected.sort(local_obj_compare); + sort(selected.begin(),selected.end(),sort_compare); } - SelContainer::iterator it(selected.begin()); + std::vector::iterator it(selected.begin()); SPItem* item=static_cast(*it); Geom::Point p1 = (item)->getCenter(); for (++it ;it != selected.end(); ++it) @@ -619,7 +615,7 @@ private : Inkscape::Preferences *prefs = Inkscape::Preferences::get(); int saved_compensation = prefs->getInt("/options/clonecompensation/value", SP_CLONE_COMPENSATION_UNMOVED); prefs->setInt("/options/clonecompensation/value", SP_CLONE_COMPENSATION_UNMOVED); - SelContainer x(_dialog.getDesktop()->getSelection()->itemList()); + std::vector x(_dialog.getDesktop()->getSelection()->itemList()); unclump (x); // restore compensation setting @@ -651,7 +647,7 @@ private : if (!selection) return; using Inkscape::Util::GSListConstIterator; - SelContainer selected(selection->itemList()); + std::vector selected(selection->itemList()); if (selected.empty()) return; //Check 2 or more selected objects @@ -675,7 +671,7 @@ private : int saved_compensation = prefs->getInt("/options/clonecompensation/value", SP_CLONE_COMPENSATION_UNMOVED); prefs->setInt("/options/clonecompensation/value", SP_CLONE_COMPENSATION_UNMOVED); - for (SelContainer::iterator it(selected.begin()); + for (std::vector::iterator it(selected.begin()); it != selected.end(); ++it) { @@ -750,7 +746,7 @@ private : if (!selection) return; using Inkscape::Util::GSListConstIterator; - SelContainer selected(selection->itemList()); + std::vector selected(selection->itemList()); if (selected.empty()) return; //Check 2 or more selected objects @@ -761,7 +757,7 @@ private : std::vector sorted; - for (SelContainer::iterator it(selected.begin()); + for (std::vector::iterator it(selected.begin()); it != selected.end(); ++it) { @@ -805,7 +801,7 @@ private : } } else { - for (SelContainer::iterator it(selected.begin()); + for (std::vector::iterator it(selected.begin()); it != selected.end(); ++it) { diff --git a/src/ui/dialog/clonetiler.cpp b/src/ui/dialog/clonetiler.cpp index abfab8b19..680757373 100644 --- a/src/ui/dialog/clonetiler.cpp +++ b/src/ui/dialog/clonetiler.cpp @@ -2104,16 +2104,17 @@ void CloneTiler::clonetiler_unclump(GtkWidget */*widget*/, void *) SPObject *obj = selection->singleItem(); SPObject *parent = obj->parent; - SelContainer to_unclump; // not including the original + std::vector to_unclump; // not including the original for (SPObject *child = parent->firstChild(); child != NULL; child = child->next) { if (clonetiler_is_a_clone_of (child, obj)) { - to_unclump.push_front(child); + to_unclump.push_back((SPItem*)child); } } desktop->getDocument()->ensureUpToDate(); - + std::vector tu2(to_unclump); + for(int i=0;igetDocument(), SP_VERB_DIALOG_CLONETILER, diff --git a/src/ui/dialog/export.cpp b/src/ui/dialog/export.cpp index 0667ba721..32eed088c 100644 --- a/src/ui/dialog/export.cpp +++ b/src/ui/dialog/export.cpp @@ -1024,8 +1024,8 @@ void Export::onExport () gint export_count = 0; - SelContainer itemlist=desktop->getSelection()->itemList(); - for(SelContainer::const_iterator i = itemlist.begin();i!=itemlist.end() && !interrupted ;i++){ + std::vector itemlist=desktop->getSelection()->itemList(); + for(std::vector::const_iterator i = itemlist.begin();i!=itemlist.end() && !interrupted ;i++){ SPItem *item = reinterpret_cast(*i); prog_dlg->set_data("current", GINT_TO_POINTER(n)); @@ -1064,7 +1064,7 @@ void Export::onExport () _("Exporting file %s..."), safeFile), desktop); MessageCleaner msgFlashCleanup(desktop->messageStack()->flashF(Inkscape::IMMEDIATE_MESSAGE, _("Exporting file %s..."), safeFile), desktop); - SelContainer x; + std::vector x; if (!sp_export_png_file (doc, path.c_str(), *area, width, height, dpi, dpi, nv->pagecolor, @@ -1154,7 +1154,7 @@ void Export::onExport () prog_dlg->set_data("total", GINT_TO_POINTER(0)); /* Do export */ - SelContainer x; + std::vector x; ExportResult status = sp_export_png_file(desktop->getDocument(), path.c_str(), Geom::Rect(Geom::Point(x0, y0), Geom::Point(x1, y1)), width, height, xdpi, ydpi, nv->pagecolor, diff --git a/src/ui/dialog/filter-effects-dialog.cpp b/src/ui/dialog/filter-effects-dialog.cpp index f67c1d173..a6312140d 100644 --- a/src/ui/dialog/filter-effects-dialog.cpp +++ b/src/ui/dialog/filter-effects-dialog.cpp @@ -1465,8 +1465,8 @@ void FilterEffectsDialog::FilterModifier::update_selection(Selection *sel) } std::set used; - SelContainer itemlist=sel->itemList(); - for(SelContainer::const_iterator i=itemlist.begin(); itemlist.end() != i; i++) { + std::vector itemlist=sel->itemList(); + for(std::vector::const_iterator i=itemlist.begin(); itemlist.end() != i; i++) { SPObject *obj = SP_OBJECT (*i); SPStyle *style = obj->style; if (!style || !SP_IS_ITEM(obj)) { @@ -1545,8 +1545,8 @@ void FilterEffectsDialog::FilterModifier::on_selection_toggled(const Glib::ustri if((*iter)[_columns.sel] == 1) filter = 0; - SelContainer itemlist=sel->itemList(); - for(SelContainer::const_iterator i=itemlist.begin(); itemlist.end() != i; i++) { + std::vector itemlist=sel->itemList(); + for(std::vector::const_iterator i=itemlist.begin(); itemlist.end() != i; i++) { SPItem * item = SP_ITEM(*i); SPStyle *style = item->style; g_assert(style != NULL); @@ -1649,9 +1649,9 @@ void FilterEffectsDialog::FilterModifier::remove_filter() SPDocument* doc = filter->document; // Delete all references to this filter - SelContainer x,y; - SelContainer all = get_all_items(x, _desktop->currentRoot(), _desktop, false, false, true, y); - for(SelContainer::const_iterator i=all.begin(); all.end() != i; i++) { + std::vector x,y; + std::vector all = get_all_items(x, _desktop->currentRoot(), _desktop, false, false, true, y); + for(std::vector::const_iterator i=all.begin(); all.end() != i; i++) { if (!SP_IS_ITEM(*i)) { continue; } diff --git a/src/ui/dialog/find.cpp b/src/ui/dialog/find.cpp index 43ecb60ac..283d79c0d 100644 --- a/src/ui/dialog/find.cpp +++ b/src/ui/dialog/find.cpp @@ -549,7 +549,7 @@ bool Find::item_font_match(SPItem *item, const gchar *text, bool exact, bool cas } -SelContainer Find::filter_fields (SelContainer &l, bool exact, bool casematch) +std::vector Find::filter_fields (std::vector &l, bool exact, bool casematch) { Glib::ustring tmp = entry_find.getEntry()->get_text(); if (tmp.empty()) { @@ -557,17 +557,17 @@ SelContainer Find::filter_fields (SelContainer &l, bool exact, bool casematch) } gchar* text = g_strdup(tmp.c_str()); - SelContainer in = l; - SelContainer out; + std::vector in = l; + std::vector out; if (check_searchin_text.get_active()) { - for(SelContainer::const_iterator i=in.begin(); in.end() != i; i++) { + for(std::vector::const_reverse_iterator i=in.rbegin(); in.rend() != i; i++) { SPObject *obj = SP_OBJECT (*i); SPItem *item = dynamic_cast(obj); g_assert(item != NULL); if (item_text_match(item, text, exact, casematch)) { if (out.end()==find(out.begin(),out.end(), *i)) { - out.push_front(*i); + out.push_back(*i); if (_action_replace) { item_text_match(item, text, exact, casematch, _action_replace); } @@ -584,12 +584,12 @@ SelContainer Find::filter_fields (SelContainer &l, bool exact, bool casematch) bool attrvalue = check_attributevalue.get_active(); if (ids) { - for(SelContainer::const_iterator i=in.begin(); in.end() != i; i++) { + for(std::vector::const_reverse_iterator i=in.rbegin(); in.rend() != i; i++) { SPObject *obj = SP_OBJECT (*i); SPItem *item = dynamic_cast(obj); if (item_id_match(item, text, exact, casematch)) { if (out.end()==find(out.begin(),out.end(), *i)) { - out.push_front(*i); + out.push_back(*i); if (_action_replace) { item_id_match(item, text, exact, casematch, _action_replace); } @@ -600,13 +600,13 @@ SelContainer Find::filter_fields (SelContainer &l, bool exact, bool casematch) if (style) { - for(SelContainer::const_iterator i=in.begin(); in.end() != i; i++) { + for(std::vector::const_reverse_iterator i=in.rbegin(); in.rend() != i; i++) { SPObject *obj = SP_OBJECT (*i); SPItem *item = dynamic_cast(obj); g_assert(item != NULL); if (item_style_match(item, text, exact, casematch)) { if (out.end()==find(out.begin(),out.end(), *i)){ - out.push_front(*i); + out.push_back(*i); if (_action_replace) { item_style_match(item, text, exact, casematch, _action_replace); } @@ -617,13 +617,13 @@ SelContainer Find::filter_fields (SelContainer &l, bool exact, bool casematch) if (attrname) { - for(SelContainer::const_iterator i=in.begin(); in.end() != i; i++) { + for(std::vector::const_reverse_iterator i=in.rbegin(); in.rend() != i; i++) { SPObject *obj = SP_OBJECT (*i); SPItem *item = dynamic_cast(obj); g_assert(item != NULL); if (item_attr_match(item, text, exact, casematch)) { if (out.end()==find(out.begin(),out.end(), *i)) { - out.push_front(*i); + out.push_back(*i); if (_action_replace) { item_attr_match(item, text, exact, casematch, _action_replace); } @@ -634,13 +634,13 @@ SelContainer Find::filter_fields (SelContainer &l, bool exact, bool casematch) if (attrvalue) { - for(SelContainer::const_iterator i=in.begin(); in.end() != i; i++) { + for(std::vector::const_reverse_iterator i=in.rbegin(); in.rend() != i; i++) { SPObject *obj = SP_OBJECT (*i); SPItem *item = dynamic_cast(obj); g_assert(item != NULL); if (item_attrvalue_match(item, text, exact, casematch)) { if (out.end()==find(out.begin(),out.end(), *i)) { - out.push_front(*i); + out.push_back(*i); if (_action_replace) { item_attrvalue_match(item, text, exact, casematch, _action_replace); } @@ -651,13 +651,13 @@ SelContainer Find::filter_fields (SelContainer &l, bool exact, bool casematch) if (font) { - for(SelContainer::const_iterator i=in.begin(); in.end() != i; i++) { + for(std::vector::const_reverse_iterator i=in.rbegin(); in.rend() != i; i++) { SPObject *obj = SP_OBJECT (*i); SPItem *item = dynamic_cast(obj); g_assert(item != NULL); if (item_font_match(item, text, exact, casematch)) { if (out.end()==find(out.begin(),out.end(),*i)) { - out.push_front(*i); + out.push_back(*i); if (_action_replace) { item_font_match(item, text, exact, casematch, _action_replace); } @@ -715,29 +715,29 @@ bool Find::item_type_match (SPItem *item) return false; } -SelContainer Find::filter_types (SelContainer &l) +std::vector Find::filter_types (std::vector &l) { - SelContainer n; - for(SelContainer::const_iterator i=l.begin(); l.end() != i; i++) { + std::vector n; + for(std::vector::const_reverse_iterator i=l.rbegin(); l.rend() != i; i++) { SPObject *obj = SP_OBJECT (*i); SPItem *item = dynamic_cast(obj); g_assert(item != NULL); if (item_type_match(item)) { - n.push_front(*i); + n.push_back(*i); } } return n; } -SelContainer &Find::filter_list (SelContainer &l, bool exact, bool casematch) +std::vector &Find::filter_list (std::vector &l, bool exact, bool casematch) { l = filter_types (l); l = filter_fields (l, exact, casematch); return l; } -SelContainer &Find::all_items (SPObject *r, SelContainer &l, bool hidden, bool locked) +std::vector &Find::all_items (SPObject *r, std::vector &l, bool hidden, bool locked) { if (dynamic_cast(r)) { return l; // we're not interested in items in defs @@ -751,7 +751,7 @@ SelContainer &Find::all_items (SPObject *r, SelContainer &l, bool hidden, bool l SPItem *item = dynamic_cast(child); if (item && !child->cloned && !desktop->isLayer(item)) { if ((hidden || !desktop->itemIsHidden(item)) && (locked || !item->isLocked())) { - l.push_front(child); + l.insert(l.begin(),(SPItem*)child); } } l = all_items (child, l, hidden, locked); @@ -759,10 +759,10 @@ SelContainer &Find::all_items (SPObject *r, SelContainer &l, bool hidden, bool l return l; } -SelContainer &Find::all_selection_items (Inkscape::Selection *s, SelContainer &l, SPObject *ancestor, bool hidden, bool locked) +std::vector &Find::all_selection_items (Inkscape::Selection *s, std::vector &l, SPObject *ancestor, bool hidden, bool locked) { - SelContainer itemlist=s->itemList(); - for(SelContainer::const_iterator i=itemlist.begin(); itemlist.end() != i; i++) { + std::vector itemlist=s->itemList(); + for(std::vector::const_iterator i=itemlist.begin(); itemlist.end() != i; i++) { SPObject *obj = SP_OBJECT (*i); SPItem *item = dynamic_cast(obj); g_assert(item != NULL); @@ -817,7 +817,7 @@ void Find::onAction() bool casematch = check_case_sensitive.get_active(); blocked = true; - SelContainer l; + std::vector l; if (check_scope_selection.get_active()) { if (check_scope_layer.get_active()) { l = all_selection_items (desktop->selection, l, desktop->currentLayer(), hidden, locked); @@ -833,7 +833,7 @@ void Find::onAction() } guint all = l.size(); - SelContainer n = filter_list (l, exact, casematch); + std::vector n = filter_list (l, exact, casematch); if (!n.empty()) { int count = n.size(); diff --git a/src/ui/dialog/find.h b/src/ui/dialog/find.h index 1aded96f2..61f4463ae 100644 --- a/src/ui/dialog/find.h +++ b/src/ui/dialog/find.h @@ -149,10 +149,10 @@ protected: /** * Function to filter a list of items based on the item type by calling each item_XXX_match function */ - SelContainer filter_fields (SelContainer &l, bool exact, bool casematch); + std::vector filter_fields (std::vector &l, bool exact, bool casematch); bool item_type_match (SPItem *item); - SelContainer filter_types (SelContainer &l); - SelContainer & filter_list (SelContainer &l, bool exact, bool casematch); + std::vector filter_types (std::vector &l); + std::vector & filter_list (std::vector &l, bool exact, bool casematch); /** * Find a string within a string and returns true if found with options for exact and casematching @@ -173,12 +173,12 @@ protected: * recursive function to return a list of all the items in the SPObject tree * */ - SelContainer & all_items (SPObject *r, SelContainer &l, bool hidden, bool locked); + std::vector & all_items (SPObject *r, std::vector &l, bool hidden, bool locked); /** * to return a list of all the selected items * */ - SelContainer & all_selection_items (Inkscape::Selection *s, SelContainer &l, SPObject *ancestor, bool hidden, bool locked); + std::vector & all_selection_items (Inkscape::Selection *s, std::vector &l, SPObject *ancestor, bool hidden, bool locked); /** * Shrink the dialog size when the expander widget is closed diff --git a/src/ui/dialog/font-substitution.cpp b/src/ui/dialog/font-substitution.cpp index 625ed99b9..e9a0fc017 100644 --- a/src/ui/dialog/font-substitution.cpp +++ b/src/ui/dialog/font-substitution.cpp @@ -70,7 +70,7 @@ FontSubstitution::checkFontSubstitutions(SPDocument* doc) int show_dlg = prefs->getInt("/options/font/substitutedlg", 0); if (show_dlg) { Glib::ustring out; - SelContainer l = getFontReplacedItems(doc, &out); + std::vector l = getFontReplacedItems(doc, &out); if (out.length() > 0) { show(out, l); } @@ -78,7 +78,7 @@ FontSubstitution::checkFontSubstitutions(SPDocument* doc) } void -FontSubstitution::show(Glib::ustring out, SelContainer &l) +FontSubstitution::show(Glib::ustring out, std::vector &l) { Gtk::MessageDialog warning(_("\nSome fonts are not available and have been substituted."), false, Gtk::MESSAGE_INFO, Gtk::BUTTONS_OK, true); @@ -148,17 +148,17 @@ FontSubstitution::show(Glib::ustring out, SelContainer &l) * b. Build up a list of the objects rendered fonts - taken for the objects layout/spans * If there are fonts in a. that are not in b. then those fonts have been substituted. */ -SelContainer FontSubstitution::getFontReplacedItems(SPDocument* doc, Glib::ustring *out) +std::vector FontSubstitution::getFontReplacedItems(SPDocument* doc, Glib::ustring *out) { SPDesktop *desktop = SP_ACTIVE_DESKTOP; - SelContainer allList; - SelContainer outList,x,y; + std::vector allList; + std::vector outList,x,y; std::set setErrors; std::set setFontSpans; std::map mapFontStyles; allList = get_all_items(x, doc->getRoot(), desktop, false, false, true, y); - for(SelContainer::const_iterator i = allList.begin();i!=allList.end();i++){ + for(std::vector::const_iterator i = allList.begin();i!=allList.end();i++){ SPItem *item = SP_ITEM(*i); SPStyle *style = item->style; Glib::ustring family = ""; @@ -214,8 +214,8 @@ SelContainer FontSubstitution::getFontReplacedItems(SPDocument* doc, Glib::ustri } // Check if any document styles are not in the actual layout - std::map::const_iterator mapIter; - for (mapIter = mapFontStyles.begin(); mapIter != mapFontStyles.end(); ++mapIter) { + std::map::const_reverse_iterator mapIter; + for (mapIter = mapFontStyles.rbegin(); mapIter != mapFontStyles.rend(); ++mapIter) { SPItem *item = mapIter->first; Glib::ustring fonts = mapIter->second; @@ -248,7 +248,7 @@ SelContainer FontSubstitution::getFontReplacedItems(SPDocument* doc, Glib::ustri Glib::ustring err = Glib::ustring::compose( _("Font '%1' substituted with '%2'"), fonts.c_str(), subName.c_str()); setErrors.insert(err); - outList.push_front(item); + outList.push_back(item); } } diff --git a/src/ui/dialog/font-substitution.h b/src/ui/dialog/font-substitution.h index eed7adcf2..cdb4e22b4 100644 --- a/src/ui/dialog/font-substitution.h +++ b/src/ui/dialog/font-substitution.h @@ -25,13 +25,13 @@ public: FontSubstitution(); virtual ~FontSubstitution(); void checkFontSubstitutions(SPDocument* doc); - void show(Glib::ustring out, SelContainer &l); + void show(Glib::ustring out, std::vector &l); static FontSubstitution &getInstance() { return *new FontSubstitution(); } Glib::ustring getSubstituteFontName (Glib::ustring font); protected: - SelContainer getFontReplacedItems(SPDocument* doc, Glib::ustring *out); + std::vector getFontReplacedItems(SPDocument* doc, Glib::ustring *out); private: FontSubstitution(FontSubstitution const &d); diff --git a/src/ui/dialog/glyphs.cpp b/src/ui/dialog/glyphs.cpp index 1ef97b996..fa469dc4b 100644 --- a/src/ui/dialog/glyphs.cpp +++ b/src/ui/dialog/glyphs.cpp @@ -578,8 +578,8 @@ void GlyphsPanel::setTargetDesktop(SPDesktop *desktop) void GlyphsPanel::insertText() { SPItem *textItem = 0; - SelContainer itemlist=targetDesktop->selection->itemList(); - for(SelContainer::const_iterator i=itemlist.begin(); itemlist.end() != i; i++) { + std::vector itemlist=targetDesktop->selection->itemList(); + for(std::vector::const_iterator i=itemlist.begin(); itemlist.end() != i; i++) { if (SP_IS_TEXT(*i) || SP_IS_FLOWTEXT(*i)) { textItem = SP_ITEM(*i); break; @@ -688,8 +688,8 @@ void GlyphsPanel::selectionModifiedCB(guint flags) void GlyphsPanel::calcCanInsert() { int items = 0; - SelContainer itemlist=targetDesktop->selection->itemList(); - for(SelContainer::const_iterator i=itemlist.begin(); itemlist.end() != i; i++) { + std::vector itemlist=targetDesktop->selection->itemList(); + for(std::vector::const_iterator i=itemlist.begin(); itemlist.end() != i; i++) { if (SP_IS_TEXT(*i) || SP_IS_FLOWTEXT(*i)) { ++items; } diff --git a/src/ui/dialog/grid-arrange-tab.cpp b/src/ui/dialog/grid-arrange-tab.cpp index ba8616d9b..d62032e9d 100644 --- a/src/ui/dialog/grid-arrange-tab.cpp +++ b/src/ui/dialog/grid-arrange-tab.cpp @@ -175,9 +175,9 @@ void GridArrangeTab::arrange() desktop->getDocument()->ensureUpToDate(); Inkscape::Selection *selection = desktop->getSelection(); - const SelContainer items = selection ? selection->itemList() : SelContainer(); + const std::vector items = selection ? selection->itemList() : std::vector(); cnt=0; - for(SelContainer::const_iterator i = items.begin();i!=items.end();i++){ + for(std::vector::const_iterator i = items.begin();i!=items.end();i++){ SPItem *item = SP_ITEM(*i); Geom::OptRect b = item->documentVisualBounds(); if (!b) { @@ -205,18 +205,17 @@ void GridArrangeTab::arrange() // require the sorting done before we can calculate row heights etc. g_return_if_fail(selection); - SelContainer rev(selection->itemList()); - rev.sort(sp_compare_y_position_obj); - SelContainer sorted(rev); - sorted.sort(sp_compare_x_position_obj); + std::vector sorted(selection->itemList()); + sort(sorted.begin(),sorted.end(),sp_compare_y_position); + sort(sorted.begin(),sorted.end(),sp_compare_x_position); // Calculate individual Row and Column sizes if necessary cnt=0; - const SelContainer sizes(sorted); - for (SelContainer::const_iterator i = sizes.begin();i!=sizes.end();i++) { + const std::vector sizes(sorted); + for (std::vector::const_iterator i = sizes.begin();i!=sizes.end();i++) { SPItem *item = SP_ITEM(*i); Geom::OptRect b = item->documentVisualBounds(); if (b) { @@ -314,7 +313,7 @@ g_print("\n row = %f col = %f selection x= %f selection y = %f", total_row_h } cnt=0; - SelContainer::iterator it = sorted.begin(); + std::vector::iterator it = sorted.begin(); for (row_cnt=0; ((it != sorted.end()) && (row_cntselection : 0; g_return_if_fail( selection ); - SelContainer const items = selection->itemList(); + std::vector const items = selection->itemList(); int selcount = items.size(); double PerCol = ceil(selcount / NoOfColsSpinner.get_value()); @@ -545,7 +544,7 @@ void GridArrangeTab::updateSelection() updating = true; SPDesktop *desktop = Parent->getDesktop(); Inkscape::Selection *selection = desktop ? desktop->selection : 0; - SelContainer const items = selection ? selection->itemList() : SelContainer(); + std::vector const items = selection ? selection->itemList() : std::vector(); if (!items.empty()) { int selcount = items.size(); diff --git a/src/ui/dialog/icon-preview.cpp b/src/ui/dialog/icon-preview.cpp index 79e5b556d..6ad3d61ac 100644 --- a/src/ui/dialog/icon-preview.cpp +++ b/src/ui/dialog/icon-preview.cpp @@ -366,8 +366,8 @@ void IconPreviewPanel::refreshPreview() if ( sel ) { //g_message("found a selection to play with"); - SelContainer const items = sel->itemList(); - for(SelContainer::const_iterator i=items.begin();!target && i!=items.end();i++){ + std::vector const items = sel->itemList(); + for(std::vector::const_iterator i=items.begin();!target && i!=items.end();i++){ SPItem* item = SP_ITEM( *i); gchar const *id = item->getId(); if ( id ) { diff --git a/src/ui/dialog/objects.cpp b/src/ui/dialog/objects.cpp index 0ae3027c7..d60780f78 100644 --- a/src/ui/dialog/objects.cpp +++ b/src/ui/dialog/objects.cpp @@ -479,8 +479,8 @@ void ObjectsPanel::_objectsSelected( Selection *sel ) { _selectedConnection.block(); _tree.get_selection()->unselect_all(); SPItem *item = NULL; - SelContainer const items = sel->itemList(); - for(SelContainer::const_iterator i=items.begin(); i!=items.end();i++){ + std::vector const items = sel->itemList(); + for(std::vector::const_iterator i=items.begin(); i!=items.end();i++){ item = reinterpret_cast(*i); if (setOpacity) { diff --git a/src/ui/dialog/pixelartdialog.cpp b/src/ui/dialog/pixelartdialog.cpp index 273a378e5..760391df6 100644 --- a/src/ui/dialog/pixelartdialog.cpp +++ b/src/ui/dialog/pixelartdialog.cpp @@ -372,8 +372,8 @@ void PixelArtDialogImpl::vectorize() return; } - SelContainer const items = desktop->selection->itemList(); - for(SelContainer::const_iterator i=items.begin(); i!=items.end();i++){ + std::vector const items = desktop->selection->itemList(); + for(std::vector::const_iterator i=items.begin(); i!=items.end();i++){ if ( !SP_IS_IMAGE(*i) ) continue; diff --git a/src/ui/dialog/polar-arrange-tab.cpp b/src/ui/dialog/polar-arrange-tab.cpp index 8a382fc93..a68e73caf 100644 --- a/src/ui/dialog/polar-arrange-tab.cpp +++ b/src/ui/dialog/polar-arrange-tab.cpp @@ -297,14 +297,14 @@ static void moveToPoint(int anchor, SPItem *item, Geom::Point p) void PolarArrangeTab::arrange() { Inkscape::Selection *selection = parent->getDesktop()->getSelection(); - const SelContainer tmp(selection->itemList()); + const std::vector tmp(selection->itemList()); SPGenericEllipse *referenceEllipse = NULL; // Last ellipse in selection bool arrangeOnEllipse = !arrangeOnParametersRadio.get_active(); bool arrangeOnFirstEllipse = arrangeOnEllipse && arrangeOnFirstCircleRadio.get_active(); int count = 0; - for(SelContainer::const_iterator i=tmp.begin();i!=tmp.end();i++) + for(std::vector::const_iterator i=tmp.begin();i!=tmp.end();i++) { if(arrangeOnEllipse) { @@ -373,7 +373,7 @@ void PolarArrangeTab::arrange() Geom::Point realCenter = Geom::Point(cx, cy) * transformation; int i = 0; - for(SelContainer::const_iterator it=tmp.begin();it!=tmp.end();it++) + for(std::vector::const_iterator it=tmp.begin();it!=tmp.end();it++) { SPItem *item = SP_ITEM(*it); diff --git a/src/ui/dialog/print.cpp b/src/ui/dialog/print.cpp index dc98b6032..351971294 100644 --- a/src/ui/dialog/print.cpp +++ b/src/ui/dialog/print.cpp @@ -81,7 +81,7 @@ static void draw_page( width, height, (unsigned long)(Inkscape::Util::Quantity::convert(width, "px", "in") * dpi), (unsigned long)(Inkscape::Util::Quantity::convert(height, "px", "in") * dpi), - dpi, dpi, bgcolor, NULL, NULL, true, SelContainer()); + dpi, dpi, bgcolor, NULL, NULL, true, std::vector()); // This doesn't seem to work: //context->set_cairo_context ( Cairo::Context::create (Cairo::ImageSurface::create_from_png (tmp_png) ), dpi, dpi ); diff --git a/src/ui/dialog/swatches.cpp b/src/ui/dialog/swatches.cpp index da24ad605..72677c07e 100644 --- a/src/ui/dialog/swatches.cpp +++ b/src/ui/dialog/swatches.cpp @@ -123,7 +123,7 @@ static void editGradientImpl( SPDesktop* desktop, SPGradient* gr ) bool shown = false; if ( desktop && desktop->doc() ) { Inkscape::Selection *selection = desktop->getSelection(); - SelContainer const items = selection->itemList(); + std::vector const items = selection->itemList(); if (!items.empty()) { SPStyle query( desktop->doc() ); int result = objects_query_fillstroke((items), &query, true); diff --git a/src/ui/dialog/tags.cpp b/src/ui/dialog/tags.cpp index ba3a6b914..c2df5fc1c 100644 --- a/src/ui/dialog/tags.cpp +++ b/src/ui/dialog/tags.cpp @@ -669,8 +669,8 @@ bool TagsPanel::_handleButtonEvent(GdkEventButton* event) if (col == _tree.get_column(COL_ADD - 1) && down_at_add) { if (SP_IS_TAG(obj)) { bool wasadded = false; - SelContainer items=_desktop->selection->itemList(); - for(SelContainer::const_iterator i=items.begin();i!=items.end();i++){ + std::vector items=_desktop->selection->itemList(); + for(std::vector::const_iterator i=items.begin();i!=items.end();i++){ SPObject *newobj = reinterpret_cast(*i); bool addchild = true; for ( SPObject *child = obj->children; child != NULL; child = child->next) { diff --git a/src/ui/dialog/text-edit.cpp b/src/ui/dialog/text-edit.cpp index 593261ec5..1c1cf5937 100644 --- a/src/ui/dialog/text-edit.cpp +++ b/src/ui/dialog/text-edit.cpp @@ -418,8 +418,8 @@ SPItem *TextEdit::getSelectedTextItem (void) if (!SP_ACTIVE_DESKTOP) return NULL; - SelContainer tmp=SP_ACTIVE_DESKTOP->getSelection()->itemList(); - for(SelContainer::const_iterator i=tmp.begin();i!=tmp.end();i++) + std::vector tmp=SP_ACTIVE_DESKTOP->getSelection()->itemList(); + for(std::vector::const_iterator i=tmp.begin();i!=tmp.end();i++) { if (SP_IS_TEXT(*i) || SP_IS_FLOWTEXT(*i)) return SP_ITEM (*i); @@ -436,8 +436,8 @@ unsigned TextEdit::getSelectedTextCount (void) unsigned int items = 0; - SelContainer tmp=SP_ACTIVE_DESKTOP->getSelection()->itemList(); - for(SelContainer::const_iterator i=tmp.begin();i!=tmp.end();i++) + std::vector tmp=SP_ACTIVE_DESKTOP->getSelection()->itemList(); + for(std::vector::const_iterator i=tmp.begin();i!=tmp.end();i++) { if (SP_IS_TEXT(*i) || SP_IS_FLOWTEXT(*i)) ++items; @@ -540,11 +540,11 @@ void TextEdit::onApply() SPDesktop *desktop = SP_ACTIVE_DESKTOP; unsigned items = 0; - const SelContainer item_list = desktop->getSelection()->itemList(); + const std::vector item_list = desktop->getSelection()->itemList(); SPCSSAttr *css = fillTextStyle (); sp_desktop_set_style(desktop, css, true); - for(SelContainer::const_iterator i=item_list.begin();i!=item_list.end();i++){ + for(std::vector::const_iterator i=item_list.begin();i!=item_list.end();i++){ // apply style to the reprs of all text objects in the selection if (SP_IS_TEXT (*i)) { diff --git a/src/ui/dialog/transformation.cpp b/src/ui/dialog/transformation.cpp index 8c52144e0..0f81a7e58 100644 --- a/src/ui/dialog/transformation.cpp +++ b/src/ui/dialog/transformation.cpp @@ -741,12 +741,12 @@ void Transformation::applyPageMove(Inkscape::Selection *selection) if (_check_move_relative.get_active()) { // shift each object relatively to the previous one using Inkscape::Util::GSListConstIterator; - SelContainer selected(selection->itemList()); + std::vector selected(selection->itemList()); if (selected.empty()) return; if (fabs(x) > 1e-6) { std::vector< BBoxSort > sorted; - for (SelContainer::iterator it(selected.begin()); + for (std::vector::iterator it(selected.begin()); it != selected.end(); ++it) { @@ -771,7 +771,7 @@ void Transformation::applyPageMove(Inkscape::Selection *selection) } if (fabs(y) > 1e-6) { std::vector< BBoxSort > sorted; - for (SelContainer::iterator it(selected.begin()); + for (std::vector::iterator it(selected.begin()); it != selected.end(); ++it) { @@ -816,8 +816,8 @@ void Transformation::applyPageScale(Inkscape::Selection *selection) bool transform_stroke = prefs->getBool("/options/transform/stroke", true); bool preserve = prefs->getBool("/options/preservetransform/value", false); if (prefs->getBool("/dialogs/transformation/applyseparately")) { - SelContainer tmp=selection->itemList(); - for(SelContainer::const_iterator i=tmp.begin();i!=tmp.end();i++){ + std::vector tmp=selection->itemList(); + for(std::vector::const_iterator i=tmp.begin();i!=tmp.end();i++){ SPItem *item = SP_ITEM(*i); Geom::OptRect bbox_pref = item->desktopPreferredBounds(); Geom::OptRect bbox_geom = item->desktopGeometricBounds(); @@ -880,8 +880,8 @@ void Transformation::applyPageRotate(Inkscape::Selection *selection) } if (prefs->getBool("/dialogs/transformation/applyseparately")) { - SelContainer tmp=selection->itemList(); - for(SelContainer::const_iterator i=tmp.begin();i!=tmp.end();i++){ + std::vector tmp=selection->itemList(); + for(std::vector::const_iterator i=tmp.begin();i!=tmp.end();i++){ SPItem *item = SP_ITEM(*i); sp_item_rotate_rel(item, Geom::Rotate (angle*M_PI/180.0)); } @@ -900,8 +900,8 @@ void Transformation::applyPageSkew(Inkscape::Selection *selection) { Inkscape::Preferences *prefs = Inkscape::Preferences::get(); if (prefs->getBool("/dialogs/transformation/applyseparately")) { - SelContainer items=selection->itemList(); - for(SelContainer::const_iterator i = items.begin();i!=items.end();i++){ + std::vector items=selection->itemList(); + for(std::vector::const_iterator i = items.begin();i!=items.end();i++){ SPItem *item = SP_ITEM(*i); if (!_units_skew.isAbsolute()) { // percentage @@ -1002,8 +1002,8 @@ void Transformation::applyPageTransform(Inkscape::Selection *selection) } if (_check_replace_matrix.get_active()) { - SelContainer tmp=selection->itemList(); - for(SelContainer::const_iterator i=tmp.begin();i!=tmp.end();i++){ + std::vector tmp=selection->itemList(); + for(std::vector::const_iterator i=tmp.begin();i!=tmp.end();i++){ SPItem *item = SP_ITEM(*i); item->set_item_transform(displayed); SP_OBJECT(item)->updateRepr(); diff --git a/src/ui/interface.cpp b/src/ui/interface.cpp index 86cf629c1..43e35df9d 100644 --- a/src/ui/interface.cpp +++ b/src/ui/interface.cpp @@ -1906,7 +1906,7 @@ void ContextMenu::ActivateGroup(void) void ContextMenu::ActivateUngroup(void) { - SelContainer children; + std::vector children; sp_item_group_ungroup(static_cast(_item), children); _desktop->selection->setList(children); @@ -1958,7 +1958,7 @@ void ContextMenu::AnchorLinkFollow(void) void ContextMenu::AnchorLinkRemove(void) { - SelContainer children; + std::vector children; sp_item_group_ungroup(static_cast(_item), children, false); DocumentUndo::done(_desktop->doc(), SP_VERB_NONE, _("Remove link")); } @@ -2075,8 +2075,8 @@ void ContextMenu::ImageEdit(void) } #endif - SelContainer itemlist=_desktop->selection->itemList(); - for(SelContainer::const_iterator i=itemlist.begin();i!=itemlist.end();i++){ + std::vector itemlist=_desktop->selection->itemList(); + for(std::vector::const_iterator i=itemlist.begin();i!=itemlist.end();i++){ Inkscape::XML::Node *ir = SP_ITEM(*i)->getRepr(); const gchar *href = ir->attribute("xlink:href"); diff --git a/src/ui/tools/connector-tool.cpp b/src/ui/tools/connector-tool.cpp index fc40c20e7..9c6eead16 100644 --- a/src/ui/tools/connector-tool.cpp +++ b/src/ui/tools/connector-tool.cpp @@ -1316,8 +1316,8 @@ void cc_selection_set_avoid(bool const set_avoid) int changes = 0; - SelContainer l = selection->itemList(); - for(SelContainer::const_iterator i=l.begin();i!=l.end();i++) { + std::vector l = selection->itemList(); + for(std::vector::const_iterator i=l.begin();i!=l.end();i++) { SPItem *item = SP_ITEM(*i); char const *value = (set_avoid) ? "true" : NULL; diff --git a/src/ui/tools/eraser-tool.cpp b/src/ui/tools/eraser-tool.cpp index 3526e015a..520b93e72 100644 --- a/src/ui/tools/eraser-tool.cpp +++ b/src/ui/tools/eraser-tool.cpp @@ -676,8 +676,7 @@ void EraserTool::set_to_accumulated() { Geom::OptRect eraserBbox = acid->visualBounds(); Geom::Rect bounds = (*eraserBbox) * desktop->doc2dt(); std::vector remainingItems; - SelContainer toWorkOn; - + std::vector toWorkOn; if (selection->isEmpty()) { if ( eraserMode ) { toWorkOn = desktop->getDocument()->getItemsPartiallyInBox(desktop->dkey, bounds); @@ -685,16 +684,15 @@ void EraserTool::set_to_accumulated() { Inkscape::Rubberband *r = Inkscape::Rubberband::get(desktop); toWorkOn = desktop->getDocument()->getItemsAtPoints(desktop->dkey, r->getPoints()); } - - toWorkOn.remove(static_cast(acid) ); + toWorkOn.erase(find(toWorkOn.begin(),toWorkOn.end(),acid)); } else { - toWorkOn = selection->itemList(); + toWorkOn= selection->itemList(); wasSelection = true; } if ( !toWorkOn.empty() ) { if ( eraserMode ) { - for (SelContainer::const_iterator i = toWorkOn.begin();i!=toWorkOn.end();i++) { + for (std::vector::const_iterator i = toWorkOn.begin();i!=toWorkOn.end();i++) { SPItem *item = SP_ITEM(*i); if ( eraserMode ) { @@ -712,8 +710,8 @@ void EraserTool::set_to_accumulated() { if ( !selection->isEmpty() ) { // If the item was not completely erased, track the new remainder. - SelContainer nowSel(selection->itemList()); - for (SelContainer::const_iterator i2 = nowSel.begin();i!=nowSel.end();i++) { + std::vector nowSel(selection->itemList()); + for (std::vector::const_iterator i2 = nowSel.begin();i!=nowSel.end();i2++) { remainingItems.push_back(SP_ITEM(*i2)); } } @@ -723,11 +721,11 @@ void EraserTool::set_to_accumulated() { } } } else { - for (SelContainer::const_iterator i = toWorkOn.begin();i!=toWorkOn.end();i++) { + for (std::vector ::const_iterator i = toWorkOn.begin();i!=toWorkOn.end();i++) { sp_object_ref( SP_ITEM(*i), 0 ); } - for (SelContainer::const_iterator i = toWorkOn.begin();i!=toWorkOn.end();i++) { + for (std::vector::const_iterator i = toWorkOn.begin();i!=toWorkOn.end();i++) { SPItem *item = SP_ITEM(*i); item->deleteObject(true); sp_object_unref(item); diff --git a/src/ui/tools/gradient-tool.cpp b/src/ui/tools/gradient-tool.cpp index d1db5fb93..6f7b220ed 100644 --- a/src/ui/tools/gradient-tool.cpp +++ b/src/ui/tools/gradient-tool.cpp @@ -504,8 +504,8 @@ bool GradientTool::root_handler(GdkEvent* event) { // always resets selection to the single object under cursor sp_gradient_context_add_stop_near_point(this, SP_ITEM(selection->itemList().front()), this->mousepoint_doc, event->button.time); } else { - SelContainer items=selection->itemList(); - for (SelContainer::const_iterator i = items.begin();i!=items.end();i++) { + std::vector items=selection->itemList(); + for (std::vector::const_iterator i = items.begin();i!=items.end();i++) { SPItem *item = SP_ITEM(*i); SPGradientType new_type = (SPGradientType) prefs->getInt("/tools/gradient/newgradient", SP_GRADIENT_TYPE_LINEAR); Inkscape::PaintTarget fsmode = (prefs->getInt("/tools/gradient/newfillorstroke", 1) != 0) ? Inkscape::FOR_FILL : Inkscape::FOR_STROKE; @@ -915,8 +915,8 @@ static void sp_gradient_drag(GradientTool &rc, Geom::Point const pt, guint /*sta } else { // Starting from empty space: // Sort items so that the topmost comes last - SelContainer items(selection->itemList()); - items.sort(sp_item_repr_compare_position_obj); + std::vector items(selection->itemList()); + sort(items.begin(),items.end(),sp_item_repr_compare_position); // take topmost vector = sp_gradient_vector_for_object(document, desktop, SP_ITEM(items.back()), fill_or_stroke); } @@ -925,8 +925,8 @@ static void sp_gradient_drag(GradientTool &rc, Geom::Point const pt, guint /*sta SPCSSAttr *css = sp_repr_css_attr_new(); sp_repr_css_set_property(css, "fill-opacity", "1.0"); - SelContainer itemlist = selection->itemList(); - for (SelContainer::const_iterator i = itemlist.begin();i!=itemlist.end();i++) { + std::vector itemlist = selection->itemList(); + for (std::vector::const_iterator i = itemlist.begin();i!=itemlist.end();i++) { //FIXME: see above sp_repr_css_change_recursive(SP_OBJECT(*i)->getRepr(), css, "style"); diff --git a/src/ui/tools/lpe-tool.cpp b/src/ui/tools/lpe-tool.cpp index ce0ad7a9a..290eeef87 100644 --- a/src/ui/tools/lpe-tool.cpp +++ b/src/ui/tools/lpe-tool.cpp @@ -407,8 +407,8 @@ lpetool_create_measuring_items(LpeTool *lc, Inkscape::Selection *selection) SPCanvasGroup *tmpgrp = lc->desktop->getTempGroup(); gchar *arc_length; double lengthval; - SelContainer items=selection->itemList(); - for(SelContainer::const_iterator i=items.begin();i!=items.end();i++){ + std::vector items=selection->itemList(); + for(std::vector::const_iterator i=items.begin();i!=items.end();i++){ if (SP_IS_PATH(*i)) { path = SP_PATH(*i); curve = path->getCurve(); diff --git a/src/ui/tools/measure-tool.cpp b/src/ui/tools/measure-tool.cpp index 8d52210ff..2b44639c8 100644 --- a/src/ui/tools/measure-tool.cpp +++ b/src/ui/tools/measure-tool.cpp @@ -441,9 +441,9 @@ bool MeasureTool::root_handler(GdkEvent* event) { // TODO switch to a different variable name. The single letter 'l' is easy to misread. //select elements crossed by line segment: - SelContainer items = desktop->getDocument()->getItemsAtPoints(desktop->dkey, points); + std::vector items = desktop->getDocument()->getItemsAtPoints(desktop->dkey, points); std::vector intersection_times; - for (SelContainer::const_iterator i=items.begin();i!=items.end();i++) { + for (std::vector::const_iterator i=items.begin();i!=items.end();i++) { SPItem *item = static_cast(*i); if (SP_IS_SHAPE(item)) { diff --git a/src/ui/tools/mesh-tool.cpp b/src/ui/tools/mesh-tool.cpp index 1cc06a5b9..0a34e4855 100644 --- a/src/ui/tools/mesh-tool.cpp +++ b/src/ui/tools/mesh-tool.cpp @@ -481,8 +481,8 @@ bool MeshTool::root_handler(GdkEvent* event) { sp_mesh_context_split_near_point(this, SP_ITEM(selection->itemList().front()), this->mousepoint_doc, event->button.time); } else { // Create a new gradient with default coordinates. - SelContainer items=selection->itemList(); - for(SelContainer::const_iterator i=items.begin();i!=items.end();i++){ + std::vector items=selection->itemList(); + for(std::vector::const_iterator i=items.begin();i!=items.end();i++){ SPItem *item = SP_ITEM(*i); SPGradientType new_type = SP_GRADIENT_TYPE_MESH; Inkscape::PaintTarget fsmode = (prefs->getInt("/tools/gradient/newfillorstroke", 1) != 0) ? Inkscape::FOR_FILL : Inkscape::FOR_STROKE; @@ -958,8 +958,8 @@ static void sp_mesh_drag(MeshTool &rc, Geom::Point const /*pt*/, guint /*state*/ } else { // Starting from empty space: // Sort items so that the topmost comes last - SelContainer items(selection->itemList()); - items.sort(sp_item_repr_compare_position_obj); + std::vector items(selection->itemList()); + sort(items.begin(),items.end(),sp_item_repr_compare_position); // take topmost vector = sp_gradient_vector_for_object(document, desktop, SP_ITEM(items.back()), fill_or_stroke); } @@ -968,8 +968,8 @@ static void sp_mesh_drag(MeshTool &rc, Geom::Point const /*pt*/, guint /*state*/ SPCSSAttr *css = sp_repr_css_attr_new(); sp_repr_css_set_property(css, "fill-opacity", "1.0"); - SelContainer items=selection->itemList(); - for(SelContainer::const_iterator i=items.begin();i!=items.end();i++){ + std::vector items=selection->itemList(); + for(std::vector::const_iterator i=items.begin();i!=items.end();i++){ //FIXME: see above sp_repr_css_change_recursive(SP_OBJECT(*i)->getRepr(), css, "style"); diff --git a/src/ui/tools/node-tool.cpp b/src/ui/tools/node-tool.cpp index 46c978c84..6ddb379cc 100644 --- a/src/ui/tools/node-tool.cpp +++ b/src/ui/tools/node-tool.cpp @@ -420,8 +420,8 @@ void NodeTool::selection_changed(Inkscape::Selection *sel) { std::set shapes; - SelContainer items=sel->itemList(); - for(SelContainer::const_iterator i=items.begin();i!=items.end();i++){ + std::vector items=sel->itemList(); + for(std::vector::const_iterator i=items.begin();i!=items.end();i++){ SPObject *obj = static_cast(*i); if (SP_IS_ITEM(obj)) { @@ -667,7 +667,7 @@ void NodeTool::select_area(Geom::Rect const &sel, GdkEventButton *event) { if (this->_multipath->empty()) { // if multipath is empty, select rubberbanded items rather than nodes Inkscape::Selection *selection = this->desktop->selection; - SelContainer items = this->desktop->getDocument()->getItemsInBox(this->desktop->dkey, sel); + std::vector items = this->desktop->getDocument()->getItemsInBox(this->desktop->dkey, sel); selection->setList(items); } else { if (!held_shift(*event)) { diff --git a/src/ui/tools/select-tool.cpp b/src/ui/tools/select-tool.cpp index f84170631..25cbf76a4 100644 --- a/src/ui/tools/select-tool.cpp +++ b/src/ui/tools/select-tool.cpp @@ -718,7 +718,7 @@ bool SelectTool::root_handler(GdkEvent* event) { if (r->is_started() && !within_tolerance) { // this was a rubberband drag - SelContainer items; + std::vector items; if (r->getMode() == RUBBERBAND_MODE_RECT) { Geom::OptRect const b = r->getRectangle(); diff --git a/src/ui/tools/spray-tool.cpp b/src/ui/tools/spray-tool.cpp index d339f6d19..ac41f3a34 100644 --- a/src/ui/tools/spray-tool.cpp +++ b/src/ui/tools/spray-tool.cpp @@ -436,9 +436,9 @@ static bool sp_spray_recursive(SPDesktop *desktop, SPItem *unionResult = NULL; // Previous union int i=1; - SelContainer items=selection->itemList(); - for(SelContainer::const_iterator it=items.begin();it!=items.end();it++){ - SPItem *item1 = dynamic_cast(static_cast(*it)); + std::vector items=selection->itemList(); + for(std::vector::const_iterator it=items.begin();it!=items.end();it++){ + SPItem *item1 = *it; if (i == 1) { parent_item = item1; } @@ -550,15 +550,15 @@ static bool sp_spray_dilate(SprayTool *tc, Geom::Point /*event_p*/, Geom::Point double move_standard_deviation = get_move_standard_deviation(tc); { - SelContainer const items(selection->itemList()); + std::vector const items(selection->itemList()); - for(SelContainer::const_iterator i=items.begin();i!=items.end();i++){ + for(std::vector::const_iterator i=items.begin();i!=items.end();i++){ SPItem *item = dynamic_cast(static_cast(*i)); g_assert(item != NULL); sp_object_ref(item); } - for(SelContainer::const_iterator i=items.begin();i!=items.end();i++){ + for(std::vector::const_iterator i=items.begin();i!=items.end();i++){ SPItem *item = dynamic_cast(static_cast(*i)); g_assert(item != NULL); @@ -573,7 +573,7 @@ static bool sp_spray_dilate(SprayTool *tc, Geom::Point /*event_p*/, Geom::Point } } - for(SelContainer::const_iterator i=items.begin();i!=items.end();i++){ + for(std::vector::const_iterator i=items.begin();i!=items.end();i++){ SPItem *item = dynamic_cast(static_cast(*i)); g_assert(item != NULL); sp_object_unref(item); diff --git a/src/ui/tools/text-tool.cpp b/src/ui/tools/text-tool.cpp index a4370256d..48c109688 100644 --- a/src/ui/tools/text-tool.cpp +++ b/src/ui/tools/text-tool.cpp @@ -1470,7 +1470,7 @@ int TextTool::_styleQueried(SPStyle *style, int property) } sp_text_context_validate_cursor_iterators(this); - SelContainer styles_list; + std::vector styles_list; Inkscape::Text::Layout::iterator begin_it, end_it; if (this->text_sel_start < this->text_sel_end) { @@ -1496,7 +1496,7 @@ int TextTool::_styleQueried(SPStyle *style, int property) while (SP_IS_STRING(pos_obj) && pos_obj->parent) { pos_obj = pos_obj->parent; // SPStrings don't have style } - styles_list.push_front(pos_obj); + styles_list.insert(styles_list.begin(),(SPItem*)pos_obj); } int result = sp_desktop_query_style_from_list (styles_list, style, property); diff --git a/src/ui/tools/tool-base.cpp b/src/ui/tools/tool-base.cpp index cc05f9775..def8080d0 100644 --- a/src/ui/tools/tool-base.cpp +++ b/src/ui/tools/tool-base.cpp @@ -1178,8 +1178,8 @@ SPItem *sp_event_context_find_item(SPDesktop *desktop, Geom::Point const &p, SPItem * sp_event_context_over_item(SPDesktop *desktop, SPItem *item, Geom::Point const &p) { - SelContainer temp; - temp.push_front(static_cast(item)); + std::vector temp; + temp.push_back(item); SPItem *item_at_point = desktop->getItemFromListAtPointBottom(temp, p); return item_at_point; } diff --git a/src/ui/tools/tweak-tool.cpp b/src/ui/tools/tweak-tool.cpp index 9342127ce..6f7764506 100644 --- a/src/ui/tools/tweak-tool.cpp +++ b/src/ui/tools/tweak-tool.cpp @@ -382,13 +382,13 @@ sp_tweak_dilate_recursive (Inkscape::Selection *selection, SPItem *item, Geom::P } if (dynamic_cast(item) || dynamic_cast(item)) { - SelContainer items; + std::vector items; items.push_back(item); - SelContainer selected; - SelContainer to_select; + std::vector selected; + std::vector to_select; SPDocument *doc = item->document; sp_item_list_to_curves (items, selected, to_select); - SPObject* newObj = doc->getObjectByRepr(dynamic_cast(to_select.front())); + SPObject* newObj = doc->getObjectByRepr(to_select.back()); item = dynamic_cast(newObj); g_assert(item != NULL); selection->add(item); @@ -1087,8 +1087,8 @@ sp_tweak_dilate (TweakTool *tc, Geom::Point event_p, Geom::Point p, Geom::Point double move_force = get_move_force(tc); double color_force = MIN(sqrt(path_force)/20.0, 1); - SelContainer items=selection->itemList(); - for(SelContainer::const_iterator i=items.begin();i!=items.end();i++){ + std::vector items=selection->itemList(); + for(std::vector::const_iterator i=items.begin();i!=items.end();i++){ SPItem *item = dynamic_cast(static_cast(*i)); if (is_color_mode (tc->mode)) { diff --git a/src/ui/widget/object-composite-settings.cpp b/src/ui/widget/object-composite-settings.cpp index ddf67fb5b..598a90e95 100644 --- a/src/ui/widget/object-composite-settings.cpp +++ b/src/ui/widget/object-composite-settings.cpp @@ -125,8 +125,8 @@ ObjectCompositeSettings::_blendBlurValueChanged() const Glib::ustring blendmode = _fe_cb.get_blend_mode(); //apply created filter to every selected item - SelContainer sel=_subject->getDesktop()->getSelection()->itemList(); - for (SelContainer::const_iterator i = sel.begin() ; i != sel.end() ; ++i ) { + std::vector sel=_subject->getDesktop()->getSelection()->itemList(); + for (std::vector::const_iterator i = sel.begin() ; i != sel.end() ; ++i ) { if (!SP_IS_ITEM(*i)) { continue; } diff --git a/src/ui/widget/style-subject.cpp b/src/ui/widget/style-subject.cpp index 9d09e67d3..1ded546dd 100644 --- a/src/ui/widget/style-subject.cpp +++ b/src/ui/widget/style-subject.cpp @@ -148,10 +148,10 @@ Geom::OptRect StyleSubject::CurrentLayer::getBounds(SPItem::BBoxType type) { } int StyleSubject::CurrentLayer::queryStyle(SPStyle *query, int property) { - SelContainer list; + std::vector list; SPObject* i=_getLayerSList(); if (i) { - list.push_back(i); + list.push_back((SPItem*)i); return sp_desktop_query_style_from_list(list, query, property); } else { return QUERY_STYLE_NOTHING; diff --git a/src/unclump.cpp b/src/unclump.cpp index d1cfc6628..29608befa 100644 --- a/src/unclump.cpp +++ b/src/unclump.cpp @@ -168,11 +168,11 @@ unclump_dist (SPItem *item1, SPItem *item2) /** Average unclump_dist from item to others */ -static double unclump_average (SPItem *item, SelContainer &others) +static double unclump_average (SPItem *item, std::list &others) { int n = 0; double sum = 0; - for (SelContainer::const_iterator i = others.begin(); i != others.end();i++) { + for (std::list::const_iterator i = others.begin(); i != others.end();i++) { SPItem *other = SP_ITEM (*i); if (other == item) @@ -191,12 +191,12 @@ static double unclump_average (SPItem *item, SelContainer &others) /** Closest to item among others */ -static SPItem *unclump_closest (SPItem *item, SelContainer &others) +static SPItem *unclump_closest (SPItem *item, std::list &others) { double min = HUGE_VAL; SPItem *closest = NULL; - for (SelContainer::const_iterator i = others.begin(); i != others.end();i++) { + for (std::list::const_iterator i = others.begin(); i != others.end();i++) { SPItem *other = SP_ITEM (*i); if (other == item) @@ -215,11 +215,11 @@ static SPItem *unclump_closest (SPItem *item, SelContainer &others) /** Most distant from item among others */ -static SPItem *unclump_farest (SPItem *item, SelContainer &others) +static SPItem *unclump_farest (SPItem *item, std::list &others) { double max = -HUGE_VAL; SPItem *farest = NULL; - for (SelContainer::const_iterator i = others.begin(); i != others.end();i++) { + for (std::list::const_iterator i = others.begin(); i != others.end();i++) { SPItem *other = SP_ITEM (*i); if (other == item) @@ -240,8 +240,8 @@ Removes from the \a rest list those items that are "behind" \a closest as seen f i.e. those on the other side of the line through \a closest perpendicular to the direction from \a item to \a closest. Returns a newly created list which must be freed. */ -static SelContainer -unclump_remove_behind (SPItem *item, SPItem *closest, SelContainer &rest) +static std::vector +unclump_remove_behind (SPItem *item, SPItem *closest, std::list &rest) { Geom::Point it = unclump_center (item); Geom::Point p1 = unclump_center (closest); @@ -258,8 +258,8 @@ unclump_remove_behind (SPItem *item, SPItem *closest, SelContainer &rest) // substitute the item into it: double val_item = A * it[Geom::X] + B * it[Geom::Y] + C; - SelContainer out; - for (SelContainer::const_iterator i = rest.begin(); i != rest.end();i++) { + std::vector out; + for (std::list::const_reverse_iterator i = rest.rbegin(); i != rest.rend();i++) { SPItem *other = SP_ITEM (*i); if (other == item) @@ -271,7 +271,7 @@ unclump_remove_behind (SPItem *item, SPItem *closest, SelContainer &rest) if (val_item * val_other <= 1e-6) { // different signs, which means item and other are on the different sides of p1-p2 line; skip } else { - out.push_front(other); + out.push_back(other); } } @@ -331,17 +331,18 @@ similar to "engraver dots". The only distribution which is unchanged by unclumpi grid. May be called repeatedly for stronger effect. */ void -unclump (SelContainer &items) +unclump (std::vector &items) { c_cache.clear(); wh_cache.clear(); - for (SelContainer::const_iterator i = items.begin(); i != items.end();i++) { // for each original/clone x: + for (std::vector::const_iterator i = items.begin(); i != items.end();i++) { // for each original/clone x: SPItem *item = SP_ITEM (*i); - SelContainer nei; + std::list nei; - SelContainer rest(items); + std::list rest; + for(int i=0;i new_rest = unclump_remove_behind (item, closest, rest); + rest.clear(); + for(int i=0;i &items); #endif /* !UNCLUMP_H_SEEN */ diff --git a/src/vanishing-point.cpp b/src/vanishing-point.cpp index 98a3eaa67..770845f38 100644 --- a/src/vanishing-point.cpp +++ b/src/vanishing-point.cpp @@ -256,8 +256,8 @@ VanishingPoint::set_pos(Proj::Pt2 const &pt) { std::list VanishingPoint::selectedBoxes(Inkscape::Selection *sel) { std::list sel_boxes; - SelContainer itemlist=sel->itemList(); - for (SelContainer::const_iterator i=itemlist.begin();i!=itemlist.end();i++) { + std::vector itemlist=sel->itemList(); + for (std::vector::const_iterator i=itemlist.begin();i!=itemlist.end();i++) { SPItem *item = static_cast(*i); SPBox3D *box = dynamic_cast(item); if (box && this->hasBox(box)) { @@ -396,8 +396,8 @@ VPDragger::VPsOfSelectedBoxes() { VanishingPoint *vp; // FIXME: Should we take the selection from the parent VPDrag? I guess it shouldn't make a difference. Inkscape::Selection *sel = SP_ACTIVE_DESKTOP->getSelection(); - SelContainer itemlist=sel->itemList(); - for (SelContainer::const_iterator i=itemlist.begin();i!=itemlist.end();i++) { + std::vector itemlist=sel->itemList(); + for (std::vector::const_iterator i=itemlist.begin();i!=itemlist.end();i++) { SPItem *item = static_cast(*i); SPBox3D *box = dynamic_cast(item); if (box) { @@ -579,8 +579,8 @@ VPDrag::updateDraggers () g_return_if_fail (this->selection != NULL); - SelContainer itemlist=this->selection->itemList(); - for (SelContainer::const_iterator i=itemlist.begin();i!=itemlist.end();i++) { + std::vector itemlist=this->selection->itemList(); + for (std::vector::const_iterator i=itemlist.begin();i!=itemlist.end();i++) { SPItem *item = static_cast(*i); SPBox3D *box = dynamic_cast(item); if (box) { @@ -612,8 +612,8 @@ VPDrag::updateLines () g_return_if_fail (this->selection != NULL); - SelContainer itemlist=this->selection->itemList(); - for (SelContainer::const_iterator i=itemlist.begin();i!=itemlist.end();i++) { + std::vector itemlist=this->selection->itemList(); + for (std::vector::const_iterator i=itemlist.begin();i!=itemlist.end();i++) { SPItem *item = static_cast(*i); SPBox3D *box = dynamic_cast(item); if (box) { @@ -630,7 +630,7 @@ VPDrag::updateBoxHandles () // FIXME: Is there a way to update the knots without accessing the // (previously) statically linked function KnotHolder::update_knots? - SelContainer sel = selection->itemList(); + std::vector sel = selection->itemList(); if (sel.empty()) return; // no selection diff --git a/src/widgets/arc-toolbar.cpp b/src/widgets/arc-toolbar.cpp index 23c248129..cb24bb8aa 100644 --- a/src/widgets/arc-toolbar.cpp +++ b/src/widgets/arc-toolbar.cpp @@ -97,8 +97,8 @@ sp_arctb_startend_value_changed(GtkAdjustment *adj, GObject *tbl, gchar const *v gchar* namespaced_name = g_strconcat("sodipodi:", value_name, NULL); bool modmade = false; - SelContainer itemlist=desktop->getSelection()->itemList(); - for(SelContainer::const_iterator i=itemlist.begin();i!=itemlist.end();i++){ + std::vector itemlist=desktop->getSelection()->itemList(); + for(std::vector::const_iterator i=itemlist.begin();i!=itemlist.end();i++){ SPItem *item = SP_ITEM(*i); if (SP_IS_GENERICELLIPSE(item)) { @@ -163,8 +163,8 @@ static void sp_arctb_open_state_changed( EgeSelectOneAction *act, GObject *tbl ) bool modmade = false; if ( ege_select_one_action_get_active(act) != 0 ) { - SelContainer itemlist=desktop->getSelection()->itemList(); - for(SelContainer::const_iterator i=itemlist.begin();i!=itemlist.end();i++){ + std::vector itemlist=desktop->getSelection()->itemList(); + for(std::vector::const_iterator i=itemlist.begin();i!=itemlist.end();i++){ SPItem *item = SP_ITEM(*i); if (SP_IS_GENERICELLIPSE(item)) { Inkscape::XML::Node *repr = item->getRepr(); @@ -174,8 +174,8 @@ static void sp_arctb_open_state_changed( EgeSelectOneAction *act, GObject *tbl ) } } } else { - SelContainer itemlist=desktop->getSelection()->itemList(); - for(SelContainer::const_iterator i=itemlist.begin();i!=itemlist.end();i++){ + std::vector itemlist=desktop->getSelection()->itemList(); + for(std::vector::const_iterator i=itemlist.begin();i!=itemlist.end();i++){ SPItem *item = SP_ITEM(*i); if (SP_IS_GENERICELLIPSE(item)) { Inkscape::XML::Node *repr = item->getRepr(); @@ -264,8 +264,8 @@ static void sp_arc_toolbox_selection_changed(Inkscape::Selection *selection, GOb purge_repr_listener( tbl, tbl ); - SelContainer itemlist=selection->itemList(); - for(SelContainer::const_iterator i=itemlist.begin();i!=itemlist.end();i++){ + std::vector itemlist=selection->itemList(); + for(std::vector::const_iterator i=itemlist.begin();i!=itemlist.end();i++){ SPItem *item = SP_ITEM(*i); if (SP_IS_GENERICELLIPSE(item)) { n_selected++; diff --git a/src/widgets/connector-toolbar.cpp b/src/widgets/connector-toolbar.cpp index 401ce932a..49cf8e6fd 100644 --- a/src/widgets/connector-toolbar.cpp +++ b/src/widgets/connector-toolbar.cpp @@ -97,8 +97,8 @@ static void sp_connector_orthogonal_toggled( GtkToggleAction* act, GObject *tbl gchar *value = is_orthog ? orthog_str : polyline_str ; bool modmade = false; - SelContainer itemlist=desktop->getSelection()->itemList(); - for(SelContainer::const_iterator i=itemlist.begin();i!=itemlist.end();i++){ + std::vector itemlist=desktop->getSelection()->itemList(); + for(std::vector::const_iterator i=itemlist.begin();i!=itemlist.end();i++){ SPItem *item = SP_ITEM(*i); if (Inkscape::UI::Tools::cc_item_is_connector(item)) { @@ -144,8 +144,8 @@ static void connector_curvature_changed(GtkAdjustment *adj, GObject* tbl) g_ascii_dtostr(value, G_ASCII_DTOSTR_BUF_SIZE, newValue); bool modmade = false; - SelContainer itemlist=desktop->getSelection()->itemList(); - for(SelContainer::const_iterator i=itemlist.begin();i!=itemlist.end();i++){ + std::vector itemlist=desktop->getSelection()->itemList(); + for(std::vector::const_iterator i=itemlist.begin();i!=itemlist.end();i++){ SPItem *item = SP_ITEM(*i); if (Inkscape::UI::Tools::cc_item_is_connector(item)) { diff --git a/src/widgets/fill-style.cpp b/src/widgets/fill-style.cpp index 2c298b04d..dbb84efba 100644 --- a/src/widgets/fill-style.cpp +++ b/src/widgets/fill-style.cpp @@ -481,7 +481,7 @@ void FillNStroke::updateFromPaint() SPDocument *document = desktop->getDocument(); Inkscape::Selection *selection = desktop->getSelection(); - SelContainer const items = selection->itemList(); + std::vector const items = selection->itemList(); switch (psel->mode) { case SPPaintSelector::MODE_EMPTY: @@ -576,7 +576,7 @@ void FillNStroke::updateFromPaint() } } - for(SelContainer::const_iterator i=items.begin();i!=items.end();i++){ + for(std::vector::const_iterator i=items.begin();i!=items.end();i++){ //FIXME: see above if (kind == FILL) { sp_repr_css_change_recursive(reinterpret_cast(*i)->getRepr(), css, "style"); @@ -602,7 +602,7 @@ void FillNStroke::updateFromPaint() // We have changed from another gradient type, or modified spread/units within // this gradient type. vector = sp_gradient_ensure_vector_normalized(vector); - for(SelContainer::const_iterator i=items.begin();i!=items.end();i++){ + for(std::vector::const_iterator i=items.begin();i!=items.end();i++){ //FIXME: see above if (kind == FILL) { sp_repr_css_change_recursive(reinterpret_cast(*i)->getRepr(), css, "style"); @@ -648,7 +648,7 @@ void FillNStroke::updateFromPaint() // cannot just call sp_desktop_set_style, because we don't want to touch those // objects who already have the same root pattern but through a different href // chain. FIXME: move this to a sp_item_set_pattern - for(SelContainer::const_iterator i=items.begin();i!=items.end();i++){ + for(std::vector::const_iterator i=items.begin();i!=items.end();i++){ Inkscape::XML::Node *selrepr = reinterpret_cast(*i)->getRepr(); if ( (kind == STROKE) && !selrepr) { continue; diff --git a/src/widgets/gradient-toolbar.cpp b/src/widgets/gradient-toolbar.cpp index b9608130b..5aa654a80 100644 --- a/src/widgets/gradient-toolbar.cpp +++ b/src/widgets/gradient-toolbar.cpp @@ -116,8 +116,8 @@ void gr_apply_gradient(Inkscape::Selection *selection, GrDrag *drag, SPGradient } // If no drag or no dragger selected, act on selection - SelContainer itemlist=selection->itemList(); - for(SelContainer::const_iterator i=itemlist.begin();i!=itemlist.end();i++){ + std::vector itemlist=selection->itemList(); + for(std::vector::const_iterator i=itemlist.begin();i!=itemlist.end();i++){ gr_apply_gradient_to_item(SP_ITEM(*i), gr, initialType, initialMode, initialMode); } } @@ -218,8 +218,8 @@ void gr_get_dt_selected_gradient(Inkscape::Selection *selection, SPGradient *&gr { SPGradient *gradient = 0; - SelContainer itemlist=selection->itemList(); - for(SelContainer::const_iterator i=itemlist.begin();i!=itemlist.end();i++){ + std::vector itemlist=selection->itemList(); + for(std::vector::const_iterator i=itemlist.begin();i!=itemlist.end();i++){ SPItem *item = SP_ITEM(*i);// get the items gradient, not the getVector() version SPStyle *style = item->style; SPPaintServer *server = 0; @@ -286,8 +286,8 @@ void gr_read_selection( Inkscape::Selection *selection, } // If no selected dragger, read desktop selection - SelContainer itemlist=selection->itemList(); - for(SelContainer::const_iterator i=itemlist.begin();i!=itemlist.end();i++){ + std::vector itemlist=selection->itemList(); + for(std::vector::const_iterator i=itemlist.begin();i!=itemlist.end();i++){ SPItem *item = SP_ITEM(*i); SPStyle *style = item->style; diff --git a/src/widgets/mesh-toolbar.cpp b/src/widgets/mesh-toolbar.cpp index b4176db6f..682c61e77 100644 --- a/src/widgets/mesh-toolbar.cpp +++ b/src/widgets/mesh-toolbar.cpp @@ -87,8 +87,8 @@ void ms_read_selection( Inkscape::Selection *selection, bool first = true; ms_smooth = SP_MESH_SMOOTH_NONE; - SelContainer itemlist=selection->itemList(); - for(SelContainer::const_iterator i=itemlist.begin();i!=itemlist.end();i++){ + std::vector itemlist=selection->itemList(); + for(std::vector::const_iterator i=itemlist.begin();i!=itemlist.end();i++){ SPItem *item = SP_ITEM(*i); SPStyle *style = item->style; @@ -214,8 +214,8 @@ void ms_get_dt_selected_gradient(Inkscape::Selection *selection, SPMeshGradient { SPMeshGradient *gradient = 0; - SelContainer itemlist=selection->itemList(); - for(SelContainer::const_iterator i=itemlist.begin();i!=itemlist.end();i++){ + std::vector itemlist=selection->itemList(); + for(std::vector::const_iterator i=itemlist.begin();i!=itemlist.end();i++){ SPItem *item = SP_ITEM(*i);// get the items gradient, not the getVector() version SPStyle *style = item->style; SPPaintServer *server = 0; diff --git a/src/widgets/rect-toolbar.cpp b/src/widgets/rect-toolbar.cpp index 1f19867ee..65078af01 100644 --- a/src/widgets/rect-toolbar.cpp +++ b/src/widgets/rect-toolbar.cpp @@ -106,8 +106,8 @@ static void sp_rtb_value_changed(GtkAdjustment *adj, GObject *tbl, gchar const * bool modmade = false; Inkscape::Selection *selection = desktop->getSelection(); - SelContainer itemlist=selection->itemList(); - for(SelContainer::const_iterator i=itemlist.begin();i!=itemlist.end();i++){ + std::vector itemlist=selection->itemList(); + for(std::vector::const_iterator i=itemlist.begin();i!=itemlist.end();i++){ if (SP_IS_RECT(*i)) { if (gtk_adjustment_get_value(adj) != 0) { (SP_RECT(*i)->*setter)(Quantity::convert(gtk_adjustment_get_value(adj), unit, desktop->getNamedView()->svg_units)); @@ -244,8 +244,8 @@ static void sp_rect_toolbox_selection_changed(Inkscape::Selection *selection, GO } purge_repr_listener( tbl, tbl ); - SelContainer itemlist=selection->itemList(); - for(SelContainer::const_iterator i=itemlist.begin();i!=itemlist.end();i++){ + std::vector itemlist=selection->itemList(); + for(std::vector::const_iterator i=itemlist.begin();i!=itemlist.end();i++){ if (SP_IS_RECT(reinterpret_cast(*i))) { n_selected++; item = reinterpret_cast(*i); diff --git a/src/widgets/spiral-toolbar.cpp b/src/widgets/spiral-toolbar.cpp index 2f4ad481d..6f967e8ae 100644 --- a/src/widgets/spiral-toolbar.cpp +++ b/src/widgets/spiral-toolbar.cpp @@ -79,8 +79,8 @@ static void sp_spl_tb_value_changed(GtkAdjustment *adj, GObject *tbl, Glib::ustr gchar* namespaced_name = g_strconcat("sodipodi:", value_name.data(), NULL); bool modmade = false; - SelContainer itemlist=desktop->getSelection()->itemList(); - for(SelContainer::const_iterator i=itemlist.begin();i!=itemlist.end();i++){ + std::vector itemlist=desktop->getSelection()->itemList(); + for(std::vector::const_iterator i=itemlist.begin();i!=itemlist.end();i++){ SPItem *item = SP_ITEM(*i); if (SP_IS_SPIRAL(item)) { Inkscape::XML::Node *repr = item->getRepr(); @@ -195,8 +195,8 @@ static void sp_spiral_toolbox_selection_changed(Inkscape::Selection *selection, purge_repr_listener( tbl, tbl ); - SelContainer itemlist=selection->itemList(); - for(SelContainer::const_iterator i=itemlist.begin();i!=itemlist.end();i++){ + std::vector itemlist=selection->itemList(); + for(std::vector::const_iterator i=itemlist.begin();i!=itemlist.end();i++){ SPItem *item = SP_ITEM(*i); if (SP_IS_SPIRAL(item)) { n_selected++; diff --git a/src/widgets/star-toolbar.cpp b/src/widgets/star-toolbar.cpp index 37daf69d0..1946dee6e 100644 --- a/src/widgets/star-toolbar.cpp +++ b/src/widgets/star-toolbar.cpp @@ -83,8 +83,8 @@ static void sp_stb_magnitude_value_changed( GtkAdjustment *adj, GObject *dataKlu bool modmade = false; Inkscape::Selection *selection = desktop->getSelection(); - SelContainer itemlist=selection->itemList(); - for(SelContainer::const_iterator i=itemlist.begin();i!=itemlist.end();i++){ + std::vector itemlist=selection->itemList(); + for(std::vector::const_iterator i=itemlist.begin();i!=itemlist.end();i++){ SPItem *item = SP_ITEM(*i); if (SP_IS_STAR(item)) { Inkscape::XML::Node *repr = item->getRepr(); @@ -128,8 +128,8 @@ static void sp_stb_proportion_value_changed( GtkAdjustment *adj, GObject *dataKl bool modmade = false; Inkscape::Selection *selection = desktop->getSelection(); - SelContainer itemlist=selection->itemList(); - for(SelContainer::const_iterator i=itemlist.begin();i!=itemlist.end();i++){ + std::vector itemlist=selection->itemList(); + for(std::vector::const_iterator i=itemlist.begin();i!=itemlist.end();i++){ SPItem *item = SP_ITEM(*i); if (SP_IS_STAR(item)) { Inkscape::XML::Node *repr = item->getRepr(); @@ -185,8 +185,8 @@ static void sp_stb_sides_flat_state_changed( EgeSelectOneAction *act, GObject *d gtk_action_set_sensitive( prop_action, !flat ); } - SelContainer itemlist=selection->itemList(); - for(SelContainer::const_iterator i=itemlist.begin();i!=itemlist.end();i++){ + std::vector itemlist=selection->itemList(); + for(std::vector::const_iterator i=itemlist.begin();i!=itemlist.end();i++){ SPItem *item = SP_ITEM(*i); if (SP_IS_STAR(item)) { Inkscape::XML::Node *repr = item->getRepr(); @@ -224,8 +224,8 @@ static void sp_stb_rounded_value_changed( GtkAdjustment *adj, GObject *dataKludg bool modmade = false; Inkscape::Selection *selection = desktop->getSelection(); - SelContainer itemlist=selection->itemList(); - for(SelContainer::const_iterator i=itemlist.begin();i!=itemlist.end();i++){ + std::vector itemlist=selection->itemList(); + for(std::vector::const_iterator i=itemlist.begin();i!=itemlist.end();i++){ SPItem *item = SP_ITEM(*i); if (SP_IS_STAR(item)) { Inkscape::XML::Node *repr = item->getRepr(); @@ -264,8 +264,8 @@ static void sp_stb_randomized_value_changed( GtkAdjustment *adj, GObject *dataKl bool modmade = false; Inkscape::Selection *selection = desktop->getSelection(); - SelContainer itemlist=selection->itemList(); - for(SelContainer::const_iterator i=itemlist.begin();i!=itemlist.end();i++){ + std::vector itemlist=selection->itemList(); + for(std::vector::const_iterator i=itemlist.begin();i!=itemlist.end();i++){ SPItem *item = SP_ITEM(*i); if (SP_IS_STAR(item)) { Inkscape::XML::Node *repr = item->getRepr(); @@ -367,8 +367,8 @@ sp_star_toolbox_selection_changed(Inkscape::Selection *selection, GObject *tbl) purge_repr_listener( tbl, tbl ); - SelContainer itemlist=selection->itemList(); - for(SelContainer::const_iterator i=itemlist.begin();i!=itemlist.end();i++){ + std::vector itemlist=selection->itemList(); + for(std::vector::const_iterator i=itemlist.begin();i!=itemlist.end();i++){ SPItem *item = SP_ITEM(*i); if (SP_IS_STAR(item)) { n_selected++; diff --git a/src/widgets/stroke-style.cpp b/src/widgets/stroke-style.cpp index 2599fe537..65390819b 100644 --- a/src/widgets/stroke-style.cpp +++ b/src/widgets/stroke-style.cpp @@ -475,8 +475,8 @@ void StrokeStyle::markerSelectCB(MarkerComboBox *marker_combo, StrokeStyle *spw, //spw->updateMarkerHist(which); Inkscape::Selection *selection = spw->desktop->getSelection(); - SelContainer itemlist=selection->itemList(); - for(SelContainer::const_iterator i=itemlist.begin();i!=itemlist.end();i++){ + std::vector itemlist=selection->itemList(); + for(std::vector::const_iterator i=itemlist.begin();i!=itemlist.end();i++){ SPItem *item = SP_ITEM(*i); if (!SP_IS_SHAPE(item) || SP_IS_RECT(item)) { // can't set marker to rect, until it's converted to using continue; @@ -901,7 +901,7 @@ StrokeStyle::updateLine() if (!sel || sel->isEmpty()) return; - SelContainer const objects = sel->itemList(); + std::vector const objects = sel->itemList(); SPObject * const object = SP_OBJECT(objects.front()); SPStyle * const style = object->style; @@ -957,7 +957,7 @@ StrokeStyle::scaleLine() SPDocument *document = desktop->getDocument(); Inkscape::Selection *selection = desktop->getSelection(); - SelContainer items=selection->itemList(); + std::vector items=selection->itemList(); /* TODO: Create some standardized method */ SPCSSAttr *css = sp_repr_css_attr_new(); @@ -977,7 +977,7 @@ StrokeStyle::scaleLine() int ndash; dashSelector->get_dash(&ndash, &dash, &offset); - for(SelContainer::const_iterator i=items.begin();i!=items.end();i++){ + for(std::vector::const_iterator i=items.begin();i!=items.end();i++){ /* Set stroke width */ double width; if (unit->type == Inkscape::Util::UNIT_TYPE_LINEAR) { @@ -1143,7 +1143,7 @@ StrokeStyle::setCapButtons(Gtk::ToggleButton *active) * that marker. */ void -StrokeStyle::updateAllMarkers(SelContainer const &objects) +StrokeStyle::updateAllMarkers(std::vector const &objects) { struct { MarkerComboBox *key; int loc; } const keyloc[] = { { startMarkerCombo, SP_MARKER_LOC_START }, @@ -1152,7 +1152,7 @@ StrokeStyle::updateAllMarkers(SelContainer const &objects) }; bool all_texts = true; - for(SelContainer::const_iterator i=objects.begin();i!=objects.end();i++){ + for(std::vector::const_iterator i=objects.begin();i!=objects.end();i++){ if (!SP_IS_TEXT (*i)) { all_texts = false; } diff --git a/src/widgets/stroke-style.h b/src/widgets/stroke-style.h index 286305ec3..2605e1acf 100644 --- a/src/widgets/stroke-style.h +++ b/src/widgets/stroke-style.h @@ -153,7 +153,7 @@ private: }; void updateLine(); - void updateAllMarkers(SelContainer const &objects); + void updateAllMarkers(std::vector const &objects); void updateMarkerHist(SPMarkerLoc const which); void setDashSelectorFromStyle(SPDashSelector *dsel, SPStyle *style); void setJoinType (unsigned const jointype); diff --git a/src/widgets/text-toolbar.cpp b/src/widgets/text-toolbar.cpp index ba7dfc1fd..71915377e 100644 --- a/src/widgets/text-toolbar.cpp +++ b/src/widgets/text-toolbar.cpp @@ -366,8 +366,8 @@ static void sp_text_align_mode_changed( EgeSelectOneAction *act, GObject *tbl ) // move the x of all texts to preserve the same bbox Inkscape::Selection *selection = desktop->getSelection(); - SelContainer itemlist=selection->itemList(); - for(SelContainer::const_iterator i=itemlist.begin();i!=itemlist.end();i++){ + std::vector itemlist=selection->itemList(); + for(std::vector::const_iterator i=itemlist.begin();i!=itemlist.end();i++){ if (SP_IS_TEXT(SP_ITEM(*i))) { SPItem *item = SP_ITEM(*i); @@ -519,8 +519,8 @@ static void sp_text_lineheight_value_changed( GtkAdjustment *adj, GObject *tbl ) // Until deprecated sodipodi:linespacing purged: Inkscape::Selection *selection = desktop->getSelection(); bool modmade = false; - SelContainer itemlist=selection->itemList(); - for(SelContainer::const_iterator i=itemlist.begin();i!=itemlist.end();i++){ + std::vector itemlist=selection->itemList(); + for(std::vector::const_iterator i=itemlist.begin();i!=itemlist.end();i++){ if (SP_IS_TEXT (*i)) { SP_OBJECT(*i)->getRepr()->setAttribute("sodipodi:linespacing", sp_repr_css_property (css, "line-height", NULL)); modmade = true; @@ -864,8 +864,8 @@ static void sp_text_toolbox_selection_changed(Inkscape::Selection */*selection*/ // Only flowed text can be justified, only normal text can be kerned... // Find out if we have flowed text now so we can use it several places gboolean isFlow = false; - SelContainer itemlist=SP_ACTIVE_DESKTOP->getSelection()->itemList(); - for(SelContainer::const_iterator i=itemlist.begin();i!=itemlist.end();i++){ + std::vector itemlist=SP_ACTIVE_DESKTOP->getSelection()->itemList(); + for(std::vector::const_iterator i=itemlist.begin();i!=itemlist.end();i++){ // const gchar* id = reinterpret_cast(items->data)->getId(); // std::cout << " " << id << std::endl; if( SP_IS_FLOWTEXT(SP_ITEM(*i))) { @@ -1153,13 +1153,13 @@ static void sp_text_toolbox_select_cb( GtkEntry* entry, GtkEntryIconPosition /*p //std::cout << "text_toolbox_missing_font_cb: selecting: " << family << std::endl; // Get all items with matching font-family set (not inherited!). - SelContainer selectList; + std::vector selectList; SPDesktop *desktop = SP_ACTIVE_DESKTOP; SPDocument *document = desktop->getDocument(); - SelContainer x,y; - SelContainer allList = get_all_items(x, document->getRoot(), desktop, false, false, true, y); - for(SelContainer::const_iterator i=allList.begin();i!=allList.end();i++){ + std::vector x,y; + std::vector allList = get_all_items(x, document->getRoot(), desktop, false, false, true, y); + for(std::vector::const_reverse_iterator i=allList.rbegin();i!=allList.rend();i++){ SPItem *item = SP_ITEM(*i); SPStyle *style = item->style; @@ -1177,7 +1177,7 @@ static void sp_text_toolbox_select_cb( GtkEntry* entry, GtkEntryIconPosition /*p if (family_style.compare( family ) == 0 ) { //std::cout << " found: " << item->getId() << std::endl; - selectList.push_front(static_cast(item)); + selectList.push_back(item); } } } -- cgit v1.2.3 From 7e4b6f793d31d3245bd8afbf6f10aa255ac3e7ae Mon Sep 17 00:00:00 2001 From: Marc Jeanmougin Date: Thu, 19 Feb 2015 20:20:09 +0100 Subject: added a set to the Selection (bzr r13922.1.6) --- src/extension/internal/cairo-renderer.cpp | 5 ++--- src/extension/internal/latex-text-renderer.cpp | 5 ++--- src/selection-chemistry.cpp | 10 ++++----- src/selection.cpp | 23 ++++++++++++++------ src/selection.h | 12 +++++------ src/sp-defs.cpp | 5 ++--- src/sp-filter.cpp | 5 ++--- src/sp-item-group.cpp | 29 +++++++++++--------------- src/sp-object.cpp | 6 +++--- src/sp-object.h | 5 +++-- src/sp-switch.cpp | 14 ++++++------- src/sp-switch.h | 2 +- src/ui/dialog/grid-arrange-tab.cpp | 28 ++++++++++--------------- src/ui/dialog/tags.cpp | 4 ++-- src/ui/tools/eraser-tool.cpp | 2 +- src/xml/repr-util.cpp | 12 +++++------ src/xml/repr.h | 3 ++- 17 files changed, 83 insertions(+), 87 deletions(-) (limited to 'src') diff --git a/src/extension/internal/cairo-renderer.cpp b/src/extension/internal/cairo-renderer.cpp index 7ce5cdf8a..f614ec745 100644 --- a/src/extension/internal/cairo-renderer.cpp +++ b/src/extension/internal/cairo-renderer.cpp @@ -294,9 +294,8 @@ static void sp_group_render(SPGroup *group, CairoRenderContext *ctx) CairoRenderer *renderer = ctx->getRenderer(); TRACE(("sp_group_render opacity: %f\n", SP_SCALE24_TO_FLOAT(item->style->opacity.value))); - SelContainer l(group->childList(false)); - l.reverse(); - for(SelContainer::const_iterator x=l.begin();x!=l.end();x++){ + std::vector l(group->childList(false)); + for(std::vector::const_iterator x=l.begin();x!=l.end();x++){ SPObject *o = reinterpret_cast(*x); SPItem *item = dynamic_cast(o); if (item) { diff --git a/src/extension/internal/latex-text-renderer.cpp b/src/extension/internal/latex-text-renderer.cpp index dab27a0e1..a2de264ab 100644 --- a/src/extension/internal/latex-text-renderer.cpp +++ b/src/extension/internal/latex-text-renderer.cpp @@ -228,9 +228,8 @@ LaTeXTextRenderer::writePostamble() void LaTeXTextRenderer::sp_group_render(SPGroup *group) { - SelContainer l = (group->childList(false)); - l.reverse(); - for(SelContainer::const_iterator x=l.begin();x!=l.end();x++){ + std::vector l = (group->childList(false)); + for(std::vector::const_iterator x=l.begin();x!=l.end();x++){ SPObject *o = reinterpret_cast(*x); SPItem *item = dynamic_cast(o); if (item) { diff --git a/src/selection-chemistry.cpp b/src/selection-chemistry.cpp index f1c96b6b8..736e020dd 100644 --- a/src/selection-chemistry.cpp +++ b/src/selection-chemistry.cpp @@ -558,7 +558,7 @@ void sp_edit_clear_all(Inkscape::Selection *selection) g_return_if_fail(group != NULL); std::vector items = sp_item_group_item_list(group); - for(int i=0;i(items[i])->deleteObject(); } @@ -3061,7 +3061,7 @@ void sp_selection_symbol(SPDesktop *desktop, bool /*apply*/ ) doc->ensureUpToDate(); - SelContainer items(selection->list()); + std::vector items(selection->list()); // Keep track of parent, this is where will be inserted. Inkscape::XML::Node *the_first_repr = reinterpret_cast( items.front() )->getRepr(); @@ -3128,7 +3128,7 @@ void sp_selection_symbol(SPDesktop *desktop, bool /*apply*/ ) } // Move selected items to new - for (SelContainer::const_iterator i=items.begin();i!=items.end();i++){ + for (std::vector::const_iterator i=items.begin();i!=items.end();i++){ Inkscape::XML::Node *repr = SP_OBJECT(*i)->getRepr(); repr->parent()->removeChild(repr); symbol_repr->addChild(repr,NULL); @@ -3195,7 +3195,7 @@ void sp_selection_unsymbol(SPDesktop *desktop) desktop->currentLayer()->getRepr()->appendChild(group); // Move all children of symbol to group - SelContainer children = symbol->childList(false); + std::vector children = symbol->childList(false); // Converting a group to a symbol inserts a group for non-translational transform. // In converting a symbol back to a group we strip out the inserted group (or any other @@ -3212,7 +3212,7 @@ void sp_selection_unsymbol(SPDesktop *desktop) } } - for (SelContainer::const_iterator i=children.begin();i!=children.end();i++){ + for (std::vector::const_iterator i=children.begin();i!=children.end();i++){ Inkscape::XML::Node *repr = SP_OBJECT(*i)->getRepr(); repr->parent()->removeChild(repr); group->addChild(repr,NULL); diff --git a/src/selection.cpp b/src/selection.cpp index 2e8251048..fd3b6abae 100644 --- a/src/selection.cpp +++ b/src/selection.cpp @@ -42,7 +42,9 @@ namespace Inkscape { Selection::Selection(LayerModel *layers, SPDesktop *desktop) : - _objs(SelContainer()), + _objs(std::list()), + _objs_vector(std::vector()), + _objs_set(std::set()), _reprs(std::vector()), _items(std::vector()), _layers(layers), @@ -145,7 +147,7 @@ bool Selection::includes(SPObject *obj) const { g_return_val_if_fail(SP_IS_OBJECT(obj), FALSE); - return ( find(_objs.begin(),_objs.end(),obj)!=_objs.end() ); + return ( _objs_set.find(obj)!=_objs_set.end() ); } void Selection::add(SPObject *obj, bool persist_selection_context/* = false */) { @@ -178,6 +180,7 @@ void Selection::_add(SPObject *obj) { _removeObjectAncestors(obj); _objs.push_front(obj); + _objs_set.insert(obj); add_3D_boxes_recursively(obj); @@ -232,6 +235,7 @@ void Selection::_remove(SPObject *obj) { remove_3D_boxes_recursively(obj); _objs.remove(obj); + _objs_set.erase(obj); } void Selection::setList(std::vector const &list) { @@ -276,8 +280,15 @@ void Selection::clear() { _emitChanged(); } -SelContainer const &Selection::list() { - return _objs; +std::vector const &Selection::list() { + if(!_objs_vector.empty()) + return _objs_vector; + + for ( std::list::const_iterator iter=_objs.begin();iter!=_objs.end();iter++ ) { + _objs_vector.push_back(*iter); + } + return _objs_vector; + } std::vector const &Selection::itemList() { @@ -285,7 +296,7 @@ std::vector const &Selection::itemList() { return _items; } - for ( SelContainer::const_iterator iter=_objs.begin();iter!=_objs.end();iter++ ) { + for ( std::list::const_iterator iter=_objs.begin();iter!=_objs.end();iter++ ) { SPObject *obj=reinterpret_cast(*iter); if (SP_IS_ITEM(obj)) { _items.push_back(SP_ITEM(obj)); @@ -470,7 +481,7 @@ std::vector Selection::getSnapPoints(SnapPreferenc } void Selection::_removeObjectDescendants(SPObject *obj) { - for ( SelContainer::const_iterator iter=_objs.begin();iter!=_objs.end();iter++ ) { + for ( std::list::const_iterator iter=_objs.begin();iter!=_objs.end();iter++ ) { SPObject *sel_obj=reinterpret_cast(*iter); SPObject *parent = sel_obj->parent; while (parent) { diff --git a/src/selection.h b/src/selection.h index 2d5e7c34a..e40810ded 100644 --- a/src/selection.h +++ b/src/selection.h @@ -16,14 +16,10 @@ #include #include #include +#include #include #include -#include -#include -#include -#include - #include "gc-managed.h" #include "gc-finalized.h" #include "gc-anchored.h" @@ -254,7 +250,7 @@ public: XML::Node *singleRepr(); /** Returns the list of selected objects. */ - std::list const &list(); + std::vector const &list(); /** Returns the list of selected SPItems. */ std::vector const &itemList(); /** Returns a list of the xml nodes of all selected objects. */ @@ -376,7 +372,9 @@ private: /** Releases an active layer object that is being removed. */ void _releaseContext(SPObject *obj); - mutable std::list _objs; + mutable std::list _objs; //to more efficiently remove arbitrary elements + mutable std::vector _objs_vector; // to be returned by list(); + mutable std::set _objs_set; //to efficiently test if object is selected mutable std::vector _reprs; mutable std::vector _items; diff --git a/src/sp-defs.cpp b/src/sp-defs.cpp index d52fa038a..76843fd28 100644 --- a/src/sp-defs.cpp +++ b/src/sp-defs.cpp @@ -46,9 +46,8 @@ void SPDefs::update(SPCtx *ctx, guint flags) { } flags &= SP_OBJECT_MODIFIED_CASCADE; - SelContainer l(this->childList(true)); - l.reverse(); - for(SelContainer::const_iterator i=l.begin();i!=l.end();i++){ + std::vector l(this->childList(true)); + for(std::vector::const_iterator i=l.begin();i!=l.end();i++){ SPObject *child = SP_OBJECT(*i); if (flags || (child->uflags & (SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_CHILD_MODIFIED_FLAG))) { child->updateDisplay(ctx, flags); diff --git a/src/sp-filter.cpp b/src/sp-filter.cpp index bf8f7a5a4..93a979287 100644 --- a/src/sp-filter.cpp +++ b/src/sp-filter.cpp @@ -244,9 +244,8 @@ void SPFilter::update(SPCtx *ctx, guint flags) { childflags |= SP_OBJECT_PARENT_MODIFIED_FLAG; } childflags &= SP_OBJECT_MODIFIED_CASCADE; - SelContainer l(this->childList(true, SPObject::ActionUpdate)); - l.reverse(); - for(SelContainer::const_iterator i=l.begin();i!=l.end();i++){ + std::vector l(this->childList(true, SPObject::ActionUpdate)); + for(std::vector::const_iterator i=l.begin();i!=l.end();i++){ SPObject *child = SP_OBJECT (*i); if( SP_IS_FILTER_PRIMITIVE( child ) ) { child->updateDisplay(ctx, childflags); diff --git a/src/sp-item-group.cpp b/src/sp-item-group.cpp index f09a4ee47..8a40df5ed 100644 --- a/src/sp-item-group.cpp +++ b/src/sp-item-group.cpp @@ -171,9 +171,8 @@ void SPGroup::update(SPCtx *ctx, unsigned int flags) { childflags |= SP_OBJECT_PARENT_MODIFIED_FLAG; } childflags &= SP_OBJECT_MODIFIED_CASCADE; - SelContainer l=this->childList(true, SPObject::ActionUpdate); - l.reverse(); - for(SelContainer::const_iterator i=l.begin();i!=l.end();i++){ + std::vector l=this->childList(true, SPObject::ActionUpdate); + for(std::vector ::const_iterator i=l.begin();i!=l.end();i++){ SPObject *child = SP_OBJECT (*i); if (childflags || (child->uflags & (SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_CHILD_MODIFIED_FLAG))) { @@ -216,9 +215,8 @@ void SPGroup::modified(guint flags) { flags &= SP_OBJECT_MODIFIED_CASCADE; - SelContainer l=this->childList(true); - l.reverse(); - for(SelContainer::const_iterator i=l.begin();i!=l.end();i++){ + std::vector l=this->childList(true); + for(std::vector::const_iterator i=l.begin();i!=l.end();i++){ SPObject *child = SP_OBJECT (*i); if (flags || (child->mflags & (SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_CHILD_MODIFIED_FLAG))) { @@ -291,8 +289,8 @@ Geom::OptRect SPGroup::bbox(Geom::Affine const &transform, SPItem::BBoxType bbox Geom::OptRect bbox; // TODO CPPIFY: replace this const_cast later - SelContainer l=const_cast(this)->childList(false, SPObject::ActionBBox); - for(SelContainer::const_iterator i=l.begin();i!=l.end();i++){ + std::vector l=const_cast(this)->childList(false, SPObject::ActionBBox); + for(std::vector::const_iterator i=l.begin();i!=l.end();i++){ SPObject *o = SP_OBJECT (*i); SPItem *item = dynamic_cast(o); if (item && !item->isHidden()) { @@ -305,9 +303,8 @@ Geom::OptRect SPGroup::bbox(Geom::Affine const &transform, SPItem::BBoxType bbox } void SPGroup::print(SPPrintContext *ctx) { - SelContainer l=this->childList(false); - l.reverse(); - for(SelContainer::const_iterator i=l.begin();i!=l.end();i++){ + std::vector l=this->childList(false); + for(std::vector::const_iterator i=l.begin();i!=l.end();i++){ SPObject *o = SP_OBJECT (*i); SPItem *item = dynamic_cast(o); if (item) { @@ -360,9 +357,8 @@ Inkscape::DrawingItem *SPGroup::show (Inkscape::Drawing &drawing, unsigned int k } void SPGroup::hide (unsigned int key) { - SelContainer l=this->childList(false, SPObject::ActionShow); - l.reverse(); - for(SelContainer::const_iterator i=l.begin();i!=l.end();i++){ + std::vector l=this->childList(false, SPObject::ActionShow); + for(std::vector::const_iterator i=l.begin();i!=l.end();i++){ SPObject *o = SP_OBJECT (*i); SPItem *item = dynamic_cast(o); @@ -793,9 +789,8 @@ gint SPGroup::getItemCount() const { void SPGroup::_showChildren (Inkscape::Drawing &drawing, Inkscape::DrawingItem *ai, unsigned int key, unsigned int flags) { Inkscape::DrawingItem *ac = NULL; - SelContainer l=this->childList(false, SPObject::ActionShow); - l.reverse(); - for(SelContainer::const_iterator i=l.begin();i!=l.end();i++){ + std::vector l=this->childList(false, SPObject::ActionShow); + for(std::vector::const_iterator i=l.begin();i!=l.end();i++){ SPObject *o = SP_OBJECT (*i); SPItem * child = dynamic_cast(o); if (child) { diff --git a/src/sp-object.cpp b/src/sp-object.cpp index 3ea480f66..6cc5d7114 100644 --- a/src/sp-object.cpp +++ b/src/sp-object.cpp @@ -382,14 +382,14 @@ void SPObject::changeCSS(SPCSSAttr *css, gchar const *attr) sp_repr_css_change(this->getRepr(), css, attr); } -SelContainer SPObject::childList(bool add_ref, Action) { - SelContainer l; +std::vector SPObject::childList(bool add_ref, Action) { + std::vector l; for ( SPObject *child = firstChild() ; child; child = child->getNext() ) { if (add_ref) { sp_object_ref (child); } - l.push_front(child); + l.push_back(child); } return l; diff --git a/src/sp-object.h b/src/sp-object.h index 858587611..1f3032a52 100644 --- a/src/sp-object.h +++ b/src/sp-object.h @@ -55,6 +55,7 @@ class SPObject; #include #include #include +#include #include "version.h" #include "util/forward-pointer-iterator.h" @@ -335,10 +336,10 @@ public: enum Action { ActionGeneral, ActionBBox, ActionUpdate, ActionShow }; /** - * Retrieves the children as a GSList object, optionally ref'ing the children + * Retrieves the children as a std vector object, optionally ref'ing the children * in the process, if add_ref is specified. */ - SelContainer childList(bool add_ref, Action action = ActionGeneral); + std::vector childList(bool add_ref, Action action = ActionGeneral); /** * Append repr as child of this object. diff --git a/src/sp-switch.cpp b/src/sp-switch.cpp index 0090f1855..2c9427df8 100644 --- a/src/sp-switch.cpp +++ b/src/sp-switch.cpp @@ -55,13 +55,13 @@ SPObject *SPSwitch::_evaluateFirst() { return first; } -SelContainer SPSwitch::_childList(bool add_ref, SPObject::Action action) { +std::vector SPSwitch::_childList(bool add_ref, SPObject::Action action) { if ( action != SPObject::ActionGeneral ) { return this->childList(add_ref, action); } SPObject *child = _evaluateFirst(); - SelContainer x; + std::vector x; if (NULL == child) return x; @@ -69,7 +69,7 @@ SelContainer SPSwitch::_childList(bool add_ref, SPObject::Action action) { //g_object_ref (G_OBJECT (child)); sp_object_ref(child); } - x.push_front(child); + x.push_back(child); return x; } @@ -110,8 +110,8 @@ void SPSwitch::_reevaluate(bool /*add_to_drawing*/) { _releaseLastItem(_cached_item); - SelContainer item_list = _childList(false, SPObject::ActionShow); - for ( SelContainer::const_iterator iter=item_list.begin();iter!=item_list.end();iter++) { + std::vector item_list = _childList(false, SPObject::ActionShow); + for ( std::vector::const_reverse_iterator iter=item_list.rbegin();iter!=item_list.rend();iter++) { SPObject *o = SP_OBJECT (*iter); if ( !SP_IS_ITEM (o) ) { continue; @@ -144,9 +144,9 @@ void SPSwitch::_releaseLastItem(SPObject *obj) void SPSwitch::_showChildren (Inkscape::Drawing &drawing, Inkscape::DrawingItem *ai, unsigned int key, unsigned int flags) { SPObject *evaluated_child = this->_evaluateFirst(); - SelContainer l = this->_childList(false, SPObject::ActionShow); + std::vector l = this->_childList(false, SPObject::ActionShow); - for ( SelContainer::const_iterator iter=l.begin();iter!=l.end();iter++) { + for ( std::vector::const_reverse_iterator iter=l.rbegin();iter!=l.rend();iter++) { SPObject *o = SP_OBJECT (*iter); if (SP_IS_ITEM (o)) { diff --git a/src/sp-switch.h b/src/sp-switch.h index 6a83072e7..7152e1b82 100644 --- a/src/sp-switch.h +++ b/src/sp-switch.h @@ -29,7 +29,7 @@ public: void resetChildEvaluated() { _reevaluate(); } - SelContainer _childList(bool add_ref, SPObject::Action action); + std::vector _childList(bool add_ref, SPObject::Action action); virtual void _showChildren (Inkscape::Drawing &drawing, Inkscape::DrawingItem *ai, unsigned int key, unsigned int flags); SPObject *_evaluateFirst(); diff --git a/src/ui/dialog/grid-arrange-tab.cpp b/src/ui/dialog/grid-arrange-tab.cpp index d62032e9d..10498b0f9 100644 --- a/src/ui/dialog/grid-arrange-tab.cpp +++ b/src/ui/dialog/grid-arrange-tab.cpp @@ -48,7 +48,7 @@ * 0 *elem1 == *elem2 * >0 *elem1 goes after *elem2 */ -static int sp_compare_x_position(SPItem *first, SPItem *second) +static bool sp_compare_x_position(SPItem *first, SPItem *second) { using Geom::X; using Geom::Y; @@ -58,7 +58,7 @@ static int sp_compare_x_position(SPItem *first, SPItem *second) if ( !a || !b ) { // FIXME? - return 0; + return false; } double const a_height = a->dimensions()[Y]; @@ -76,44 +76,38 @@ static int sp_compare_x_position(SPItem *first, SPItem *second) } if (!a_in_b_vert) { - return -1; + return true; } if (a_in_b_vert && a->min()[X] > b->min()[X]) { - return 1; + return false; } if (a_in_b_vert && a->min()[X] < b->min()[X]) { - return -1; + return true; } - return 0; + return false; } /* * Sort items by their y co-ordinates. */ -static int sp_compare_y_position(SPItem *first, SPItem *second) +static bool sp_compare_y_position(SPItem *first, SPItem *second) { Geom::OptRect a = first->documentVisualBounds(); Geom::OptRect b = second->documentVisualBounds(); if ( !a || !b ) { // FIXME? - return 0; + return false; } if (a->min()[Geom::Y] > b->min()[Geom::Y]) { - return 1; + return false; } if (a->min()[Geom::Y] < b->min()[Geom::Y]) { - return -1; + return true; } - return 0; -} -static bool sp_compare_y_position_obj(SPObject *first, SPObject *second){ - return sp_compare_y_position(static_cast(first),static_cast(second))<0; -} -static bool sp_compare_x_position_obj(SPObject *first, SPObject *second){ - return sp_compare_x_position(static_cast(first),static_cast(second))<0; + return false; } diff --git a/src/ui/dialog/tags.cpp b/src/ui/dialog/tags.cpp index c2df5fc1c..bd34c7c66 100644 --- a/src/ui/dialog/tags.cpp +++ b/src/ui/dialog/tags.cpp @@ -371,8 +371,8 @@ void TagsPanel::_objectsSelected( Selection *sel ) { _selectedConnection.block(); _tree.get_selection()->unselect_all(); - SelContainer tmp=sel->list(); - for(SelContainer::const_iterator i=tmp.begin();i!=tmp.end();i++) + std::vector tmp=sel->list(); + for(std::vector::const_iterator i=tmp.begin();i!=tmp.end();i++) { SPObject *obj = reinterpret_cast(*i); _store->foreach(sigc::bind( sigc::mem_fun(*this, &TagsPanel::_checkForSelected), obj)); diff --git a/src/ui/tools/eraser-tool.cpp b/src/ui/tools/eraser-tool.cpp index 520b93e72..b61a108f0 100644 --- a/src/ui/tools/eraser-tool.cpp +++ b/src/ui/tools/eraser-tool.cpp @@ -711,7 +711,7 @@ void EraserTool::set_to_accumulated() { if ( !selection->isEmpty() ) { // If the item was not completely erased, track the new remainder. std::vector nowSel(selection->itemList()); - for (std::vector::const_iterator i2 = nowSel.begin();i!=nowSel.end();i2++) { + for (std::vector::const_iterator i2 = nowSel.begin();i2!=nowSel.end();i2++) { remainingItems.push_back(SP_ITEM(*i2)); } } diff --git a/src/xml/repr-util.cpp b/src/xml/repr-util.cpp index 12280ea5a..447f2ff40 100644 --- a/src/xml/repr-util.cpp +++ b/src/xml/repr-util.cpp @@ -259,7 +259,7 @@ gchar const *sp_xml_ns_prefix_uri(gchar const *prefix) * -1 first object's position is less than the second * @todo Rewrite this function's description to be understandable */ -int sp_repr_compare_position(Inkscape::XML::Node const *first, Inkscape::XML::Node const *second) +bool sp_repr_compare_position(Inkscape::XML::Node const *first, Inkscape::XML::Node const *second) { int p1, p2; if (first->parent() == second->parent()) { @@ -276,9 +276,9 @@ int sp_repr_compare_position(Inkscape::XML::Node const *first, Inkscape::XML::No g_assert(ancestor != NULL); if (ancestor == first) { - return 1; + return false; } else if (ancestor == second) { - return -1; + return true; } else { Inkscape::XML::Node const *to_first = AncetreFils(first, ancestor); Inkscape::XML::Node const *to_second = AncetreFils(second, ancestor); @@ -288,9 +288,9 @@ int sp_repr_compare_position(Inkscape::XML::Node const *first, Inkscape::XML::No } } - if (p1 > p2) return 1; - if (p1 < p2) return -1; - return 0; + if (p1 > p2) return false; + if (p1 < p2) return true; + return false; /* effic: Assuming that the parent--child relationship is consistent (i.e. that the parent really does contain first and second among diff --git a/src/xml/repr.h b/src/xml/repr.h index e1d7fdfd6..c96560a98 100644 --- a/src/xml/repr.h +++ b/src/xml/repr.h @@ -118,7 +118,8 @@ unsigned sp_repr_set_svg_double(Inkscape::XML::Node *repr, char const *key, doub unsigned sp_repr_set_point(Inkscape::XML::Node *repr, char const *key, Geom::Point const & val); unsigned sp_repr_get_point(Inkscape::XML::Node *repr, char const *key, Geom::Point *val); -int sp_repr_compare_position(Inkscape::XML::Node const *first, Inkscape::XML::Node const *second); +//c++-style comparison : returns (bool)(a Date: Mon, 23 Feb 2015 22:41:06 +0100 Subject: Removed eclipse files, added removed pot file (bzr r13922.1.7) --- src/helper/png-write.h | 4 ---- src/selection.h | 2 -- src/sp-object.h | 3 --- 3 files changed, 9 deletions(-) (limited to 'src') diff --git a/src/helper/png-write.h b/src/helper/png-write.h index 04ca85cd6..2657fb635 100644 --- a/src/helper/png-write.h +++ b/src/helper/png-write.h @@ -14,12 +14,8 @@ * Released under GNU GPL, read the file 'COPYING' for more information */ -#include #include <2geom/forward.h> -//should be in selection.h -typedef std::list SelContainer; - class SPDocument; diff --git a/src/selection.h b/src/selection.h index e40810ded..71be6dd6b 100644 --- a/src/selection.h +++ b/src/selection.h @@ -33,8 +33,6 @@ class SPItem; class SPBox3D; class Persp3D; -typedef std::list SelContainer; - namespace Inkscape { class LayerModel; namespace XML { diff --git a/src/sp-object.h b/src/sp-object.h index 1f3032a52..7c189b01b 100644 --- a/src/sp-object.h +++ b/src/sp-object.h @@ -64,9 +64,6 @@ class SPCSSAttr; class SPStyle; typedef struct _GSList GSList; -//should be in selection.h -typedef std::list SelContainer; - namespace Inkscape { -- cgit v1.2.3 From 9a7fa4d1899d30ec745107823f307b2a0bf3172f Mon Sep 17 00:00:00 2001 From: Marc Jeanmougin Date: Fri, 27 Feb 2015 03:10:36 +0100 Subject: corrected the casts (hopefully) (bzr r13922.1.10) --- src/conn-avoid-ref.cpp | 4 +- src/desktop-style.cpp | 38 +++--- src/desktop-style.h | 2 +- src/document.cpp | 2 +- src/document.h | 1 - src/extension/execution-env.cpp | 2 +- src/extension/implementation/implementation.cpp | 2 +- src/extension/implementation/script.cpp | 2 +- src/extension/internal/bitmap/imagemagick.cpp | 4 +- src/extension/internal/bluredge.cpp | 2 +- src/extension/internal/cairo-renderer.cpp | 2 +- src/extension/internal/filter/filter.cpp | 2 +- src/extension/internal/grid.cpp | 2 +- src/extension/internal/latex-text-renderer.cpp | 4 +- src/file.cpp | 2 +- src/filter-chemistry.cpp | 2 +- src/gradient-chemistry.cpp | 10 +- src/gradient-drag.cpp | 12 +- src/graphlayout.cpp | 4 +- src/live_effects/lpe-knot.cpp | 2 +- src/main.cpp | 3 - src/object-snapper.cpp | 4 +- src/path-chemistry.cpp | 49 +++----- src/removeoverlap.cpp | 2 +- src/selcue.cpp | 10 +- src/selection-chemistry.cpp | 148 ++++++++++-------------- src/selection-chemistry.h | 1 - src/selection-describer.cpp | 8 +- src/selection.cpp | 16 +-- src/selection.h | 8 -- src/seltrans.cpp | 9 +- src/snap.cpp | 2 +- src/sp-conn-end.cpp | 2 +- src/sp-defs.cpp | 2 +- src/sp-filter.cpp | 2 +- src/sp-item-group.cpp | 14 +-- src/sp-item-group.h | 1 - src/sp-marker.cpp | 2 +- src/sp-object.h | 4 - src/sp-pattern.cpp | 2 +- src/sp-switch.cpp | 4 +- src/splivarot.cpp | 21 ++-- src/splivarot.h | 3 +- src/text-chemistry.cpp | 10 +- src/text-editing.cpp | 2 +- src/trace/trace.cpp | 2 +- src/ui/clipboard.cpp | 10 +- src/ui/dialog/align-and-distribute.cpp | 26 ++--- src/ui/dialog/export.cpp | 4 +- src/ui/dialog/filter-effects-dialog.cpp | 6 +- src/ui/dialog/find.cpp | 2 +- src/ui/dialog/find.h | 1 - src/ui/dialog/font-substitution.cpp | 2 +- src/ui/dialog/font-substitution.h | 3 +- src/ui/dialog/glyphs.cpp | 2 +- src/ui/dialog/grid-arrange-tab.cpp | 2 +- src/ui/dialog/icon-preview.cpp | 2 +- src/ui/dialog/objects.cpp | 2 +- src/ui/dialog/polar-arrange-tab.cpp | 4 +- src/ui/dialog/tags.cpp | 2 +- src/ui/dialog/text-edit.cpp | 2 +- src/ui/dialog/transformation.cpp | 20 ++-- src/ui/interface.cpp | 2 +- src/ui/tools/connector-tool.cpp | 2 +- src/ui/tools/eraser-tool.cpp | 10 +- src/ui/tools/gradient-tool.cpp | 20 ++-- src/ui/tools/gradient-tool.h | 3 +- src/ui/tools/measure-tool.cpp | 2 +- src/ui/tools/mesh-tool.cpp | 11 +- src/ui/tools/select-tool.cpp | 2 +- src/ui/tools/spray-tool.cpp | 6 +- src/ui/tools/tweak-tool.cpp | 2 +- src/unclump.cpp | 10 +- src/unclump.h | 1 - src/vanishing-point.cpp | 8 +- src/widgets/arc-toolbar.cpp | 8 +- src/widgets/connector-toolbar.cpp | 4 +- src/widgets/fill-style.cpp | 6 +- src/widgets/gradient-toolbar.cpp | 6 +- src/widgets/mesh-toolbar.cpp | 4 +- src/widgets/rect-toolbar.cpp | 4 +- src/widgets/spiral-toolbar.cpp | 4 +- src/widgets/star-toolbar.cpp | 12 +- src/widgets/stroke-style.cpp | 7 +- src/widgets/text-toolbar.cpp | 8 +- 85 files changed, 294 insertions(+), 370 deletions(-) (limited to 'src') diff --git a/src/conn-avoid-ref.cpp b/src/conn-avoid-ref.cpp index fb9fbd935..eb6694233 100644 --- a/src/conn-avoid-ref.cpp +++ b/src/conn-avoid-ref.cpp @@ -253,8 +253,8 @@ static std::vector approxItemWithPoints(SPItem const *item, const G SPGroup* group = SP_GROUP(item); // consider all first-order children std::vector itemlist = sp_item_group_item_list(group); - for (std::vector::const_iterator i=itemlist.begin();i!=itemlist.end();i++) { - SPItem* child_item = SP_ITEM(*i); + for (std::vector::const_iterator i = itemlist.begin(); i != itemlist.end(); i++) { + SPItem* child_item = *i; std::vector child_points = approxItemWithPoints(child_item, item_transform * child_item->transform); poly_points.insert(poly_points.end(), child_points.begin(), child_points.end()); } diff --git a/src/desktop-style.cpp b/src/desktop-style.cpp index e1a81f00a..82f66dcdf 100644 --- a/src/desktop-style.cpp +++ b/src/desktop-style.cpp @@ -195,9 +195,9 @@ sp_desktop_set_style(SPDesktop *desktop, SPCSSAttr *css, bool change, bool write sp_css_attr_unset_uris(css_write); prefs->mergeStyle("/desktop/style", css_write); std::vector const itemlist = desktop->selection->itemList(); - for (std::vector::const_iterator i=itemlist.begin();i!=itemlist.end();i++) { + for (std::vector::const_iterator i = itemlist.begin(); i!= itemlist.end(); i++) { /* last used styles for 3D box faces are stored separately */ - SPObject *obj = reinterpret_cast(*i); // TODO unsafe until Selection is refactored. + SPObject *obj = reinterpret_cast(*i); Box3DSide *side = dynamic_cast(obj); if (side) { const char * descr = box3d_side_axes_string(side); @@ -235,8 +235,8 @@ sp_desktop_set_style(SPDesktop *desktop, SPCSSAttr *css, bool change, bool write css_no_text = sp_css_attr_unset_text(css_no_text); std::vector const itemlist = desktop->selection->itemList(); - for (std::vector::const_iterator i=itemlist.begin();i!=itemlist.end();i++) { - SPItem *item = reinterpret_cast(*i); + for (std::vector::const_iterator i = itemlist.begin(); i!= itemlist.end(); i++) { + SPItem *item = *i; // If not text, don't apply text attributes (can a group have text attributes? Yes! FIXME) if (isTextualItem(item)) { @@ -447,9 +447,9 @@ stroke_average_width (const std::vector &objects) gdouble avgwidth = 0.0; bool notstroked = true; int n_notstroked = 0; - for (std::vector::const_iterator i=objects.begin();i!=objects.end();i++) { + for (std::vector::const_iterator i = objects.begin(); i != objects.end(); i++) { SPObject *obj = reinterpret_cast(*i); - SPItem *item = dynamic_cast(obj); + SPItem *item = *i; if (!item) { continue; } @@ -514,7 +514,7 @@ objects_query_fillstroke (const std::vector &objects, SPStyle *style_re prev[0] = prev[1] = prev[2] = 0.0; bool same_color = true; - for (std::vector::const_iterator i=objects.begin();i!=objects.end();i++) { + for (std::vector::const_iterator i = objects.begin(); i!= objects.end(); i++) { SPObject *obj = reinterpret_cast(*i); if (!obj) { continue; @@ -698,7 +698,7 @@ objects_query_opacity (const std::vector &objects, SPStyle *style_res) guint opacity_items = 0; - for (std::vector::const_iterator i=objects.begin();i!=objects.end();i++) { + for (std::vector::const_iterator i = objects.begin(); i != objects.end(); i++) { SPObject *obj = reinterpret_cast(*i); if (!obj) { continue; @@ -754,7 +754,7 @@ objects_query_strokewidth (const std::vector &objects, SPStyle *style_r int n_stroked = 0; - for (std::vector::const_iterator i=objects.begin();i!=objects.end();i++) { + for (std::vector::const_iterator i = objects.begin(); i != objects.end(); i++) { SPObject *obj = reinterpret_cast(*i); if (!obj) { continue; @@ -828,7 +828,7 @@ objects_query_miterlimit (const std::vector &objects, SPStyle *style_re gdouble prev_ml = -1; bool same_ml = true; - for (std::vector::const_iterator i=objects.begin();i!=objects.end();i++) { + for (std::vector::const_iterator i = objects.begin(); i != objects.end(); i++) { SPObject *obj = reinterpret_cast(*i); if (!dynamic_cast(obj)) { continue; @@ -887,7 +887,7 @@ objects_query_strokecap (const std::vector &objects, SPStyle *style_res bool same_cap = true; int n_stroked = 0; - for (std::vector::const_iterator i=objects.begin();i!=objects.end();i++) { + for (std::vector::const_iterator i = objects.begin(); i != objects.end(); i++) { SPObject *obj = reinterpret_cast(*i); if (!dynamic_cast(obj)) { continue; @@ -941,7 +941,7 @@ objects_query_strokejoin (const std::vector &objects, SPStyle *style_re bool same_join = true; int n_stroked = 0; - for (std::vector::const_iterator i=objects.begin();i!=objects.end();i++) { + for (std::vector::const_iterator i = objects.begin(); i != objects.end(); i++) { SPObject *obj = reinterpret_cast(*i); if (!dynamic_cast(obj)) { continue; @@ -1004,7 +1004,7 @@ objects_query_fontnumbers (const std::vector &objects, SPStyle *style_r int texts = 0; int no_size = 0; - for (std::vector::const_iterator i=objects.begin();i!=objects.end();i++) { + for (std::vector::const_iterator i = objects.begin(); i != objects.end(); i++) { SPObject *obj = reinterpret_cast(*i); if (!isTextualItem(obj)) { @@ -1123,7 +1123,7 @@ objects_query_fontstyle (const std::vector &objects, SPStyle *style_res int texts = 0; - for (std::vector::const_iterator i=objects.begin();i!=objects.end();i++) { + for (std::vector::const_iterator i = objects.begin(); i != objects.end(); i++) { SPObject *obj = reinterpret_cast(*i); if (!isTextualItem(obj)) { @@ -1192,7 +1192,7 @@ objects_query_baselines (const std::vector &objects, SPStyle *style_res int texts = 0; - for (std::vector::const_iterator i=objects.begin();i!=objects.end();i++) { + for (std::vector::const_iterator i = objects.begin(); i != objects.end(); i++) { SPObject *obj = reinterpret_cast(*i); if (!isTextualItem(obj)) { @@ -1280,7 +1280,7 @@ objects_query_fontfamily (const std::vector &objects, SPStyle *style_re } style_res->font_family.set = FALSE; - for (std::vector::const_iterator i=objects.begin();i!=objects.end();i++) { + for (std::vector::const_iterator i = objects.begin(); i != objects.end(); i++) { SPObject *obj = reinterpret_cast(*i); // std::cout << " " << reinterpret_cast(i->data)->getId() << std::endl; @@ -1336,7 +1336,7 @@ objects_query_fontspecification (const std::vector &objects, SPStyle *s } style_res->font_specification.set = FALSE; - for (std::vector::const_iterator i=objects.begin();i!=objects.end();i++) { + for (std::vector::const_iterator i = objects.begin(); i != objects.end(); i++) { SPObject *obj = reinterpret_cast(*i); // std::cout << " " << reinterpret_cast(i->data)->getId() << std::endl; @@ -1394,7 +1394,7 @@ objects_query_blend (const std::vector &objects, SPStyle *style_res) bool same_blend = true; guint items = 0; - for (std::vector::const_iterator i=objects.begin();i!=objects.end();i++) { + for (std::vector::const_iterator i = objects.begin(); i != objects.end(); i++) { SPObject *obj = reinterpret_cast(*i); if (!obj) { continue; @@ -1484,7 +1484,7 @@ objects_query_blur (const std::vector &objects, SPStyle *style_res) guint blur_items = 0; guint items = 0; - for (std::vector::const_iterator i=objects.begin();i!=objects.end();i++) { + for (std::vector::const_iterator i = objects.begin(); i != objects.end(); i++) { SPObject *obj = reinterpret_cast(*i); if (!obj) { continue; diff --git a/src/desktop-style.h b/src/desktop-style.h index 7ca25b9ae..a72f49776 100644 --- a/src/desktop-style.h +++ b/src/desktop-style.h @@ -13,11 +13,11 @@ * Released under GNU GPL, read the file 'COPYING' for more information */ -#include "selection.h" // SelContainer class ColorRGBA; class SPCSSAttr; class SPDesktop; class SPObject; +class SPItem; class SPStyle; typedef struct _GSList GSList; namespace Inkscape { diff --git a/src/document.cpp b/src/document.cpp index 07ad10505..0582f1a70 100644 --- a/src/document.cpp +++ b/src/document.cpp @@ -1289,7 +1289,7 @@ SPItem *SPDocument::getItemFromListAtPointBottom(unsigned int dkey, SPGroup *gro Inkscape::DrawingItem *arenaitem = item->get_arenaitem(dkey); if (arenaitem && arenaitem->pick(p, delta, 1) != NULL && (take_insensitive || item->isVisibleAndUnlocked(dkey))) { - if (find(list.begin(),list.end(),item)==list.end() ) { + if (find(list.begin(),list.end(),item)!=list.end() ) { bottomMost = item; } } diff --git a/src/document.h b/src/document.h index 57ff7643c..bc5b2745a 100644 --- a/src/document.h +++ b/src/document.h @@ -27,7 +27,6 @@ #include #include #include -#include "selection.h" namespace Avoid { class Router; diff --git a/src/extension/execution-env.cpp b/src/extension/execution-env.cpp index 90a7810e6..971f0b64a 100644 --- a/src/extension/execution-env.cpp +++ b/src/extension/execution-env.cpp @@ -65,7 +65,7 @@ ExecutionEnv::ExecutionEnv (Effect * effect, Inkscape::UI::View::View * doc, Imp if (desktop != NULL) { std::vector selected = desktop->getSelection()->itemList(); - for(std::vector::const_iterator x=selected.begin();x!=selected.end();x++){ + for(std::vector::const_iterator x = selected.begin(); x != selected.end(); x++){ Glib::ustring selected_id; selected_id = (*x)->getId(); _selected.insert(_selected.end(), selected_id); diff --git a/src/extension/implementation/implementation.cpp b/src/extension/implementation/implementation.cpp index cea6d139f..11c494b18 100644 --- a/src/extension/implementation/implementation.cpp +++ b/src/extension/implementation/implementation.cpp @@ -51,7 +51,7 @@ Gtk::Widget *Implementation::prefs_effect(Inkscape::Extension::Effect *module, I std::vector selected = ((SPDesktop *)view)->getSelection()->itemList(); Inkscape::XML::Node const* first_select = NULL; if (!selected.empty()) { - const SPItem * item = SP_ITEM(selected.front()); + const SPItem * item = selected.front(); first_select = item->getRepr(); } diff --git a/src/extension/implementation/script.cpp b/src/extension/implementation/script.cpp index 95d5c7edc..5c708cf9a 100644 --- a/src/extension/implementation/script.cpp +++ b/src/extension/implementation/script.cpp @@ -691,7 +691,7 @@ void Script::effect(Inkscape::Extension::Effect *module, std::vector selected = desktop->getSelection()->itemList(); //desktop should not be NULL since doc was checked and desktop is a casted pointer - for(std::vector::const_iterator x=selected.begin();x!=selected.end();x++){ + for(std::vector::const_iterator x = selected.begin(); x != selected.end(); x++){ Glib::ustring selected_id; selected_id += "--id="; selected_id += (*x)->getId(); diff --git a/src/extension/internal/bitmap/imagemagick.cpp b/src/extension/internal/bitmap/imagemagick.cpp index 64abd6c4d..3a29b3dc0 100644 --- a/src/extension/internal/bitmap/imagemagick.cpp +++ b/src/extension/internal/bitmap/imagemagick.cpp @@ -83,8 +83,8 @@ ImageMagickDocCache::ImageMagickDocCache(Inkscape::UI::View::View * view) : _imageItems = new SPItem*[selectCount]; // Loop through selected items - for (std::vector::const_iterator i=selectedItemList.begin();i!=selectedItemList.end();i++) { - SPItem *item = static_cast(*i); + for (std::vector::const_iterator i = selectedItemList.begin(); i != selectedItemList.end(); i++) { + SPItem *item = *i; Inkscape::XML::Node *node = reinterpret_cast(item->getRepr()); if (!strcmp(node->name(), "image") || !strcmp(node->name(), "svg:image")) { diff --git a/src/extension/internal/bluredge.cpp b/src/extension/internal/bluredge.cpp index 257cac161..b80e5ddbb 100644 --- a/src/extension/internal/bluredge.cpp +++ b/src/extension/internal/bluredge.cpp @@ -70,7 +70,7 @@ BlurEdge::effect (Inkscape::Extension::Effect *module, Inkscape::UI::View::View for(std::vector::iterator item = items.begin(); item != items.end(); ++item) { - SPItem * spitem = static_cast(*item); + SPItem * spitem = *item; std::vector new_items(steps); Inkscape::XML::Document *xml_doc = desktop->doc()->getReprDoc(); diff --git a/src/extension/internal/cairo-renderer.cpp b/src/extension/internal/cairo-renderer.cpp index f614ec745..b30c8892e 100644 --- a/src/extension/internal/cairo-renderer.cpp +++ b/src/extension/internal/cairo-renderer.cpp @@ -295,7 +295,7 @@ static void sp_group_render(SPGroup *group, CairoRenderContext *ctx) TRACE(("sp_group_render opacity: %f\n", SP_SCALE24_TO_FLOAT(item->style->opacity.value))); std::vector l(group->childList(false)); - for(std::vector::const_iterator x=l.begin();x!=l.end();x++){ + for(std::vector::const_iterator x = l.begin(); x!= l.end(); x++){ SPObject *o = reinterpret_cast(*x); SPItem *item = dynamic_cast(o); if (item) { diff --git a/src/extension/internal/filter/filter.cpp b/src/extension/internal/filter/filter.cpp index a5eb7de60..65162af22 100644 --- a/src/extension/internal/filter/filter.cpp +++ b/src/extension/internal/filter/filter.cpp @@ -133,7 +133,7 @@ void Filter::effect(Inkscape::Extension::Effect *module, Inkscape::UI::View::Vie for(std::vector::iterator item = items.begin(); item != items.end(); ++item) { - SPItem * spitem = static_cast(*item); + SPItem * spitem = *item; Inkscape::XML::Node * node = spitem->getRepr(); SPCSSAttr * css = sp_repr_css_attr(node, "style"); diff --git a/src/extension/internal/grid.cpp b/src/extension/internal/grid.cpp index 440c6b822..60d606a02 100644 --- a/src/extension/internal/grid.cpp +++ b/src/extension/internal/grid.cpp @@ -195,7 +195,7 @@ Grid::prefs_effect(Inkscape::Extension::Effect *module, Inkscape::UI::View::View std::vector selected = ((SPDesktop *)view)->getSelection()->itemList(); Inkscape::XML::Node * first_select = NULL; if (!selected.empty()) { - first_select = (selected.front())->getRepr(); + first_select = selected[0]->getRepr(); } return module->autogui(current_document, first_select, changeSignal); diff --git a/src/extension/internal/latex-text-renderer.cpp b/src/extension/internal/latex-text-renderer.cpp index a2de264ab..831a8d030 100644 --- a/src/extension/internal/latex-text-renderer.cpp +++ b/src/extension/internal/latex-text-renderer.cpp @@ -229,8 +229,8 @@ LaTeXTextRenderer::writePostamble() void LaTeXTextRenderer::sp_group_render(SPGroup *group) { std::vector l = (group->childList(false)); - for(std::vector::const_iterator x=l.begin();x!=l.end();x++){ - SPObject *o = reinterpret_cast(*x); + for(std::vector::const_iterator x = l.begin(); x != l.end(); x++){ + SPObject *o = *x; SPItem *item = dynamic_cast(o); if (item) { renderItem(item); diff --git a/src/file.cpp b/src/file.cpp index f33e284b2..07e41c550 100644 --- a/src/file.cpp +++ b/src/file.cpp @@ -1088,7 +1088,7 @@ void sp_import_document(SPDesktop *desktop, SPDocument *clipdoc, bool in_place) target_parent->appendChild(obj_copy); Inkscape::GC::release(obj_copy); - pasted_objects.push_back((obj_copy)); + pasted_objects.push_back(obj_copy); } // Change the selection to the freshly pasted objects diff --git a/src/filter-chemistry.cpp b/src/filter-chemistry.cpp index c89cf6220..9298a1ffc 100644 --- a/src/filter-chemistry.cpp +++ b/src/filter-chemistry.cpp @@ -23,9 +23,9 @@ #include "filter-chemistry.h" #include "filter-enums.h" + #include "filters/blend.h" #include "filters/gaussian-blur.h" -#include "selection.h" #include "sp-filter.h" #include "sp-filter-reference.h" #include "svg/css-ostringstream.h" diff --git a/src/gradient-chemistry.cpp b/src/gradient-chemistry.cpp index a72423bbb..b59b38475 100644 --- a/src/gradient-chemistry.cpp +++ b/src/gradient-chemistry.cpp @@ -1571,8 +1571,8 @@ void sp_gradient_invert_selected_gradients(SPDesktop *desktop, Inkscape::PaintTa Inkscape::Selection *selection = desktop->getSelection(); const std::vector list=selection->itemList(); - for (std::vector::const_iterator i=list.begin();i!=list.end();i++) { - sp_item_gradient_invert_vector_color(SP_ITEM(*i), fill_or_stroke); + for (std::vector::const_iterator i = list.begin(); i != list.end(); i++) { + sp_item_gradient_invert_vector_color(*i, fill_or_stroke); } // we did an undoable action @@ -1596,9 +1596,9 @@ void sp_gradient_reverse_selected_gradients(SPDesktop *desktop) drag->selected_reverse_vector(); } else { // If no drag or no dragger selected, act on selection (both fill and stroke gradients) const std::vector list=selection->itemList(); - for (std::vector::const_iterator i=list.begin();i!=list.end();i++) { - sp_item_gradient_reverse_vector(SP_ITEM(*i), Inkscape::FOR_FILL); - sp_item_gradient_reverse_vector(SP_ITEM(*i), Inkscape::FOR_STROKE); + for (std::vector::const_iterator i = list.begin(); i != list.end(); i++) { + sp_item_gradient_reverse_vector(*i, Inkscape::FOR_FILL); + sp_item_gradient_reverse_vector(*i, Inkscape::FOR_STROKE); } } diff --git a/src/gradient-drag.cpp b/src/gradient-drag.cpp index 525fc074f..5a49435d4 100644 --- a/src/gradient-drag.cpp +++ b/src/gradient-drag.cpp @@ -2083,8 +2083,8 @@ void GrDrag::updateDraggers() g_return_if_fail(this->selection != NULL); std::vector list = this->selection->itemList(); - for (std::vector::const_iterator i=list.begin();i!=list.end();i++) { - SPItem *item = SP_ITEM(*i); + for (std::vector::const_iterator i = list.begin(); i != list.end(); i++) { + SPItem *item = *i; SPStyle *style = item->style; if (style && (style->fill.isPaintserver())) { @@ -2152,8 +2152,8 @@ void GrDrag::updateLines() g_return_if_fail(this->selection != NULL); std::vector list = this->selection->itemList(); - for (std::vector::const_iterator i=list.begin();i!=list.end();i++) { - SPItem *item = SP_ITEM(*i); + for (std::vector::const_iterator i = list.begin(); i != list.end(); i++) { + SPItem *item = *i; SPStyle *style = item->style; @@ -2296,8 +2296,8 @@ void GrDrag::updateLevels() g_return_if_fail (this->selection != NULL); std::vector list = this->selection->itemList(); - for (std::vector::const_iterator i=list.begin();i!=list.end();i++) { - SPItem *item = SP_ITEM(*i); + for (std::vector::const_iterator i = list.begin(); i != list.end(); i++) { + SPItem *item = *i; Geom::OptRect rect = item->desktopVisualBounds(); if (rect) { // Remember the edges of the bbox and the center axis diff --git a/src/graphlayout.cpp b/src/graphlayout.cpp index 4d590173a..40994347c 100644 --- a/src/graphlayout.cpp +++ b/src/graphlayout.cpp @@ -89,8 +89,8 @@ struct CheckProgress : TestConvergence { * not connectors in filtered */ void filterConnectors(std::vector const &items, list &filtered) { - for(std::vector::const_iterator i=items.begin();i!=items.end();i++){ - SPItem *item = SP_ITEM(*i); + for(std::vector::const_iterator i = items.begin();i !=items.end(); i++){ + SPItem *item = *i; if(!isConnector(item)) { filtered.push_back(item); } diff --git a/src/live_effects/lpe-knot.cpp b/src/live_effects/lpe-knot.cpp index 6cdf09180..7a1d391a3 100644 --- a/src/live_effects/lpe-knot.cpp +++ b/src/live_effects/lpe-knot.cpp @@ -506,7 +506,7 @@ static void collectPathsAndWidths (SPLPEItem const *lpeitem, std::vector &paths, std::vector &stroke_widths){ if (SP_IS_GROUP(lpeitem)) { std::vector item_list = sp_item_group_item_list(SP_GROUP(lpeitem)); - for ( std::vector::const_iterator iter=item_list.begin();iter!=item_list.end();iter++) { + for ( std::vector::const_iterator iter = item_list.begin(); iter != item_list.end(); iter++) { SPObject *subitem = static_cast(*iter); if (SP_IS_LPE_ITEM(subitem)) { collectPathsAndWidths(SP_LPE_ITEM(subitem), paths, stroke_widths); diff --git a/src/main.cpp b/src/main.cpp index c62b9cd25..062edcb98 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1174,9 +1174,6 @@ static int sp_process_file_list(GSList *fl) sp_item_list_to_curves(items, selected, to_select); - items.clear(); - selected.clear(); - to_select.clear(); } if(sp_export_id) { doc->ensureUpToDate(); diff --git a/src/object-snapper.cpp b/src/object-snapper.cpp index 830c3c1db..f9c189c58 100644 --- a/src/object-snapper.cpp +++ b/src/object-snapper.cpp @@ -238,8 +238,8 @@ void Inkscape::ObjectSnapper::_collectNodes(SnapSourceType const &t, bool old_pref2 = _snapmanager->snapprefs.isTargetSnappable(SNAPTARGET_ROTATION_CENTER); if (old_pref2) { std::vector rotationSource=_snapmanager->getRotationCenterSource(); - for ( std::vector::const_iterator itemlist=rotationSource.begin();itemlist!=rotationSource.end();itemlist++) { - if ((*i).item == reinterpret_cast(*itemlist)) { + for ( std::vector::const_iterator itemlist = rotationSource.begin(); itemlist != rotationSource.end(); itemlist++) { + if ((*i).item == *itemlist) { // don't snap to this item's rotation center _snapmanager->snapprefs.setTargetSnappable(SNAPTARGET_ROTATION_CENTER, false); break; diff --git a/src/path-chemistry.cpp b/src/path-chemistry.cpp index ae1e0064f..53ad96596 100644 --- a/src/path-chemistry.cpp +++ b/src/path-chemistry.cpp @@ -45,16 +45,10 @@ using Inkscape::DocumentUndo; -inline bool less_than_objects(SPObject const *first, SPObject const *second) -{ - return sp_repr_compare_position(first->getRepr(), - second->getRepr())<0; -} - inline bool less_than_items(SPItem const *first, SPItem const *second) { return sp_repr_compare_position(first->getRepr(), - second->getRepr())<0; + second->getRepr())>0; } void @@ -77,21 +71,19 @@ sp_selected_path_combine(SPDesktop *desktop) items = sp_degroup_list (items); // descend into any groups in selection std::vector to_paths; - for (std::vector::const_reverse_iterator i=items.rbegin();i!=items.rend();i++) { - SPItem *item = (SPItem *) (*i); - if (!dynamic_cast(item) && !dynamic_cast(item)) { - to_paths.push_back(item); + for (std::vector::const_reverse_iterator i = items.rbegin(); i != items.rend(); i++) { + if (!dynamic_cast(*i) && !dynamic_cast(*i)) { + to_paths.push_back(*i); } } std::vector converted; bool did = sp_item_list_to_curves(to_paths, items, converted); - to_paths.clear(); - for (std::vector::const_iterator i=converted.begin();i!=converted.end();i++) - items.push_back((SPItem*)doc->getObjectByRepr((Inkscape::XML::Node*)(*i))); + for (std::vector::const_iterator i = converted.begin(); i != converted.end(); i++) + items.push_back((SPItem*)doc->getObjectByRepr(*i)); items = sp_degroup_list (items); // converting to path may have added more groups, descend again - sort(items.begin(),items.end(),less_than_objects); + sort(items.begin(),items.end(),less_than_items); assert(!items.empty()); // cannot be NULL because of list length check at top of function // remember the position, id, transform and style of the topmost path, they will be assigned to the combined one @@ -109,9 +101,9 @@ sp_selected_path_combine(SPDesktop *desktop) selection->clear(); } - for (std::vector::const_reverse_iterator i=items.rbegin();i!=items.rend();i++){ + for (std::vector::const_reverse_iterator i = items.rbegin(); i != items.rend(); i++){ - SPItem *item = (SPItem *) (*i); + SPItem *item = *i; SPPath *path = dynamic_cast(item); if (!path) { continue; @@ -212,9 +204,9 @@ sp_selected_path_break_apart(SPDesktop *desktop) bool did = false; std::vector itemlist(selection->itemList()); - for (std::vector::const_iterator i=itemlist.begin();i!=itemlist.end();i++){ + for (std::vector::const_iterator i = itemlist.begin(); i != itemlist.end(); i++){ - SPItem *item = (SPItem *) (*i); + SPItem *item = *i; SPPath *path = dynamic_cast(item); if (!path) { @@ -277,11 +269,10 @@ sp_selected_path_break_apart(SPDesktop *desktop) if (l == list) repr->setAttribute("id", id); - reprs.push_back(repr); + reprs.insert(reprs.begin(),repr); Inkscape::GC::release(repr); } - //reverse selection->setReprList(reprs); g_slist_free(list); @@ -323,11 +314,8 @@ sp_selected_path_to_curves(Inkscape::Selection *selection, SPDesktop *desktop, b did = sp_item_list_to_curves(items, selected, to_select); - items.clear(); selection->setReprList(to_select); selection->addList(selected); - to_select.clear(); - selected.clear(); if (interactive && desktop) { desktop->clearWaitingCursor(); @@ -367,9 +355,9 @@ sp_item_list_to_curves(const std::vector &items, std::vector& { bool did = false; - for (std::vector::const_iterator i=items.begin();i!=items.end();i++){ + for (std::vector::const_iterator i = items.begin(); i != items.end(); i++){ - SPItem *item = dynamic_cast(static_cast(*i)); + SPItem *item = *i; g_assert(item != NULL); SPDocument *document = item->document; @@ -400,7 +388,7 @@ sp_item_list_to_curves(const std::vector &items, std::vector& Inkscape::XML::Node *repr = box3d_convert_to_group(box)->getRepr(); if (repr) { - to_select.push_back(repr); + to_select.insert(to_select.begin(),repr); did = true; selected.erase(find(selected.begin(),selected.end(),item)); } @@ -418,9 +406,6 @@ sp_item_list_to_curves(const std::vector &items, std::vector& if (sp_item_list_to_curves(item_list, item_selected, item_to_select)) did = true; - item_list.clear(); - item_to_select.clear(); - item_selected.clear(); continue; } @@ -472,7 +457,7 @@ sp_item_list_to_curves(const std::vector &items, std::vector& /* Buglet: We don't re-add the (new version of the) object to the selection of any other * desktops where it was previously selected. */ - to_select.push_back(repr); + to_select.insert(to_select.begin(),repr); Inkscape::GC::release(repr); } @@ -628,7 +613,7 @@ sp_selected_path_reverse(SPDesktop *desktop) bool did = false; desktop->messageStack()->flash(Inkscape::IMMEDIATE_MESSAGE, _("Reversing paths...")); - for (std::vector::const_iterator i=items.begin();i!=items.end();i++){ + for (std::vector::const_iterator i = items.begin(); i != items.end(); i++){ SPPath *path = dynamic_cast(static_cast(*i)); if (!path) { diff --git a/src/removeoverlap.cpp b/src/removeoverlap.cpp index 7cb1694e3..01ce2c47e 100644 --- a/src/removeoverlap.cpp +++ b/src/removeoverlap.cpp @@ -49,7 +49,7 @@ void removeoverlap(std::vector const &items, double const xGap, double it != selected.end(); ++it) { - SPItem* item=static_cast(*it); + SPItem* item = *it; using Geom::X; using Geom::Y; Geom::OptRect item_box((item)->desktopVisualBounds()); if (item_box) { diff --git a/src/selcue.cpp b/src/selcue.cpp index f48378cdc..76eae3fa8 100644 --- a/src/selcue.cpp +++ b/src/selcue.cpp @@ -104,8 +104,8 @@ void Inkscape::SelCue::_updateItemBboxes(gint mode, int prefs_bbox) int bcount = 0; std::vector ll=_selection->itemList(); - for (std::vector::const_iterator l=ll.begin();l!=ll.end();l++) { - SPItem *item = static_cast(*l); + for (std::vector::const_iterator l = ll.begin(); l != ll.end(); l++) { + SPItem *item = *l; SPCanvasItem* box = _item_bboxes[bcount ++]; if (box) { @@ -147,8 +147,8 @@ void Inkscape::SelCue::_newItemBboxes() int prefs_bbox = prefs->getBool("/tools/bounding_box"); std::vector ll=_selection->itemList(); - for (std::vector::const_iterator l=ll.begin();l!=ll.end();l++) { - SPItem *item = static_cast(*l); + for (std::vector::const_iterator l = ll.begin(); l != ll.end(); l++) { + SPItem *item = *l; Geom::OptRect const b = (prefs_bbox == 0) ? item->desktopVisualBounds() : item->desktopGeometricBounds(); @@ -201,7 +201,7 @@ void Inkscape::SelCue::_newTextBaselines() } _text_baselines.clear(); - std::vector ll=_selection->itemList(); + std::vector ll = _selection->itemList(); for (std::vector::const_iterator l=ll.begin();l!=ll.end();l++) { SPItem *item = static_cast(*l); diff --git a/src/selection-chemistry.cpp b/src/selection-chemistry.cpp index 3c91392cf..d6f8b8a37 100644 --- a/src/selection-chemistry.cpp +++ b/src/selection-chemistry.cpp @@ -283,8 +283,8 @@ void SelectionHelper::fixSelection(SPDesktop *dt) std::vector const selList = selection->itemList(); - for( std::vector::const_reverse_iterator i=selList.rbegin();i!=selList.rend();i++ ) { - SPItem *item = dynamic_cast(static_cast(*i)); + for( std::vector::const_reverse_iterator i = selList.rbegin(); i != selList.rend(); i++ ) { + SPItem *item = *i; if( item && !dt->isLayer(item) && (!item->isLocked())) @@ -303,7 +303,7 @@ void SelectionHelper::fixSelection(SPDesktop *dt) * Copies repr and its inherited css style elements, along with the accumulated transform 'full_t', * then prepends the copy to 'clip'. */ -static void sp_selection_copy_one(Inkscape::XML::Node *repr, Geom::Affine full_t, std::vector &clip, Inkscape::XML::Document* xml_doc) +static void sp_selection_copy_one(Inkscape::XML::Node *repr, Geom::Affine full_t, std::vector &clip, Inkscape::XML::Document* xml_doc) { Inkscape::XML::Node *copy = repr->duplicate(xml_doc); @@ -319,31 +319,32 @@ static void sp_selection_copy_one(Inkscape::XML::Node *repr, Geom::Affine full_t copy->setAttribute("transform", affinestr); g_free(affinestr); - clip.insert(clip.begin(),dynamic_cast(copy)); + clip.insert(clip.begin(),copy); } -static void sp_selection_copy_impl(std::vector const &items, std::vector &clip, Inkscape::XML::Document* xml_doc) +static void sp_selection_copy_impl(std::vector const &items, std::vector &clip, Inkscape::XML::Document* xml_doc) { // Sort items: std::vector sorted_items(items); sort(sorted_items.begin(),sorted_items.end(),sp_object_compare_position); // Copy item reprs: - for (std::vector::const_iterator i = sorted_items.begin();i!=sorted_items.end();i++) { - SPItem *item = dynamic_cast(SP_OBJECT(*i)); + for (std::vector::const_iterator i = sorted_items.begin(); i != sorted_items.end(); i++) { + SPItem *item = *i; if (item) { sp_selection_copy_one(item->getRepr(), item->i2doc_affine(), clip, xml_doc); } else { g_assert_not_reached(); } } - std::vector tmp(clip); - for(int i=0;i tmp(clip); + for(int i=0;i sp_selection_paste_impl(SPDocument *doc, SPObject *parent, std::vector &clip) +static std::vector sp_selection_paste_impl(SPDocument *doc, SPObject *parent, std::vector &clip) { Inkscape::XML::Document *xml_doc = doc->getReprDoc(); @@ -352,8 +353,8 @@ static std::vector sp_selection_paste_impl(SPDocument *doc std::vector copied; // add objects to document - for (std::vector::const_iterator l=clip.begin();l!=clip.end();l++) { - Inkscape::XML::Node *repr = dynamic_cast(*l); + for (std::vector::const_iterator l = clip.begin(); l != clip.end(); l++) { + Inkscape::XML::Node *repr = *l; Inkscape::XML::Node *copy = repr->duplicate(xml_doc); // premultiply the item transform by the accumulated parent transform in the paste layer @@ -379,11 +380,11 @@ static std::vector sp_selection_paste_impl(SPDocument *doc static void sp_selection_delete_impl(std::vector const &items, bool propagate = true, bool propagate_descendants = true) { - for (std::vector::const_iterator i=items.begin();i!=items.end();i++) { - sp_object_ref(static_cast(*i), NULL); + for (std::vector::const_iterator i = items.begin(); i != items.end(); i++) { + sp_object_ref(*i, NULL); } - for (std::vector::const_iterator i=items.begin();i!=items.end();i++) { - SPItem *item = static_cast(*i); + for (std::vector::const_iterator i = items.begin(); i != items.end(); i++) { + SPItem *item = *i; item->deleteObject(propagate, propagate_descendants); sp_object_unref(item, NULL); } @@ -413,7 +414,6 @@ void sp_selection_delete(SPDesktop *desktop) std::vector selected(selection->itemList()); selection->clear(); sp_selection_delete_impl(selected); - selected.clear(); desktop->currentLayer()->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); /* a tool may have set up private information in it's selection context @@ -440,10 +440,6 @@ static void add_ids_recursive(std::vector &ids, SPObject *obj) } } } -/* -bool sp_repr_compare_position_obj(SPObject* &a,SPObject* &b){ - return sp_repr_compare_position(dynamic_cast(a),dynamic_cast(b)); -}*/ void sp_selection_duplicate(SPDesktop *desktop, bool suppressDone) { @@ -476,8 +472,8 @@ void sp_selection_duplicate(SPDesktop *desktop, bool suppressDone) bool relink_clones = prefs->getBool("/options/relinkclonesonduplicate/value"); const bool fork_livepatheffects = prefs->getBool("/options/forklpeonduplicate/value", true); - for(std::vector::const_iterator i=reprs.begin();i!=reprs.end();i++){ - Inkscape::XML::Node *old_repr = (*i); + for(std::vector::const_reverse_iterator i=reprs.rbegin();i!=reprs.rend();i++){ + Inkscape::XML::Node *old_repr = *i; Inkscape::XML::Node *parent = old_repr->parent(); Inkscape::XML::Node *copy = old_repr->duplicate(xml_doc); @@ -558,7 +554,7 @@ void sp_edit_clear_all(Inkscape::Selection *selection) g_return_if_fail(group != NULL); std::vector items = sp_item_group_item_list(group); - for(unsigned int i=0;i(items[i])->deleteObject(); } @@ -644,7 +640,6 @@ static void sp_edit_select_all_full(SPDesktop *dt, bool force_all_layers, bool i } } - all_items.clear(); break; } case PREFS_SELECTION_LAYER_RECURSIVE: { @@ -653,17 +648,14 @@ static void sp_edit_select_all_full(SPDesktop *dt, bool force_all_layers, bool i break; } default: { - std::vector x; - items = get_all_items(x, dt->currentRoot(), dt, onlyvisible, onlysensitive, FALSE, exclude); + std::vector x; + items = get_all_items(x, dt->currentRoot(), dt, onlyvisible, onlysensitive, FALSE, exclude); break; } } selection->setList(items); - if (!items.empty()) { - items.clear(); - } } void sp_edit_select_all(SPDesktop *desktop) @@ -694,8 +686,8 @@ static void sp_selection_group_impl(std::vector p, Inkscap gint topmost = (dynamic_cast(p.back()))->position(); Inkscape::XML::Node *topmost_parent = (dynamic_cast(p.back()))->parent(); - for(std::vector::const_iterator i=p.begin();i!=p.end();i++){ - Inkscape::XML::Node *current = (*i); + for(std::vector::const_iterator i = p.begin(); i != p.end(); i++){ + Inkscape::XML::Node *current = *i; if (current->parent() == topmost_parent) { Inkscape::XML::Node *spnew = current->duplicate(xml_doc); @@ -704,7 +696,7 @@ static void sp_selection_group_impl(std::vector p, Inkscap Inkscape::GC::release(spnew); topmost --; // only reduce count for those items deleted from topmost_parent } else { // move it to topmost_parent first - std::vector temp_clip; + std::vector temp_clip; // At this point, current may already have no item, due to its being a clone whose original is already moved away // So we copy it artificially calculating the transform from its repr->attr("transform") and the parent transform @@ -817,7 +809,7 @@ void sp_selection_ungroup(Inkscape::Selection *selection, SPDesktop *desktop) // If any of the clones refer to the groups, unlink them and replace them with successors // in the items list. GSList *clones_to_unlink = NULL; - for (std::vector::const_iterator item = items.begin(); item!=items.end(); item++) { + for (std::vector::const_iterator item = items.begin(); item != items.end(); item++) { SPUse *use = dynamic_cast(static_cast(*item)); SPItem *original = use; @@ -838,13 +830,13 @@ void sp_selection_ungroup(Inkscape::Selection *selection, SPDesktop *desktop) for (GSList *item = clones_to_unlink; item; item = item->next) { SPUse *use = static_cast(item->data); std::vector::iterator items_node = std::find(items.begin(),items.end(), item->data); - (*items_node) = use->unlink(); + *items_node = use->unlink(); } g_slist_free(clones_to_unlink); // do the actual work - for (std::vector::iterator item = items.begin(); item!=items.end(); item++) { - SPItem *obj = static_cast(*item); + for (std::vector::iterator item = items.begin(); item != items.end(); item++) { + SPItem *obj = *item; // ungroup only the groups marked earlier if (g_slist_find(groups, *item) != NULL) { @@ -852,7 +844,7 @@ void sp_selection_ungroup(Inkscape::Selection *selection, SPDesktop *desktop) sp_item_group_ungroup(dynamic_cast(obj), children, false); // add the items resulting from ungrouping to the selection new_select.insert(new_select.end(),children.begin(),children.end()); - (*item) = NULL; // zero out the original pointer, which is no longer valid + *item = NULL; // zero out the original pointer, which is no longer valid } else { // if not a group, keep in the selection new_select.push_back(*item); @@ -860,8 +852,6 @@ void sp_selection_ungroup(Inkscape::Selection *selection, SPDesktop *desktop) } selection->addList(new_select); - new_select.clear(); - items.clear(); DocumentUndo::done(selection->layers()->getDocument(), SP_VERB_SELECTION_UNGROUP, _("Ungroup")); @@ -886,7 +876,6 @@ sp_degroup_list(std::vector &items) members.clear(); } } - items.clear(); if (has_groups) { // recurse if we unwrapped a group - it may have contained others out = sp_degroup_list(out); @@ -903,13 +892,13 @@ sp_item_list_common_parent_group(std::vector const items) if (items.empty()) { return NULL; } - SPObject *parent = SP_OBJECT(items.front())->parent; + SPObject *parent = SP_OBJECT(items[0])->parent; // Strictly speaking this CAN happen, if user selects from Inkscape::XML editor if (!dynamic_cast(parent)) { return NULL; } for (std::vector::const_iterator item=items.begin();item!=items.end();item++) { - if((*item)==items.front())continue; + if((*item)==items[0])continue; if (SP_OBJECT(*item)->parent != parent) { return NULL; } @@ -992,10 +981,7 @@ sp_selection_raise(Inkscape::Selection *selection, SPDesktop *desktop) } } } - } else { - rev.clear(); } - DocumentUndo::done(selection->layers()->getDocument(), SP_VERB_SELECTION_RAISE, //TRANSLATORS: "Raise" means "to raise an object" in the undo history C_("Undo action", "Raise")); @@ -1078,8 +1064,6 @@ void sp_selection_lower(Inkscape::Selection *selection, SPDesktop *desktop) } } } - } else { - rev.clear(); } DocumentUndo::done(selection->layers()->getDocument(), SP_VERB_SELECTION_LOWER, @@ -1261,7 +1245,7 @@ void sp_selection_remove_livepatheffect(SPDesktop *desktop) } std::vector list=selection->itemList(); for ( std::vector::const_iterator itemlist=list.begin();itemlist!=list.end();itemlist++) { - SPItem *item = reinterpret_cast(*itemlist); + SPItem *item = *itemlist; sp_selection_remove_livepatheffect_impl(item); @@ -1318,7 +1302,7 @@ void sp_selection_paste_size_separately(SPDesktop *desktop, bool apply_x, bool a void sp_selection_change_layer_maintain_clones(std::vector const &items,SPObject *where) { for (std::vector::const_iterator i = items.begin(); i != items.end(); i++) { - SPItem *item = dynamic_cast(SP_OBJECT(*i)); + SPItem *item = *i; if (item) { SPItem *oldparent = dynamic_cast(item->parent); SPItem *newparent = dynamic_cast(where); @@ -1346,7 +1330,7 @@ void sp_selection_to_next_layer(SPDesktop *dt, bool suppressDone) SPObject *next=Inkscape::next_layer(dt->currentRoot(), dt->currentLayer()); if (next) { sp_selection_change_layer_maintain_clones(items,next); - std::vector temp_clip; + std::vector temp_clip; sp_selection_copy_impl(items, temp_clip, dt->doc()->getReprDoc()); sp_selection_delete_impl(items, false, false); next=Inkscape::next_layer(dt->currentRoot(), dt->currentLayer()); // Fixes bug 1482973: crash while moving layers @@ -1358,8 +1342,6 @@ void sp_selection_to_next_layer(SPDesktop *dt, bool suppressDone) no_more = true; } selection->setReprList(copied); - copied.clear(); - if (!temp_clip.empty()) temp_clip.clear(); if (next) dt->setCurrentLayer(next); if ( !suppressDone ) { DocumentUndo::done(dt->getDocument(), SP_VERB_LAYER_MOVE_TO_NEXT, @@ -1373,7 +1355,6 @@ void sp_selection_to_next_layer(SPDesktop *dt, bool suppressDone) dt->messageStack()->flash(Inkscape::WARNING_MESSAGE, _("No more layers above.")); } - items.clear(); } void sp_selection_to_prev_layer(SPDesktop *dt, bool suppressDone) @@ -1392,7 +1373,7 @@ void sp_selection_to_prev_layer(SPDesktop *dt, bool suppressDone) SPObject *next=Inkscape::previous_layer(dt->currentRoot(), dt->currentLayer()); if (next) { sp_selection_change_layer_maintain_clones(items,next); - std::vector temp_clip; + std::vector temp_clip; sp_selection_copy_impl(items, temp_clip, dt->doc()->getReprDoc()); // we're in the same doc, so no need to copy defs sp_selection_delete_impl(items, false, false); next=Inkscape::previous_layer(dt->currentRoot(), dt->currentLayer()); // Fixes bug 1482973: crash while moving layers @@ -1404,8 +1385,6 @@ void sp_selection_to_prev_layer(SPDesktop *dt, bool suppressDone) no_more = true; } selection->setReprList( copied); - copied.clear(); - if (!temp_clip.empty()) temp_clip.clear(); if (next) dt->setCurrentLayer(next); if ( !suppressDone ) { DocumentUndo::done(dt->getDocument(), SP_VERB_LAYER_MOVE_TO_PREV, @@ -1434,7 +1413,7 @@ void sp_selection_to_layer(SPDesktop *dt, SPObject *moveto, bool suppressDone) if (moveto) { sp_selection_change_layer_maintain_clones(items,moveto); - std::vector temp_clip; + std::vector temp_clip; sp_selection_copy_impl(items, temp_clip, dt->doc()->getReprDoc()); // we're in the same doc, so no need to copy defs sp_selection_delete_impl(items, false, false); std::vector copied = sp_selection_paste_impl(dt->getDocument(), moveto, temp_clip); @@ -1483,7 +1462,7 @@ selection_contains_both_clone_and_original(Inkscape::Selection *selection) bool clone_with_original = false; std::vector items = selection->itemList(); for (std::vector::const_iterator l=items.begin();l!=items.end() ;l++) { - SPItem *item = dynamic_cast(static_cast(*l)); + SPItem *item = *l; if (item) { clone_with_original |= selection_contains_original(item, selection); if (clone_with_original) @@ -1528,7 +1507,7 @@ void sp_selection_apply_affine(Inkscape::Selection *selection, Geom::Affine cons } std::vector items = selection->itemList(); for (std::vector::const_iterator l=items.begin();l!=items.end() ;l++) { - SPItem *item = dynamic_cast(static_cast(*l)); + SPItem *item = *l; if( dynamic_cast(item) ) { // An SVG element cannot have a transform. We could change 'x' and 'y' in response @@ -1800,7 +1779,7 @@ void sp_selection_rotate_90(SPDesktop *desktop, bool ccw) std::vector items = selection->itemList(); Geom::Rotate const rot_90(Geom::Point(0, ccw ? 1 : -1)); // pos. or neg. rotation, depending on the value of ccw for (std::vector::const_iterator l=items.begin();l!=items.end() ;l++) { - SPItem *item = dynamic_cast(static_cast(*l)); + SPItem *item = *l; if (item) { sp_item_rotate_rel(item, rot_90); } else { @@ -1863,7 +1842,7 @@ void sp_select_same_fill_stroke_style(SPDesktop *desktop, gboolean fill, gboolea Inkscape::Selection *selection = desktop->getSelection(); std::vector items = selection->itemList(); for (std::vector::const_iterator sel_iter=items.begin();sel_iter!=items.end();sel_iter++) { - SPItem *sel = dynamic_cast(static_cast(*sel_iter)); + SPItem *sel = *sel_iter; std::vector matches = all_list; if (fill && stroke && style) { matches = sp_get_same_style(sel, matches); @@ -1911,7 +1890,7 @@ void sp_select_same_object_type(SPDesktop *desktop) std::vector items=selection->itemList(); for (std::vector::const_iterator sel_iter=items.begin();sel_iter!=items.end();sel_iter++) { - SPItem *sel = dynamic_cast(static_cast(*sel_iter)); + SPItem *sel = *sel_iter; if (sel) { matches = sp_get_same_object_type(sel, matches); } else { @@ -1938,7 +1917,7 @@ std::vector sp_get_same_fill_or_stroke_color(SPItem *sel, std::vectorstyle->fill) : &(sel->style->stroke); for (std::vector::const_reverse_iterator i=src.rbegin();i!=src.rend();i++) { - SPItem *iter = dynamic_cast(static_cast(*i)); + SPItem *iter = *i; if (iter) { SPIPaint *iter_paint = (type == SP_FILL_COLOR) ? &(iter->style->fill) : &(iter->style->stroke); match = false; @@ -2033,7 +2012,7 @@ std::vector sp_get_same_object_type(SPItem *sel, std::vector & std::vector matches; for (std::vector::const_reverse_iterator i=src.rbegin();i!=src.rend();i++) { - SPItem *item = dynamic_cast(static_cast(*i)); + SPItem *item = *i; if (item && item_type_match(sel, item) && !item->cloned) { matches.push_back(item); } @@ -2091,7 +2070,6 @@ std::vector sp_get_same_style(SPItem *sel, std::vector &src, S if (sel_style_for_width) { match = (sel_style_for_width->stroke_width.computed == tmp_style.stroke_width.computed); } - objects.clear(); } } match_g = match_g && match; @@ -2579,7 +2557,7 @@ void sp_selection_clone(SPDesktop *desktop) std::vector newsel; - for(std::vector::const_iterator i=reprs.begin();i!=reprs.end();i++){ + for(std::vector::const_reverse_iterator i=reprs.rbegin();i!=reprs.rend();i++){ Inkscape::XML::Node *sel_repr = *i; Inkscape::XML::Node *parent = sel_repr->parent(); @@ -2631,7 +2609,7 @@ sp_selection_relink(SPDesktop *desktop) bool relinked = false; std::vector items=selection->itemList(); for (std::vector::const_iterator i=items.begin();i!=items.end();i++){ - SPItem *item = static_cast(*i); + SPItem *item = *i; if (dynamic_cast(item)) { item->getRepr()->setAttribute("xlink:href", newref); @@ -2669,7 +2647,7 @@ sp_selection_unlink(SPDesktop *desktop) bool unlinked = false; std::vector items=selection->itemList(); for (std::vector::const_reverse_iterator i=items.rbegin();i!=items.rend();i++){ - SPItem *item = static_cast(*i); + SPItem *item = *i; if (dynamic_cast(item)) { SPObject *tspan = sp_tref_convert_to_tspan(item); @@ -2922,7 +2900,7 @@ void sp_selection_to_marker(SPDesktop *desktop, bool apply) //items = g_slist_sort(items, (GCompareFunc) sp_object_compare_position); // Why needed? // bottommost object, after sorting - SPObject *parent = SP_OBJECT(items.front())->parent; + SPObject *parent = SP_OBJECT(items[0])->parent; Geom::Affine parent_transform; { @@ -2976,7 +2954,7 @@ static void sp_selection_to_guides_recursive(SPItem *item, bool wholegroups) { if (group && !dynamic_cast(item) && !wholegroups) { std::vector items=sp_item_group_item_list(group); for (std::vector::const_iterator i=items.begin();i!=items.end();i++){ - sp_selection_to_guides_recursive(static_cast(*i), wholegroups); + sp_selection_to_guides_recursive(*i, wholegroups); } } else { item->convert_to_guides(); @@ -3007,7 +2985,7 @@ void sp_selection_to_guides(SPDesktop *desktop) // Therefore: first convert all, then delete all. for (std::vector::const_iterator i=items.begin();i!=items.end();i++){ - sp_selection_to_guides_recursive(static_cast(*i), wholegroups); + sp_selection_to_guides_recursive(*i, wholegroups); } if (deleteitems) { @@ -3060,7 +3038,7 @@ void sp_selection_symbol(SPDesktop *desktop, bool /*apply*/ ) std::vector items(selection->list()); // Keep track of parent, this is where will be inserted. - Inkscape::XML::Node *the_first_repr = reinterpret_cast( items.front() )->getRepr(); + Inkscape::XML::Node *the_first_repr = items[0]->getRepr(); Inkscape::XML::Node *the_parent_repr = the_first_repr->parent(); // Find out if we have a single group @@ -3068,7 +3046,7 @@ void sp_selection_symbol(SPDesktop *desktop, bool /*apply*/ ) SPGroup *the_group = NULL; Geom::Affine transform; if( items.size() == 1 ) { - SPObject *object = reinterpret_cast( items.front() ); + SPObject *object = items[0]; the_group = dynamic_cast(object); if ( the_group ) { single_group = true; @@ -3125,7 +3103,7 @@ void sp_selection_symbol(SPDesktop *desktop, bool /*apply*/ ) // Move selected items to new for (std::vector::const_iterator i=items.begin();i!=items.end();i++){ - Inkscape::XML::Node *repr = SP_OBJECT(*i)->getRepr(); + Inkscape::XML::Node *repr = (*i)->getRepr(); repr->parent()->removeChild(repr); symbol_repr->addChild(repr,NULL); } @@ -3197,7 +3175,7 @@ void sp_selection_unsymbol(SPDesktop *desktop) // In converting a symbol back to a group we strip out the inserted group (or any other // group that only adds a transform to the symbol content). if( children.size() == 1 ) { - SPObject *object = reinterpret_cast( children.front() ); + SPObject *object = children[0]; if ( dynamic_cast( object ) ) { if( object->getAttribute("style") == NULL || object->getAttribute("class") == NULL ) { @@ -3209,7 +3187,7 @@ void sp_selection_unsymbol(SPDesktop *desktop) } for (std::vector::const_iterator i=children.begin();i!=children.end();i++){ - Inkscape::XML::Node *repr = SP_OBJECT(*i)->getRepr(); + Inkscape::XML::Node *repr = (*i)->getRepr(); repr->parent()->removeChild(repr); group->addChild(repr,NULL); } @@ -3274,7 +3252,7 @@ sp_selection_tile(SPDesktop *desktop, bool apply) sort(items.begin(),items.end(),sp_object_compare_position); // bottommost object, after sorting - SPObject *parent = SP_OBJECT(items.front())->parent; + SPObject *parent = SP_OBJECT(items[0])->parent; Geom::Affine parent_transform; @@ -3288,7 +3266,7 @@ sp_selection_tile(SPDesktop *desktop, bool apply) } // remember the position of the first item - gint pos = SP_OBJECT(items.front())->getRepr()->position(); + gint pos = SP_OBJECT(items[0])->getRepr()->position(); // create a list of duplicates std::vector repr_copies; @@ -3446,7 +3424,7 @@ void sp_selection_get_export_hints(Inkscape::Selection *selection, Glib::ustring for (std::vector::const_iterator i=reprlst.begin();filename_search&&xdpi_search&&ydpi_search&&i!=reprlst.end();i++){ gchar const *dpi_string; - Inkscape::XML::Node * repr = (*i); + Inkscape::XML::Node *repr = *i; if (filename_search) { const gchar* tmp = repr->attribute("inkscape:export-filename"); @@ -3546,7 +3524,7 @@ void sp_selection_create_bitmap_copy(SPDesktop *desktop) // Create the filename. gchar *const basename = g_strdup_printf("%s-%s-%u.png", document->getName(), - SP_OBJECT(items.front())->getRepr()->attribute("id"), + SP_OBJECT(items[0])->getRepr()->attribute("id"), current); // Imagemagick is known not to handle spaces in filenames, so we replace anything but letters, // digits, and a few other chars, with "_" @@ -3755,7 +3733,7 @@ void sp_selection_set_clipgroup(SPDesktop *desktop) Inkscape::GC::release(spnew); topmost --; // only reduce count for those items deleted from topmost_parent } else { // move it to topmost_parent first - std::vector temp_clip; + std::vector temp_clip; // At this point, current may already have no item, due to its being a clone whose original is already moved away // So we copy it artificially calculating the transform from its repr->attr("transform") and the parent transform @@ -3896,7 +3874,7 @@ void sp_selection_set_mask(SPDesktop *desktop, bool apply_clip_path, bool apply_ } } else if (!topmost) { // topmost item is used as a mask, which is applied to other items in a selection - Inkscape::XML::Node *dup = SP_OBJECT(items.front())->getRepr()->duplicate(xml_doc); + Inkscape::XML::Node *dup = SP_OBJECT(items[0])->getRepr()->duplicate(xml_doc); mask_items = g_slist_prepend(mask_items, dup); if (remove_original) { @@ -4060,7 +4038,7 @@ void sp_selection_unset_mask(SPDesktop *desktop, bool apply_clip_path) { for (std::vector::const_iterator i=items.begin();i!=items.end();i++){ if (remove_original) { // remember referenced mask/clippath, so orphaned masks can be moved back to document - SPItem *item = reinterpret_cast(*i); + SPItem *item = *i; Inkscape::URIReference *uri_ref = NULL; if (apply_clip_path) { diff --git a/src/selection-chemistry.h b/src/selection-chemistry.h index ce0b5d3da..8bcab664b 100644 --- a/src/selection-chemistry.h +++ b/src/selection-chemistry.h @@ -19,7 +19,6 @@ #include <2geom/forward.h> #include "sp-item.h" -#include "selection.h" class SPCSSAttr; class SPDesktop; diff --git a/src/selection-describer.cpp b/src/selection-describer.cpp index d86cfa700..441ce6ea6 100644 --- a/src/selection-describer.cpp +++ b/src/selection-describer.cpp @@ -47,7 +47,7 @@ char* collect_terms (const std::vector &items) bool first = true; for ( std::vector::const_iterator iter=items.begin();iter!=items.end();iter++ ) { - SPItem *item = dynamic_cast(reinterpret_cast(*iter)); + SPItem *item = *iter; if (item) { const char *term = item->displayName(); if (term != NULL && g_slist_find (check, term) == NULL) { @@ -66,7 +66,7 @@ static int count_terms (const std::vector &items) GSList *check = NULL; int count=0; for ( std::vector::const_iterator iter=items.begin();iter!=items.end();iter++ ) { - SPItem *item = dynamic_cast(reinterpret_cast(*iter)); + SPItem *item = *iter; if (item) { const char *term = item->displayName(); if (term != NULL && g_slist_find (check, term) == NULL) { @@ -83,7 +83,7 @@ static int count_filtered (const std::vector &items) { int count=0; for ( std::vector::const_iterator iter=items.begin();iter!=items.end();iter++ ) { - SPItem *item = dynamic_cast(reinterpret_cast((*iter))); + SPItem *item = *iter; if (item) { count += item->isFiltered(); } @@ -127,7 +127,7 @@ void SelectionDescriber::_updateMessageFromSelection(Inkscape::Selection *select if (items.empty()) { // no items _context.set(Inkscape::NORMAL_MESSAGE, _when_nothing); } else { - SPItem *item = dynamic_cast(reinterpret_cast(items.front())); + SPItem *item = items[0]; g_assert(item != NULL); SPObject *layer = selection->layers()->layerForObject(item); SPObject *root = selection->layers()->currentRoot(); diff --git a/src/selection.cpp b/src/selection.cpp index fd3b6abae..19e78512b 100644 --- a/src/selection.cpp +++ b/src/selection.cpp @@ -130,7 +130,7 @@ void Selection::_invalidateCachedLists() { void Selection::_clear() { _invalidateCachedLists(); while (!_objs.empty()) { - SPObject *obj=reinterpret_cast(_objs.front()); + SPObject *obj=_objs.front(); _remove(obj); } } @@ -254,7 +254,7 @@ void Selection::addList(std::vector const &list) { _invalidateCachedLists(); for ( std::vector::const_iterator iter=list.begin();iter!=list.end();iter++ ) { - SPObject *obj = reinterpret_cast(*iter); + SPObject *obj = *iter; if (includes(obj)) continue; _add (obj); } @@ -297,7 +297,7 @@ std::vector const &Selection::itemList() { } for ( std::list::const_iterator iter=_objs.begin();iter!=_objs.end();iter++ ) { - SPObject *obj=reinterpret_cast(*iter); + SPObject *obj=*iter; if (SP_IS_ITEM(obj)) { _items.push_back(SP_ITEM(obj)); } @@ -342,7 +342,7 @@ std::list const Selection::box3DList(Persp3D *persp) { SPObject *Selection::single() { if ( _objs.size() == 1 ) { - return reinterpret_cast(_objs.front()); + return _objs.front(); } else { return NULL; } @@ -351,7 +351,7 @@ SPObject *Selection::single() { SPItem *Selection::singleItem() { std::vector const items=itemList(); if ( items.size()==1) { - return reinterpret_cast(items.front()); + return items[0]; } else { return NULL; } @@ -447,7 +447,7 @@ Geom::OptRect Selection::documentBounds(SPItem::BBoxType type) const boost::optional Selection::center() const { std::vector const items = const_cast(this)->itemList(); if (!items.empty()) { - SPItem *first = reinterpret_cast(items.back()); // from the first item in selection + SPItem *first = items.back(); // from the first item in selection if (first->isCenterSet()) { // only if set explicitly return first->getCenter(); } @@ -467,7 +467,7 @@ std::vector Selection::getSnapPoints(SnapPreferenc snapprefs_dummy.setTargetSnappable(Inkscape::SNAPTARGET_ROTATION_CENTER, false); // locally disable snapping to the item center std::vector p; for ( std::vector::const_iterator iter=items.begin();iter!=items.end();iter++ ) { - SPItem *this_item = SP_ITEM(*iter); + SPItem *this_item = *iter; this_item->getSnappoints(p, &snapprefs_dummy); //Include the transformation origin for snapping @@ -482,7 +482,7 @@ std::vector Selection::getSnapPoints(SnapPreferenc void Selection::_removeObjectDescendants(SPObject *obj) { for ( std::list::const_iterator iter=_objs.begin();iter!=_objs.end();iter++ ) { - SPObject *sel_obj=reinterpret_cast(*iter); + SPObject *sel_obj= *iter; SPObject *parent = sel_obj->parent; while (parent) { if ( parent == obj ) { diff --git a/src/selection.h b/src/selection.h index 71be6dd6b..9eada3eed 100644 --- a/src/selection.h +++ b/src/selection.h @@ -40,14 +40,6 @@ class Node; } } -/*template -const GSList* std_list_to_GS_list(const std::list list) const -{ - gpointer l=NULL; - for(auto x:list){ - - } -}*/ namespace Inkscape { diff --git a/src/seltrans.cpp b/src/seltrans.cpp index 0a428edf2..61d8a1ab1 100644 --- a/src/seltrans.cpp +++ b/src/seltrans.cpp @@ -434,8 +434,7 @@ void Inkscape::SelTrans::ungrab() for (int i = 0; i < 4; i++) sp_canvas_item_hide(_l[i]); } - - if (!_stamp_cache.empty()) { + if(!_stamp_cache.empty()){ _stamp_cache.clear(); } @@ -494,7 +493,7 @@ void Inkscape::SelTrans::ungrab() // we were dragging center; update reprs and commit undoable action std::vector items=_desktop->selection->itemList(); for ( std::vector::const_iterator iter=items.begin();iter!=items.end();iter++ ) { - SPItem *it = SP_ITEM(*iter); + SPItem *it = *iter; it->updateRepr(); } DocumentUndo::done(_desktop->getDocument(), SP_VERB_CONTEXT_SELECT, @@ -535,7 +534,7 @@ void Inkscape::SelTrans::stamp() } for(std::vector::const_iterator x=l.begin();x!=l.end();x++) { - SPItem *original_item = SP_ITEM(*x); + SPItem *original_item = *x; Inkscape::XML::Node *original_repr = original_item->getRepr(); // remember the position of the item @@ -713,7 +712,7 @@ void Inkscape::SelTrans::handleClick(SPKnot */*knot*/, guint state, SPSelTransHa // Unset the center position for all selected items std::vector items=_desktop->selection->itemList(); for ( std::vector::const_iterator iter=items.begin();iter!=items.end();iter++ ) { - SPItem *it = SP_ITEM(*iter); + SPItem *it = *iter; it->unsetCenter(); it->updateRepr(); _center_is_set = false; // center has changed diff --git a/src/snap.cpp b/src/snap.cpp index c711874d7..31cafafcd 100644 --- a/src/snap.cpp +++ b/src/snap.cpp @@ -1055,7 +1055,7 @@ void SnapManager::setupIgnoreSelection(SPDesktop const *desktop, Inkscape::Selection *sel = _desktop->selection; std::vector const items = sel->itemList(); for (std::vector::const_iterator i=items.begin();i!=items.end();i++) { - _items_to_ignore.push_back(static_cast(*i)); + _items_to_ignore.push_back(*i); } } diff --git a/src/sp-conn-end.cpp b/src/sp-conn-end.cpp index d09699f41..1e478d1c9 100644 --- a/src/sp-conn-end.cpp +++ b/src/sp-conn-end.cpp @@ -52,7 +52,7 @@ static bool try_get_intersect_point_with_item_recursive(Geom::PathVector& conn_p double child_pos = 0.0; std::vector g = sp_item_group_item_list(group); for (std::vector::const_iterator i = g.begin();i!=g.end();i++) { - SPItem* child_item = SP_ITEM(*i); + SPItem* child_item = *i; try_get_intersect_point_with_item_recursive(conn_pv, child_item, item_transform * child_item->transform, child_pos); if (intersect_pos < child_pos) diff --git a/src/sp-defs.cpp b/src/sp-defs.cpp index 76843fd28..74d29a05c 100644 --- a/src/sp-defs.cpp +++ b/src/sp-defs.cpp @@ -48,7 +48,7 @@ void SPDefs::update(SPCtx *ctx, guint flags) { flags &= SP_OBJECT_MODIFIED_CASCADE; std::vector l(this->childList(true)); for(std::vector::const_iterator i=l.begin();i!=l.end();i++){ - SPObject *child = SP_OBJECT(*i); + SPObject *child = *i; if (flags || (child->uflags & (SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_CHILD_MODIFIED_FLAG))) { child->updateDisplay(ctx, flags); } diff --git a/src/sp-filter.cpp b/src/sp-filter.cpp index 93a979287..5386a4373 100644 --- a/src/sp-filter.cpp +++ b/src/sp-filter.cpp @@ -246,7 +246,7 @@ void SPFilter::update(SPCtx *ctx, guint flags) { childflags &= SP_OBJECT_MODIFIED_CASCADE; std::vector l(this->childList(true, SPObject::ActionUpdate)); for(std::vector::const_iterator i=l.begin();i!=l.end();i++){ - SPObject *child = SP_OBJECT (*i); + SPObject *child = *i; if( SP_IS_FILTER_PRIMITIVE( child ) ) { child->updateDisplay(ctx, childflags); } diff --git a/src/sp-item-group.cpp b/src/sp-item-group.cpp index d58676235..620c0b70f 100644 --- a/src/sp-item-group.cpp +++ b/src/sp-item-group.cpp @@ -173,7 +173,7 @@ void SPGroup::update(SPCtx *ctx, unsigned int flags) { childflags &= SP_OBJECT_MODIFIED_CASCADE; std::vector l=this->childList(true, SPObject::ActionUpdate); for(std::vector ::const_iterator i=l.begin();i!=l.end();i++){ - SPObject *child = SP_OBJECT (*i); + SPObject *child = *i; if (childflags || (child->uflags & (SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_CHILD_MODIFIED_FLAG))) { SPItem *item = dynamic_cast(child); @@ -217,7 +217,7 @@ void SPGroup::modified(guint flags) { std::vector l=this->childList(true); for(std::vector::const_iterator i=l.begin();i!=l.end();i++){ - SPObject *child = SP_OBJECT (*i); + SPObject *child = *i; if (flags || (child->mflags & (SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_CHILD_MODIFIED_FLAG))) { child->emitModified(flags); @@ -289,9 +289,9 @@ Geom::OptRect SPGroup::bbox(Geom::Affine const &transform, SPItem::BBoxType bbox Geom::OptRect bbox; // TODO CPPIFY: replace this const_cast later - std::vector l=const_cast(this)->childList(false, SPObject::ActionBBox); + std::vector l = const_cast(this)->childList(false, SPObject::ActionBBox); for(std::vector::const_iterator i=l.begin();i!=l.end();i++){ - SPObject *o = SP_OBJECT (*i); + SPObject *o = *i; SPItem *item = dynamic_cast(o); if (item && !item->isHidden()) { Geom::Affine const ct(item->transform * transform); @@ -305,7 +305,7 @@ Geom::OptRect SPGroup::bbox(Geom::Affine const &transform, SPItem::BBoxType bbox void SPGroup::print(SPPrintContext *ctx) { std::vector l=this->childList(false); for(std::vector::const_iterator i=l.begin();i!=l.end();i++){ - SPObject *o = SP_OBJECT (*i); + SPObject *o = *i; SPItem *item = dynamic_cast(o); if (item) { item->invoke_print(ctx); @@ -359,7 +359,7 @@ Inkscape::DrawingItem *SPGroup::show (Inkscape::Drawing &drawing, unsigned int k void SPGroup::hide (unsigned int key) { std::vector l=this->childList(false, SPObject::ActionShow); for(std::vector::const_iterator i=l.begin();i!=l.end();i++){ - SPObject *o = SP_OBJECT (*i); + SPObject *o = *i; SPItem *item = dynamic_cast(o); if (item) { @@ -799,7 +799,7 @@ void SPGroup::_showChildren (Inkscape::Drawing &drawing, Inkscape::DrawingItem * Inkscape::DrawingItem *ac = NULL; std::vector l=this->childList(false, SPObject::ActionShow); for(std::vector::const_iterator i=l.begin();i!=l.end();i++){ - SPObject *o = SP_OBJECT (*i); + SPObject *o = *i; SPItem * child = dynamic_cast(o); if (child) { ac = child->invoke_show (drawing, key, flags); diff --git a/src/sp-item-group.h b/src/sp-item-group.h index 2258c2133..fc0b6382f 100644 --- a/src/sp-item-group.h +++ b/src/sp-item-group.h @@ -15,7 +15,6 @@ #include #include "sp-lpe-item.h" -#include "selection.h"//SelContainer #define SP_GROUP(obj) (dynamic_cast((SPObject*)obj)) #define SP_IS_GROUP(obj) (dynamic_cast((SPObject*)obj) != NULL) diff --git a/src/sp-marker.cpp b/src/sp-marker.cpp index 5bb80bd39..9618c5484 100644 --- a/src/sp-marker.cpp +++ b/src/sp-marker.cpp @@ -453,7 +453,7 @@ const gchar *generate_marker(std::vector &reprs, Geom::Rec SPObject *mark_object = document->getObjectById(mark_id); for (std::vector::const_iterator i=reprs.begin();i!=reprs.end();i++){ - Inkscape::XML::Node *node = (*i); + Inkscape::XML::Node *node = *i; SPItem *copy = SP_ITEM(mark_object->appendChildRepr(node)); Geom::Affine dup_transform; diff --git a/src/sp-object.h b/src/sp-object.h index 8651258bd..df773fea7 100644 --- a/src/sp-object.h +++ b/src/sp-object.h @@ -47,8 +47,6 @@ class SPObject; #define SP_OBJECT_WRITE_ALL (1 << 2) #define SP_OBJECT_WRITE_NO_CHILDREN (1 << 3) - - #include #include #include @@ -64,8 +62,6 @@ class SPCSSAttr; class SPStyle; typedef struct _GSList GSList; - - namespace Inkscape { namespace XML { class Node; diff --git a/src/sp-pattern.cpp b/src/sp-pattern.cpp index 33d66c5dc..b3aeec7bd 100644 --- a/src/sp-pattern.cpp +++ b/src/sp-pattern.cpp @@ -427,7 +427,7 @@ const gchar *pattern_tile(const std::vector &reprs, Geom:: SPObject *pat_object = document->getObjectById(pat_id); for (std::vector::const_iterator i=reprs.begin();i!=reprs.end();i++){ - Inkscape::XML::Node *node = (Inkscape::XML::Node *)(*i); + Inkscape::XML::Node *node = *i; SPItem *copy = SP_ITEM(pat_object->appendChildRepr(node)); Geom::Affine dup_transform; diff --git a/src/sp-switch.cpp b/src/sp-switch.cpp index 2c9427df8..f252438a4 100644 --- a/src/sp-switch.cpp +++ b/src/sp-switch.cpp @@ -112,7 +112,7 @@ void SPSwitch::_reevaluate(bool /*add_to_drawing*/) { std::vector item_list = _childList(false, SPObject::ActionShow); for ( std::vector::const_reverse_iterator iter=item_list.rbegin();iter!=item_list.rend();iter++) { - SPObject *o = SP_OBJECT (*iter); + SPObject *o = *iter; if ( !SP_IS_ITEM (o) ) { continue; } @@ -147,7 +147,7 @@ void SPSwitch::_showChildren (Inkscape::Drawing &drawing, Inkscape::DrawingItem std::vector l = this->_childList(false, SPObject::ActionShow); for ( std::vector::const_reverse_iterator iter=l.rbegin();iter!=l.rend();iter++) { - SPObject *o = SP_OBJECT (*iter); + SPObject *o = *iter; if (SP_IS_ITEM (o)) { SPItem * child = SP_ITEM(o); diff --git a/src/splivarot.cpp b/src/splivarot.cpp index 6e47dfff3..bc09802f0 100644 --- a/src/splivarot.cpp +++ b/src/splivarot.cpp @@ -60,11 +60,6 @@ using Inkscape::DocumentUndo; bool Ancetre(Inkscape::XML::Node *a, Inkscape::XML::Node *who); -//SHOULD DISAPPEAR -bool sp_repr_compare_position_obj(SPObject* &a,SPObject* &b){ - return sp_repr_compare_position(dynamic_cast(a),dynamic_cast(b)); -} - void sp_selected_path_boolop(Inkscape::Selection *selection, SPDesktop *desktop, bool_op bop, const unsigned int verb=SP_VERB_NONE, const Glib::ustring description=""); void sp_selected_path_do_offset(SPDesktop *desktop, bool expand, double prefOffset); void sp_selected_path_create_offset_object(SPDesktop *desktop, int expand, bool updating); @@ -405,7 +400,7 @@ sp_selected_path_boolop(Inkscape::Selection *selection, SPDesktop *desktop, bool // otherwise bail out for (std::vector::const_iterator l = il.begin(); l != il.end(); l++) { - SPItem *item = SP_ITEM(*l); + SPItem *item = *l; if (!SP_IS_SHAPE(item) && !SP_IS_TEXT(item) && !SP_IS_FLOWTEXT(item)) { boolop_display_error_message(desktop, _("One of the objects is not a path, cannot perform boolean operation.")); @@ -428,7 +423,7 @@ sp_selected_path_boolop(Inkscape::Selection *selection, SPDesktop *desktop, bool SP_LPE_ITEM(*l)->removeAllPathEffects(true); } - SPCSSAttr *css = sp_repr_css_attr(reinterpret_cast(il.front())->getRepr(), "style"); + SPCSSAttr *css = sp_repr_css_attr(reinterpret_cast(il[0])->getRepr(), "style"); gchar const *val = sp_repr_css_property(css, "fill-rule", NULL); if (val && strcmp(val, "nonzero") == 0) { origWind[curOrig]= fill_nonZero; @@ -438,7 +433,7 @@ sp_selected_path_boolop(Inkscape::Selection *selection, SPDesktop *desktop, bool origWind[curOrig]= fill_nonZero; } - originaux[curOrig] = Path_for_item((SPItem *) (*l), true, true); + originaux[curOrig] = Path_for_item(*l, true, true); if (originaux[curOrig] == NULL || originaux[curOrig]->descr_cmd.size() <= 1) { for (int i = curOrig; i >= 0; i--) delete originaux[i]; @@ -475,7 +470,7 @@ sp_selected_path_boolop(Inkscape::Selection *selection, SPDesktop *desktop, bool curOrig = 1; for (std::vector::const_iterator l = il.begin(); l != il.end(); l++){ - if(*l==il.front())continue; + if(*l==il[0])continue; originaux[curOrig]->ConvertWithBackData(0.1); originaux[curOrig]->Fill(theShape, curOrig); @@ -685,7 +680,7 @@ sp_selected_path_boolop(Inkscape::Selection *selection, SPDesktop *desktop, bool SPObject *source; if ( bop == bool_op_diff || bop == bool_op_cut || bop == bool_op_slice ) { if (reverseOrderForOp) { - source = SP_OBJECT(il.front()); + source = SP_OBJECT(il[0]); } else { source = SP_OBJECT(il.back()); } @@ -1159,7 +1154,7 @@ sp_selected_path_outline(SPDesktop *desktop) bool did = false; std::vector il(selection->itemList()); for (std::vector::const_iterator l = il.begin(); l != il.end(); l++){ - SPItem *item = SP_ITEM(*l); + SPItem *item = *l; if (!SP_IS_SHAPE(item) && !SP_IS_TEXT(item)) continue; @@ -1771,7 +1766,7 @@ sp_selected_path_do_offset(SPDesktop *desktop, bool expand, double prefOffset) bool did = false; std::vector il(selection->itemList()); for (std::vector::const_iterator l = il.begin(); l != il.end(); l++){ - SPItem *item = SP_ITEM(*l); + SPItem *item = *l; SPCurve *curve = NULL; if (!SP_IS_SHAPE(item) && !SP_IS_TEXT(item)) @@ -2143,7 +2138,7 @@ sp_selected_path_simplify_items(SPDesktop *desktop, desktop->setWaitingCursor(); for (std::vector::const_iterator l = items.begin(); l != items.end(); l++){ - SPItem *item = SP_ITEM(*l); + SPItem *item = *l; if (!(SP_IS_GROUP(item) || SP_IS_SHAPE(item) || SP_IS_TEXT(item))) continue; diff --git a/src/splivarot.h b/src/splivarot.h index 79b9b98a6..ba314399f 100644 --- a/src/splivarot.h +++ b/src/splivarot.h @@ -10,7 +10,6 @@ #include <2geom/forward.h> #include <2geom/path.h> #include "livarot/Path.h" -#include "sp-object.h"//kill it class SPCurve; class SPDesktop; @@ -19,7 +18,7 @@ class SPItem; namespace Inkscape { class Selection; } -bool sp_repr_compare_position_obj(SPObject* &a,SPObject* &b);//kill it with fire + // boolean operations // work on the current selection // selection has 2 contain exactly 2 items diff --git a/src/text-chemistry.cpp b/src/text-chemistry.cpp index 33192a330..eadab90dd 100644 --- a/src/text-chemistry.cpp +++ b/src/text-chemistry.cpp @@ -46,7 +46,7 @@ flowtext_in_selection(Inkscape::Selection *selection) std::vector items = selection->itemList(); for(std::vector::const_iterator i=items.begin();i!=items.end();i++){ if (SP_IS_FLOWTEXT(*i)) - return ((SPItem *) *i); + return *i; } return NULL; } @@ -57,7 +57,7 @@ text_or_flowtext_in_selection(Inkscape::Selection *selection) std::vector items = selection->itemList(); for(std::vector::const_iterator i=items.begin();i!=items.end();i++){ if (SP_IS_TEXT(*i) || SP_IS_FLOWTEXT(*i)) - return ((SPItem *) *i); + return *i; } return NULL; } @@ -68,7 +68,7 @@ shape_in_selection(Inkscape::Selection *selection) std::vector items = selection->itemList(); for(std::vector::const_iterator i=items.begin();i!=items.end();i++){ if (SP_IS_SHAPE(*i)) - return ((SPItem *) *i); + return *i; } return NULL; } @@ -402,7 +402,7 @@ text_unflow () continue; } - SPItem *flowtext = SP_ITEM(*i); + SPItem *flowtext = *i; // we discard transform when unflowing, but we must preserve expansion which is visible as // font size multiplier @@ -482,7 +482,7 @@ flowtext_to_text() std::vector items(selection->itemList()); for(std::vector::const_iterator i=items.begin();i!=items.end();i++){ - SPItem *item = (SPItem *) *i; + SPItem *item = *i; if (!SP_IS_FLOWTEXT(item)) continue; diff --git a/src/text-editing.cpp b/src/text-editing.cpp index 88210dc0b..050e223eb 100644 --- a/src/text-editing.cpp +++ b/src/text-editing.cpp @@ -69,7 +69,7 @@ void te_update_layout_now_recursive(SPItem *item) if (SP_IS_GROUP(item)) { std::vector item_list = sp_item_group_item_list(SP_GROUP(item)); for(std::vector::const_iterator i=item_list.begin();i!=item_list.end();i++){ - SPItem* list_item = static_cast(*i); + SPItem* list_item = *i; te_update_layout_now_recursive(list_item); } } else if (SP_IS_TEXT(item)) diff --git a/src/trace/trace.cpp b/src/trace/trace.cpp index 4853f127c..91c230920 100644 --- a/src/trace/trace.cpp +++ b/src/trace/trace.cpp @@ -80,7 +80,7 @@ SPImage *Tracer::getSelectedSPImage() { continue; } - SPItem *item = SP_ITEM(*i); + SPItem *item = *i; items.insert(items.begin(), item); } std::vector::iterator iter; diff --git a/src/ui/clipboard.cpp b/src/ui/clipboard.cpp index 52bc24f5f..a38a52371 100644 --- a/src/ui/clipboard.cpp +++ b/src/ui/clipboard.cpp @@ -525,7 +525,7 @@ bool ClipboardManagerImpl::pasteSize(SPDesktop *desktop, bool separately, bool a if (separately) { std::vector itemlist=selection->itemList(); for(std::vector::const_iterator i=itemlist.begin();i!=itemlist.end();i++){ - SPItem *item = SP_ITEM(*i); + SPItem *item = *i; if (item) { Geom::OptRect obj_size = item->desktopVisualBounds(); if ( obj_size ) { @@ -581,7 +581,7 @@ bool ClipboardManagerImpl::pastePathEffect(SPDesktop *desktop) sp_selected_to_lpeitems(desktop); std::vector itemlist=selection->itemList(); for(std::vector::const_iterator i=itemlist.begin();i!=itemlist.end();i++){ - SPItem *item = SP_ITEM(*i); + SPItem *item = *i; _applyPathEffect(item, effectstack); } @@ -664,7 +664,7 @@ void ClipboardManagerImpl::_copySelection(Inkscape::Selection *selection) // copy the defs used by all items std::vector itemlist=selection->itemList(); for(std::vector::const_iterator i=itemlist.begin();i!=itemlist.end();i++){ - SPItem *item = SP_ITEM(*i); + SPItem *item = *i; if (item) { _copyUsedDefs(item); } else { @@ -677,7 +677,7 @@ void ClipboardManagerImpl::_copySelection(Inkscape::Selection *selection) sort(sorted_items.begin(),sorted_items.end(),sp_object_compare_position); for(std::vector::const_iterator i=sorted_items.begin();i!=sorted_items.end();i++){ - SPItem *item = SP_ITEM(*i); + SPItem *item = *i; if (item) { Inkscape::XML::Node *obj = item->getRepr(); Inkscape::XML::Node *obj_copy = _copyNode(obj, _doc, _root); @@ -706,7 +706,7 @@ void ClipboardManagerImpl::_copySelection(Inkscape::Selection *selection) // copy style for Paste Style action if (!sorted_items.empty()) { - SPObject *object = static_cast(sorted_items.front()); + SPObject *object = static_cast(sorted_items[0]); SPItem *item = dynamic_cast(object); if (item) { SPCSSAttr *style = take_style_from_item(item); diff --git a/src/ui/dialog/align-and-distribute.cpp b/src/ui/dialog/align-and-distribute.cpp index 34dbd150b..1ee72dcbc 100644 --- a/src/ui/dialog/align-and-distribute.cpp +++ b/src/ui/dialog/align-and-distribute.cpp @@ -151,7 +151,7 @@ void ActionAlign::do_action(SPDesktop *desktop, int index) for (std::vector::iterator it(selected.begin()); it != selected.end(); ++it) { - SPItem* item=static_cast (*it); + SPItem* item= *it; desktop->getDocument()->ensureUpToDate(); if (!sel_as_group) b = (item)->desktopPreferredBounds(); @@ -264,8 +264,8 @@ private : std::vector< BBoxSort > sorted; for (std::vector::iterator it(selected.begin()); it != selected.end(); - ++it) - {SPItem *item=static_cast(*it); + ++it){ + SPItem *item = *it; Geom::OptRect bbox = !prefs_bbox ? (item)->desktopVisualBounds() : (item)->desktopGeometricBounds(); if (bbox) { sorted.push_back(BBoxSort(item, *bbox, _orientation, _kBegin, _kEnd)); @@ -570,19 +570,19 @@ private : sort(selected.begin(),selected.end(),sort_compare); } std::vector::iterator it(selected.begin()); - SPItem* item=static_cast(*it); - Geom::Point p1 = (item)->getCenter(); + SPItem* item = *it; + Geom::Point p1 = item->getCenter(); for (++it ;it != selected.end(); ++it) { - item=static_cast(*it); - Geom::Point p2 = (item)->getCenter(); + item = *it; + Geom::Point p2 = item->getCenter(); Geom::Point delta = p1 - p2; - sp_item_move_rel((item),Geom::Translate(delta[Geom::X],delta[Geom::Y] )); + sp_item_move_rel(item,Geom::Translate(delta[Geom::X],delta[Geom::Y] )); p1 = p2; } - Geom::Point p2 = static_cast(selected.front())->getCenter(); + Geom::Point p2 = selected.front()->getCenter(); Geom::Point delta = p1 - p2; - sp_item_move_rel(static_cast(selected.front()),Geom::Translate(delta[Geom::X],delta[Geom::Y] )); + sp_item_move_rel(selected.front(),Geom::Translate(delta[Geom::X],delta[Geom::Y] )); // restore compensation setting prefs->setInt("/options/clonecompensation/value", saved_compensation); @@ -675,7 +675,7 @@ private : it != selected.end(); ++it) { - SPItem* item=static_cast(*it); + SPItem* item = *it; desktop->getDocument()->ensureUpToDate(); Geom::OptRect item_box = !prefs_bbox ? (item)->desktopVisualBounds() : (item)->desktopGeometricBounds(); if (item_box) { @@ -761,7 +761,7 @@ private : it != selected.end(); ++it) { - SPItem* item=static_cast(*it); + SPItem* item = *it; if (SP_IS_TEXT (item) || SP_IS_FLOWTEXT (item)) { Inkscape::Text::Layout const *layout = te_get_layout(item); boost::optional pt = layout->baselineAnchorPoint(); @@ -805,7 +805,7 @@ private : it != selected.end(); ++it) { - SPItem* item=static_cast(*it); + SPItem* item = *it; if (SP_IS_TEXT (item) || SP_IS_FLOWTEXT (item)) { Inkscape::Text::Layout const *layout = te_get_layout(item); boost::optional pt = layout->baselineAnchorPoint(); diff --git a/src/ui/dialog/export.cpp b/src/ui/dialog/export.cpp index 32eed088c..ca3971019 100644 --- a/src/ui/dialog/export.cpp +++ b/src/ui/dialog/export.cpp @@ -819,7 +819,7 @@ void Export::onAreaToggled () const gchar * id = "object"; const std::vector reprlst = SP_ACTIVE_DESKTOP->getSelection()->reprList(); for(std::vector::const_iterator i=reprlst.begin(); reprlst.end() != i; i++) { - Inkscape::XML::Node * repr = (*i); + Inkscape::XML::Node * repr = *i; if (repr->attribute("id")) { id = repr->attribute("id"); break; @@ -1026,7 +1026,7 @@ void Export::onExport () std::vector itemlist=desktop->getSelection()->itemList(); for(std::vector::const_iterator i = itemlist.begin();i!=itemlist.end() && !interrupted ;i++){ - SPItem *item = reinterpret_cast(*i); + SPItem *item = *i; prog_dlg->set_data("current", GINT_TO_POINTER(n)); prog_dlg->set_data("total", GINT_TO_POINTER(num)); diff --git a/src/ui/dialog/filter-effects-dialog.cpp b/src/ui/dialog/filter-effects-dialog.cpp index a6312140d..45c8ce68a 100644 --- a/src/ui/dialog/filter-effects-dialog.cpp +++ b/src/ui/dialog/filter-effects-dialog.cpp @@ -690,7 +690,7 @@ private: void select_svg_element(){ Inkscape::Selection* sel = _desktop->getSelection(); if (sel->isEmpty()) return; - Inkscape::XML::Node* node = sel->reprList().front(); + Inkscape::XML::Node* node = sel->reprList()[0]; if (!node || !node->matchAttributeName("id")) return; std::ostringstream xlikhref; @@ -1547,7 +1547,7 @@ void FilterEffectsDialog::FilterModifier::on_selection_toggled(const Glib::ustri std::vector itemlist=sel->itemList(); for(std::vector::const_iterator i=itemlist.begin(); itemlist.end() != i; i++) { - SPItem * item = SP_ITEM(*i); + SPItem * item = *i; SPStyle *style = item->style; g_assert(style != NULL); @@ -1655,7 +1655,7 @@ void FilterEffectsDialog::FilterModifier::remove_filter() if (!SP_IS_ITEM(*i)) { continue; } - SPItem *item = SP_ITEM(*i); + SPItem *item = *i; if (!item->style) { continue; } diff --git a/src/ui/dialog/find.cpp b/src/ui/dialog/find.cpp index 283d79c0d..dde040036 100644 --- a/src/ui/dialog/find.cpp +++ b/src/ui/dialog/find.cpp @@ -857,7 +857,7 @@ void Find::onAction() Inkscape::Selection *selection = desktop->getSelection(); selection->clear(); selection->setList(n); - SPObject *obj = reinterpret_cast(n.front()); + SPObject *obj = reinterpret_cast(n[0]); SPItem *item = dynamic_cast(obj); g_assert(item != NULL); scroll_to_show_item(desktop, item); diff --git a/src/ui/dialog/find.h b/src/ui/dialog/find.h index 61f4463ae..4bcb900b6 100644 --- a/src/ui/dialog/find.h +++ b/src/ui/dialog/find.h @@ -16,7 +16,6 @@ # include #endif -#include "selection.h" #include "ui/widget/panel.h" #include "ui/widget/button.h" #include "ui/widget/entry.h" diff --git a/src/ui/dialog/font-substitution.cpp b/src/ui/dialog/font-substitution.cpp index e9a0fc017..1be87d180 100644 --- a/src/ui/dialog/font-substitution.cpp +++ b/src/ui/dialog/font-substitution.cpp @@ -159,7 +159,7 @@ std::vector FontSubstitution::getFontReplacedItems(SPDocument* doc, Gli allList = get_all_items(x, doc->getRoot(), desktop, false, false, true, y); for(std::vector::const_iterator i = allList.begin();i!=allList.end();i++){ - SPItem *item = SP_ITEM(*i); + SPItem *item = *i; SPStyle *style = item->style; Glib::ustring family = ""; diff --git a/src/ui/dialog/font-substitution.h b/src/ui/dialog/font-substitution.h index cdb4e22b4..0818d778c 100644 --- a/src/ui/dialog/font-substitution.h +++ b/src/ui/dialog/font-substitution.h @@ -13,7 +13,8 @@ #define INKSCAPE_UI_FONT_SUBSTITUTION_H #include -#include "selection.h" + +class SPItem; class SPDocument; namespace Inkscape { diff --git a/src/ui/dialog/glyphs.cpp b/src/ui/dialog/glyphs.cpp index fa469dc4b..7ca277ea2 100644 --- a/src/ui/dialog/glyphs.cpp +++ b/src/ui/dialog/glyphs.cpp @@ -581,7 +581,7 @@ void GlyphsPanel::insertText() std::vector itemlist=targetDesktop->selection->itemList(); for(std::vector::const_iterator i=itemlist.begin(); itemlist.end() != i; i++) { if (SP_IS_TEXT(*i) || SP_IS_FLOWTEXT(*i)) { - textItem = SP_ITEM(*i); + textItem = *i; break; } } diff --git a/src/ui/dialog/grid-arrange-tab.cpp b/src/ui/dialog/grid-arrange-tab.cpp index 10498b0f9..8bd130c2e 100644 --- a/src/ui/dialog/grid-arrange-tab.cpp +++ b/src/ui/dialog/grid-arrange-tab.cpp @@ -172,7 +172,7 @@ void GridArrangeTab::arrange() const std::vector items = selection ? selection->itemList() : std::vector(); cnt=0; for(std::vector::const_iterator i = items.begin();i!=items.end();i++){ - SPItem *item = SP_ITEM(*i); + SPItem *item = *i; Geom::OptRect b = item->documentVisualBounds(); if (!b) { continue; diff --git a/src/ui/dialog/icon-preview.cpp b/src/ui/dialog/icon-preview.cpp index 6ad3d61ac..e9ee7802d 100644 --- a/src/ui/dialog/icon-preview.cpp +++ b/src/ui/dialog/icon-preview.cpp @@ -368,7 +368,7 @@ void IconPreviewPanel::refreshPreview() std::vector const items = sel->itemList(); for(std::vector::const_iterator i=items.begin();!target && i!=items.end();i++){ - SPItem* item = SP_ITEM( *i); + SPItem* item = *i; gchar const *id = item->getId(); if ( id ) { targetId = id; diff --git a/src/ui/dialog/objects.cpp b/src/ui/dialog/objects.cpp index 6e09be2ba..781c6ef93 100644 --- a/src/ui/dialog/objects.cpp +++ b/src/ui/dialog/objects.cpp @@ -479,7 +479,7 @@ void ObjectsPanel::_objectsSelected( Selection *sel ) { SPItem *item = NULL; std::vector const items = sel->itemList(); for(std::vector::const_iterator i=items.begin(); i!=items.end();i++){ - item = reinterpret_cast(*i); + item = *i; if (setOpacity) { _setCompositingValues(item); diff --git a/src/ui/dialog/polar-arrange-tab.cpp b/src/ui/dialog/polar-arrange-tab.cpp index a68e73caf..af1386e27 100644 --- a/src/ui/dialog/polar-arrange-tab.cpp +++ b/src/ui/dialog/polar-arrange-tab.cpp @@ -308,7 +308,7 @@ void PolarArrangeTab::arrange() { if(arrangeOnEllipse) { - SPItem *item = SP_ITEM(*i); + SPItem *item = *i; if(arrangeOnFirstEllipse) { @@ -375,7 +375,7 @@ void PolarArrangeTab::arrange() int i = 0; for(std::vector::const_iterator it=tmp.begin();it!=tmp.end();it++) { - SPItem *item = SP_ITEM(*it); + SPItem *item = *it; // Ignore the reference ellipse if any if(item != referenceEllipse) diff --git a/src/ui/dialog/tags.cpp b/src/ui/dialog/tags.cpp index b677711ff..5fab9fcfc 100644 --- a/src/ui/dialog/tags.cpp +++ b/src/ui/dialog/tags.cpp @@ -355,7 +355,7 @@ void TagsPanel::_objectsSelected( Selection *sel ) { std::vector tmp=sel->list(); for(std::vector::const_iterator i=tmp.begin();i!=tmp.end();i++) { - SPObject *obj = reinterpret_cast(*i); + SPObject *obj = *i; _store->foreach(sigc::bind( sigc::mem_fun(*this, &TagsPanel::_checkForSelected), obj)); } _selectedConnection.unblock(); diff --git a/src/ui/dialog/text-edit.cpp b/src/ui/dialog/text-edit.cpp index 1c1cf5937..9c4790379 100644 --- a/src/ui/dialog/text-edit.cpp +++ b/src/ui/dialog/text-edit.cpp @@ -422,7 +422,7 @@ SPItem *TextEdit::getSelectedTextItem (void) for(std::vector::const_iterator i=tmp.begin();i!=tmp.end();i++) { if (SP_IS_TEXT(*i) || SP_IS_FLOWTEXT(*i)) - return SP_ITEM (*i); + return *i; } return NULL; diff --git a/src/ui/dialog/transformation.cpp b/src/ui/dialog/transformation.cpp index 0f81a7e58..459e6e937 100644 --- a/src/ui/dialog/transformation.cpp +++ b/src/ui/dialog/transformation.cpp @@ -655,7 +655,7 @@ void Transformation::updatePageTransform(Inkscape::Selection *selection) { if (selection && !selection->isEmpty()) { if (_check_replace_matrix.get_active()) { - Geom::Affine current (SP_ITEM(selection->itemList().front())->transform); // take from the first item in selection + Geom::Affine current (selection->itemList()[0]->transform); // take from the first item in selection Geom::Affine new_displayed = current; @@ -750,8 +750,8 @@ void Transformation::applyPageMove(Inkscape::Selection *selection) it != selected.end(); ++it) { - SPItem* item=static_cast(*it); - Geom::OptRect bbox = (item)->desktopPreferredBounds(); + SPItem* item = *it; + Geom::OptRect bbox = item->desktopPreferredBounds(); if (bbox) { sorted.push_back(BBoxSort(item, *bbox, Geom::X, x > 0? 1. : 0., x > 0? 0. : 1.)); } @@ -775,8 +775,8 @@ void Transformation::applyPageMove(Inkscape::Selection *selection) it != selected.end(); ++it) { - SPItem* item=static_cast(*it); - Geom::OptRect bbox = (item)->desktopPreferredBounds(); + SPItem* item = *it; + Geom::OptRect bbox = item->desktopPreferredBounds(); if (bbox) { sorted.push_back(BBoxSort(item, *bbox, Geom::Y, y > 0? 1. : 0., y > 0? 0. : 1.)); } @@ -818,7 +818,7 @@ void Transformation::applyPageScale(Inkscape::Selection *selection) if (prefs->getBool("/dialogs/transformation/applyseparately")) { std::vector tmp=selection->itemList(); for(std::vector::const_iterator i=tmp.begin();i!=tmp.end();i++){ - SPItem *item = SP_ITEM(*i); + SPItem *item = *i; Geom::OptRect bbox_pref = item->desktopPreferredBounds(); Geom::OptRect bbox_geom = item->desktopGeometricBounds(); if (bbox_pref && bbox_geom) { @@ -882,7 +882,7 @@ void Transformation::applyPageRotate(Inkscape::Selection *selection) if (prefs->getBool("/dialogs/transformation/applyseparately")) { std::vector tmp=selection->itemList(); for(std::vector::const_iterator i=tmp.begin();i!=tmp.end();i++){ - SPItem *item = SP_ITEM(*i); + SPItem *item = *i; sp_item_rotate_rel(item, Geom::Rotate (angle*M_PI/180.0)); } } else { @@ -902,7 +902,7 @@ void Transformation::applyPageSkew(Inkscape::Selection *selection) if (prefs->getBool("/dialogs/transformation/applyseparately")) { std::vector items=selection->itemList(); for(std::vector::const_iterator i = items.begin();i!=items.end();i++){ - SPItem *item = SP_ITEM(*i); + SPItem *item = *i; if (!_units_skew.isAbsolute()) { // percentage double skewX = _scalar_skew_horizontal.getValue("%"); @@ -1004,7 +1004,7 @@ void Transformation::applyPageTransform(Inkscape::Selection *selection) if (_check_replace_matrix.get_active()) { std::vector tmp=selection->itemList(); for(std::vector::const_iterator i=tmp.begin();i!=tmp.end();i++){ - SPItem *item = SP_ITEM(*i); + SPItem *item = *i; item->set_item_transform(displayed); SP_OBJECT(item)->updateRepr(); } @@ -1155,7 +1155,7 @@ void Transformation::onReplaceMatrixToggled() double f = _scalar_transform_f.getValue(); Geom::Affine displayed (a, b, c, d, e, f); - Geom::Affine current = SP_ITEM(selection->itemList().front())->transform; // take from the first item in selection + Geom::Affine current = selection->itemList()[0]->transform; // take from the first item in selection Geom::Affine new_displayed; if (_check_replace_matrix.get_active()) { diff --git a/src/ui/interface.cpp b/src/ui/interface.cpp index 193dff33c..760d19e89 100644 --- a/src/ui/interface.cpp +++ b/src/ui/interface.cpp @@ -2077,7 +2077,7 @@ void ContextMenu::ImageEdit(void) std::vector itemlist=_desktop->selection->itemList(); for(std::vector::const_iterator i=itemlist.begin();i!=itemlist.end();i++){ - Inkscape::XML::Node *ir = SP_ITEM(*i)->getRepr(); + Inkscape::XML::Node *ir = (*i)->getRepr(); const gchar *href = ir->attribute("xlink:href"); if (strncmp (href,"file:",5) == 0) { diff --git a/src/ui/tools/connector-tool.cpp b/src/ui/tools/connector-tool.cpp index 9c6eead16..f48e572df 100644 --- a/src/ui/tools/connector-tool.cpp +++ b/src/ui/tools/connector-tool.cpp @@ -1318,7 +1318,7 @@ void cc_selection_set_avoid(bool const set_avoid) std::vector l = selection->itemList(); for(std::vector::const_iterator i=l.begin();i!=l.end();i++) { - SPItem *item = SP_ITEM(*i); + SPItem *item = *i; char const *value = (set_avoid) ? "true" : NULL; diff --git a/src/ui/tools/eraser-tool.cpp b/src/ui/tools/eraser-tool.cpp index b61a108f0..adbbb2bd3 100644 --- a/src/ui/tools/eraser-tool.cpp +++ b/src/ui/tools/eraser-tool.cpp @@ -692,8 +692,8 @@ void EraserTool::set_to_accumulated() { if ( !toWorkOn.empty() ) { if ( eraserMode ) { - for (std::vector::const_iterator i = toWorkOn.begin();i!=toWorkOn.end();i++) { - SPItem *item = SP_ITEM(*i); + for (std::vector::const_iterator i = toWorkOn.begin(); i != toWorkOn.end(); i++){ + SPItem *item = *i; if ( eraserMode ) { Geom::OptRect bbox = item->visualBounds(); @@ -712,7 +712,7 @@ void EraserTool::set_to_accumulated() { // If the item was not completely erased, track the new remainder. std::vector nowSel(selection->itemList()); for (std::vector::const_iterator i2 = nowSel.begin();i2!=nowSel.end();i2++) { - remainingItems.push_back(SP_ITEM(*i2)); + remainingItems.push_back(*i2); } } } else { @@ -722,11 +722,11 @@ void EraserTool::set_to_accumulated() { } } else { for (std::vector ::const_iterator i = toWorkOn.begin();i!=toWorkOn.end();i++) { - sp_object_ref( SP_ITEM(*i), 0 ); + sp_object_ref( *i, 0 ); } for (std::vector::const_iterator i = toWorkOn.begin();i!=toWorkOn.end();i++) { - SPItem *item = SP_ITEM(*i); + SPItem *item = *i; item->deleteObject(true); sp_object_unref(item); workDone = true; diff --git a/src/ui/tools/gradient-tool.cpp b/src/ui/tools/gradient-tool.cpp index 6f7b220ed..21ad18c26 100644 --- a/src/ui/tools/gradient-tool.cpp +++ b/src/ui/tools/gradient-tool.cpp @@ -506,7 +506,7 @@ bool GradientTool::root_handler(GdkEvent* event) { } else { std::vector items=selection->itemList(); for (std::vector::const_iterator i = items.begin();i!=items.end();i++) { - SPItem *item = SP_ITEM(*i); + SPItem *item = *i; SPGradientType new_type = (SPGradientType) prefs->getInt("/tools/gradient/newgradient", SP_GRADIENT_TYPE_LINEAR); Inkscape::PaintTarget fsmode = (prefs->getInt("/tools/gradient/newfillorstroke", 1) != 0) ? Inkscape::FOR_FILL : Inkscape::FOR_STROKE; @@ -890,12 +890,6 @@ bool GradientTool::root_handler(GdkEvent* event) { return ret; } -int sp_item_repr_compare_position_obj(SPObject const *first, SPObject const *second) -{ - return sp_repr_compare_position(((SPItem*)first)->getRepr(), - ((SPItem*)second)->getRepr())<0; -} - static void sp_gradient_drag(GradientTool &rc, Geom::Point const pt, guint /*state*/, guint32 etime) { SPDesktop *desktop = SP_EVENT_CONTEXT(&rc)->desktop; @@ -931,14 +925,14 @@ static void sp_gradient_drag(GradientTool &rc, Geom::Point const pt, guint /*sta //FIXME: see above sp_repr_css_change_recursive(SP_OBJECT(*i)->getRepr(), css, "style"); - sp_item_set_gradient(SP_ITEM(*i), vector, (SPGradientType) type, fill_or_stroke); + sp_item_set_gradient(*i, vector, (SPGradientType) type, fill_or_stroke); if (type == SP_GRADIENT_TYPE_LINEAR) { - sp_item_gradient_set_coords (SP_ITEM(*i), POINT_LG_BEGIN, 0, rc.origin, fill_or_stroke, true, false); - sp_item_gradient_set_coords (SP_ITEM(*i), POINT_LG_END, 0, pt, fill_or_stroke, true, false); + sp_item_gradient_set_coords (*i, POINT_LG_BEGIN, 0, rc.origin, fill_or_stroke, true, false); + sp_item_gradient_set_coords (*i, POINT_LG_END, 0, pt, fill_or_stroke, true, false); } else if (type == SP_GRADIENT_TYPE_RADIAL) { - sp_item_gradient_set_coords (SP_ITEM(*i), POINT_RG_CENTER, 0, rc.origin, fill_or_stroke, true, false); - sp_item_gradient_set_coords (SP_ITEM(*i), POINT_RG_R1, 0, pt, fill_or_stroke, true, false); + sp_item_gradient_set_coords (*i, POINT_RG_CENTER, 0, rc.origin, fill_or_stroke, true, false); + sp_item_gradient_set_coords (*i, POINT_RG_R1, 0, pt, fill_or_stroke, true, false); } SP_OBJECT(*i)->requestModified(SP_OBJECT_MODIFIED_FLAG); } @@ -949,7 +943,7 @@ static void sp_gradient_drag(GradientTool &rc, Geom::Point const pt, guint /*sta ec->_grdrag->local_change = true; // give the grab out-of-bounds values of xp/yp because we're already dragging // and therefore are already out of tolerance - ec->_grdrag->grabKnot (SP_ITEM(selection->itemList().front()), + ec->_grdrag->grabKnot (selection->itemList()[0], type == SP_GRADIENT_TYPE_LINEAR? POINT_LG_END : POINT_RG_R1, -1, // ignore number (though it is always 1) fill_or_stroke, 99999, 99999, etime); diff --git a/src/ui/tools/gradient-tool.h b/src/ui/tools/gradient-tool.h index 786aed372..6fe3bca9f 100644 --- a/src/ui/tools/gradient-tool.h +++ b/src/ui/tools/gradient-tool.h @@ -18,7 +18,6 @@ #include #include #include "ui/tools/tool-base.h" -class SPObject;//kill it #define SP_GRADIENT_CONTEXT(obj) (dynamic_cast((Inkscape::UI::Tools::ToolBase*)obj)) #define SP_IS_GRADIENT_CONTEXT(obj) (dynamic_cast((const Inkscape::UI::Tools::ToolBase*)obj) != NULL) @@ -26,12 +25,12 @@ class SPObject;//kill it namespace Inkscape { namespace UI { namespace Tools { -int sp_item_repr_compare_position_obj(SPObject const *first, SPObject const *second);//kill it class GradientTool : public ToolBase { public: GradientTool(); virtual ~GradientTool(); + Geom::Point origin; bool cursor_addnode; diff --git a/src/ui/tools/measure-tool.cpp b/src/ui/tools/measure-tool.cpp index 2b44639c8..5295a16c0 100644 --- a/src/ui/tools/measure-tool.cpp +++ b/src/ui/tools/measure-tool.cpp @@ -444,7 +444,7 @@ bool MeasureTool::root_handler(GdkEvent* event) { std::vector items = desktop->getDocument()->getItemsAtPoints(desktop->dkey, points); std::vector intersection_times; for (std::vector::const_iterator i=items.begin();i!=items.end();i++) { - SPItem *item = static_cast(*i); + SPItem *item = *i; if (SP_IS_SHAPE(item)) { calculate_intersections(desktop, item, lineseg, SP_SHAPE(item)->getCurve(), intersection_times); diff --git a/src/ui/tools/mesh-tool.cpp b/src/ui/tools/mesh-tool.cpp index 0a34e4855..c8e032089 100644 --- a/src/ui/tools/mesh-tool.cpp +++ b/src/ui/tools/mesh-tool.cpp @@ -48,7 +48,6 @@ // Mesh specific #include "ui/tools/mesh-tool.h" -#include "ui/tools/gradient-tool.h"//not needed #include "sp-mesh-gradient.h" #include "display/sp-ctrlcurve.h" @@ -478,12 +477,12 @@ bool MeshTool::root_handler(GdkEvent* event) { if (over_line) { // We take the first item in selection, because with doubleclick, the first click // always resets selection to the single object under cursor - sp_mesh_context_split_near_point(this, SP_ITEM(selection->itemList().front()), this->mousepoint_doc, event->button.time); + sp_mesh_context_split_near_point(this, selection->itemList()[0], this->mousepoint_doc, event->button.time); } else { // Create a new gradient with default coordinates. std::vector items=selection->itemList(); for(std::vector::const_iterator i=items.begin();i!=items.end();i++){ - SPItem *item = SP_ITEM(*i); + SPItem *item = *i; SPGradientType new_type = SP_GRADIENT_TYPE_MESH; Inkscape::PaintTarget fsmode = (prefs->getInt("/tools/gradient/newfillorstroke", 1) != 0) ? Inkscape::FOR_FILL : Inkscape::FOR_STROKE; @@ -932,12 +931,6 @@ bool MeshTool::root_handler(GdkEvent* event) { return ret; } -/* -int sp_item_repr_compare_position_obj(SPObject const *first, SPObject const *second) -{ - return sp_repr_compare_position(((SPItem*)first)->getRepr(), - ((SPItem*)second)->getRepr())<0; -}*/ static void sp_mesh_drag(MeshTool &rc, Geom::Point const /*pt*/, guint /*state*/, guint32 /*etime*/) { SPDesktop *desktop = SP_EVENT_CONTEXT(&rc)->desktop; diff --git a/src/ui/tools/select-tool.cpp b/src/ui/tools/select-tool.cpp index 25cbf76a4..fbc1a9e6c 100644 --- a/src/ui/tools/select-tool.cpp +++ b/src/ui/tools/select-tool.cpp @@ -481,7 +481,7 @@ bool SelectTool::root_handler(GdkEvent* event) { case GDK_2BUTTON_PRESS: if (event->button.button == 1) { if (!selection->isEmpty()) { - SPItem *clicked_item = static_cast(selection->itemList().front()); + SPItem *clicked_item = selection->itemList()[0]; if (dynamic_cast(clicked_item) && !dynamic_cast(clicked_item)) { // enter group if it's not a 3D box desktop->setCurrentLayer(clicked_item); diff --git a/src/ui/tools/spray-tool.cpp b/src/ui/tools/spray-tool.cpp index ac41f3a34..d92d326e0 100644 --- a/src/ui/tools/spray-tool.cpp +++ b/src/ui/tools/spray-tool.cpp @@ -553,13 +553,13 @@ static bool sp_spray_dilate(SprayTool *tc, Geom::Point /*event_p*/, Geom::Point std::vector const items(selection->itemList()); for(std::vector::const_iterator i=items.begin();i!=items.end();i++){ - SPItem *item = dynamic_cast(static_cast(*i)); + SPItem *item = *i; g_assert(item != NULL); sp_object_ref(item); } for(std::vector::const_iterator i=items.begin();i!=items.end();i++){ - SPItem *item = dynamic_cast(static_cast(*i)); + SPItem *item = *i; g_assert(item != NULL); if (is_transform_modes(tc->mode)) { @@ -574,7 +574,7 @@ static bool sp_spray_dilate(SprayTool *tc, Geom::Point /*event_p*/, Geom::Point } for(std::vector::const_iterator i=items.begin();i!=items.end();i++){ - SPItem *item = dynamic_cast(static_cast(*i)); + SPItem *item = *i; g_assert(item != NULL); sp_object_unref(item); } diff --git a/src/ui/tools/tweak-tool.cpp b/src/ui/tools/tweak-tool.cpp index 6f7764506..8c5e4215e 100644 --- a/src/ui/tools/tweak-tool.cpp +++ b/src/ui/tools/tweak-tool.cpp @@ -1089,7 +1089,7 @@ sp_tweak_dilate (TweakTool *tc, Geom::Point event_p, Geom::Point p, Geom::Point std::vector items=selection->itemList(); for(std::vector::const_iterator i=items.begin();i!=items.end();i++){ - SPItem *item = dynamic_cast(static_cast(*i)); + SPItem *item = *i; if (is_color_mode (tc->mode)) { if (do_fill || do_stroke || do_opacity) { diff --git a/src/unclump.cpp b/src/unclump.cpp index 29608befa..81c958937 100644 --- a/src/unclump.cpp +++ b/src/unclump.cpp @@ -173,7 +173,7 @@ static double unclump_average (SPItem *item, std::list &others) int n = 0; double sum = 0; for (std::list::const_iterator i = others.begin(); i != others.end();i++) { - SPItem *other = SP_ITEM (*i); + SPItem *other = *i; if (other == item) continue; @@ -197,7 +197,7 @@ static SPItem *unclump_closest (SPItem *item, std::list &others) SPItem *closest = NULL; for (std::list::const_iterator i = others.begin(); i != others.end();i++) { - SPItem *other = SP_ITEM (*i); + SPItem *other = *i; if (other == item) continue; @@ -220,7 +220,7 @@ static SPItem *unclump_farest (SPItem *item, std::list &others) double max = -HUGE_VAL; SPItem *farest = NULL; for (std::list::const_iterator i = others.begin(); i != others.end();i++) { - SPItem *other = SP_ITEM (*i); + SPItem *other = *i; if (other == item) continue; @@ -260,7 +260,7 @@ unclump_remove_behind (SPItem *item, SPItem *closest, std::list &rest) std::vector out; for (std::list::const_reverse_iterator i = rest.rbegin(); i != rest.rend();i++) { - SPItem *other = SP_ITEM (*i); + SPItem *other = *i; if (other == item) continue; @@ -337,7 +337,7 @@ unclump (std::vector &items) wh_cache.clear(); for (std::vector::const_iterator i = items.begin(); i != items.end();i++) { // for each original/clone x: - SPItem *item = SP_ITEM (*i); + SPItem *item = *i; std::list nei; diff --git a/src/unclump.h b/src/unclump.h index 407628f3a..461e99d0b 100644 --- a/src/unclump.h +++ b/src/unclump.h @@ -12,7 +12,6 @@ #define SEEN_DIALOGS_UNCLUMP_H typedef struct _GSList GSList; -#include "selection.h" void unclump(std::vector &items); diff --git a/src/vanishing-point.cpp b/src/vanishing-point.cpp index 770845f38..46f895c06 100644 --- a/src/vanishing-point.cpp +++ b/src/vanishing-point.cpp @@ -258,7 +258,7 @@ VanishingPoint::selectedBoxes(Inkscape::Selection *sel) { std::list sel_boxes; std::vector itemlist=sel->itemList(); for (std::vector::const_iterator i=itemlist.begin();i!=itemlist.end();i++) { - SPItem *item = static_cast(*i); + SPItem *item = *i; SPBox3D *box = dynamic_cast(item); if (box && this->hasBox(box)) { sel_boxes.push_back(box); @@ -398,7 +398,7 @@ VPDragger::VPsOfSelectedBoxes() { Inkscape::Selection *sel = SP_ACTIVE_DESKTOP->getSelection(); std::vector itemlist=sel->itemList(); for (std::vector::const_iterator i=itemlist.begin();i!=itemlist.end();i++) { - SPItem *item = static_cast(*i); + SPItem *item = *i; SPBox3D *box = dynamic_cast(item); if (box) { vp = this->findVPWithBox(box); @@ -581,7 +581,7 @@ VPDrag::updateDraggers () std::vector itemlist=this->selection->itemList(); for (std::vector::const_iterator i=itemlist.begin();i!=itemlist.end();i++) { - SPItem *item = static_cast(*i); + SPItem *item = *i; SPBox3D *box = dynamic_cast(item); if (box) { VanishingPoint vp; @@ -614,7 +614,7 @@ VPDrag::updateLines () std::vector itemlist=this->selection->itemList(); for (std::vector::const_iterator i=itemlist.begin();i!=itemlist.end();i++) { - SPItem *item = static_cast(*i); + SPItem *item = *i; SPBox3D *box = dynamic_cast(item); if (box) { this->drawLinesForFace (box, Proj::X); diff --git a/src/widgets/arc-toolbar.cpp b/src/widgets/arc-toolbar.cpp index cb24bb8aa..71418e238 100644 --- a/src/widgets/arc-toolbar.cpp +++ b/src/widgets/arc-toolbar.cpp @@ -99,7 +99,7 @@ sp_arctb_startend_value_changed(GtkAdjustment *adj, GObject *tbl, gchar const *v bool modmade = false; std::vector itemlist=desktop->getSelection()->itemList(); for(std::vector::const_iterator i=itemlist.begin();i!=itemlist.end();i++){ - SPItem *item = SP_ITEM(*i); + SPItem *item = *i; if (SP_IS_GENERICELLIPSE(item)) { SPGenericEllipse *ge = SP_GENERICELLIPSE(item); @@ -165,7 +165,7 @@ static void sp_arctb_open_state_changed( EgeSelectOneAction *act, GObject *tbl ) if ( ege_select_one_action_get_active(act) != 0 ) { std::vector itemlist=desktop->getSelection()->itemList(); for(std::vector::const_iterator i=itemlist.begin();i!=itemlist.end();i++){ - SPItem *item = SP_ITEM(*i); + SPItem *item = *i; if (SP_IS_GENERICELLIPSE(item)) { Inkscape::XML::Node *repr = item->getRepr(); repr->setAttribute("sodipodi:open", "true"); @@ -176,7 +176,7 @@ static void sp_arctb_open_state_changed( EgeSelectOneAction *act, GObject *tbl ) } else { std::vector itemlist=desktop->getSelection()->itemList(); for(std::vector::const_iterator i=itemlist.begin();i!=itemlist.end();i++){ - SPItem *item = SP_ITEM(*i); + SPItem *item = *i; if (SP_IS_GENERICELLIPSE(item)) { Inkscape::XML::Node *repr = item->getRepr(); repr->setAttribute("sodipodi:open", NULL); @@ -266,7 +266,7 @@ static void sp_arc_toolbox_selection_changed(Inkscape::Selection *selection, GOb std::vector itemlist=selection->itemList(); for(std::vector::const_iterator i=itemlist.begin();i!=itemlist.end();i++){ - SPItem *item = SP_ITEM(*i); + SPItem *item = *i; if (SP_IS_GENERICELLIPSE(item)) { n_selected++; repr = item->getRepr(); diff --git a/src/widgets/connector-toolbar.cpp b/src/widgets/connector-toolbar.cpp index 49cf8e6fd..1c99f283d 100644 --- a/src/widgets/connector-toolbar.cpp +++ b/src/widgets/connector-toolbar.cpp @@ -99,7 +99,7 @@ static void sp_connector_orthogonal_toggled( GtkToggleAction* act, GObject *tbl bool modmade = false; std::vector itemlist=desktop->getSelection()->itemList(); for(std::vector::const_iterator i=itemlist.begin();i!=itemlist.end();i++){ - SPItem *item = SP_ITEM(*i); + SPItem *item = *i; if (Inkscape::UI::Tools::cc_item_is_connector(item)) { item->setAttribute( "inkscape:connector-type", @@ -146,7 +146,7 @@ static void connector_curvature_changed(GtkAdjustment *adj, GObject* tbl) bool modmade = false; std::vector itemlist=desktop->getSelection()->itemList(); for(std::vector::const_iterator i=itemlist.begin();i!=itemlist.end();i++){ - SPItem *item = SP_ITEM(*i); + SPItem *item = *i; if (Inkscape::UI::Tools::cc_item_is_connector(item)) { item->setAttribute( "inkscape:connector-curvature", diff --git a/src/widgets/fill-style.cpp b/src/widgets/fill-style.cpp index dbb84efba..7d5a89cf5 100644 --- a/src/widgets/fill-style.cpp +++ b/src/widgets/fill-style.cpp @@ -591,11 +591,11 @@ void FillNStroke::updateFromPaint() if ( gr && createSwatch ) { gr->setSwatch(); } - sp_item_set_gradient(SP_ITEM(*i), + sp_item_set_gradient(*i, gr, gradient_type, (kind == FILL) ? Inkscape::FOR_FILL : Inkscape::FOR_STROKE); } else { - sp_item_set_gradient(SP_ITEM(*i), vector, gradient_type, (kind == FILL) ? Inkscape::FOR_FILL : Inkscape::FOR_STROKE); + sp_item_set_gradient(*i, vector, gradient_type, (kind == FILL) ? Inkscape::FOR_FILL : Inkscape::FOR_STROKE); } } } else { @@ -608,7 +608,7 @@ void FillNStroke::updateFromPaint() sp_repr_css_change_recursive(reinterpret_cast(*i)->getRepr(), css, "style"); } - SPGradient *gr = sp_item_set_gradient(SP_ITEM(*i), vector, gradient_type, (kind == FILL) ? Inkscape::FOR_FILL : Inkscape::FOR_STROKE); + SPGradient *gr = sp_item_set_gradient(*i, vector, gradient_type, (kind == FILL) ? Inkscape::FOR_FILL : Inkscape::FOR_STROKE); psel->pushAttrsToGradient( gr ); } } diff --git a/src/widgets/gradient-toolbar.cpp b/src/widgets/gradient-toolbar.cpp index 5aa654a80..6743dd23a 100644 --- a/src/widgets/gradient-toolbar.cpp +++ b/src/widgets/gradient-toolbar.cpp @@ -118,7 +118,7 @@ void gr_apply_gradient(Inkscape::Selection *selection, GrDrag *drag, SPGradient // If no drag or no dragger selected, act on selection std::vector itemlist=selection->itemList(); for(std::vector::const_iterator i=itemlist.begin();i!=itemlist.end();i++){ - gr_apply_gradient_to_item(SP_ITEM(*i), gr, initialType, initialMode, initialMode); + gr_apply_gradient_to_item(*i, gr, initialType, initialMode, initialMode); } } @@ -220,7 +220,7 @@ void gr_get_dt_selected_gradient(Inkscape::Selection *selection, SPGradient *&gr std::vector itemlist=selection->itemList(); for(std::vector::const_iterator i=itemlist.begin();i!=itemlist.end();i++){ - SPItem *item = SP_ITEM(*i);// get the items gradient, not the getVector() version + SPItem *item = *i;// get the items gradient, not the getVector() version SPStyle *style = item->style; SPPaintServer *server = 0; @@ -288,7 +288,7 @@ void gr_read_selection( Inkscape::Selection *selection, // If no selected dragger, read desktop selection std::vector itemlist=selection->itemList(); for(std::vector::const_iterator i=itemlist.begin();i!=itemlist.end();i++){ - SPItem *item = SP_ITEM(*i); + SPItem *item = *i; SPStyle *style = item->style; if (style && (style->fill.isPaintserver())) { diff --git a/src/widgets/mesh-toolbar.cpp b/src/widgets/mesh-toolbar.cpp index 682c61e77..49fc7b67c 100644 --- a/src/widgets/mesh-toolbar.cpp +++ b/src/widgets/mesh-toolbar.cpp @@ -89,7 +89,7 @@ void ms_read_selection( Inkscape::Selection *selection, std::vector itemlist=selection->itemList(); for(std::vector::const_iterator i=itemlist.begin();i!=itemlist.end();i++){ - SPItem *item = SP_ITEM(*i); + SPItem *item = *i; SPStyle *style = item->style; if (style && (style->fill.isPaintserver())) { @@ -216,7 +216,7 @@ void ms_get_dt_selected_gradient(Inkscape::Selection *selection, SPMeshGradient std::vector itemlist=selection->itemList(); for(std::vector::const_iterator i=itemlist.begin();i!=itemlist.end();i++){ - SPItem *item = SP_ITEM(*i);// get the items gradient, not the getVector() version + SPItem *item = *i;// get the items gradient, not the getVector() version SPStyle *style = item->style; SPPaintServer *server = 0; diff --git a/src/widgets/rect-toolbar.cpp b/src/widgets/rect-toolbar.cpp index 65078af01..2b07dd3b9 100644 --- a/src/widgets/rect-toolbar.cpp +++ b/src/widgets/rect-toolbar.cpp @@ -246,9 +246,9 @@ static void sp_rect_toolbox_selection_changed(Inkscape::Selection *selection, GO std::vector itemlist=selection->itemList(); for(std::vector::const_iterator i=itemlist.begin();i!=itemlist.end();i++){ - if (SP_IS_RECT(reinterpret_cast(*i))) { + if (SP_IS_RECT(*i)) { n_selected++; - item = reinterpret_cast(*i); + item = *i; repr = item->getRepr(); } } diff --git a/src/widgets/spiral-toolbar.cpp b/src/widgets/spiral-toolbar.cpp index 6f967e8ae..751a60f06 100644 --- a/src/widgets/spiral-toolbar.cpp +++ b/src/widgets/spiral-toolbar.cpp @@ -81,7 +81,7 @@ static void sp_spl_tb_value_changed(GtkAdjustment *adj, GObject *tbl, Glib::ustr bool modmade = false; std::vector itemlist=desktop->getSelection()->itemList(); for(std::vector::const_iterator i=itemlist.begin();i!=itemlist.end();i++){ - SPItem *item = SP_ITEM(*i); + SPItem *item = *i; if (SP_IS_SPIRAL(item)) { Inkscape::XML::Node *repr = item->getRepr(); sp_repr_set_svg_double( repr, namespaced_name, @@ -197,7 +197,7 @@ static void sp_spiral_toolbox_selection_changed(Inkscape::Selection *selection, std::vector itemlist=selection->itemList(); for(std::vector::const_iterator i=itemlist.begin();i!=itemlist.end();i++){ - SPItem *item = SP_ITEM(*i); + SPItem *item = *i; if (SP_IS_SPIRAL(item)) { n_selected++; repr = item->getRepr(); diff --git a/src/widgets/star-toolbar.cpp b/src/widgets/star-toolbar.cpp index 1946dee6e..96005d7df 100644 --- a/src/widgets/star-toolbar.cpp +++ b/src/widgets/star-toolbar.cpp @@ -85,7 +85,7 @@ static void sp_stb_magnitude_value_changed( GtkAdjustment *adj, GObject *dataKlu Inkscape::Selection *selection = desktop->getSelection(); std::vector itemlist=selection->itemList(); for(std::vector::const_iterator i=itemlist.begin();i!=itemlist.end();i++){ - SPItem *item = SP_ITEM(*i); + SPItem *item = *i; if (SP_IS_STAR(item)) { Inkscape::XML::Node *repr = item->getRepr(); sp_repr_set_int(repr,"sodipodi:sides", @@ -130,7 +130,7 @@ static void sp_stb_proportion_value_changed( GtkAdjustment *adj, GObject *dataKl Inkscape::Selection *selection = desktop->getSelection(); std::vector itemlist=selection->itemList(); for(std::vector::const_iterator i=itemlist.begin();i!=itemlist.end();i++){ - SPItem *item = SP_ITEM(*i); + SPItem *item = *i; if (SP_IS_STAR(item)) { Inkscape::XML::Node *repr = item->getRepr(); @@ -187,7 +187,7 @@ static void sp_stb_sides_flat_state_changed( EgeSelectOneAction *act, GObject *d std::vector itemlist=selection->itemList(); for(std::vector::const_iterator i=itemlist.begin();i!=itemlist.end();i++){ - SPItem *item = SP_ITEM(*i); + SPItem *item = *i; if (SP_IS_STAR(item)) { Inkscape::XML::Node *repr = item->getRepr(); repr->setAttribute("inkscape:flatsided", flat ? "true" : "false" ); @@ -226,7 +226,7 @@ static void sp_stb_rounded_value_changed( GtkAdjustment *adj, GObject *dataKludg Inkscape::Selection *selection = desktop->getSelection(); std::vector itemlist=selection->itemList(); for(std::vector::const_iterator i=itemlist.begin();i!=itemlist.end();i++){ - SPItem *item = SP_ITEM(*i); + SPItem *item = *i; if (SP_IS_STAR(item)) { Inkscape::XML::Node *repr = item->getRepr(); sp_repr_set_svg_double(repr, "inkscape:rounded", @@ -266,7 +266,7 @@ static void sp_stb_randomized_value_changed( GtkAdjustment *adj, GObject *dataKl Inkscape::Selection *selection = desktop->getSelection(); std::vector itemlist=selection->itemList(); for(std::vector::const_iterator i=itemlist.begin();i!=itemlist.end();i++){ - SPItem *item = SP_ITEM(*i); + SPItem *item = *i; if (SP_IS_STAR(item)) { Inkscape::XML::Node *repr = item->getRepr(); sp_repr_set_svg_double(repr, "inkscape:randomized", @@ -369,7 +369,7 @@ sp_star_toolbox_selection_changed(Inkscape::Selection *selection, GObject *tbl) std::vector itemlist=selection->itemList(); for(std::vector::const_iterator i=itemlist.begin();i!=itemlist.end();i++){ - SPItem *item = SP_ITEM(*i); + SPItem *item = *i; if (SP_IS_STAR(item)) { n_selected++; repr = item->getRepr(); diff --git a/src/widgets/stroke-style.cpp b/src/widgets/stroke-style.cpp index 65390819b..c05ef93e7 100644 --- a/src/widgets/stroke-style.cpp +++ b/src/widgets/stroke-style.cpp @@ -477,7 +477,7 @@ void StrokeStyle::markerSelectCB(MarkerComboBox *marker_combo, StrokeStyle *spw, Inkscape::Selection *selection = spw->desktop->getSelection(); std::vector itemlist=selection->itemList(); for(std::vector::const_iterator i=itemlist.begin();i!=itemlist.end();i++){ - SPItem *item = SP_ITEM(*i); + SPItem *item = *i; if (!SP_IS_SHAPE(item) || SP_IS_RECT(item)) { // can't set marker to rect, until it's converted to using continue; } @@ -902,7 +902,7 @@ StrokeStyle::updateLine() return; std::vector const objects = sel->itemList(); - SPObject * const object = SP_OBJECT(objects.front()); + SPObject * const object = SP_OBJECT(objects[0]); SPStyle * const style = object->style; /* Markers */ @@ -1155,6 +1155,7 @@ StrokeStyle::updateAllMarkers(std::vector const &objects) for(std::vector::const_iterator i=objects.begin();i!=objects.end();i++){ if (!SP_IS_TEXT (*i)) { all_texts = false; + break; } } @@ -1166,7 +1167,7 @@ StrokeStyle::updateAllMarkers(std::vector const &objects) // We show markers of the first object in the list only // FIXME: use the first in the list that has the marker of each type, if any - SPObject *object = SP_OBJECT(objects.front()); + SPObject *object = SP_OBJECT(objects[0]); for (unsigned i = 0; i < G_N_ELEMENTS(keyloc); ++i) { // For all three marker types, diff --git a/src/widgets/text-toolbar.cpp b/src/widgets/text-toolbar.cpp index 71915377e..6b0fb34e6 100644 --- a/src/widgets/text-toolbar.cpp +++ b/src/widgets/text-toolbar.cpp @@ -368,8 +368,8 @@ static void sp_text_align_mode_changed( EgeSelectOneAction *act, GObject *tbl ) Inkscape::Selection *selection = desktop->getSelection(); std::vector itemlist=selection->itemList(); for(std::vector::const_iterator i=itemlist.begin();i!=itemlist.end();i++){ - if (SP_IS_TEXT(SP_ITEM(*i))) { - SPItem *item = SP_ITEM(*i); + if (SP_IS_TEXT(*i)) { + SPItem *item = *i; unsigned writing_mode = item->style->writing_mode.value; // below, variable names suggest horizontal move, but we check the writing direction @@ -868,7 +868,7 @@ static void sp_text_toolbox_selection_changed(Inkscape::Selection */*selection*/ for(std::vector::const_iterator i=itemlist.begin();i!=itemlist.end();i++){ // const gchar* id = reinterpret_cast(items->data)->getId(); // std::cout << " " << id << std::endl; - if( SP_IS_FLOWTEXT(SP_ITEM(*i))) { + if( SP_IS_FLOWTEXT(*i)) { isFlow = true; // std::cout << " Found flowed text" << std::endl; break; @@ -1160,7 +1160,7 @@ static void sp_text_toolbox_select_cb( GtkEntry* entry, GtkEntryIconPosition /*p std::vector x,y; std::vector allList = get_all_items(x, document->getRoot(), desktop, false, false, true, y); for(std::vector::const_reverse_iterator i=allList.rbegin();i!=allList.rend();i++){ - SPItem *item = SP_ITEM(*i); + SPItem *item = *i; SPStyle *style = item->style; if (style) { -- cgit v1.2.3 From 9bdc157f705ca61516e599cb416580283d21ec35 Mon Sep 17 00:00:00 2001 From: Marc Jeanmougin Date: Fri, 27 Feb 2015 04:21:48 +0100 Subject: more cast cleanup (bzr r13922.1.11) --- src/desktop-style.cpp | 29 ++++++++++---------- src/extension/implementation/implementation.cpp | 2 +- src/extension/internal/cairo-renderer.cpp | 3 +-- src/extension/internal/latex-text-renderer.cpp | 3 +-- src/live_effects/lpe-knot.cpp | 2 +- src/path-chemistry.cpp | 4 +-- src/selcue.cpp | 2 +- src/selection-chemistry.cpp | 36 ++++++++++++------------- src/selection.cpp | 2 +- src/seltrans.cpp | 2 +- src/sp-item-group.cpp | 4 +-- src/sp-lpe-item.cpp | 10 +++---- src/splivarot.cpp | 10 +++---- src/text-chemistry.cpp | 8 +++--- src/ui/clipboard.cpp | 2 +- src/ui/dialog/filter-effects-dialog.cpp | 2 +- src/ui/dialog/find.cpp | 18 ++++++------- src/ui/dialog/grid-arrange-tab.cpp | 2 +- src/ui/dialog/tags.cpp | 2 +- src/ui/dialog/text-edit.cpp | 2 +- src/ui/tools/gradient-tool.cpp | 2 +- src/ui/tools/mesh-tool.cpp | 6 ++--- src/ui/tools/node-tool.cpp | 2 +- src/ui/widget/style-subject.cpp | 4 +-- src/widgets/fill-style.cpp | 8 +++--- src/widgets/rect-toolbar.cpp | 2 +- src/widgets/stroke-style.cpp | 4 +-- src/widgets/text-toolbar.cpp | 2 +- 28 files changed, 86 insertions(+), 89 deletions(-) (limited to 'src') diff --git a/src/desktop-style.cpp b/src/desktop-style.cpp index 82f66dcdf..afdc3064a 100644 --- a/src/desktop-style.cpp +++ b/src/desktop-style.cpp @@ -197,7 +197,7 @@ sp_desktop_set_style(SPDesktop *desktop, SPCSSAttr *css, bool change, bool write std::vector const itemlist = desktop->selection->itemList(); for (std::vector::const_iterator i = itemlist.begin(); i!= itemlist.end(); i++) { /* last used styles for 3D box faces are stored separately */ - SPObject *obj = reinterpret_cast(*i); + SPObject *obj = *i; Box3DSide *side = dynamic_cast(obj); if (side) { const char * descr = box3d_side_axes_string(side); @@ -448,7 +448,6 @@ stroke_average_width (const std::vector &objects) bool notstroked = true; int n_notstroked = 0; for (std::vector::const_iterator i = objects.begin(); i != objects.end(); i++) { - SPObject *obj = reinterpret_cast(*i); SPItem *item = *i; if (!item) { continue; @@ -515,7 +514,7 @@ objects_query_fillstroke (const std::vector &objects, SPStyle *style_re bool same_color = true; for (std::vector::const_iterator i = objects.begin(); i!= objects.end(); i++) { - SPObject *obj = reinterpret_cast(*i); + SPObject *obj = *i; if (!obj) { continue; } @@ -699,7 +698,7 @@ objects_query_opacity (const std::vector &objects, SPStyle *style_res) for (std::vector::const_iterator i = objects.begin(); i != objects.end(); i++) { - SPObject *obj = reinterpret_cast(*i); + SPObject *obj = *i; if (!obj) { continue; } @@ -755,7 +754,7 @@ objects_query_strokewidth (const std::vector &objects, SPStyle *style_r int n_stroked = 0; for (std::vector::const_iterator i = objects.begin(); i != objects.end(); i++) { - SPObject *obj = reinterpret_cast(*i); + SPObject *obj = *i; if (!obj) { continue; } @@ -829,7 +828,7 @@ objects_query_miterlimit (const std::vector &objects, SPStyle *style_re bool same_ml = true; for (std::vector::const_iterator i = objects.begin(); i != objects.end(); i++) { - SPObject *obj = reinterpret_cast(*i); + SPObject *obj = *i; if (!dynamic_cast(obj)) { continue; } @@ -888,7 +887,7 @@ objects_query_strokecap (const std::vector &objects, SPStyle *style_res int n_stroked = 0; for (std::vector::const_iterator i = objects.begin(); i != objects.end(); i++) { - SPObject *obj = reinterpret_cast(*i); + SPObject *obj = *i; if (!dynamic_cast(obj)) { continue; } @@ -942,7 +941,7 @@ objects_query_strokejoin (const std::vector &objects, SPStyle *style_re int n_stroked = 0; for (std::vector::const_iterator i = objects.begin(); i != objects.end(); i++) { - SPObject *obj = reinterpret_cast(*i); + SPObject *obj = *i; if (!dynamic_cast(obj)) { continue; } @@ -1005,7 +1004,7 @@ objects_query_fontnumbers (const std::vector &objects, SPStyle *style_r int no_size = 0; for (std::vector::const_iterator i = objects.begin(); i != objects.end(); i++) { - SPObject *obj = reinterpret_cast(*i); + SPObject *obj = *i; if (!isTextualItem(obj)) { continue; @@ -1124,7 +1123,7 @@ objects_query_fontstyle (const std::vector &objects, SPStyle *style_res int texts = 0; for (std::vector::const_iterator i = objects.begin(); i != objects.end(); i++) { - SPObject *obj = reinterpret_cast(*i); + SPObject *obj = *i; if (!isTextualItem(obj)) { continue; @@ -1193,7 +1192,7 @@ objects_query_baselines (const std::vector &objects, SPStyle *style_res int texts = 0; for (std::vector::const_iterator i = objects.begin(); i != objects.end(); i++) { - SPObject *obj = reinterpret_cast(*i); + SPObject *obj = *i; if (!isTextualItem(obj)) { continue; @@ -1281,7 +1280,7 @@ objects_query_fontfamily (const std::vector &objects, SPStyle *style_re style_res->font_family.set = FALSE; for (std::vector::const_iterator i = objects.begin(); i != objects.end(); i++) { - SPObject *obj = reinterpret_cast(*i); + SPObject *obj = *i; // std::cout << " " << reinterpret_cast(i->data)->getId() << std::endl; if (!isTextualItem(obj)) { @@ -1337,7 +1336,7 @@ objects_query_fontspecification (const std::vector &objects, SPStyle *s style_res->font_specification.set = FALSE; for (std::vector::const_iterator i = objects.begin(); i != objects.end(); i++) { - SPObject *obj = reinterpret_cast(*i); + SPObject *obj = *i; // std::cout << " " << reinterpret_cast(i->data)->getId() << std::endl; if (!isTextualItem(obj)) { @@ -1395,7 +1394,7 @@ objects_query_blend (const std::vector &objects, SPStyle *style_res) guint items = 0; for (std::vector::const_iterator i = objects.begin(); i != objects.end(); i++) { - SPObject *obj = reinterpret_cast(*i); + SPObject *obj = *i; if (!obj) { continue; } @@ -1485,7 +1484,7 @@ objects_query_blur (const std::vector &objects, SPStyle *style_res) guint items = 0; for (std::vector::const_iterator i = objects.begin(); i != objects.end(); i++) { - SPObject *obj = reinterpret_cast(*i); + SPObject *obj = *i; if (!obj) { continue; } diff --git a/src/extension/implementation/implementation.cpp b/src/extension/implementation/implementation.cpp index 11c494b18..717ca3310 100644 --- a/src/extension/implementation/implementation.cpp +++ b/src/extension/implementation/implementation.cpp @@ -51,7 +51,7 @@ Gtk::Widget *Implementation::prefs_effect(Inkscape::Extension::Effect *module, I std::vector selected = ((SPDesktop *)view)->getSelection()->itemList(); Inkscape::XML::Node const* first_select = NULL; if (!selected.empty()) { - const SPItem * item = selected.front(); + const SPItem * item = selected[0]; first_select = item->getRepr(); } diff --git a/src/extension/internal/cairo-renderer.cpp b/src/extension/internal/cairo-renderer.cpp index b30c8892e..a2cea014b 100644 --- a/src/extension/internal/cairo-renderer.cpp +++ b/src/extension/internal/cairo-renderer.cpp @@ -296,8 +296,7 @@ static void sp_group_render(SPGroup *group, CairoRenderContext *ctx) std::vector l(group->childList(false)); for(std::vector::const_iterator x = l.begin(); x!= l.end(); x++){ - SPObject *o = reinterpret_cast(*x); - SPItem *item = dynamic_cast(o); + SPItem *item = static_cast(*x); if (item) { renderer->renderItem(ctx, item); } diff --git a/src/extension/internal/latex-text-renderer.cpp b/src/extension/internal/latex-text-renderer.cpp index 831a8d030..ab863f8b1 100644 --- a/src/extension/internal/latex-text-renderer.cpp +++ b/src/extension/internal/latex-text-renderer.cpp @@ -230,8 +230,7 @@ void LaTeXTextRenderer::sp_group_render(SPGroup *group) { std::vector l = (group->childList(false)); for(std::vector::const_iterator x = l.begin(); x != l.end(); x++){ - SPObject *o = *x; - SPItem *item = dynamic_cast(o); + SPItem *item = static_cast(*x); if (item) { renderItem(item); } diff --git a/src/live_effects/lpe-knot.cpp b/src/live_effects/lpe-knot.cpp index 7a1d391a3..6ec4b969b 100644 --- a/src/live_effects/lpe-knot.cpp +++ b/src/live_effects/lpe-knot.cpp @@ -507,7 +507,7 @@ collectPathsAndWidths (SPLPEItem const *lpeitem, std::vector &paths, if (SP_IS_GROUP(lpeitem)) { std::vector item_list = sp_item_group_item_list(SP_GROUP(lpeitem)); for ( std::vector::const_iterator iter = item_list.begin(); iter != item_list.end(); iter++) { - SPObject *subitem = static_cast(*iter); + SPObject *subitem = *iter; if (SP_IS_LPE_ITEM(subitem)) { collectPathsAndWidths(SP_LPE_ITEM(subitem), paths, stroke_widths); } diff --git a/src/path-chemistry.cpp b/src/path-chemistry.cpp index 53ad96596..b128535bc 100644 --- a/src/path-chemistry.cpp +++ b/src/path-chemistry.cpp @@ -48,7 +48,7 @@ using Inkscape::DocumentUndo; inline bool less_than_items(SPItem const *first, SPItem const *second) { return sp_repr_compare_position(first->getRepr(), - second->getRepr())>0; + second->getRepr())<0; } void @@ -615,7 +615,7 @@ sp_selected_path_reverse(SPDesktop *desktop) for (std::vector::const_iterator i = items.begin(); i != items.end(); i++){ - SPPath *path = dynamic_cast(static_cast(*i)); + SPPath *path = dynamic_cast(*i); if (!path) { continue; } diff --git a/src/selcue.cpp b/src/selcue.cpp index 76eae3fa8..c73219b7d 100644 --- a/src/selcue.cpp +++ b/src/selcue.cpp @@ -203,7 +203,7 @@ void Inkscape::SelCue::_newTextBaselines() std::vector ll = _selection->itemList(); for (std::vector::const_iterator l=ll.begin();l!=ll.end();l++) { - SPItem *item = static_cast(*l); + SPItem *item = *l; SPCanvasItem* baseline_point = NULL; if (SP_IS_TEXT(item) || SP_IS_FLOWTEXT(item)) { // visualize baseline diff --git a/src/selection-chemistry.cpp b/src/selection-chemistry.cpp index d6f8b8a37..0100e1040 100644 --- a/src/selection-chemistry.cpp +++ b/src/selection-chemistry.cpp @@ -555,7 +555,7 @@ void sp_edit_clear_all(Inkscape::Selection *selection) std::vector items = sp_item_group_item_list(group); for(unsigned int i = 0; i < items.size(); i++){ - reinterpret_cast(items[i])->deleteObject(); + items[i]->deleteObject(); } DocumentUndo::done(doc, SP_VERB_EDIT_CLEAR_ALL, @@ -627,7 +627,7 @@ static void sp_edit_select_all_full(SPDesktop *dt, bool force_all_layers, bool i std::vector all_items = sp_item_group_item_list(dynamic_cast(dt->currentLayer())); for (std::vector::const_reverse_iterator i=all_items.rbegin();i!=all_items.rend();i++) { - SPItem *item = dynamic_cast(static_cast(*i)); + SPItem *item = *i; if (item && (!onlysensitive || !item->isLocked())) { if (!onlyvisible || !dt->itemIsHidden(item)) { @@ -683,8 +683,8 @@ static void sp_selection_group_impl(std::vector p, Inkscap sort(p.begin(),p.end(),sp_repr_compare_position); // Remember the position and parent of the topmost object. - gint topmost = (dynamic_cast(p.back()))->position(); - Inkscape::XML::Node *topmost_parent = (dynamic_cast(p.back()))->parent(); + gint topmost = p.back()->position(); + Inkscape::XML::Node *topmost_parent = p.back()->parent(); for(std::vector::const_iterator i = p.begin(); i != p.end(); i++){ Inkscape::XML::Node *current = *i; @@ -791,7 +791,7 @@ void sp_selection_ungroup(Inkscape::Selection *selection, SPDesktop *desktop) std::vector new_select; GSList *groups = NULL; for (std::vector::const_iterator item = old_select.begin(); item!=old_select.end(); item++) { - SPItem *obj = static_cast(*item); + SPItem *obj = *item; if (dynamic_cast(obj)) { groups = g_slist_prepend(groups, obj); } @@ -810,7 +810,7 @@ void sp_selection_ungroup(Inkscape::Selection *selection, SPDesktop *desktop) // in the items list. GSList *clones_to_unlink = NULL; for (std::vector::const_iterator item = items.begin(); item != items.end(); item++) { - SPUse *use = dynamic_cast(static_cast(*item)); + SPUse *use = dynamic_cast(*item); SPItem *original = use; while (dynamic_cast(original)) { @@ -864,7 +864,7 @@ sp_degroup_list(std::vector &items) std::vector out; bool has_groups = false; for (std::vector::const_iterator item=items.begin();item!=items.end();item++) { - SPGroup *group = dynamic_cast(static_cast(*item)); + SPGroup *group = dynamic_cast(*item); if (!group) { out.push_back(*item); } else { @@ -915,7 +915,7 @@ enclose_items(std::vector const &items) Geom::OptRect r; for (std::vector::const_iterator i = items.begin();i!=items.end();i++) { - r.unionWith(static_cast(*i)->desktopVisualBounds()); + r.unionWith((*i)->desktopVisualBounds()); } return r; } @@ -963,7 +963,7 @@ sp_selection_raise(Inkscape::Selection *selection, SPDesktop *desktop) // Iterate over all objects in the selection (starting from top). if (selected) { for (std::vector::const_iterator item=rev.begin();item!=rev.end();item++) { - SPObject *child = reinterpret_cast(*item); + SPObject *child = *item; // for each selected object, find the next sibling for (SPObject *newref = child->next; newref; newref = newref->next) { // if the sibling is an item AND overlaps our selection, @@ -1042,7 +1042,7 @@ void sp_selection_lower(Inkscape::Selection *selection, SPDesktop *desktop) // Iterate over all objects in the selection (starting from top). if (selected) { for (std::vector::const_reverse_iterator item=rev.rbegin();item!=rev.rend();item++) { - SPObject *child = reinterpret_cast(*item); + SPObject *child = *item; // for each selected object, find the prev sibling for (SPObject *newref = prev_sibling(child); newref; newref = prev_sibling(newref)) { // if the sibling is an item AND overlaps our selection, @@ -2053,7 +2053,7 @@ std::vector sp_get_same_style(SPItem *sel, std::vector &src, S } bool match_g; for (std::vector::const_iterator i=src.begin();i!=src.end();i++) { - SPItem *iter = dynamic_cast(static_cast(*i)); + SPItem *iter = *i; if (iter) { match_g=true; SPStyle *iter_style = iter->style; @@ -2356,7 +2356,7 @@ SPItem *next_item_from_list(SPDesktop *desktop, std::vector const items { SPObject *current=root; for(std::vector::const_iterator i = items.begin();i!=items.end();i++) { - SPItem *item = dynamic_cast(static_cast(*i)); + SPItem *item = *i; if ( root->isAncestorOf(item) && ( !only_in_viewport || desktop->isWithinViewport(item) ) ) { @@ -2925,7 +2925,7 @@ void sp_selection_to_marker(SPDesktop *desktop, bool apply) // Delete objects so that their clones don't get alerted; // the objects will be restored inside the marker element. for (std::vector::const_iterator i=items.begin();i!=items.end();i++){ - SPObject *item = reinterpret_cast(*i); + SPObject *item = *i; item->deleteObject(false); } } @@ -3280,7 +3280,7 @@ sp_selection_tile(SPDesktop *desktop, bool apply) if (apply) { // delete objects so that their clones don't get alerted; this object will be restored shortly for (std::vector::const_iterator i=items.begin();i!=items.end();i++){ - SPObject *item = reinterpret_cast(*i); + SPObject *item = *i; item->deleteObject(false); } } @@ -3354,7 +3354,7 @@ void sp_selection_untile(SPDesktop *desktop) std::vector items(selection->itemList()); for (std::vector::const_reverse_iterator i=items.rbegin();i!=items.rend();i++){ - SPItem *item = static_cast(*i); + SPItem *item = *i; SPStyle *style = item->style; @@ -3864,7 +3864,7 @@ void sp_selection_set_mask(SPDesktop *desktop, bool apply_clip_path, bool apply_ Inkscape::XML::Node *dup = SP_OBJECT(*i)->getRepr()->duplicate(xml_doc); mask_items = g_slist_prepend(mask_items, dup); - SPObject *item = reinterpret_cast(*i); + SPObject *item = *i; if (remove_original) { items_to_delete = g_slist_prepend(items_to_delete, item); } @@ -3878,7 +3878,7 @@ void sp_selection_set_mask(SPDesktop *desktop, bool apply_clip_path, bool apply_ mask_items = g_slist_prepend(mask_items, dup); if (remove_original) { - SPObject *item = reinterpret_cast(items.front()); + SPObject *item = items.front(); items_to_delete = g_slist_prepend(items_to_delete, item); } @@ -4055,7 +4055,7 @@ void sp_selection_unset_mask(SPDesktop *desktop, bool apply_clip_path) { SP_OBJECT(*i)->getRepr()->setAttribute(attributeName, "none"); - SPGroup *group = dynamic_cast(static_cast(*i)); + SPGroup *group = dynamic_cast(*i); if (ungroup_masked && group) { // if we had previously enclosed masked object in group, // add it to list so we can ungroup it later diff --git a/src/selection.cpp b/src/selection.cpp index 19e78512b..7e8190237 100644 --- a/src/selection.cpp +++ b/src/selection.cpp @@ -309,7 +309,7 @@ std::vector const &Selection::reprList() { if (!_reprs.empty()) { return _reprs; } std::vector list = itemList(); for ( std::vector::const_iterator iter=list.begin();iter!=list.end();iter++ ) { - SPObject *obj=reinterpret_cast(*iter); + SPObject *obj = *iter; _reprs.push_back(obj->getRepr()); } return _reprs; diff --git a/src/seltrans.cpp b/src/seltrans.cpp index 61d8a1ab1..bfb8d53f1 100644 --- a/src/seltrans.cpp +++ b/src/seltrans.cpp @@ -271,7 +271,7 @@ void Inkscape::SelTrans::grab(Geom::Point const &p, gdouble x, gdouble y, bool s std::vector items=_desktop->selection->itemList(); for ( std::vector::const_iterator iter=items.begin();iter!=items.end();iter++ ) { - SPItem *it = reinterpret_cast(sp_object_ref(SP_ITEM(*iter), NULL)); + SPItem *it = static_cast(sp_object_ref(*iter, NULL)); _items.push_back(it); _items_const.push_back(it); _items_affines.push_back(it->i2dt_affine()); diff --git a/src/sp-item-group.cpp b/src/sp-item-group.cpp index 620c0b70f..64ad9ff43 100644 --- a/src/sp-item-group.cpp +++ b/src/sp-item-group.cpp @@ -818,7 +818,7 @@ void SPGroup::update_patheffect(bool write) { std::vector const item_list = sp_item_group_item_list(this); for ( std::vector::const_iterator iter=item_list.begin();iter!=item_list.end();iter++) { - SPObject *subitem = static_cast(*iter); + SPObject *subitem = *iter; SPLPEItem *lpeItem = dynamic_cast(subitem); if (lpeItem) { @@ -846,7 +846,7 @@ sp_group_perform_patheffect(SPGroup *group, SPGroup *topgroup, bool write) std::vector const item_list = sp_item_group_item_list(group); for ( std::vector::const_iterator iter=item_list.begin();iter!=item_list.end();iter++) { - SPObject *subitem = static_cast(*iter); + SPObject *subitem = *iter; SPGroup *subGroup = dynamic_cast(subitem); if (subGroup) { diff --git a/src/sp-lpe-item.cpp b/src/sp-lpe-item.cpp index 1f4704e22..6228f3692 100644 --- a/src/sp-lpe-item.cpp +++ b/src/sp-lpe-item.cpp @@ -355,7 +355,7 @@ sp_lpe_item_create_original_path_recursive(SPLPEItem *lpeitem) if (SP_IS_GROUP(lpeitem)) { std::vector item_list = sp_item_group_item_list(SP_GROUP(lpeitem)); for ( std::vector::const_iterator iter=item_list.begin();iter!=item_list.end();iter++) { - SPObject *subitem = static_cast(*iter); + SPObject *subitem = *iter; if (SP_IS_LPE_ITEM(subitem)) { sp_lpe_item_create_original_path_recursive(SP_LPE_ITEM(subitem)); } @@ -389,7 +389,7 @@ sp_lpe_item_cleanup_original_path_recursive(SPLPEItem *lpeitem) } std::vector item_list = sp_item_group_item_list(SP_GROUP(lpeitem)); for ( std::vector::const_iterator iter=item_list.begin();iter!=item_list.end();iter++) { - SPObject *subitem = static_cast(*iter); + SPObject *subitem = *iter; if (SP_IS_LPE_ITEM(subitem)) { sp_lpe_item_cleanup_original_path_recursive(SP_LPE_ITEM(subitem)); } @@ -682,7 +682,7 @@ SPLPEItem::apply_to_clippath(SPItem *item) if(SP_IS_GROUP(item)){ std::vector item_list = sp_item_group_item_list(SP_GROUP(item)); for ( std::vector::const_iterator iter=item_list.begin();iter!=item_list.end();iter++) { - SPObject *subitem = static_cast(*iter); + SPObject *subitem = *iter; apply_to_clippath(SP_ITEM(subitem)); } } @@ -734,7 +734,7 @@ SPLPEItem::apply_to_mask(SPItem *item) if(SP_IS_GROUP(item)){ std::vector item_list = sp_item_group_item_list(SP_GROUP(item)); for ( std::vector::const_iterator iter=item_list.begin();iter!=item_list.end();iter++) { - SPObject *subitem = static_cast(*iter); + SPObject *subitem = *iter; apply_to_mask(SP_ITEM(subitem)); } } @@ -748,7 +748,7 @@ SPLPEItem::apply_to_clip_or_mask_group(SPItem *group, SPItem *item) } std::vector item_list = sp_item_group_item_list(SP_GROUP(group)); for ( std::vector::const_iterator iter=item_list.begin();iter!=item_list.end();iter++) { - SPObject *subitem = static_cast(*iter); + SPObject *subitem = *iter; if (SP_IS_GROUP(subitem)) { apply_to_clip_or_mask_group(SP_ITEM(subitem), item); } else if (SP_IS_SHAPE(subitem)) { diff --git a/src/splivarot.cpp b/src/splivarot.cpp index bc09802f0..c668199c0 100644 --- a/src/splivarot.cpp +++ b/src/splivarot.cpp @@ -667,7 +667,7 @@ sp_selected_path_boolop(Inkscape::Selection *selection, SPDesktop *desktop, bool { // only one command, presumably a moveto: it isn't a path for (std::vector::const_iterator l = il.begin(); l != il.end(); l++){ - SP_OBJECT(*l)->deleteObject(); + (*l)->deleteObject(); } DocumentUndo::done(doc, SP_VERB_NONE, description); selection->clear(); @@ -680,9 +680,9 @@ sp_selected_path_boolop(Inkscape::Selection *selection, SPDesktop *desktop, bool SPObject *source; if ( bop == bool_op_diff || bop == bool_op_cut || bop == bool_op_slice ) { if (reverseOrderForOp) { - source = SP_OBJECT(il[0]); + source = il[0]; } else { - source = SP_OBJECT(il.back()); + source = il.back(); } } else { // find out the bottom object @@ -719,10 +719,10 @@ sp_selected_path_boolop(Inkscape::Selection *selection, SPDesktop *desktop, bool // if this is the bottommost object, if (!strcmp(reinterpret_cast(*l)->getRepr()->attribute("id"), id)) { // delete it so that its clones don't get alerted; this object will be restored shortly, with the same id - SP_OBJECT(*l)->deleteObject(false); + (*l)->deleteObject(false); } else { // delete the object for real, so that its clones can take appropriate action - SP_OBJECT(*l)->deleteObject(); + (*l)->deleteObject(); } } diff --git a/src/text-chemistry.cpp b/src/text-chemistry.cpp index eadab90dd..5d57ac020 100644 --- a/src/text-chemistry.cpp +++ b/src/text-chemistry.cpp @@ -198,7 +198,7 @@ text_remove_from_path() bool did = false; std::vector items(selection->itemList()); for(std::vector::const_iterator i=items.begin();i!=items.end();i++){ - SPObject *obj = SP_OBJECT(*i); + SPObject *obj = *i; if (SP_IS_TEXT_TEXTPATH(obj)) { SPObject *tp = obj->firstChild(); @@ -262,7 +262,7 @@ text_remove_all_kerns() std::vector items = selection->itemList(); for(std::vector::const_iterator i=items.begin();i!=items.end();i++){ - SPObject *obj = SP_OBJECT(*i); + SPObject *obj = *i; if (!SP_IS_TEXT(obj) && !SP_IS_TSPAN(obj) && !SP_IS_FLOWTEXT(obj)) { continue; @@ -322,7 +322,7 @@ text_flow_into_shape() /* Add clones */ std::vector items = selection->itemList(); for(std::vector::const_iterator i=items.begin();i!=items.end();i++){ - SPItem *item = SP_ITEM(*i); + SPItem *item = *i; if (SP_IS_SHAPE(item)){ Inkscape::XML::Node *clone = xml_doc->createElement("svg:use"); clone->setAttribute("x", "0"); @@ -398,7 +398,7 @@ text_unflow () std::vector items = selection->itemList(); for(std::vector::const_reverse_iterator i=items.rbegin();i!=items.rend();i++){ - if (!SP_IS_FLOWTEXT(SP_OBJECT(*i))) { + if (!SP_IS_FLOWTEXT(*i)) { continue; } diff --git a/src/ui/clipboard.cpp b/src/ui/clipboard.cpp index a38a52371..3fe935e7d 100644 --- a/src/ui/clipboard.cpp +++ b/src/ui/clipboard.cpp @@ -706,7 +706,7 @@ void ClipboardManagerImpl::_copySelection(Inkscape::Selection *selection) // copy style for Paste Style action if (!sorted_items.empty()) { - SPObject *object = static_cast(sorted_items[0]); + SPObject *object = sorted_items[0]; SPItem *item = dynamic_cast(object); if (item) { SPCSSAttr *style = take_style_from_item(item); diff --git a/src/ui/dialog/filter-effects-dialog.cpp b/src/ui/dialog/filter-effects-dialog.cpp index 45c8ce68a..cb2771503 100644 --- a/src/ui/dialog/filter-effects-dialog.cpp +++ b/src/ui/dialog/filter-effects-dialog.cpp @@ -1467,7 +1467,7 @@ void FilterEffectsDialog::FilterModifier::update_selection(Selection *sel) std::set used; std::vector itemlist=sel->itemList(); for(std::vector::const_iterator i=itemlist.begin(); itemlist.end() != i; i++) { - SPObject *obj = SP_OBJECT (*i); + SPObject *obj = *i; SPStyle *style = obj->style; if (!style || !SP_IS_ITEM(obj)) { continue; diff --git a/src/ui/dialog/find.cpp b/src/ui/dialog/find.cpp index dde040036..173acca93 100644 --- a/src/ui/dialog/find.cpp +++ b/src/ui/dialog/find.cpp @@ -562,7 +562,7 @@ std::vector Find::filter_fields (std::vector &l, bool exact, b if (check_searchin_text.get_active()) { for(std::vector::const_reverse_iterator i=in.rbegin(); in.rend() != i; i++) { - SPObject *obj = SP_OBJECT (*i); + SPObject *obj = *i; SPItem *item = dynamic_cast(obj); g_assert(item != NULL); if (item_text_match(item, text, exact, casematch)) { @@ -585,7 +585,7 @@ std::vector Find::filter_fields (std::vector &l, bool exact, b if (ids) { for(std::vector::const_reverse_iterator i=in.rbegin(); in.rend() != i; i++) { - SPObject *obj = SP_OBJECT (*i); + SPObject *obj = *i; SPItem *item = dynamic_cast(obj); if (item_id_match(item, text, exact, casematch)) { if (out.end()==find(out.begin(),out.end(), *i)) { @@ -601,7 +601,7 @@ std::vector Find::filter_fields (std::vector &l, bool exact, b if (style) { for(std::vector::const_reverse_iterator i=in.rbegin(); in.rend() != i; i++) { - SPObject *obj = SP_OBJECT (*i); + SPObject *obj = *i; SPItem *item = dynamic_cast(obj); g_assert(item != NULL); if (item_style_match(item, text, exact, casematch)) { @@ -618,7 +618,7 @@ std::vector Find::filter_fields (std::vector &l, bool exact, b if (attrname) { for(std::vector::const_reverse_iterator i=in.rbegin(); in.rend() != i; i++) { - SPObject *obj = SP_OBJECT (*i); + SPObject *obj = *i; SPItem *item = dynamic_cast(obj); g_assert(item != NULL); if (item_attr_match(item, text, exact, casematch)) { @@ -635,7 +635,7 @@ std::vector Find::filter_fields (std::vector &l, bool exact, b if (attrvalue) { for(std::vector::const_reverse_iterator i=in.rbegin(); in.rend() != i; i++) { - SPObject *obj = SP_OBJECT (*i); + SPObject *obj = *i; SPItem *item = dynamic_cast(obj); g_assert(item != NULL); if (item_attrvalue_match(item, text, exact, casematch)) { @@ -652,7 +652,7 @@ std::vector Find::filter_fields (std::vector &l, bool exact, b if (font) { for(std::vector::const_reverse_iterator i=in.rbegin(); in.rend() != i; i++) { - SPObject *obj = SP_OBJECT (*i); + SPObject *obj = *i; SPItem *item = dynamic_cast(obj); g_assert(item != NULL); if (item_font_match(item, text, exact, casematch)) { @@ -719,7 +719,7 @@ std::vector Find::filter_types (std::vector &l) { std::vector n; for(std::vector::const_reverse_iterator i=l.rbegin(); l.rend() != i; i++) { - SPObject *obj = SP_OBJECT (*i); + SPObject *obj = *i; SPItem *item = dynamic_cast(obj); g_assert(item != NULL); if (item_type_match(item)) { @@ -763,7 +763,7 @@ std::vector &Find::all_selection_items (Inkscape::Selection *s, std::ve { std::vector itemlist=s->itemList(); for(std::vector::const_iterator i=itemlist.begin(); itemlist.end() != i; i++) { - SPObject *obj = SP_OBJECT (*i); + SPObject *obj = *i; SPItem *item = dynamic_cast(obj); g_assert(item != NULL); if (item && !item->cloned && !desktop->isLayer(item)) { @@ -857,7 +857,7 @@ void Find::onAction() Inkscape::Selection *selection = desktop->getSelection(); selection->clear(); selection->setList(n); - SPObject *obj = reinterpret_cast(n[0]); + SPObject *obj = n[0]; SPItem *item = dynamic_cast(obj); g_assert(item != NULL); scroll_to_show_item(desktop, item); diff --git a/src/ui/dialog/grid-arrange-tab.cpp b/src/ui/dialog/grid-arrange-tab.cpp index 8bd130c2e..4465d73a9 100644 --- a/src/ui/dialog/grid-arrange-tab.cpp +++ b/src/ui/dialog/grid-arrange-tab.cpp @@ -210,7 +210,7 @@ void GridArrangeTab::arrange() cnt=0; const std::vector sizes(sorted); for (std::vector::const_iterator i = sizes.begin();i!=sizes.end();i++) { - SPItem *item = SP_ITEM(*i); + SPItem *item = *i; Geom::OptRect b = item->documentVisualBounds(); if (b) { width = b->dimensions()[Geom::X]; diff --git a/src/ui/dialog/tags.cpp b/src/ui/dialog/tags.cpp index 5fab9fcfc..ed71c826f 100644 --- a/src/ui/dialog/tags.cpp +++ b/src/ui/dialog/tags.cpp @@ -652,7 +652,7 @@ bool TagsPanel::_handleButtonEvent(GdkEventButton* event) bool wasadded = false; std::vector items=_desktop->selection->itemList(); for(std::vector::const_iterator i=items.begin();i!=items.end();i++){ - SPObject *newobj = reinterpret_cast(*i); + SPObject *newobj = *i; bool addchild = true; for ( SPObject *child = obj->children; child != NULL; child = child->next) { if (SP_IS_TAG_USE(child) && SP_TAG_USE(child)->ref->getObject() == newobj) { diff --git a/src/ui/dialog/text-edit.cpp b/src/ui/dialog/text-edit.cpp index 9c4790379..815aa12ef 100644 --- a/src/ui/dialog/text-edit.cpp +++ b/src/ui/dialog/text-edit.cpp @@ -549,7 +549,7 @@ void TextEdit::onApply() if (SP_IS_TEXT (*i)) { // backwards compatibility: - reinterpret_cast(*i)->getRepr()->setAttribute("sodipodi:linespacing", sp_repr_css_property (css, "line-height", NULL)); + (*i)->getRepr()->setAttribute("sodipodi:linespacing", sp_repr_css_property (css, "line-height", NULL)); ++items; } diff --git a/src/ui/tools/gradient-tool.cpp b/src/ui/tools/gradient-tool.cpp index 21ad18c26..a9e109b5c 100644 --- a/src/ui/tools/gradient-tool.cpp +++ b/src/ui/tools/gradient-tool.cpp @@ -934,7 +934,7 @@ static void sp_gradient_drag(GradientTool &rc, Geom::Point const pt, guint /*sta sp_item_gradient_set_coords (*i, POINT_RG_CENTER, 0, rc.origin, fill_or_stroke, true, false); sp_item_gradient_set_coords (*i, POINT_RG_R1, 0, pt, fill_or_stroke, true, false); } - SP_OBJECT(*i)->requestModified(SP_OBJECT_MODIFIED_FLAG); + (*i)->requestModified(SP_OBJECT_MODIFIED_FLAG); } if (ec->_grdrag) { ec->_grdrag->updateDraggers(); diff --git a/src/ui/tools/mesh-tool.cpp b/src/ui/tools/mesh-tool.cpp index c8e032089..2c817694e 100644 --- a/src/ui/tools/mesh-tool.cpp +++ b/src/ui/tools/mesh-tool.cpp @@ -965,13 +965,13 @@ static void sp_mesh_drag(MeshTool &rc, Geom::Point const /*pt*/, guint /*state*/ for(std::vector::const_iterator i=items.begin();i!=items.end();i++){ //FIXME: see above - sp_repr_css_change_recursive(SP_OBJECT(*i)->getRepr(), css, "style"); + sp_repr_css_change_recursive((*i)->getRepr(), css, "style"); - sp_item_set_gradient(SP_ITEM(*i), vector, (SPGradientType) type, fill_or_stroke); + sp_item_set_gradient(*i, vector, (SPGradientType) type, fill_or_stroke); // We don't need to do anything. Mesh is already sized appropriately. - SP_OBJECT(*i)->requestModified(SP_OBJECT_MODIFIED_FLAG); + (*i)->requestModified(SP_OBJECT_MODIFIED_FLAG); } // if (ec->_grdrag) { // ec->_grdrag->updateDraggers(); diff --git a/src/ui/tools/node-tool.cpp b/src/ui/tools/node-tool.cpp index 6ddb379cc..374386686 100644 --- a/src/ui/tools/node-tool.cpp +++ b/src/ui/tools/node-tool.cpp @@ -422,7 +422,7 @@ void NodeTool::selection_changed(Inkscape::Selection *sel) { std::vector items=sel->itemList(); for(std::vector::const_iterator i=items.begin();i!=items.end();i++){ - SPObject *obj = static_cast(*i); + SPObject *obj = *i; if (SP_IS_ITEM(obj)) { gather_items(this, NULL, static_cast(obj), SHAPE_ROLE_NORMAL, shapes); diff --git a/src/ui/widget/style-subject.cpp b/src/ui/widget/style-subject.cpp index 1ded546dd..95b89bf5f 100644 --- a/src/ui/widget/style-subject.cpp +++ b/src/ui/widget/style-subject.cpp @@ -114,7 +114,7 @@ void StyleSubject::CurrentLayer::_setLayer(SPObject *layer) { _layer_release.disconnect(); _layer_modified.disconnect(); if (_element) { - sp_object_unref(static_cast(_element), NULL); + sp_object_unref(_element, NULL); } _element = layer; if (layer) { @@ -126,7 +126,7 @@ void StyleSubject::CurrentLayer::_setLayer(SPObject *layer) { } SPObject *StyleSubject::CurrentLayer::_getLayer() const { - return static_cast(_element); + return _element; } SPObject *StyleSubject::CurrentLayer::_getLayerSList() const { diff --git a/src/widgets/fill-style.cpp b/src/widgets/fill-style.cpp index 7d5a89cf5..1d258bbb0 100644 --- a/src/widgets/fill-style.cpp +++ b/src/widgets/fill-style.cpp @@ -579,7 +579,7 @@ void FillNStroke::updateFromPaint() for(std::vector::const_iterator i=items.begin();i!=items.end();i++){ //FIXME: see above if (kind == FILL) { - sp_repr_css_change_recursive(reinterpret_cast(*i)->getRepr(), css, "style"); + sp_repr_css_change_recursive((*i)->getRepr(), css, "style"); } if (!vector) { @@ -605,7 +605,7 @@ void FillNStroke::updateFromPaint() for(std::vector::const_iterator i=items.begin();i!=items.end();i++){ //FIXME: see above if (kind == FILL) { - sp_repr_css_change_recursive(reinterpret_cast(*i)->getRepr(), css, "style"); + sp_repr_css_change_recursive((*i)->getRepr(), css, "style"); } SPGradient *gr = sp_item_set_gradient(*i, vector, gradient_type, (kind == FILL) ? Inkscape::FOR_FILL : Inkscape::FOR_STROKE); @@ -649,11 +649,11 @@ void FillNStroke::updateFromPaint() // objects who already have the same root pattern but through a different href // chain. FIXME: move this to a sp_item_set_pattern for(std::vector::const_iterator i=items.begin();i!=items.end();i++){ - Inkscape::XML::Node *selrepr = reinterpret_cast(*i)->getRepr(); + Inkscape::XML::Node *selrepr = (*i)->getRepr(); if ( (kind == STROKE) && !selrepr) { continue; } - SPObject *selobj = reinterpret_cast(*i); + SPObject *selobj = *i; SPStyle *style = selobj->style; if (style && ((kind == FILL) ? style->fill : style->stroke).isPaintserver()) { diff --git a/src/widgets/rect-toolbar.cpp b/src/widgets/rect-toolbar.cpp index 2b07dd3b9..37ffd7553 100644 --- a/src/widgets/rect-toolbar.cpp +++ b/src/widgets/rect-toolbar.cpp @@ -112,7 +112,7 @@ static void sp_rtb_value_changed(GtkAdjustment *adj, GObject *tbl, gchar const * if (gtk_adjustment_get_value(adj) != 0) { (SP_RECT(*i)->*setter)(Quantity::convert(gtk_adjustment_get_value(adj), unit, desktop->getNamedView()->svg_units)); } else { - SP_OBJECT(*i)->getRepr()->setAttribute(value_name, NULL); + (*i)->getRepr()->setAttribute(value_name, NULL); } modmade = true; } diff --git a/src/widgets/stroke-style.cpp b/src/widgets/stroke-style.cpp index c05ef93e7..481fa0609 100644 --- a/src/widgets/stroke-style.cpp +++ b/src/widgets/stroke-style.cpp @@ -983,7 +983,7 @@ StrokeStyle::scaleLine() if (unit->type == Inkscape::Util::UNIT_TYPE_LINEAR) { width = Inkscape::Util::Quantity::convert(width_typed, unit, "px"); } else { // percentage - gdouble old_w = SP_OBJECT(*i)->style->stroke_width.computed; + gdouble old_w = (*i)->style->stroke_width.computed; width = old_w * width_typed / 100; } @@ -1167,7 +1167,7 @@ StrokeStyle::updateAllMarkers(std::vector const &objects) // We show markers of the first object in the list only // FIXME: use the first in the list that has the marker of each type, if any - SPObject *object = SP_OBJECT(objects[0]); + SPObject *object = objects[0]; for (unsigned i = 0; i < G_N_ELEMENTS(keyloc); ++i) { // For all three marker types, diff --git a/src/widgets/text-toolbar.cpp b/src/widgets/text-toolbar.cpp index 6b0fb34e6..2160cad2e 100644 --- a/src/widgets/text-toolbar.cpp +++ b/src/widgets/text-toolbar.cpp @@ -522,7 +522,7 @@ static void sp_text_lineheight_value_changed( GtkAdjustment *adj, GObject *tbl ) std::vector itemlist=selection->itemList(); for(std::vector::const_iterator i=itemlist.begin();i!=itemlist.end();i++){ if (SP_IS_TEXT (*i)) { - SP_OBJECT(*i)->getRepr()->setAttribute("sodipodi:linespacing", sp_repr_css_property (css, "line-height", NULL)); + (*i)->getRepr()->setAttribute("sodipodi:linespacing", sp_repr_css_property (css, "line-height", NULL)); modmade = true; } } -- cgit v1.2.3 From 3c37a2f5b4779c78ff90f6194dcb5b32244306f3 Mon Sep 17 00:00:00 2001 From: Jabier Arraiza Cenoz Date: Mon, 13 Apr 2015 23:01:49 +0200 Subject: Fix for the bug 1443039. Now reset old perspective-envelope effects and prevent crash, also when all handles go to the same position Fixed bugs: - https://launchpad.net/bugs/1443039 (bzr r14056) --- src/live_effects/lpe-perspective-envelope.cpp | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'src') diff --git a/src/live_effects/lpe-perspective-envelope.cpp b/src/live_effects/lpe-perspective-envelope.cpp index 4eac2d6eb..fc59fb333 100644 --- a/src/live_effects/lpe-perspective-envelope.cpp +++ b/src/live_effects/lpe-perspective-envelope.cpp @@ -63,6 +63,13 @@ void LPEPerspectiveEnvelope::doEffect(SPCurve *curve) { using Geom::X; using Geom::Y; + if(are_near(up_left_point, up_right_point) && + are_near(up_right_point, down_left_point) && + are_near(down_left_point, down_right_point)) { + g_warning("Perspective/Envelope LPE::doBeforeEffect - lpeobj with invalid parameter, the same value in 4 handles!"); + resetGrid(); + return; + } double projmatrix[3][3]; if(deform_type == DEFORMATION_PERSPECTIVE) { std::vector handles(4); -- cgit v1.2.3 From 0f8b775f3a02380dd593ae58ad3b989f58aec643 Mon Sep 17 00:00:00 2001 From: Tavmjong Bah Date: Tue, 14 Apr 2015 14:44:34 +0200 Subject: Replace GList by std::vector (bzr r14057) --- src/ui/tools/flood-tool.cpp | 54 +++++++++++++++---------------------- src/ui/tools/flood-tool.h | 6 ++--- src/widgets/paintbucket-toolbar.cpp | 21 +++++++-------- 3 files changed, 34 insertions(+), 47 deletions(-) (limited to 'src') diff --git a/src/ui/tools/flood-tool.cpp b/src/ui/tools/flood-tool.cpp index bb8782dfa..ffd41d97d 100644 --- a/src/ui/tools/flood-tool.cpp +++ b/src/ui/tools/flood-tool.cpp @@ -84,6 +84,28 @@ const std::string& FloodTool::getPrefsPath() { const std::string FloodTool::prefsPath = "/tools/paintbucket"; +// TODO: Replace by C++11 initialization +// Must match PaintBucketChannels enum +Glib::ustring ch_init[8] = { + _("Visible Colors"), + _("Red"), + _("Green"), + _("Blue"), + _("Hue"), + _("Saturation"), + _("Lightness"), + _("Alpha"), +}; +const std::vector FloodTool::channel_list( ch_init, ch_init+8 ); + +Glib::ustring gap_init[4] = { + C_("Flood autogap", "None"), + C_("Flood autogap", "Small"), + C_("Flood autogap", "Medium"), + C_("Flood autogap", "Large") +}; +const std::vector FloodTool::gap_list( gap_init, gap_init+4 ); + FloodTool::FloodTool() : ToolBase(cursor_paintbucket_xpm, 11, 30) , item(NULL) @@ -173,38 +195,6 @@ inline unsigned char * get_trace_pixel(guchar *trace_px, int x, int y, int width return trace_px + (x + y * width); } -/** - * Generate the list of trace channel selection entries. - */ -GList * flood_channels_dropdown_items_list() { - GList *glist = NULL; - - glist = g_list_append (glist, _("Visible Colors")); - glist = g_list_append (glist, _("Red")); - glist = g_list_append (glist, _("Green")); - glist = g_list_append (glist, _("Blue")); - glist = g_list_append (glist, _("Hue")); - glist = g_list_append (glist, _("Saturation")); - glist = g_list_append (glist, _("Lightness")); - glist = g_list_append (glist, _("Alpha")); - - return glist; -} - -/** - * Generate the list of autogap selection entries. - */ -GList * flood_autogap_dropdown_items_list() { - GList *glist = NULL; - - glist = g_list_append (glist, (void*) C_("Flood autogap", "None")); - glist = g_list_append (glist, (void*) C_("Flood autogap", "Small")); - glist = g_list_append (glist, (void*) C_("Flood autogap", "Medium")); - glist = g_list_append (glist, (void*) C_("Flood autogap", "Large")); - - return glist; -} - /** * Compare a pixel in a pixel buffer with another pixel to determine if a point should be included in the fill operation. * @param check The pixel in the pixel buffer to check. diff --git a/src/ui/tools/flood-tool.h b/src/ui/tools/flood-tool.h index 5104a42e9..100875f22 100644 --- a/src/ui/tools/flood-tool.h +++ b/src/ui/tools/flood-tool.h @@ -13,6 +13,7 @@ #include #include "ui/tools/tool-base.h" +#include #define SP_FLOOD_CONTEXT(obj) (dynamic_cast((Inkscape::UI::Tools::ToolBase*)obj)) #define SP_IS_FLOOD_CONTEXT(obj) (dynamic_cast((const Inkscape::UI::Tools::ToolBase*)obj) != NULL) @@ -39,15 +40,14 @@ public: virtual const std::string& getPrefsPath(); static void set_channels(gint channels); + static const std::vector channel_list; + static const std::vector gap_list; private: void selection_changed(Inkscape::Selection* selection); void finishItem(); }; -GList* flood_channels_dropdown_items_list (void); -GList* flood_autogap_dropdown_items_list (void); - enum PaintBucketChannels { FLOOD_CHANNELS_RGB, FLOOD_CHANNELS_R, diff --git a/src/widgets/paintbucket-toolbar.cpp b/src/widgets/paintbucket-toolbar.cpp index d8edeb9f6..eb55287c4 100644 --- a/src/widgets/paintbucket-toolbar.cpp +++ b/src/widgets/paintbucket-toolbar.cpp @@ -121,17 +121,16 @@ void sp_paintbucket_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions { GtkListStore* model = gtk_list_store_new( 2, G_TYPE_STRING, G_TYPE_INT ); - GList* items = 0; gint count = 0; - for ( items = Inkscape::UI::Tools::flood_channels_dropdown_items_list(); items ; items = g_list_next(items) ) - { + const std::vector& channel_list = Inkscape::UI::Tools::FloodTool::channel_list; + for (std::vector::const_iterator iterator = channel_list.begin(); + iterator != channel_list.end(); ++iterator ) { GtkTreeIter iter; gtk_list_store_append( model, &iter ); - gtk_list_store_set( model, &iter, 0, reinterpret_cast(items->data), 1, count, -1 ); + gtk_list_store_set( model, &iter, 0, (*iterator).c_str(), 1, count, -1 ); count++; } - g_list_free( items ); - items = 0; + EgeSelectOneAction* act1 = ege_select_one_action_new( "ChannelsAction", _("Fill by"), (""), NULL, GTK_TREE_MODEL(model) ); g_object_set( act1, "short_label", _("Fill by:"), NULL ); ege_select_one_action_set_appearance( act1, "compact" ); @@ -188,17 +187,15 @@ void sp_paintbucket_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions { GtkListStore* model = gtk_list_store_new( 2, G_TYPE_STRING, G_TYPE_INT ); - GList* items = 0; gint count = 0; - for ( items = Inkscape::UI::Tools::flood_autogap_dropdown_items_list(); items ; items = g_list_next(items) ) - { + const std::vector& gap_list = Inkscape::UI::Tools::FloodTool::gap_list; + for (std::vector::const_iterator iterator = gap_list.begin(); + iterator != gap_list.end(); ++iterator ) { GtkTreeIter iter; gtk_list_store_append( model, &iter ); - gtk_list_store_set( model, &iter, 0, reinterpret_cast(items->data), 1, count, -1 ); + gtk_list_store_set( model, &iter, 0, (*iterator).c_str(), 1, count, -1 ); count++; } - g_list_free( items ); - items = 0; EgeSelectOneAction* act2 = ege_select_one_action_new( "AutoGapAction", _("Close gaps"), (""), NULL, GTK_TREE_MODEL(model) ); g_object_set( act2, "short_label", _("Close gaps:"), NULL ); ege_select_one_action_set_appearance( act2, "compact" ); -- cgit v1.2.3 From f752dab8b460b9ca069d444930f65b3d41f67695 Mon Sep 17 00:00:00 2001 From: Jabier Arraiza Cenoz Date: Tue, 21 Apr 2015 19:46:29 +0200 Subject: Add mirror symmetry to envelope/perspective LPE (bzr r14058) --- src/live_effects/lpe-perspective-envelope.cpp | 57 ++++++++++++++++++++++++++- src/live_effects/lpe-perspective-envelope.h | 6 +++ 2 files changed, 62 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/live_effects/lpe-perspective-envelope.cpp b/src/live_effects/lpe-perspective-envelope.cpp index fc59fb333..08100bb2d 100644 --- a/src/live_effects/lpe-perspective-envelope.cpp +++ b/src/live_effects/lpe-perspective-envelope.cpp @@ -40,7 +40,8 @@ static const Util::EnumDataConverter DeformationTypeConverter(Deformat LPEPerspectiveEnvelope::LPEPerspectiveEnvelope(LivePathEffectObject *lpeobject) : Effect(lpeobject), - // initialise your parameters here: + horizontal_mirror(_("Mirror movements in horizontal"), _("Mirror movements in horizontal"), "horizontal_mirror", &wr, this, false), + vertical_mirror(_("Mirror movements in vertical"), _("Mirror movements in vertical"), "vertical_mirror", &wr, this, false), deform_type(_("Type"), _("Select the type of deformation"), "deform_type", DeformationTypeConverter, &wr, this, DEFORMATION_PERSPECTIVE), up_left_point(_("Top Left"), _("Top Left - Ctrl+Alt+Click: reset, Ctrl: move along axes"), "up_left_point", &wr, this), up_right_point(_("Top Right"), _("Top Right - Ctrl+Alt+Click: reset, Ctrl: move along axes"), "up_right_point", &wr, this), @@ -49,6 +50,8 @@ LPEPerspectiveEnvelope::LPEPerspectiveEnvelope(LivePathEffectObject *lpeobject) { // register all your parameters here, so Inkscape knows which parameters this effect has: registerParameter(&deform_type); + registerParameter(&horizontal_mirror); + registerParameter(&vertical_mirror); registerParameter(&up_left_point); registerParameter(&up_right_point); registerParameter(&down_left_point); @@ -312,10 +315,62 @@ LPEPerspectiveEnvelope::newWidget() return dynamic_cast(vbox); } +void +LPEPerspectiveEnvelope::vertical(PointParam ¶m_one, PointParam ¶m_two, Geom::Line vert) +{ + Geom::Point A = param_one; + Geom::Point B = param_two; + double Y = (A[Geom::Y] + B[Geom::Y])/2; + A[Geom::Y] = Y; + B[Geom::Y] = Y; + Geom::Point nearest = vert.pointAt(vert.nearestPoint(A)); + double distance_one = Geom::distance(A,nearest); + double distance_two = Geom::distance(B,nearest); + double distance_middle = (distance_one + distance_two)/2; + if(A[Geom::X] > B[Geom::X]) { + distance_middle *= -1; + } + A[Geom::X] = nearest[Geom::X] - distance_middle; + B[Geom::X] = nearest[Geom::X] + distance_middle; + param_one.param_setValue(A, true); + param_two.param_setValue(B, true); +} + +void +LPEPerspectiveEnvelope::horizontal(PointParam ¶m_one, PointParam ¶m_two, Geom::Line horiz) +{ + Geom::Point A = param_one; + Geom::Point B = param_two; + double X = (A[Geom::X] + B[Geom::X])/2; + A[Geom::X] = X; + B[Geom::X] = X; + Geom::Point nearest = horiz.pointAt(horiz.nearestPoint(A)); + double distance_one = Geom::distance(A,nearest); + double distance_two = Geom::distance(B,nearest); + double distance_middle = (distance_one + distance_two)/2; + if(A[Geom::Y] > B[Geom::Y]) { + distance_middle *= -1; + } + A[Geom::Y] = nearest[Geom::Y] - distance_middle; + B[Geom::Y] = nearest[Geom::Y] + distance_middle; + param_one.param_setValue(A, true); + param_two.param_setValue(B, true); +} + void LPEPerspectiveEnvelope::doBeforeEffect (SPLPEItem const* lpeitem) { original_bbox(lpeitem); + Geom::Line vert(Geom::Point(boundingbox_X.middle(),boundingbox_Y.max()), Geom::Point(boundingbox_X.middle(), boundingbox_Y.min())); + Geom::Line horiz(Geom::Point(boundingbox_X.min(),boundingbox_Y.middle()), Geom::Point(boundingbox_X.max(), boundingbox_Y.middle())); + if(vertical_mirror) { + vertical(up_left_point, up_right_point,vert); + vertical(down_left_point, down_right_point,vert); + } + if(horizontal_mirror) { + horizontal(up_left_point, down_left_point,horiz); + horizontal(up_right_point, down_right_point,horiz); + } SPLPEItem * item = const_cast(lpeitem); item->apply_to_clippath(item); item->apply_to_mask(item); diff --git a/src/live_effects/lpe-perspective-envelope.h b/src/live_effects/lpe-perspective-envelope.h index e25f059a3..dd14dc212 100644 --- a/src/live_effects/lpe-perspective-envelope.h +++ b/src/live_effects/lpe-perspective-envelope.h @@ -42,6 +42,10 @@ public: virtual void resetDefaults(SPItem const* item); + virtual void vertical(PointParam ¶mA,PointParam ¶mB, Geom::Line vert); + + virtual void horizontal(PointParam ¶mA,PointParam ¶mB,Geom::Line horiz); + virtual void doBeforeEffect(SPLPEItem const* lpeitem); virtual Gtk::Widget * newWidget(); @@ -54,6 +58,8 @@ protected: void addCanvasIndicators(SPLPEItem const */*lpeitem*/, std::vector &hp_vec); private: + BoolParam horizontal_mirror; + BoolParam vertical_mirror; EnumParam deform_type; PointParam up_left_point; PointParam up_right_point; -- cgit v1.2.3 From 746649e82ce4b1ea144dabdee26d4abab510cce8 Mon Sep 17 00:00:00 2001 From: Marc Jeanmougin Date: Sun, 26 Apr 2015 14:23:26 +0200 Subject: fix (bzr r13922.1.14) --- src/widgets/rect-toolbar.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/widgets/rect-toolbar.cpp b/src/widgets/rect-toolbar.cpp index 29a10a534..96ba699dc 100644 --- a/src/widgets/rect-toolbar.cpp +++ b/src/widgets/rect-toolbar.cpp @@ -110,7 +110,7 @@ static void sp_rtb_value_changed(GtkAdjustment *adj, GObject *tbl, gchar const * for(std::vector::const_iterator i=itemlist.begin();i!=itemlist.end();i++){ if (SP_IS_RECT(*i)) { if (gtk_adjustment_get_value(adj) != 0) { - (SP_RECT(items->data)->*setter)(Quantity::convert(gtk_adjustment_get_value(adj), unit, "px")); + (SP_RECT(*i)->*setter)(Quantity::convert(gtk_adjustment_get_value(adj), unit, "px")); } else { (*i)->getRepr()->setAttribute(value_name, NULL); } -- cgit v1.2.3 From 60bdd590969d1c32c392a8fed15f4ceac4a678d2 Mon Sep 17 00:00:00 2001 From: Marc Jeanmougin Date: Mon, 27 Apr 2015 01:12:03 +0200 Subject: Just reread the entire diff against trunk. Given the diff size, i must have forgotten things, but hopefully, there are only very few changes of semantics: ->childList is now in the intuitive order (childList()[0] is now firstChild) -> sp_selection_paste_impl is now in the opposite order (change is local to selection-chemistry.cpp, and simplify a few things) -> selection.setReprList now takes the list in the opposite order. It was always the case (the list was always reversed before handing to it) -> a few comparison functions now work "the c++ way": the C way was to return -1 if ab, now they return (bool)(agetSelection(); selection->setReprList(pasted_objects); diff --git a/src/main.cpp b/src/main.cpp index 66452906b..d1ebdc3bb 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1641,7 +1641,9 @@ static int sp_do_export_png(SPDocument *doc) g_print("Background RRGGBBAA: %08x\n", bgcolor); g_print("Area %g:%g:%g:%g exported to %lu x %lu pixels (%g dpi)\n", area[Geom::X][0], area[Geom::Y][0], area[Geom::X][1], area[Geom::Y][1], width, height, dpi); - + + reverse(items.begin(),items.end()); + if ((width >= 1) && (height >= 1) && (width <= PNG_UINT_31_MAX) && (height <= PNG_UINT_31_MAX)) { if( sp_export_png_file(doc, path.c_str(), area, width, height, dpi, dpi, bgcolor, NULL, NULL, true, sp_export_id_only ? items : std::vector()) == 1 ) { diff --git a/src/path-chemistry.cpp b/src/path-chemistry.cpp index b128535bc..bb313ef1a 100644 --- a/src/path-chemistry.cpp +++ b/src/path-chemistry.cpp @@ -269,7 +269,7 @@ sp_selected_path_break_apart(SPDesktop *desktop) if (l == list) repr->setAttribute("id", id); - reprs.insert(reprs.begin(),repr); + reprs.push_back(repr); Inkscape::GC::release(repr); } diff --git a/src/selection-chemistry.cpp b/src/selection-chemistry.cpp index 0100e1040..c1d4f58e4 100644 --- a/src/selection-chemistry.cpp +++ b/src/selection-chemistry.cpp @@ -337,10 +337,7 @@ static void sp_selection_copy_impl(std::vector const &items, std::vecto g_assert_not_reached(); } } - std::vector tmp(clip); - for(int i=0;i copied = sp_selection_paste_impl(dt->getDocument(), moveto, temp_clip); selection->setReprList(copied); - copied.clear(); if (!temp_clip.empty()) temp_clip.clear(); if (moveto) dt->setCurrentLayer(moveto); if ( !suppressDone ) { @@ -2051,7 +2047,7 @@ std::vector sp_get_same_style(SPItem *sel, std::vector &src, S sel_style_for_width = new SPStyle(SP_ACTIVE_DOCUMENT); objects_query_strokewidth (objects, sel_style_for_width); } - bool match_g; + bool match_g; for (std::vector::const_iterator i=src.begin();i!=src.end();i++) { SPItem *iter = *i; if (iter) { @@ -3186,7 +3182,7 @@ void sp_selection_unsymbol(SPDesktop *desktop) } } - for (std::vector::const_iterator i=children.begin();i!=children.end();i++){ + for (std::vector::const_reverse_iterator i=children.rbegin();i!=children.rend();i++){ Inkscape::XML::Node *repr = (*i)->getRepr(); repr->parent()->removeChild(repr); group->addChild(repr,NULL); diff --git a/src/selection.cpp b/src/selection.cpp index 7e8190237..d9266b599 100644 --- a/src/selection.cpp +++ b/src/selection.cpp @@ -42,9 +42,9 @@ namespace Inkscape { Selection::Selection(LayerModel *layers, SPDesktop *desktop) : - _objs(std::list()), - _objs_vector(std::vector()), - _objs_set(std::set()), + _objs(std::list()), + _objs_vector(std::vector()), + _objs_set(std::set()), _reprs(std::vector()), _items(std::vector()), _layers(layers), @@ -281,10 +281,10 @@ void Selection::clear() { } std::vector const &Selection::list() { - if(!_objs_vector.empty()) + if(!_objs_vector.empty()) return _objs_vector; - for ( std::list::const_iterator iter=_objs.begin();iter!=_objs.end();iter++ ) { + for ( std::list::const_iterator iter=_objs.begin();iter!=_objs.end();iter++ ) { _objs_vector.push_back(*iter); } return _objs_vector; @@ -349,7 +349,7 @@ SPObject *Selection::single() { } SPItem *Selection::singleItem() { - std::vector const items=itemList(); + std::vector const items=itemList(); if ( items.size()==1) { return items[0]; } else { @@ -366,7 +366,7 @@ SPItem *Selection::largestItem(Selection::CompareSize compare) { } SPItem *Selection::_sizeistItem(bool sml, Selection::CompareSize compare) { - std::vector const items = const_cast(this)->itemList(); + std::vector const items = const_cast(this)->itemList(); gdouble max = sml ? 1e18 : 0; SPItem *ist = NULL; @@ -399,7 +399,7 @@ Geom::OptRect Selection::bounds(SPItem::BBoxType type) const Geom::OptRect Selection::geometricBounds() const { - std::vector const items = const_cast(this)->itemList(); + std::vector const items = const_cast(this)->itemList(); Geom::OptRect bbox; for ( std::vector::const_iterator iter=items.begin();iter!=items.end();iter++ ) { @@ -410,7 +410,7 @@ Geom::OptRect Selection::geometricBounds() const Geom::OptRect Selection::visualBounds() const { - std::vector const items = const_cast(this)->itemList(); + std::vector const items = const_cast(this)->itemList(); Geom::OptRect bbox; for ( std::vector::const_iterator iter=items.begin();iter!=items.end();iter++ ) { @@ -445,7 +445,7 @@ Geom::OptRect Selection::documentBounds(SPItem::BBoxType type) const // If we have a selection of multiple items, then the center of the first item // will be returned; this is also the case in SelTrans::centerRequest() boost::optional Selection::center() const { - std::vector const items = const_cast(this)->itemList(); + std::vector const items = const_cast(this)->itemList(); if (!items.empty()) { SPItem *first = items.back(); // from the first item in selection if (first->isCenterSet()) { // only if set explicitly @@ -461,7 +461,7 @@ boost::optional Selection::center() const { } std::vector Selection::getSnapPoints(SnapPreferences const *snapprefs) const { - std::vector const items = const_cast(this)->itemList(); + std::vector const items = const_cast(this)->itemList(); SnapPreferences snapprefs_dummy = *snapprefs; // create a local copy of the snapping prefs snapprefs_dummy.setTargetSnappable(Inkscape::SNAPTARGET_ROTATION_CENTER, false); // locally disable snapping to the item center @@ -514,8 +514,8 @@ SPObject *Selection::_objectForXMLNode(Inkscape::XML::Node *repr) const { } uint Selection::numberOfLayers() { - std::vector const items = const_cast(this)->itemList(); - std::set layers; + std::vector const items = const_cast(this)->itemList(); + std::set layers; for ( std::vector::const_iterator iter=items.begin();iter!=items.end();iter++ ) { SPObject *layer = _layers->layerForObject(SP_OBJECT(*iter)); layers.insert(layer); @@ -524,8 +524,8 @@ uint Selection::numberOfLayers() { } guint Selection::numberOfParents() { - std::vector const items = const_cast(this)->itemList(); - std::set parents; + std::vector const items = const_cast(this)->itemList(); + std::set parents; for ( std::vector::const_iterator iter=items.begin();iter!=items.end();iter++ ) { SPObject *parent = SP_OBJECT(*iter)->parent; parents.insert(parent); diff --git a/src/sp-object.h b/src/sp-object.h index df773fea7..f5d47be05 100644 --- a/src/sp-object.h +++ b/src/sp-object.h @@ -52,7 +52,6 @@ class SPObject; #include #include #include -#include #include #include "version.h" diff --git a/src/text-chemistry.cpp b/src/text-chemistry.cpp index 5d57ac020..9fc862ad2 100644 --- a/src/text-chemistry.cpp +++ b/src/text-chemistry.cpp @@ -396,7 +396,7 @@ text_unflow () GSList *old_objs = NULL; std::vector items = selection->itemList(); - for(std::vector::const_reverse_iterator i=items.rbegin();i!=items.rend();i++){ + for(std::vector::const_iterator i=items.begin();i!=items.end();i++){ if (!SP_IS_FLOWTEXT(*i)) { continue; @@ -452,6 +452,7 @@ text_unflow () } selection->clear(); + reverse(new_objs.begin(),new_objs.end()); selection->setList(new_objs); for (GSList *i = old_objs; i; i = i->next) { SP_OBJECT(i->data)->deleteObject (true); diff --git a/src/ui/dialog/clonetiler.cpp b/src/ui/dialog/clonetiler.cpp index b348bdcad..f84a2ffd6 100644 --- a/src/ui/dialog/clonetiler.cpp +++ b/src/ui/dialog/clonetiler.cpp @@ -2113,8 +2113,7 @@ void CloneTiler::clonetiler_unclump(GtkWidget */*widget*/, void *) } desktop->getDocument()->ensureUpToDate(); - std::vector tu2(to_unclump); - for(int i=0;igetDocument(), SP_VERB_DIALOG_CLONETILER, diff --git a/src/ui/dialog/find.cpp b/src/ui/dialog/find.cpp index 173acca93..a8ac42a1b 100644 --- a/src/ui/dialog/find.cpp +++ b/src/ui/dialog/find.cpp @@ -762,7 +762,7 @@ std::vector &Find::all_items (SPObject *r, std::vector &l, boo std::vector &Find::all_selection_items (Inkscape::Selection *s, std::vector &l, SPObject *ancestor, bool hidden, bool locked) { std::vector itemlist=s->itemList(); - for(std::vector::const_iterator i=itemlist.begin(); itemlist.end() != i; i++) { + for(std::vector::const_reverse_iterator i=itemlist.rbegin(); itemlist.rend() != i; i++) { SPObject *obj = *i; SPItem *item = dynamic_cast(obj); g_assert(item != NULL); diff --git a/src/ui/tools/tweak-tool.cpp b/src/ui/tools/tweak-tool.cpp index 76c748ae0..76b52f9be 100644 --- a/src/ui/tools/tweak-tool.cpp +++ b/src/ui/tools/tweak-tool.cpp @@ -378,7 +378,7 @@ sp_tweak_dilate_recursive (Inkscape::Selection *selection, SPItem *item, Geom::P std::vector to_select; SPDocument *doc = item->document; sp_item_list_to_curves (items, selected, to_select); - SPObject* newObj = doc->getObjectByRepr(to_select.back()); + SPObject* newObj = doc->getObjectByRepr(to_select[0]); item = dynamic_cast(newObj); g_assert(item != NULL); selection->add(item); -- cgit v1.2.3 From f20da2a7a6e65bcf3a907c3ee5cb5fd69a71c867 Mon Sep 17 00:00:00 2001 From: Mark Harmer Date: Mon, 27 Apr 2015 12:01:19 -0400 Subject: Mainloop fix for possible data loss if closing before save has completed. Fixed bugs: - https://launchpad.net/bugs/967416 (bzr r14060) --- src/extension/implementation/script.cpp | 5 ++++- src/extension/implementation/script.h | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/extension/implementation/script.cpp b/src/extension/implementation/script.cpp index bbc567f75..52c360fcd 100644 --- a/src/extension/implementation/script.cpp +++ b/src/extension/implementation/script.cpp @@ -1027,7 +1027,10 @@ int Script::execute (const std::list &in_command, return 0; } - _main_loop = Glib::MainLoop::create(false); + // Create a new MainContext for the loop so that the original context sources are not run here, + // this enforces that only the file_listeners should be read in this new MainLoop + Glib::RefPtr _main_context = Glib::MainContext::create(); + _main_loop = Glib::MainLoop::create(_main_context, false); file_listener fileerr; fileout.init(stdout_pipe, _main_loop); diff --git a/src/extension/implementation/script.h b/src/extension/implementation/script.h index 6a7d0c3b8..4cf33c989 100644 --- a/src/extension/implementation/script.h +++ b/src/extension/implementation/script.h @@ -90,7 +90,7 @@ private: void init (int fd, Glib::RefPtr main) { _channel = Glib::IOChannel::create_from_fd(fd); _channel->set_encoding(); - _conn = Glib::signal_io().connect(sigc::mem_fun(*this, &file_listener::read), _channel, Glib::IO_IN | Glib::IO_HUP | Glib::IO_ERR); + _conn = main->get_context()->signal_io().connect(sigc::mem_fun(*this, &file_listener::read), _channel, Glib::IO_IN | Glib::IO_HUP | Glib::IO_ERR); _main_loop = main; return; -- cgit v1.2.3 From e40a878a5843b71f06b1d0fa5cb0681abc5787e6 Mon Sep 17 00:00:00 2001 From: Diederik van Lierop Date: Mon, 27 Apr 2015 20:14:55 +0200 Subject: Enable snapping of cusp nodes by default (bzr r14061) --- src/sp-namedview.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/sp-namedview.cpp b/src/sp-namedview.cpp index 3154c9e7b..12c2cdf8e 100644 --- a/src/sp-namedview.cpp +++ b/src/sp-namedview.cpp @@ -517,7 +517,7 @@ void SPNamedView::set(unsigned int key, const gchar* value) { this->requestModified(SP_OBJECT_MODIFIED_FLAG); break; case SP_ATTR_INKSCAPE_SNAP_NODE_CUSP: - this->snap_manager.snapprefs.setTargetSnappable(Inkscape::SNAPTARGET_NODE_CUSP, value ? sp_str_to_bool(value) : FALSE); + this->snap_manager.snapprefs.setTargetSnappable(Inkscape::SNAPTARGET_NODE_CUSP, value ? sp_str_to_bool(value) : TRUE); this->requestModified(SP_OBJECT_MODIFIED_FLAG); break; case SP_ATTR_INKSCAPE_SNAP_BBOX_EDGE: -- cgit v1.2.3 From ac063302cd13238523a4f62744282944761c2a49 Mon Sep 17 00:00:00 2001 From: mathog <> Date: Mon, 27 Apr 2015 11:49:22 -0700 Subject: patch for bugs 1447850 and 1447382 (bzr r14062) --- src/extension/internal/emf-inout.cpp | 50 +- src/extension/internal/emf-inout.h | 2 + src/extension/internal/emf-print.cpp | 12 +- src/extension/internal/wmf-inout.cpp | 64 +- src/extension/internal/wmf-print.cpp | 6 +- src/libuemf/Makefile_insert | 2 + src/libuemf/README | 100 +- src/libuemf/uemf.c | 273 +++--- src/libuemf/uemf.h | 180 +++- src/libuemf/uemf_endian.c | 1673 ++++++++++++++++++++++------------ src/libuemf/uemf_endian.h | 7 +- src/libuemf/uemf_print.c | 652 ++++++++----- src/libuemf/uemf_print.h | 14 +- src/libuemf/upmf.c | 1282 ++++++++++++++++++-------- src/libuemf/upmf.h | 146 +-- src/libuemf/upmf_print.c | 818 +++++++++++------ src/libuemf/upmf_print.h | 137 +-- src/libuemf/uwmf.c | 100 +- src/libuemf/uwmf.h | 5 +- src/libuemf/uwmf_print.c | 14 +- src/libuemf/uwmf_print.h | 2 +- 21 files changed, 3706 insertions(+), 1833 deletions(-) (limited to 'src') diff --git a/src/extension/internal/emf-inout.cpp b/src/extension/internal/emf-inout.cpp index 31e69706f..e88cf3d42 100644 --- a/src/extension/internal/emf-inout.cpp +++ b/src/extension/internal/emf-inout.cpp @@ -480,7 +480,7 @@ uint32_t Emf::add_image(PEMF_CALLBACK_DATA d, void *pEmr, uint32_t cbBits, uint uint32_t width, height, colortype, numCt, invert; // if needed these values will be set in get_DIB_params if(cbBits && cbBmi && (iUsage == U_DIB_RGB_COLORS)){ // next call returns pointers and values, but allocates no memory - dibparams = get_DIB_params(pEmr, offBits, offBmi, &px, (const U_RGBQUAD **) &ct, + dibparams = get_DIB_params((const char *)pEmr, offBits, offBmi, &px, (const U_RGBQUAD **) &ct, &numCt, &width, &height, &colortype, &invert); if(dibparams ==U_BI_RGB){ // U_EMRCREATEMONOBRUSH uses text/bk colors instead of what is in the color map. @@ -1307,7 +1307,7 @@ Emf::select_extpen(PEMF_CALLBACK_DATA d, int index) d->dc[d->level].stroke_set = true; } else if(pEmr->elp.elpBrushStyle == U_BS_DIBPATTERN || pEmr->elp.elpBrushStyle == U_BS_DIBPATTERNPT){ - d->dc[d->level].stroke_idx = add_image(d, pEmr, pEmr->cbBits, pEmr->cbBmi, *(uint32_t *) &(pEmr->elp.elpColor), pEmr->offBits, pEmr->offBmi); + d->dc[d->level].stroke_idx = add_image(d, (void *)pEmr, pEmr->cbBits, pEmr->cbBmi, *(uint32_t *) &(pEmr->elp.elpColor), pEmr->offBits, pEmr->offBmi); d->dc[d->level].stroke_mode = DRAW_IMAGE; d->dc[d->level].stroke_set = true; } @@ -1530,7 +1530,7 @@ void Emf::common_image_extraction(PEMF_CALLBACK_DATA d, void *pEmr, uint32_t width, height, colortype, numCt, invert; // if needed these values will be set in get_DIB_params if(cbBits && cbBmi && (iUsage == U_DIB_RGB_COLORS)){ // next call returns pointers and values, but allocates no memory - dibparams = get_DIB_params(pEmr, offBits, offBmi, &px, (const U_RGBQUAD **) &ct, + dibparams = get_DIB_params((const char *)pEmr, offBits, offBmi, &px, (const U_RGBQUAD **) &ct, &numCt, &width, &height, &colortype, &invert); if(dibparams ==U_BI_RGB){ if(sw == 0 || sh == 0){ @@ -1611,6 +1611,10 @@ int Emf::myEnhMetaFileProc(char *contents, unsigned int length, PEMF_CALLBACK_DA uint32_t off=0; uint32_t emr_mask; int OK =1; + int file_status=1; + uint32_t nSize; + uint32_t iType; + const char *blimit = contents + length; PU_ENHMETARECORD lpEMFR; TCHUNK_SPECS tsp; uint32_t tbkMode = U_TRANSPARENT; // holds proposed change to bkMode, if text is involved saving these to the DC must wait until the text is written @@ -1641,19 +1645,32 @@ int Emf::myEnhMetaFileProc(char *contents, unsigned int length, PEMF_CALLBACK_DA while(OK){ if(off>=length)return(0); //normally should exit from while after EMREOF sets OK to false. + // check record sizes and types thoroughly + int badrec = 0; + if (!U_emf_record_sizeok(contents + off, blimit, &nSize, &iType, 1) || + !U_emf_record_safe(contents + off)){ + badrec = 1; + } + else { + emr_mask = emr_properties(iType); + if (emr_mask == U_EMR_INVALID) { badrec = 1; } + } + if (badrec) { + file_status = 0; + break; + } + lpEMFR = (PU_ENHMETARECORD)(contents + off); + // Uncomment the following to track down toxic records -// std::cout << "record type: " << lpEMFR->iType << " name " << U_emr_names(lpEMFR->iType) << " length: " << lpEMFR->nSize << " offset: " << off <nSize; +// std::cout << "record type: " << iType << " name " << U_emr_names(iType) << " length: " << nSize << " offset: " << off <iType); - if(emr_mask == U_EMR_INVALID){ throw "Inkscape fatal memory allocation error - cannot continue"; } - /* Uncomment the following to track down text problems */ //std::cout << "tri->dirty:"<< d->tri->dirty << " emr_mask: " << std::hex << emr_mask << std::dec << std::endl; @@ -1753,7 +1770,7 @@ std::cout << "BEFORE DRAW" } // std::cout << "AFTER DRAW logic d->mask: " << std::hex << d->mask << " emr_mask: " << emr_mask << std::dec << std::endl; - switch (lpEMFR->iType) + switch (iType) { case U_EMR_HEADER: { @@ -3471,7 +3488,7 @@ std::cout << "BEFORE DRAW" // std::cout << d->outsvg << std::endl; (void) emr_properties(U_EMR_INVALID); // force the release of the lookup table memory, returned value is irrelevant - return 1; + return(file_status); } void Emf::free_emf_strings(EMF_STRINGS name){ @@ -3486,12 +3503,14 @@ void Emf::free_emf_strings(EMF_STRINGS name){ SPDocument * Emf::open( Inkscape::Extension::Input * /*mod*/, const gchar *uri ) { - EMF_CALLBACK_DATA d; - if (uri == NULL) { return NULL; } + EMF_CALLBACK_DATA d; + + d.n_obj = 0; //these might not be set otherwise if the input file is corrupt + d.emf_obj = NULL; d.dc[0].font_name = strdup("Arial"); // Default font, set only on lowest level, it copies up from there EMF spec says device can pick whatever it wants // set up the size default for patterns in defs. This might not be referenced if there are no patterns defined in the drawing. @@ -3518,14 +3537,17 @@ Emf::open( Inkscape::Extension::Input * /*mod*/, const gchar *uri ) FT_LOAD_NO_SCALE | FT_LOAD_NO_HINTING | FT_LOAD_NO_BITMAP, FT_KERNING_UNSCALED); - (void) myEnhMetaFileProc(contents,length, &d); + int good = myEnhMetaFileProc(contents,length, &d); free(contents); if (d.pDesc){ free( d.pDesc ); } // std::cout << "SVG Output: " << std::endl << d.outsvg << std::endl; - SPDocument *doc = SPDocument::createNewDocFromMem(d.outsvg.c_str(), strlen(d.outsvg.c_str()), TRUE); + SPDocument *doc = NULL; + if (good) { + doc = SPDocument::createNewDocFromMem(d.outsvg.c_str(), strlen(d.outsvg.c_str()), TRUE); + } free_emf_strings(d.hatches); free_emf_strings(d.images); diff --git a/src/extension/internal/emf-inout.h b/src/extension/internal/emf-inout.h index c64299093..dd1d8f9c4 100644 --- a/src/extension/internal/emf-inout.h +++ b/src/extension/internal/emf-inout.h @@ -13,6 +13,8 @@ #define SEEN_EXTENSION_INTERNAL_EMF_H #include +#include +#include // for U_emf_record_sizeok() #include "extension/internal/metafile-inout.h" // picks up PNG #include "extension/implementation/implementation.h" #include "style.h" diff --git a/src/extension/internal/emf-print.cpp b/src/extension/internal/emf-print.cpp index 67a9242bc..ed3ae158a 100644 --- a/src/extension/internal/emf-print.cpp +++ b/src/extension/internal/emf-print.cpp @@ -60,6 +60,7 @@ #include "splivarot.h" // pieces for union on shapes #include "2geom/svg-path-parser.h" // to get from SVG text to Geom::Path #include "display/canvas-bpath.h" // for SPWindRule +#include "display/cairo-utils.h" // for Inkscape::Pixbuf::PF_CAIRO #include "emf-print.h" @@ -70,7 +71,6 @@ namespace Internal { #define PXPERMETER 2835 - /* globals */ static double PX2WORLD; static bool FixPPTCharPos, FixPPTDashLine, FixPPTGrad2Polys, FixPPTLinGrad, FixPPTPatternAsHatch, FixImageRot; @@ -481,9 +481,8 @@ int PrintEmf::create_brush(SPStyle const *style, PU_COLORREF fcolor) rgba_px = (char *) pixbuf->pixels(); // Do NOT free this!!! colortype = U_BCBM_COLOR32; (void) RGBA_to_DIB(&px, &cbPx, &ct, &numCt, rgba_px, width, height, width * 4, colortype, 0, 1); - // Not sure why the next swap is needed because the preceding does it, and the code is identical - // to that in stretchdibits_set, which does not need this. - swapRBinRGBA(px, width * height); + // pixbuf can be either PF_CAIRO or PF_GDK, and these have R and B bytes swapped + if (pixbuf->pixelFormat() == Inkscape::Pixbuf::PF_CAIRO) { swapRBinRGBA(px, width * height); } Bmih = bitmapinfoheader_set(width, height, 1, colortype, U_BI_RGB, 0, PXPERMETER, PXPERMETER, numCt, 0); Bmi = bitmapinfo_set(Bmih, ct); rec = createdibpatternbrushpt_set(&brush, eht, U_DIB_RGB_COLORS, Bmi, cbPx, px); @@ -584,9 +583,8 @@ int PrintEmf::create_pen(SPStyle const *style, const Geom::Affine &transform) rgba_px = (char *) pixbuf->pixels(); // Do NOT free this!!! colortype = U_BCBM_COLOR32; (void) RGBA_to_DIB(&px, &cbPx, &ct, &numCt, rgba_px, width, height, width * 4, colortype, 0, 1); - // Not sure why the next swap is needed because the preceding does it, and the code is identical - // to that in stretchdibits_set, which does not need this. - swapRBinRGBA(px, width * height); + // pixbuf can be either PF_CAIRO or PF_GDK, and these have R and B bytes swapped + if (pixbuf->pixelFormat() == Inkscape::Pixbuf::PF_CAIRO) { swapRBinRGBA(px, width * height); } Bmih = bitmapinfoheader_set(width, height, 1, colortype, U_BI_RGB, 0, PXPERMETER, PXPERMETER, numCt, 0); Bmi = bitmapinfo_set(Bmih, ct); } else { // pattern diff --git a/src/extension/internal/wmf-inout.cpp b/src/extension/internal/wmf-inout.cpp index 503a93418..30a028eec 100644 --- a/src/extension/internal/wmf-inout.cpp +++ b/src/extension/internal/wmf-inout.cpp @@ -1497,6 +1497,7 @@ int Wmf::myMetaFileProc(const char *contents, unsigned int length, PWMF_CALLBACK uint32_t off=0; uint32_t wmr_mask; int OK =1; + int file_status=1; TCHUNK_SPECS tsp; uint8_t iType; int nSize; // size of the current record, in bytes, or an error value if <=0 @@ -1562,7 +1563,9 @@ int Wmf::myMetaFileProc(const char *contents, unsigned int length, PWMF_CALLBACK U_WMRHEADER Header; off = 0; nSize = wmfheader_get(contents, blimit, &Placeable, &Header); - if(!nSize)return(0); + if (!nSize) { + return(0); + } if(!Header.nObjects){ Header.nObjects = 256; }// there _may_ be WMF files with no objects, more likely it is corrupt. Try to use it anyway. d->n_obj = Header.nObjects; d->wmf_obj = new WMF_OBJECT[d->n_obj]; @@ -1602,7 +1605,10 @@ int Wmf::myMetaFileProc(const char *contents, unsigned int length, PWMF_CALLBACK else { off += nSize; } - } + } + else { + return(0); + } } off=0; nSize = hold_nSize; @@ -1665,27 +1671,32 @@ int Wmf::myMetaFileProc(const char *contents, unsigned int length, PWMF_CALLBACK while(OK){ - if(off>=length)return(0); //normally should exit from while after WMREOF sets OK to false. + if (off>=length) { + return(0); //normally should exit from while after WMREOF sets OK to false. + } contents += nSize; // pointer to the start of the next record off += nSize; // offset from beginning of buffer to the start of the next record - SVGOStringStream tmp_path; - SVGOStringStream tmp_str; - - /* Check that the current record size is OK, abort if not. - Pointer math might wrap, so check both sides of the range. - Some of the records will reset this with the same value,others will not - return a value at this time. */ + /* Currently this is a weaker check than for EMF, it only checks the size of the constant part + of the record */ nSize = U_WMRRECSAFE_get(contents, blimit); - if(!nSize)break; + if(!nSize) { + file_status = 0; + break; + } iType = *(uint8_t *)(contents + offsetof(U_METARECORD, iType ) ); + wmr_mask = U_wmr_properties(iType); + if (wmr_mask == U_WMR_INVALID) { + file_status = 0; + break; + } // Uncomment the following to track down toxic records // std::cout << "record type: " << (int) iType << " name " << U_wmr_names(iType) << " length: " << nSize << " offset: " << off <dirty:"<< d->tri->dirty << " wmr_mask: " << std::hex << wmr_mask << std::dec << std::endl; @@ -3026,14 +3037,17 @@ std::cout << "BEFORE DRAW" // When testing, uncomment the following to place a comment for each processed WMR record in the SVG // d->outsvg += dbg_str.str().c_str(); d->path += tmp_path.str().c_str(); - if(!nSize){ OK=0; std::cout << "nSize == 0, oops!!!" << std::endl; } // There was some problem with this record, it is not safe to continue + if(!nSize){ // There was some problem with the processing of this record, it is not safe to continue + file_status = 0; + break; + } - } //end of while + } //end of while on OK // When testing, uncomment the following to show the final SVG derived from the WMF // std::cout << d->outsvg << std::endl; (void) U_wmr_properties(U_WMR_INVALID); // force the release of the lookup table memory, returned value is irrelevant - return 1; + return(file_status); } void Wmf::free_wmf_strings(WMF_STRINGS name){ @@ -3049,7 +3063,14 @@ SPDocument * Wmf::open( Inkscape::Extension::Input * /*mod*/, const gchar *uri ) { + if (uri == NULL) { + return NULL; + } + WMF_CALLBACK_DATA d; + + d.n_obj = 0; //these might not be set otherwise if the input file is corrupt + d.wmf_obj=NULL; // Default font, WMF spec says device can pick whatever it wants. // WMF files that do not specify a font are unlikely to look very good! @@ -3067,10 +3088,6 @@ Wmf::open( Inkscape::Extension::Input * /*mod*/, const gchar *uri ) d.dc[0].style.stroke_width.value = 1.0; // will be reset to something reasonable once WMF draying size is known d.dc[0].style.stroke.value.color.set( 0, 0, 0 ); - if (uri == NULL) { - return NULL; - } - d.dc[0].font_name = strdup("Arial"); // Default font, set only on lowest level, it copies up from there WMF spec says device can pick whatever it wants // set up the size default for patterns in defs. This might not be referenced if there are no patterns defined in the drawing. @@ -3095,12 +3112,15 @@ Wmf::open( Inkscape::Extension::Input * /*mod*/, const gchar *uri ) FT_LOAD_NO_SCALE | FT_LOAD_NO_HINTING | FT_LOAD_NO_BITMAP, FT_KERNING_UNSCALED); - (void) myMetaFileProc(contents,length, &d); + int good = myMetaFileProc(contents,length, &d); free(contents); // std::cout << "SVG Output: " << std::endl << d.outsvg << std::endl; - SPDocument *doc = SPDocument::createNewDocFromMem(d.outsvg.c_str(), strlen(d.outsvg.c_str()), TRUE); + SPDocument *doc = NULL; + if (good) { + doc = SPDocument::createNewDocFromMem(d.outsvg.c_str(), strlen(d.outsvg.c_str()), TRUE); + } free_wmf_strings(d.hatches); free_wmf_strings(d.images); diff --git a/src/extension/internal/wmf-print.cpp b/src/extension/internal/wmf-print.cpp index 567f9f366..9fe1a0259 100644 --- a/src/extension/internal/wmf-print.cpp +++ b/src/extension/internal/wmf-print.cpp @@ -61,6 +61,7 @@ #include "splivarot.h" // pieces for union on shapes #include "2geom/svg-path-parser.h" // to get from SVG text to Geom::Path #include "display/canvas-bpath.h" // for SPWindRule +#include "display/cairo-utils.h" // for Inkscape::Pixbuf::PF_CAIRO #include "wmf-print.h" @@ -471,9 +472,8 @@ int PrintWmf::create_brush(SPStyle const *style, U_COLORREF *fcolor) rgba_px = (char *) pixbuf->pixels(); // Do NOT free this!!! colortype = U_BCBM_COLOR32; (void) RGBA_to_DIB(&px, &cbPx, &ct, &numCt, rgba_px, width, height, width * 4, colortype, 0, 1); - // Not sure why the next swap is needed because the preceding does it, and the code is identical - // to that in stretchdibits_set, which does not need this. - swapRBinRGBA(px, width * height); + // pixbuf can be either PF_CAIRO or PF_GDK, and these have R and B bytes swapped + if (pixbuf->pixelFormat() == Inkscape::Pixbuf::PF_CAIRO) { swapRBinRGBA(px, width * height); } Bmih = bitmapinfoheader_set(width, height, 1, colortype, U_BI_RGB, 0, PXPERMETER, PXPERMETER, numCt, 0); Bmi = bitmapinfo_set(Bmih, ct); rec = wcreatedibpatternbrush_srcdib_set(&brush, wht, U_DIB_RGB_COLORS, Bmi, cbPx, px); diff --git a/src/libuemf/Makefile_insert b/src/libuemf/Makefile_insert index 004c56dfc..427a0e80e 100644 --- a/src/libuemf/Makefile_insert +++ b/src/libuemf/Makefile_insert @@ -12,6 +12,8 @@ libuemf_libuemf_a_SOURCES = \ libuemf/uemf_endian.h \ libuemf/uemf_print.c \ libuemf/uemf_print.h \ + libuemf/uemf_safe.c \ + libuemf/uemf_safe.h \ libuemf/uemf_utf.c \ libuemf/uemf_utf.h \ libuemf/uwmf.c \ diff --git a/src/libuemf/README b/src/libuemf/README index cfa322178..a3dff9b4c 100644 --- a/src/libuemf/README +++ b/src/libuemf/README @@ -1,22 +1,25 @@ Overview: -libUEMF is a portable C99 implementation for reading/writing Enhanced Metafile (EMF) -and Windows Metafile (WMF) files. libUEMF avoids collisions with with Microsoft defined -functions and values, so portable programs which use it, and have a Windows version, do -not require any conditional logic to separate the native GDI support from the WMF/EMF support -proviced by libUEMF. To accomplish this libUEMF does not implement GDI calls. Instead, -for each WMR/EMR record type, and each object type incorporated into such a record, it provides -corresponding *_set, *_print, and *_swap functions. (For WMF there are also *_get functions, see below.) -For example, for the U_EMRBITBLT record there are corresponding functions: -U_EMRBITBLT_set, U_EMRBITBLT_print, and U_EMRBITBLT_swap. A few additional functions are provided for -assembling the EMF in memory, debugging, and converting the EMF file to/from Little Endian representation. -(EMF files' internal data representation is always Little Endian.) - -This code has been tested on 32 bit Ubuntu (LE), 32 bit Mingw, 64 bit Manriva, and 64 bit Solaris (BE). +libUEMF is a portable C99 implementation for reading/writing Enhanced Metafile (EMF), +Enhanced Metafile Format Plus (PMF), and Windows Metafile (WMF) files. libUEMF +avoids collisions with Microsoft defined functions and values, so portable programs +which use it and have a Windows version, do not require any conditional logic to +separate the native GDI support from the WMF/EMF/PMF support proviced by libUEMF. To +accomplish this libUEMF does not implement GDI calls. Instead, for each WMR/EMR/PMR +record type, and each object type incorporated into such a record, it provides +corresponding *_set, *_print, and *_swap functions. For PMF and WMF there are also +*_get functions, see below. For example, for the U_EMRBITBLT record there are +corresponding functions: U_EMRBITBLT_set, U_EMRBITBLT_print, and U_EMRBITBLT_swap. A +few additional functions are provided for assembling the EMF in memory, debugging, and +converting the EMF file to/from Little Endian representation. (EMF files' internal +data representation is always Little Endian.) + +This code has been tested on 32 bit Ubuntu (LE), 32 bit Mingw, 64 bit Mageia, and 64 +bit Solaris (BE). libUEMF is released under the GPL 2 license, read the file 'COPYING' for more information -Version 0.1.10, released January 15, 2014. +Version 0.2.1, released April 23, 2015. To report bugs or provide feedback send email to David Mathog, mathog@caltech.edu. @@ -76,7 +79,14 @@ uemf_endian.c Contains the *_swap functions needed to rearrange bytes betwee uemf_endian.h Prototype for U_emf_endian() and definitions for Endian type of the local machine. - +uemf_safe.c Contains the *_safe functions for EMF records, which verify that all + offsets and counts stay within the declared size of a record. Also checks that + core record sizes are sane. U_emf_record_safe() is the only _safe function which + user code should call directly, and then ONLY after a previous call to + U_emf_record_sizeok(), which is in the endian file. + +uemf_safe.h Prototype for U_emf_record_safe(). + . upmf.c Contains the *_set and *_get functions needed to construct or read an EMF+ file. Also contains auxilliary functions for debugging and constructing EMF+ files in memory. @@ -366,9 +376,69 @@ History (Note, version numbers in files represent the libUEMF release where it was last modified, so not all files will show the same version numbers in each release.) +0.2.1.2015_04_23 + Bug in safety check on EMREXTCREATEFONTINDIRECTW because it had alternative "standard" record sizes. + Changed warnings on unimplemented EMF record types encounterd in swap or safe from stdout to stderr. + Added memory checking for WMF polyline and polygon records, for the variable part and some others. + Note: U_WMRCREATEREGION_get does not check that the variable part stays within the record. Current + implementation seems to be broken since it does not show up in XP preview. +0.2.0 2015_03_20 + Added UEMF _safe functions to better handle corrupt records, where variable sizes fields might + have been specified to read past the end of memory. These are records with offsets, arrays + with counts, and bitmaps. Also any record which specifies a size smaller than the minimum + for that record type. + Added similar code for EMF+. + These changed the API so the minor version number was bumped by 1. + +0.1.18 2015_01_15 + Pierre-Francois Carpentier sent some EMF examples which used U_EMR_EXTSELECTCLIPRGN, which had + not previously been encountered and showed that the handling of regions was broken. + Added tests for U_EMRFILLRGN, U_EMRFRAMERGN, U_EMRFRAMERGN, U_EMREXTSELECTCLIPRGN to testbed_emf. + +0.1.18 2014_04_28 + Fixed typo in testbed_wmf.c. "include,include" in one place should have been + "exclude,exclude". + +0.1.17 2014_04_25 + Added text clipping tests to testbed_emf.c, testbed_wmf.c, and testbed_pmf.c. + Added option to omit clipping tests in testbed's. + +0.1.16 2014_04_14 + Fixed bug in U_WMRRESTOREDC_set. + Added clipping tests to testbed_wmf.c. + +0.1.15 2014_04_04 + Changed record flags for U_EMRSELECTCLIPPATH record, it consumes a path but does not ALTER (which + forced a premature draw.) + Added U_EMROFFSETCLIPRGN test to testbed_emf.c. + Changed location on dist drawing where clipping appears. + +0.1.14 2014_03_27 + Fixed bug, in U_PMF_RECTN_set() in upmf.c. Never tested. + Fixed a few potential bugs in upmf.c if a null pointer was passed for + certain function arguments. (Previously unhandled cases.) + Fixed bug, operations setting variables that are never read along those + execution paths: upmf_print.c, uemf.c, uwmf.c, uemf_endian.cm upmf.c. + Fixed potential (but very unlikely) memory leaks in upmf.c and uemf_utf.c. + Added test of U_PMF_RECTN_set to testbed_pmf.c. + Changed U_wmr_names() and U_wmr_escnames() to const char* (from char*). + Changed method for suppressing unused parameter warnings. + + +0.1.13 2014-03-21 + Fixed bug, cutemf was messing up the object count (pens, brushes, etc.). + Added cutemf can now take ranges of lines. + Added testbed_emf generates clipping records for rect and path (but not region). + +0.1.12 2014-02-14 + Documentation change, U_WMRCREATEPATTERNBRUSH is obsolete. + Changed wmf_finish() so that it accurately reflects the largest number of objects used, + previously it showed the number of appends, which was much larger. + 0.1.11 2014-01-29 Fixed bug in uwmf.c (wrong minimum record size on U_WMRTEXTOUT) Fixed bug in uwmf.c (U_WMRCREATEPATTERNBRUSH not right) + Fixed bug in uwmf_print.c (U_WMRTEXTOUT_print, x,y were reversed) Added error handling to uemf_utf.c for cases where src is a null pointer. Added a test of createpatternbrush to testlib_wmf diff --git a/src/libuemf/uemf.c b/src/libuemf/uemf.c index 1d417dece..3180c757c 100644 --- a/src/libuemf/uemf.c +++ b/src/libuemf/uemf.c @@ -16,11 +16,11 @@ /* File: uemf.c -Version: 0.0.28 -Date: 04-APR-2014 +Version: 0.0.30 +Date: 20-MAR-2015 Author: David Mathog, Biology Division, Caltech email: mathog@caltech.edu -Copyright: 2014 David Mathog and California Institute of Technology (Caltech) +Copyright: 2015 David Mathog and California Institute of Technology (Caltech) */ #ifdef __cplusplus @@ -199,7 +199,7 @@ definitions are not needed in end user code, so they are here rather than in uem // this one may also be used A=Msk,B=MskBmi and F=cbMsk #define SET_CB_FROM_PXBMI(A,B,C,D,E,F) /* A=Px, B=Bmi, C=cbImage, D=cbImage4, E=cbBmi, F=cbPx */ \ if(A){\ - if(!B)return(NULL); /* size is derived from U_BIMAPINFO, but NOT from its size field, go figure*/ \ + if(!B)return(NULL); /* size is derived from U_BITMAPINFO, but NOT from its size field, go figure*/ \ C = F;\ D = UP4(C); /* pixel array might not be a multiples of 4 bytes*/ \ E = sizeof(U_BITMAPINFOHEADER) + 4 * get_real_color_count((const char *) &(B->bmiHeader)); /* bmiheader + colortable*/ \ @@ -851,7 +851,7 @@ int get_real_color_icount( \brief Get the DIB parameters from the BMI of the record for use by DBI_to_RGBA() \return BI_Compression Enumeration. For anything other than U_BI_RGB values other than px may not be valid. - \param pEmr pointer to EMR record that has a U_BITMAPINFO and bitmap + \param record pointer to EMR record that has a U_BITMAPINFO and bitmap \param offBitsSrc Offset to the bitmap \param offBmiSrc Offset to the U_BITMAPINFO \param px pointer to DIB pixel array in pEmr @@ -863,7 +863,7 @@ int get_real_color_icount( \param invert If DIB rows are in opposite order from RGBA rows */ int get_DIB_params( - void *pEmr, + const char *record, uint32_t offBitsSrc, uint32_t offBmiSrc, const char **px, @@ -875,7 +875,7 @@ int get_DIB_params( uint32_t *invert ){ uint32_t bic; - PU_BITMAPINFO Bmi = (PU_BITMAPINFO)((char *)pEmr + offBmiSrc); + PU_BITMAPINFO Bmi = (PU_BITMAPINFO)(record + offBmiSrc); PU_BITMAPINFOHEADER Bmih = &(Bmi->bmiHeader); /* if biCompression is not U_BI_RGB some or all of the following might not hold real values */ bic = Bmih->biCompression; @@ -903,7 +903,7 @@ int get_DIB_params( *numCt = Bmih->biSizeImage; *ct = NULL; } - *px = (char *)((char *)pEmr + offBitsSrc); + *px = record + offBitsSrc; return(bic); } @@ -1610,6 +1610,26 @@ U_RECTL rectl_set( return(rct); } +/** + \brief Set rect and rectl objects from Upper Left and Lower Right corner points. + \param array array of rectangles + \param index array entry to fill, numbered from 0 + \param ul upper left corner of rectangle + \param lr lower right corner of rectangle +*/ +void rectli_set( + PU_RECTL array, + int index, + U_POINTL ul, + U_POINTL lr + ){ + PU_RECTL rct = &(array[index]); + rct->left = ul.x; + rct->top = ul.y; + rct->right = lr.x; + rct->bottom = lr.y; +} + /** \brief Set sizel objects with X,Y values. \param x X coordinate @@ -2192,7 +2212,7 @@ U_RGNDATAHEADER rgndataheader_set( rdh.dwSize = U_RDH_OBJSIZE; rdh.iType = U_RDH_RECTANGLES; rdh.nCount = nCount; - rdh.nRgnSize = nCount * sizeof(U_RECTL); // Size in bytes of retangle array + rdh.nRgnSize = nCount * sizeof(U_RECTL); // Size in bytes of rectangle array rdh.rclBounds = rclBounds; return(rdh); } @@ -2857,7 +2877,7 @@ by end user code and to further that end prototypes are NOT provided and they ar // Functions with the same form starting with U_EMRPOLYBEZIER_set -char *U_EMR_CORE1(uint32_t iType, U_RECTL rclBounds, const uint32_t cptl, const U_POINTL *points){ +char *U_EMR_CORE1_set(uint32_t iType, U_RECTL rclBounds, const uint32_t cptl, const U_POINTL *points){ char *record; int cbPoints; int irecsize; @@ -2876,7 +2896,7 @@ char *U_EMR_CORE1(uint32_t iType, U_RECTL rclBounds, const uint32_t cptl, const } // Functions with the same form starting with U_EMR_POLYPOLYLINE -char *U_EMR_CORE2(uint32_t iType, U_RECTL rclBounds, const uint32_t nPolys, const uint32_t *aPolyCounts,const uint32_t cptl, const U_POINTL *points){ +char *U_EMR_CORE2_set(uint32_t iType, U_RECTL rclBounds, const uint32_t nPolys, const uint32_t *aPolyCounts,const uint32_t cptl, const U_POINTL *points){ char *record; int cbPolys,cbPoints,off; int irecsize; @@ -2899,7 +2919,7 @@ char *U_EMR_CORE2(uint32_t iType, U_RECTL rclBounds, const uint32_t nPolys, cons } // Functions with the same form starting with U_EMR_SETMAPMODE_set -char *U_EMR_CORE3(uint32_t iType, uint32_t iMode){ +char *U_EMR_CORE3_set(uint32_t iType, uint32_t iMode){ char *record; int irecsize; @@ -2914,7 +2934,7 @@ char *U_EMR_CORE3(uint32_t iType, uint32_t iMode){ } // Functions taking a single U_RECT or U_RECTL, starting with U_EMRELLIPSE_set, also U_EMRFILLPATH, -char *U_EMR_CORE4(uint32_t iType, U_RECTL rclBox){ +char *U_EMR_CORE4_set(uint32_t iType, U_RECTL rclBox){ char *record; int irecsize; @@ -2930,7 +2950,7 @@ char *U_EMR_CORE4(uint32_t iType, U_RECTL rclBox){ } // Functions with the same form starting with U_EMRSETMETARGN_set -char *U_EMR_CORE5(uint32_t iType){ +char *U_EMR_CORE5_set(uint32_t iType){ char *record; int irecsize = 8; @@ -2943,7 +2963,7 @@ char *U_EMR_CORE5(uint32_t iType){ } // Functions with the same form starting with U_EMRPOLYBEZIER16_set -char *U_EMR_CORE6(uint32_t iType, U_RECTL rclBounds, const uint32_t cpts, const U_POINT16 *points){ +char *U_EMR_CORE6_set(uint32_t iType, U_RECTL rclBounds, const uint32_t cpts, const U_POINT16 *points){ char *record; int cbPoints,cbPoints4,off; int irecsize; @@ -2970,7 +2990,7 @@ char *U_EMR_CORE6(uint32_t iType, U_RECTL rclBounds, const uint32_t cpts, const // Functions that take a single struct argument which contains two uint32_t, starting with U_EMRSETWINDOWEXTEX_set // these all pass two 32 bit ints and are cast by the caller to U_PAIR -char *U_EMR_CORE7(uint32_t iType, U_PAIR pair){ +char *U_EMR_CORE7_set(uint32_t iType, U_PAIR pair){ char *record; int irecsize = sizeof(U_EMRGENERICPAIR); @@ -2984,7 +3004,7 @@ char *U_EMR_CORE7(uint32_t iType, U_PAIR pair){ } // For U_EMREXTTEXTOUTA and U_EMREXTTEXTOUTW -char *U_EMR_CORE8( +char *U_EMR_CORE8_set( uint32_t iType, U_RECTL rclBounds, // Bounding rectangle in device units uint32_t iGraphicsMode, // Graphics mode Enumeration @@ -3033,7 +3053,7 @@ char *U_EMR_CORE8( } // Functions that take a rect and a pair of points, starting with U_EMRARC_set -char *U_EMR_CORE9(uint32_t iType, U_RECTL rclBox, U_POINTL ptlStart, U_POINTL ptlEnd){ +char *U_EMR_CORE9_set(uint32_t iType, U_RECTL rclBox, U_POINTL ptlStart, U_POINTL ptlEnd){ char *record; int irecsize = sizeof(U_EMRARC); @@ -3049,7 +3069,7 @@ char *U_EMR_CORE9(uint32_t iType, U_RECTL rclBox, U_POINTL ptlStart, U_POINTL pt } // Functions with the same form starting with U_EMR_POLYPOLYLINE16 -char *U_EMR_CORE10(uint32_t iType, U_RECTL rclBounds, const uint32_t nPolys, const uint32_t *aPolyCounts,const uint32_t cpts, const U_POINT16 *points){ +char *U_EMR_CORE10_set(uint32_t iType, U_RECTL rclBounds, const uint32_t nPolys, const uint32_t *aPolyCounts,const uint32_t cpts, const U_POINT16 *points){ char *record; int cbPoints,cbPolys,off; int irecsize; @@ -3072,25 +3092,27 @@ char *U_EMR_CORE10(uint32_t iType, U_RECTL rclBounds, const uint32_t nPolys, con } // common code for U_EMRINVERTRGN and U_EMRPAINTRGN, -char *U_EMR_CORE11(uint32_t iType, PU_RGNDATA RgnData){ +char *U_EMR_CORE11_set(uint32_t iType, PU_RGNDATA RgnData){ char *record; int irecsize; - int cbRgns,cbRgns4,off; + int cbRgns,cbRgns4,rds,rds4,off; if(!RgnData)return(NULL); cbRgns = ((PU_RGNDATAHEADER) RgnData)->nRgnSize; cbRgns4 = UP4(cbRgns); - irecsize = sizeof(U_EMRINVERTRGN) + cbRgns4 - sizeof(U_RGNDATAHEADER); // core + array - overlap - record = malloc(irecsize); + rds = sizeof(U_RGNDATAHEADER) + cbRgns; + rds4 = UP4(rds); + irecsize = sizeof(U_EMRINVERTRGN) - sizeof(U_RECTL) + cbRgns4; // core + array - overlap of one rectL + record = malloc(irecsize); if(record){ ((PU_EMR) record)->iType = iType; ((PU_EMR) record)->nSize = irecsize; ((PU_EMRINVERTRGN) record)->rclBounds = ((PU_RGNDATAHEADER) RgnData)->rclBounds; - ((PU_EMRINVERTRGN) record)->cbRgnData = cbRgns; - off = irecsize - cbRgns4; - memcpy(record + off, RgnData, cbRgns); - off += cbRgns; - if(cbRgns < cbRgns4){ memset(record + off,0, cbRgns4 - cbRgns); } // clear any unused bytes + ((PU_EMRINVERTRGN) record)->cbRgnData = rds; + off = sizeof(U_EMRINVERTRGN) - sizeof(U_RGNDATA); + memcpy(record + off, RgnData, rds); + off += rds; + if(rds < rds4){ memset(record + off,0, rds4 - rds); } // clear any unused bytes } return(record); } @@ -3274,7 +3296,7 @@ char *U_EMRPOLYBEZIER_set( const uint32_t cptl, const U_POINTL *points ){ - return(U_EMR_CORE1(U_EMR_POLYBEZIER, rclBounds, cptl, points)); + return(U_EMR_CORE1_set(U_EMR_POLYBEZIER, rclBounds, cptl, points)); } // U_EMRPOLYGON_set 3 @@ -3290,7 +3312,7 @@ char *U_EMRPOLYGON_set( const uint32_t cptl, const U_POINTL *points ){ - return(U_EMR_CORE1(U_EMR_POLYGON, rclBounds, cptl, points)); + return(U_EMR_CORE1_set(U_EMR_POLYGON, rclBounds, cptl, points)); } // U_EMRPOLYLINE_set 4 @@ -3306,7 +3328,7 @@ char *U_EMRPOLYLINE_set( const uint32_t cptl, const U_POINTL *points ){ - return(U_EMR_CORE1(U_EMR_POLYLINE, rclBounds, cptl, points)); + return(U_EMR_CORE1_set(U_EMR_POLYLINE, rclBounds, cptl, points)); } // U_EMRPOLYBEZIERTO_set 5 @@ -3322,7 +3344,7 @@ char *U_EMRPOLYBEZIERTO_set( const uint32_t cptl, const U_POINTL *points ){ - return(U_EMR_CORE1(U_EMR_POLYBEZIERTO, rclBounds, cptl, points)); + return(U_EMR_CORE1_set(U_EMR_POLYBEZIERTO, rclBounds, cptl, points)); } // U_EMRPOLYLINETO_set 6 @@ -3338,7 +3360,7 @@ char *U_EMRPOLYLINETO_set( const uint32_t cptl, const U_POINTL *points ){ - return(U_EMR_CORE1(U_EMR_POLYLINETO, rclBounds, cptl, points)); + return(U_EMR_CORE1_set(U_EMR_POLYLINETO, rclBounds, cptl, points)); } // U_EMRPOLYPOLYLINE_set 7 @@ -3358,7 +3380,7 @@ char *U_EMRPOLYPOLYLINE_set( const uint32_t cptl, const U_POINTL *points ){ - return(U_EMR_CORE2(U_EMR_POLYPOLYLINE, rclBounds, nPolys, aPolyCounts,cptl, points)); + return(U_EMR_CORE2_set(U_EMR_POLYPOLYLINE, rclBounds, nPolys, aPolyCounts,cptl, points)); } // U_EMRPOLYPOLYGON_set 8 @@ -3378,7 +3400,7 @@ char *U_EMRPOLYPOLYGON_set( const uint32_t cptl, const U_POINTL *points ){ - return(U_EMR_CORE2(U_EMR_POLYPOLYGON, rclBounds, nPolys, aPolyCounts,cptl, points)); + return(U_EMR_CORE2_set(U_EMR_POLYPOLYGON, rclBounds, nPolys, aPolyCounts,cptl, points)); } // U_EMRSETWINDOWEXTEX_set 9 @@ -3393,7 +3415,7 @@ char *U_EMRSETWINDOWEXTEX_set( U_PAIR temp; temp.x = szlExtent.cx; temp.y = szlExtent.cy; - return(U_EMR_CORE7(U_EMR_SETWINDOWEXTEX, temp)); + return(U_EMR_CORE7_set(U_EMR_SETWINDOWEXTEX, temp)); } // U_EMRSETWINDOWORGEX_set 10 @@ -3405,7 +3427,7 @@ char *U_EMRSETWINDOWEXTEX_set( char *U_EMRSETWINDOWORGEX_set( const U_POINTL ptlOrigin ){ - return(U_EMR_CORE7(U_EMR_SETWINDOWORGEX, ptlOrigin)); // U_PAIR and U_POINTL are the same thing + return(U_EMR_CORE7_set(U_EMR_SETWINDOWORGEX, ptlOrigin)); // U_PAIR and U_POINTL are the same thing } // U_EMRSETVIEWPORTEXTEX_set 11 @@ -3420,7 +3442,7 @@ char *U_EMRSETVIEWPORTEXTEX_set( U_PAIR temp; temp.x = szlExtent.cx; temp.y = szlExtent.cy; - return(U_EMR_CORE7(U_EMR_SETVIEWPORTEXTEX, temp)); + return(U_EMR_CORE7_set(U_EMR_SETVIEWPORTEXTEX, temp)); } // U_EMRSETVIEWPORTORGEX_set 12 @@ -3432,7 +3454,7 @@ char *U_EMRSETVIEWPORTEXTEX_set( char *U_EMRSETVIEWPORTORGEX_set( const U_POINTL ptlOrigin ){ - return(U_EMR_CORE7(U_EMR_SETVIEWPORTORGEX, ptlOrigin)); // U_PAIR and U_POINTL are the same thing + return(U_EMR_CORE7_set(U_EMR_SETVIEWPORTORGEX, ptlOrigin)); // U_PAIR and U_POINTL are the same thing } // U_EMRSETBRUSHORGEX_set 13 @@ -3444,7 +3466,7 @@ char *U_EMRSETVIEWPORTORGEX_set( char *U_EMRSETBRUSHORGEX_set( const U_POINTL ptlOrigin ){ - return(U_EMR_CORE7(U_EMR_SETBRUSHORGEX, *((PU_PAIR) & ptlOrigin))); + return(U_EMR_CORE7_set(U_EMR_SETBRUSHORGEX, *((PU_PAIR) & ptlOrigin))); } // U_EMREOF_set 14 @@ -3544,7 +3566,7 @@ char *U_EMRSETMAPPERFLAGS_set(void){ char *U_EMRSETMAPMODE_set( const uint32_t iMode ){ - return(U_EMR_CORE3(U_EMR_SETMAPMODE, iMode)); + return(U_EMR_CORE3_set(U_EMR_SETMAPMODE, iMode)); } // U_EMRSETBKMODE_set 18 @@ -3556,7 +3578,7 @@ char *U_EMRSETMAPMODE_set( char *U_EMRSETBKMODE_set( const uint32_t iMode ){ - return(U_EMR_CORE3(U_EMR_SETBKMODE, iMode)); + return(U_EMR_CORE3_set(U_EMR_SETBKMODE, iMode)); } // U_EMRSETPOLYFILLMODE_set 19 @@ -3568,7 +3590,7 @@ char *U_EMRSETBKMODE_set( char *U_EMRSETPOLYFILLMODE_set( const uint32_t iMode ){ - return(U_EMR_CORE3(U_EMR_SETPOLYFILLMODE, iMode)); + return(U_EMR_CORE3_set(U_EMR_SETPOLYFILLMODE, iMode)); } // U_EMRSETROP2_set 20 @@ -3580,7 +3602,7 @@ char *U_EMRSETPOLYFILLMODE_set( char *U_EMRSETROP2_set( const uint32_t iMode ){ - return(U_EMR_CORE3(U_EMR_SETROP2, iMode)); + return(U_EMR_CORE3_set(U_EMR_SETROP2, iMode)); } // U_EMRSETSTRETCHBLTMODE_set 21 @@ -3592,7 +3614,7 @@ char *U_EMRSETROP2_set( char *U_EMRSETSTRETCHBLTMODE_set( const uint32_t iMode ){ - return(U_EMR_CORE3(U_EMR_SETSTRETCHBLTMODE, iMode)); + return(U_EMR_CORE3_set(U_EMR_SETSTRETCHBLTMODE, iMode)); } // U_EMRSETTEXTALIGN_set 22 @@ -3604,7 +3626,7 @@ char *U_EMRSETSTRETCHBLTMODE_set( char *U_EMRSETTEXTALIGN_set( const uint32_t iMode ){ - return(U_EMR_CORE3(U_EMR_SETTEXTALIGN, iMode)); + return(U_EMR_CORE3_set(U_EMR_SETTEXTALIGN, iMode)); } // U_EMRSETCOLORADJUSTMENT_set 23 @@ -3638,7 +3660,7 @@ char *U_EMRSETCOLORADJUSTMENT_set( char *U_EMRSETTEXTCOLOR_set( const U_COLORREF crColor ){ - return(U_EMR_CORE3(U_EMR_SETTEXTCOLOR, *(uint32_t *) &crColor)); + return(U_EMR_CORE3_set(U_EMR_SETTEXTCOLOR, *(uint32_t *) &crColor)); } // U_EMRSETBKCOLOR_set 25 @@ -3650,7 +3672,7 @@ char *U_EMRSETTEXTCOLOR_set( char *U_EMRSETBKCOLOR_set( const U_COLORREF crColor ){ - return(U_EMR_CORE3(U_EMR_SETBKCOLOR, *(uint32_t *) &crColor)); + return(U_EMR_CORE3_set(U_EMR_SETBKCOLOR, *(uint32_t *) &crColor)); } // U_EMROFFSETCLIPRGN_set 26 @@ -3662,7 +3684,7 @@ char *U_EMRSETBKCOLOR_set( char *U_EMROFFSETCLIPRGN_set( const U_POINTL ptl ){ - return(U_EMR_CORE7(U_EMR_OFFSETCLIPRGN, ptl)); + return(U_EMR_CORE7_set(U_EMR_OFFSETCLIPRGN, ptl)); } // U_EMRMOVETOEX_set 27 @@ -3674,7 +3696,7 @@ char *U_EMROFFSETCLIPRGN_set( char *U_EMRMOVETOEX_set( const U_POINTL ptl ){ - return(U_EMR_CORE7(U_EMR_MOVETOEX, ptl)); + return(U_EMR_CORE7_set(U_EMR_MOVETOEX, ptl)); } // U_EMRSETMETARGN_set 28 @@ -3683,7 +3705,7 @@ char *U_EMRMOVETOEX_set( \return pointer to U_EMR_SETMETARGN record, or NULL on error. */ char *U_EMRSETMETARGN_set(void){ - return(U_EMR_CORE5(U_EMR_SETMETARGN)); + return(U_EMR_CORE5_set(U_EMR_SETMETARGN)); } // U_EMREXCLUDECLIPRECT_set 29 @@ -3695,7 +3717,7 @@ char *U_EMRSETMETARGN_set(void){ char *U_EMREXCLUDECLIPRECT_set( const U_RECTL rclClip ){ - return(U_EMR_CORE4(U_EMR_EXCLUDECLIPRECT,rclClip)); + return(U_EMR_CORE4_set(U_EMR_EXCLUDECLIPRECT,rclClip)); } // U_EMRINTERSECTCLIPRECT_set 30 @@ -3707,7 +3729,7 @@ char *U_EMREXCLUDECLIPRECT_set( char *U_EMRINTERSECTCLIPRECT_set( const U_RECTL rclClip ){ - return(U_EMR_CORE4(U_EMR_INTERSECTCLIPRECT,rclClip)); + return(U_EMR_CORE4_set(U_EMR_INTERSECTCLIPRECT,rclClip)); } // U_EMRSCALEVIEWPORTEXTEX_set 31 @@ -3725,7 +3747,7 @@ char *U_EMRSCALEVIEWPORTEXTEX_set( const int32_t yNum, const int32_t yDenom ){ - return(U_EMR_CORE4(U_EMR_SCALEVIEWPORTEXTEX,(U_RECTL){xNum,xDenom,yNum,yDenom})); + return(U_EMR_CORE4_set(U_EMR_SCALEVIEWPORTEXTEX,(U_RECTL){xNum,xDenom,yNum,yDenom})); } @@ -3744,7 +3766,7 @@ char *U_EMRSCALEWINDOWEXTEX_set( const int32_t yNum, const int32_t yDenom ){ - return(U_EMR_CORE4(U_EMR_SCALEWINDOWEXTEX,(U_RECTL){xNum,xDenom,yNum,yDenom})); + return(U_EMR_CORE4_set(U_EMR_SCALEWINDOWEXTEX,(U_RECTL){xNum,xDenom,yNum,yDenom})); } // U_EMRSAVEDC_set 33 @@ -3753,7 +3775,7 @@ char *U_EMRSCALEWINDOWEXTEX_set( \return pointer to U_EMR_SAVEDC record, or NULL on error. */ char *U_EMRSAVEDC_set(void){ - return(U_EMR_CORE5(U_EMR_SAVEDC)); + return(U_EMR_CORE5_set(U_EMR_SAVEDC)); } // U_EMRRESTOREDC_set 34 @@ -3765,7 +3787,7 @@ char *U_EMRSAVEDC_set(void){ char *U_EMRRESTOREDC_set( const int32_t iRelative ){ - return(U_EMR_CORE3(U_EMR_RESTOREDC, (uint32_t) iRelative)); + return(U_EMR_CORE3_set(U_EMR_RESTOREDC, (uint32_t) iRelative)); } // U_EMRSETWORLDTRANSFORM_set 35 @@ -3952,7 +3974,7 @@ char *U_EMRANGLEARC_set( char *U_EMRELLIPSE_set( const U_RECTL rclBox ){ - return(U_EMR_CORE4(U_EMR_ELLIPSE,rclBox)); + return(U_EMR_CORE4_set(U_EMR_ELLIPSE,rclBox)); } // U_EMRRECTANGLE_set 43 @@ -3964,7 +3986,7 @@ char *U_EMRELLIPSE_set( char *U_EMRRECTANGLE_set( const U_RECTL rclBox ){ - return(U_EMR_CORE4(U_EMR_RECTANGLE,rclBox)); + return(U_EMR_CORE4_set(U_EMR_RECTANGLE,rclBox)); } // U_EMRROUNDRECT_set 44 @@ -4005,7 +4027,7 @@ char *U_EMRARC_set( const U_POINTL ptlStart, const U_POINTL ptlEnd ){ - return(U_EMR_CORE9(U_EMR_ARC,rclBox, ptlStart, ptlEnd)); + return(U_EMR_CORE9_set(U_EMR_ARC,rclBox, ptlStart, ptlEnd)); } // U_EMRCHORD_set 46 @@ -4021,7 +4043,7 @@ char *U_EMRCHORD_set( const U_POINTL ptlStart, const U_POINTL ptlEnd ){ - return(U_EMR_CORE9(U_EMR_CHORD,rclBox, ptlStart, ptlEnd)); + return(U_EMR_CORE9_set(U_EMR_CHORD,rclBox, ptlStart, ptlEnd)); } // U_EMRPIE_set 47 @@ -4037,7 +4059,7 @@ char *U_EMRPIE_set( const U_POINTL ptlStart, const U_POINTL ptlEnd ){ - return(U_EMR_CORE9(U_EMR_PIE,rclBox, ptlStart, ptlEnd)); + return(U_EMR_CORE9_set(U_EMR_PIE,rclBox, ptlStart, ptlEnd)); } // U_EMRSELECTPALETTE_set 48 @@ -4049,7 +4071,7 @@ char *U_EMRPIE_set( char *U_EMRSELECTPALETTE_set( const uint32_t ihPal ){ - return(U_EMR_CORE3(U_EMR_SELECTPALETTE, ihPal)); + return(U_EMR_CORE3_set(U_EMR_SELECTPALETTE, ihPal)); } // U_EMRCREATEPALETTE_set 49 @@ -4124,7 +4146,7 @@ char *U_EMRRESIZEPALETTE_set( const uint32_t ihPal, const uint32_t cEntries ){ - return(U_EMR_CORE7(U_EMR_RESIZEPALETTE, (U_PAIR){ihPal,cEntries})); + return(U_EMR_CORE7_set(U_EMR_RESIZEPALETTE, (U_PAIR){ihPal,cEntries})); } // U_EMRREALIZEPALETTE_set 52 @@ -4133,7 +4155,7 @@ char *U_EMRRESIZEPALETTE_set( \return pointer to U_EMR_REALIZEPALETTE record, or NULL on error. */ char *U_EMRREALIZEPALETTE_set(void){ - return(U_EMR_CORE5(U_EMR_REALIZEPALETTE)); + return(U_EMR_CORE5_set(U_EMR_REALIZEPALETTE)); } // U_EMREXTFLOODFILL_set 53 @@ -4173,7 +4195,7 @@ char *U_EMREXTFLOODFILL_set( char *U_EMRLINETO_set( const U_POINTL ptl ){ - return(U_EMR_CORE7(U_EMR_LINETO, ptl)); + return(U_EMR_CORE7_set(U_EMR_LINETO, ptl)); } // U_EMRARCTO_set 55 @@ -4192,7 +4214,7 @@ char *U_EMRARCTO_set( U_POINTL ptlStart, U_POINTL ptlEnd ){ - return(U_EMR_CORE9(U_EMR_ARCTO,rclBox, ptlStart, ptlEnd)); + return(U_EMR_CORE9_set(U_EMR_ARCTO,rclBox, ptlStart, ptlEnd)); } // U_EMRPOLYDRAW_set 56 @@ -4216,7 +4238,7 @@ char *U_EMRPOLYDRAW_set( if(!cptl || !aptl || !abTypes)return(NULL); cbPoints = cptl * sizeof(U_POINTL); // space for aptl - cbAbTypes = cptl; // number of abTypes (also size, 1 byte each) + cbAbTypes = cptl; // number of abTypes (same array size, 1 byte each) cbAbTypes4 = UP4(cbAbTypes); // space for abTypes irecsize = sizeof(U_EMRPOLYDRAW) + cbPoints + cbAbTypes4 - sizeof(U_POINTL) - 1; record = malloc(irecsize); @@ -4244,7 +4266,7 @@ char *U_EMRPOLYDRAW_set( char *U_EMRSETARCDIRECTION_set( const uint32_t iArcDirection ){ - return(U_EMR_CORE3(U_EMR_SETARCDIRECTION, iArcDirection)); + return(U_EMR_CORE3_set(U_EMR_SETARCDIRECTION, iArcDirection)); } // U_EMRSETMITERLIMIT_set 58 @@ -4256,7 +4278,7 @@ char *U_EMRSETARCDIRECTION_set( char *U_EMRSETMITERLIMIT_set( const uint32_t eMiterLimit ){ - return(U_EMR_CORE3(U_EMR_SETMITERLIMIT, eMiterLimit)); + return(U_EMR_CORE3_set(U_EMR_SETMITERLIMIT, eMiterLimit)); } @@ -4266,7 +4288,7 @@ char *U_EMRSETMITERLIMIT_set( \return pointer to U_EMR_BEGINPATH record, or NULL on error. */ char *U_EMRBEGINPATH_set(void){ - return(U_EMR_CORE5(U_EMR_BEGINPATH)); + return(U_EMR_CORE5_set(U_EMR_BEGINPATH)); } // U_EMRENDPATH_set 60 @@ -4275,7 +4297,7 @@ char *U_EMRBEGINPATH_set(void){ \return pointer to U_EMR_ENDPATH record, or NULL on error. */ char *U_EMRENDPATH_set(void){ - return(U_EMR_CORE5(U_EMR_ENDPATH)); + return(U_EMR_CORE5_set(U_EMR_ENDPATH)); } // U_EMRCLOSEFIGURE_set 61 @@ -4284,7 +4306,7 @@ char *U_EMRENDPATH_set(void){ \return pointer to U_EMR_CLOSEFIGURE record, or NULL on error. */ char *U_EMRCLOSEFIGURE_set(void){ - return(U_EMR_CORE5(U_EMR_CLOSEFIGURE)); + return(U_EMR_CORE5_set(U_EMR_CLOSEFIGURE)); } // U_EMRFILLPATH_set 62 @@ -4298,7 +4320,7 @@ char *U_EMRCLOSEFIGURE_set(void){ char *U_EMRFILLPATH_set( const U_RECTL rclBox ){ - return(U_EMR_CORE4(U_EMR_FILLPATH,rclBox)); + return(U_EMR_CORE4_set(U_EMR_FILLPATH,rclBox)); } // U_EMRSTROKEANDFILLPATH_set 63 @@ -4314,7 +4336,7 @@ char *U_EMRFILLPATH_set( char *U_EMRSTROKEANDFILLPATH_set( const U_RECTL rclBox ){ - return(U_EMR_CORE4(U_EMR_STROKEANDFILLPATH,rclBox)); + return(U_EMR_CORE4_set(U_EMR_STROKEANDFILLPATH,rclBox)); } // U_EMRSTROKEPATH_set 64 @@ -4328,7 +4350,7 @@ char *U_EMRSTROKEANDFILLPATH_set( char *U_EMRSTROKEPATH_set( const U_RECTL rclBox ){ - return(U_EMR_CORE4(U_EMR_STROKEPATH,rclBox)); + return(U_EMR_CORE4_set(U_EMR_STROKEPATH,rclBox)); } // U_EMRFLATTENPATH_set 65 @@ -4337,7 +4359,7 @@ char *U_EMRSTROKEPATH_set( \return pointer to U_EMR_FLATTENPATH record, or NULL on error. */ char *U_EMRFLATTENPATH_set(void){ - return(U_EMR_CORE5(U_EMR_FLATTENPATH)); + return(U_EMR_CORE5_set(U_EMR_FLATTENPATH)); } // U_EMRWIDENPATH_set 66 @@ -4346,7 +4368,7 @@ char *U_EMRFLATTENPATH_set(void){ \return pointer to U_EMR_WIDENPATH record, or NULL on error. */ char *U_EMRWIDENPATH_set(void){ - return(U_EMR_CORE5(U_EMR_WIDENPATH)); + return(U_EMR_CORE5_set(U_EMR_WIDENPATH)); } // U_EMRSELECTCLIPPATH_set 67 @@ -4358,7 +4380,7 @@ char *U_EMRWIDENPATH_set(void){ char *U_EMRSELECTCLIPPATH_set( const uint32_t iMode ){ - return(U_EMR_CORE3(U_EMR_SELECTCLIPPATH, iMode)); + return(U_EMR_CORE3_set(U_EMR_SELECTCLIPPATH, iMode)); } // U_EMRABORTPATH_set 68 @@ -4367,7 +4389,7 @@ char *U_EMRSELECTCLIPPATH_set( \return pointer to U_EMR_ABORTPATH record, or NULL on error. */ char *U_EMRABORTPATH_set(void){ - return(U_EMR_CORE5(U_EMR_ABORTPATH)); + return(U_EMR_CORE5_set(U_EMR_ABORTPATH)); } // U_EMRUNDEF69 69 @@ -4416,23 +4438,25 @@ char *U_EMRFILLRGN_set( ){ char *record; int irecsize; - int cbRgns,cbRgns4,off; + int cbRgns,cbRgns4,rds,rds4,off; if(!RgnData)return(NULL); cbRgns = ((PU_RGNDATAHEADER) RgnData)->nRgnSize; - cbRgns4 = UP4(cbRgns); - irecsize = sizeof(U_EMRFILLRGN) + cbRgns4 - sizeof(U_RGNDATAHEADER); // core + array - overlap + cbRgns4 = UP4(cbRgns); + rds = sizeof(U_RGNDATAHEADER) + cbRgns; + rds4 = UP4(rds); + irecsize = sizeof(U_EMRFILLRGN) - sizeof(U_RECTL) + cbRgns4; // core + array - overlap of one rectL record = malloc(irecsize); if(record){ ((PU_EMR) record)->iType = U_EMR_FILLRGN; ((PU_EMR) record)->nSize = irecsize; - ((PU_EMRFILLRGN) record)->rclBounds = rclBounds; // or ??? ((PU_RGNDATAHEADER) RgnData)->rclBounds; - ((PU_EMRFILLRGN) record)->cbRgnData = cbRgns; + ((PU_EMRFILLRGN) record)->rclBounds = rclBounds; + ((PU_EMRFILLRGN) record)->cbRgnData = rds; ((PU_EMRFILLRGN) record)->ihBrush = ihBrush; - off = irecsize - cbRgns4; - memcpy(record + off, RgnData, cbRgns); - off += cbRgns; - if(cbRgns4 > cbRgns){ memset(record + off,0,cbRgns4-cbRgns); } // clear any unused bytes + off = sizeof(U_EMRFILLRGN) - sizeof(U_RGNDATA); + memcpy(record + off, RgnData, rds); + off += rds; + if(rds < rds4){ memset(record + off,0, rds4 - rds); } // clear any unused bytes } return(record); } @@ -4455,24 +4479,26 @@ char *U_EMRFRAMERGN_set( ){ char *record; int irecsize; - int cbRgns,cbRgns4,off; + int cbRgns,cbRgns4,rds,rds4,off; if(!RgnData)return(NULL); cbRgns = ((PU_RGNDATAHEADER) RgnData)->nRgnSize; - cbRgns4 = UP4(cbRgns); - irecsize = sizeof(U_EMRFRAMERGN) + cbRgns4 - sizeof(U_RGNDATAHEADER); // core + array - overlap + cbRgns4 = UP4(cbRgns); + rds = sizeof(U_RGNDATAHEADER) + cbRgns; + rds4 = UP4(rds); + irecsize = sizeof(U_EMRFRAMERGN) - sizeof(U_RECTL) + cbRgns4; // core + array - overlap of one rectL record = malloc(irecsize); if(record){ ((PU_EMR) record)->iType = U_EMR_FRAMERGN; ((PU_EMR) record)->nSize = irecsize; - ((PU_EMRFRAMERGN) record)->rclBounds = rclBounds; // or ??? ((PU_RGNDATAHEADER) RgnData)->rclBounds; - ((PU_EMRFRAMERGN) record)->cbRgnData = cbRgns; + ((PU_EMRFRAMERGN) record)->rclBounds = rclBounds; + ((PU_EMRFRAMERGN) record)->cbRgnData = rds; ((PU_EMRFRAMERGN) record)->ihBrush = ihBrush; ((PU_EMRFRAMERGN) record)->szlStroke = szlStroke; - off = irecsize - cbRgns4; - memcpy(record + off, RgnData, cbRgns); - off += cbRgns; - if(cbRgns4 > cbRgns){ memset(record + off,0,cbRgns4-cbRgns); } // clear any unused bytes + off = sizeof(U_EMRFRAMERGN) - sizeof(U_RGNDATA); + memcpy(record + off, RgnData, rds); + off += rds; + if(rds < rds4){ memset(record + off,0, rds4 - rds); } // clear any unused bytes } return(record); } @@ -4486,7 +4512,7 @@ char *U_EMRFRAMERGN_set( char *U_EMRINVERTRGN_set( const PU_RGNDATA RgnData ){ - return(U_EMR_CORE11(U_EMR_INVERTRGN, RgnData)); + return(U_EMR_CORE11_set(U_EMR_INVERTRGN, RgnData)); } // U_EMRPAINTRGN_set 74 @@ -4498,7 +4524,7 @@ char *U_EMRINVERTRGN_set( char *U_EMRPAINTRGN_set( const PU_RGNDATA RgnData ){ - return(U_EMR_CORE11(U_EMR_PAINTRGN, RgnData)); + return(U_EMR_CORE11_set(U_EMR_PAINTRGN, RgnData)); } // U_EMREXTSELECTCLIPRGN_set 75 @@ -4514,22 +4540,24 @@ char *U_EMREXTSELECTCLIPRGN_set( ){ char *record; int irecsize; - int cbRgns,cbRgns4,off; + int cbRgns,cbRgns4,rds,rds4,off; if(!RgnData)return(NULL); cbRgns = ((PU_RGNDATAHEADER) RgnData)->nRgnSize; - cbRgns4 = UP4(cbRgns); - irecsize = sizeof(U_EMREXTSELECTCLIPRGN) + cbRgns4 - sizeof(U_RGNDATAHEADER); // core + array - overlap + cbRgns4 = UP4(cbRgns); + rds = sizeof(U_RGNDATAHEADER) + cbRgns; + rds4 = UP4(rds); + irecsize = sizeof(U_EMREXTSELECTCLIPRGN) - sizeof(U_RECTL) + cbRgns4; // core + array - overlap of one rectL record = malloc(irecsize); if(record){ ((PU_EMR) record)->iType = U_EMR_EXTSELECTCLIPRGN; ((PU_EMR) record)->nSize = irecsize; - ((PU_EMREXTSELECTCLIPRGN) record)->cbRgnData = cbRgns; + ((PU_EMREXTSELECTCLIPRGN) record)->cbRgnData = rds; ((PU_EMREXTSELECTCLIPRGN) record)->iMode = iMode; - off = irecsize - cbRgns4; - memcpy(record + off, RgnData, cbRgns); - off += cbRgns; - if(cbRgns4 > cbRgns){ memset(record + off,0,cbRgns4-cbRgns); } // clear any unused bytes + off = sizeof(U_EMREXTSELECTCLIPRGN) - sizeof(U_RGNDATA); + memcpy(record + off, RgnData, rds); + off += rds; + if(rds < rds4){ memset(record + off,0, rds4 - rds); } // clear any unused bytes } return(record); } @@ -4568,7 +4596,6 @@ char *U_EMRBITBLT_set( int cbImage,cbImage4,cbBmi,off; SET_CB_FROM_PXBMI(Px,Bmi,cbImage,cbImage4,cbBmi,cbPx); - irecsize = sizeof(U_EMRBITBLT) + cbBmi + cbImage4; record = malloc(irecsize); if(record){ @@ -4933,7 +4960,7 @@ char *U_EMREXTTEXTOUTA_set( const U_FLOAT eyScale, const PU_EMRTEXT emrtext ){ - return(U_EMR_CORE8(U_EMR_EXTTEXTOUTA,rclBounds, iGraphicsMode, exScale, eyScale,emrtext)); + return(U_EMR_CORE8_set(U_EMR_EXTTEXTOUTA,rclBounds, iGraphicsMode, exScale, eyScale,emrtext)); } // U_EMREXTTEXTOUTW_set 84 @@ -4953,7 +4980,7 @@ char *U_EMREXTTEXTOUTW_set( const U_FLOAT eyScale, const PU_EMRTEXT emrtext ){ - return(U_EMR_CORE8(U_EMR_EXTTEXTOUTW,rclBounds, iGraphicsMode, exScale, eyScale,emrtext)); + return(U_EMR_CORE8_set(U_EMR_EXTTEXTOUTW,rclBounds, iGraphicsMode, exScale, eyScale,emrtext)); } // U_EMRPOLYBEZIER16_set 85 @@ -4969,7 +4996,7 @@ char *U_EMRPOLYBEZIER16_set( const uint32_t cpts, const U_POINT16 *points ){ - return(U_EMR_CORE6(U_EMR_POLYBEZIER16, rclBounds, cpts, points)); + return(U_EMR_CORE6_set(U_EMR_POLYBEZIER16, rclBounds, cpts, points)); } // U_EMRPOLYGON16_set 86 @@ -4985,7 +5012,7 @@ char *U_EMRPOLYGON16_set( const uint32_t cpts, const U_POINT16 *points ){ - return(U_EMR_CORE6(U_EMR_POLYGON16, rclBounds, cpts, points)); + return(U_EMR_CORE6_set(U_EMR_POLYGON16, rclBounds, cpts, points)); } // U_EMRPOLYLINE16_set 87 @@ -5001,7 +5028,7 @@ char *U_EMRPOLYLINE16_set( const uint32_t cpts, const U_POINT16 *points ){ - return(U_EMR_CORE6(U_EMR_POLYLINE16, rclBounds, cpts, points)); + return(U_EMR_CORE6_set(U_EMR_POLYLINE16, rclBounds, cpts, points)); } // U_EMRPOLYBEZIERTO16_set 88 @@ -5017,7 +5044,7 @@ char *U_EMRPOLYBEZIERTO16_set( const uint32_t cpts, const U_POINT16 *points ){ - return(U_EMR_CORE6(U_EMR_POLYBEZIERTO16, rclBounds, cpts, points)); + return(U_EMR_CORE6_set(U_EMR_POLYBEZIERTO16, rclBounds, cpts, points)); } // U_EMRPOLYLINETO16_set 89 @@ -5033,7 +5060,7 @@ char *U_EMRPOLYLINETO16_set( const uint32_t cpts, const U_POINT16 *points ){ - return(U_EMR_CORE6(U_EMR_POLYLINETO16, rclBounds, cpts, points)); + return(U_EMR_CORE6_set(U_EMR_POLYLINETO16, rclBounds, cpts, points)); } // U_EMRPOLYPOLYLINE16_set 90 @@ -5053,7 +5080,7 @@ char *U_EMRPOLYPOLYLINE16_set( const uint32_t cpts, const U_POINT16 *points ){ - return(U_EMR_CORE10(U_EMR_POLYPOLYLINE16, rclBounds, nPolys, aPolyCounts,cpts, points)); + return(U_EMR_CORE10_set(U_EMR_POLYPOLYLINE16, rclBounds, nPolys, aPolyCounts,cpts, points)); } // U_EMRPOLYPOLYGON16_set 91 @@ -5073,7 +5100,7 @@ char *U_EMRPOLYPOLYGON16_set( const uint32_t cpts, const U_POINT16 *points ){ - return(U_EMR_CORE10(U_EMR_POLYPOLYGON16, rclBounds, nPolys, aPolyCounts,cpts, points)); + return(U_EMR_CORE10_set(U_EMR_POLYPOLYGON16, rclBounds, nPolys, aPolyCounts,cpts, points)); } @@ -5098,7 +5125,7 @@ char *U_EMRPOLYDRAW16_set( if(!cpts || !aptl || !abTypes)return(NULL); cbPoints = cpts * sizeof(U_POINT16); // space for aptl - cbAbTypes = cpts; // number of abTypes (also size, 1 byte each) + cbAbTypes = cpts; // number of abTypes (same array size, 1 byte each) cbAbTypes4 = UP4(cbAbTypes); // space for abTypes irecsize = sizeof(U_EMRPOLYDRAW16) + cbPoints + cbAbTypes4 - sizeof(U_POINT16) - 1; record = malloc(irecsize); @@ -5242,7 +5269,7 @@ char *U_EMREXTCREATEPEN_set( char *U_EMRSETICMMODE_set( const uint32_t iMode ){ - return(U_EMR_CORE3(U_EMR_SETICMMODE, iMode)); + return(U_EMR_CORE3_set(U_EMR_SETICMMODE, iMode)); } // U_EMRCREATECOLORSPACE_set 99 @@ -5280,7 +5307,7 @@ char *U_EMRCREATECOLORSPACE_set( char *U_EMRSETCOLORSPACE_set( const uint32_t ihCS ){ - return(U_EMR_CORE3(U_EMR_SETCOLORSPACE, ihCS)); + return(U_EMR_CORE3_set(U_EMR_SETCOLORSPACE, ihCS)); } // U_EMRDELETECOLORSPACE_set 101 @@ -5292,7 +5319,7 @@ char *U_EMRSETCOLORSPACE_set( char *U_EMRDELETECOLORSPACE_set( const uint32_t ihCS ){ - return(U_EMR_CORE3(U_EMR_DELETECOLORSPACE, ihCS)); + return(U_EMR_CORE3_set(U_EMR_DELETECOLORSPACE, ihCS)); } // U_EMRGLSRECORD_set 102 Not implemented @@ -5428,7 +5455,7 @@ char *U_EMRALPHABLEND_set( \param iMode Mirroring Enumeration */ char *U_EMRSETLAYOUT_set(uint32_t iMode){ - return(U_EMR_CORE3(U_EMR_SETLAYOUT, iMode)); + return(U_EMR_CORE3_set(U_EMR_SETLAYOUT, iMode)); } // U_EMRTRANSPARENTBLT_set 116 diff --git a/src/libuemf/uemf.h b/src/libuemf/uemf.h index a792a65de..53426cb55 100644 --- a/src/libuemf/uemf.h +++ b/src/libuemf/uemf.h @@ -95,11 +95,11 @@ these WMF enumerations is by referencing the following table: /* File: uemf.h -Version: 0.0.27 -Date: 28-MAR-2014 +Version: 0.0.31 +Date: 23-APR-2015 Author: David Mathog, Biology Division, Caltech email: mathog@caltech.edu -Copyright: 2014 David Mathog and California Institute of Technology (Caltech) +Copyright: 2015 David Mathog and California Institute of Technology (Caltech) */ #ifndef _UEMF_ @@ -167,6 +167,9 @@ extern "C" { /** Solaris 8 has problems with round/roundf, just use this everywhere */ #define U_ROUND(A) ( (A) > 0 ? floor((A)+0.5) : ( (A) < 0 ? -floor(-(A)+0.5) : (A) ) ) +#define MAKE_MIN_PTR(A,B) ( A < B ? A : B) +#define IS_MEM_UNSAFE(A,B,C) ( (int8_t *)(A) > (int8_t *)(C) ? 1 : ((int8_t *)(C) - (int8_t *)(A) >= (int)(B) ? 0 : 1 )) //!< Return 1 when a region of memory starting at A of B bytes extends beyond pointer C + /** @} */ @@ -1799,7 +1802,7 @@ typedef struct { //!< In MS documentation this is Log *PU_PATTERN; //!< EMF manual 2.2.12 /** - \brief For U_LOGFONT_PANOSE elfLogFont field + \brief For U_LOGFONT elfLogFont field EMF manual 2.2.13, Microsoft name: LogFont Object */ @@ -2075,6 +2078,9 @@ typedef struct { // *********************************************************************************** // The following have U_EMR_# records. They are ordered by their record index, not by EMF manual position. +// records which are documented but not implemented +#define U_SIZE_EMRNOTIMPLEMENTED 2048 + /* Index 1 */ /** \brief The first U_ENHMETARECORD record in the metafile. @@ -2117,6 +2123,8 @@ typedef struct { U_SIZEL szlMicrometers; //!< Size of the display device in micrometer } U_EMRHEADER, *PU_EMRHEADER; //!< EMF manual 2.2.9 +#define U_SIZE_EMRHEADER sizeof(U_EMRHEADER) // modern EMF files, for _really_ old ones the _MIN size applies +#define U_SIZE_EMRHEADER_MIN (U_SIZE_EMRHEADER - sizeof(U_CBPXLFMT) - sizeof(U_OFFPXLFMT) - sizeof(uint32_t) - sizeof(U_SIZEL)) /* Index 2,3,4,5,6 */ /** EMF manual 2.3.5.16 @@ -2137,6 +2145,11 @@ typedef struct { *PU_EMRPOLYBEZIERTO, //!< EMF manual 2.3.5.18 *PU_EMRPOLYLINETO; //!< EMF manual 2.3.5.26 +#define U_SIZE_EMRPOLYBEZIER (sizeof(U_EMR) + sizeof(U_RECTL) + sizeof(U_NUM_POINTL) ) +#define U_SIZE_EMRPOLYGON U_SIZE_EMRPOLYBEZIER +#define U_SIZE_EMRPOLYLINE U_SIZE_EMRPOLYBEZIER +#define U_SIZE_EMRPOLYBEZIERTO U_SIZE_EMRPOLYBEZIER +#define U_SIZE_EMRPOLYLINETO U_SIZE_EMRPOLYBEZIER /* Index 7,8 */ /** EMF manual 2.3.5.30 @@ -2153,6 +2166,8 @@ typedef struct { U_EMRPOLYPOLYGON, //!< EMF manual 2.3.5.28 *PU_EMRPOLYPOLYLINE, //!< EMF manual 2.3.5.30 *PU_EMRPOLYPOLYGON; //!< EMF manual 2.3.5.28 +#define U_SIZE_EMRPOLYPOLYLINE (sizeof(U_EMR) + sizeof(U_RECTL) + sizeof(U_NUM_POLYCOUNTS) + sizeof(U_POLYCOUNTS)) +#define U_SIZE_EMRPOLYPOLYGON U_SIZE_EMRPOLYPOLYLINE /* Index 9,11 (numbers interleave with next one) */ /** EMF manual 2.3.11.30 @@ -2164,6 +2179,8 @@ typedef struct { U_EMRSETVIEWPORTEXTEX, //!< EMF manual manual 2.3.11.28 *PU_EMRSETWINDOWEXTEX, //!< EMF manual manual 2.3.11.30 *PU_EMRSETVIEWPORTEXTEX; //!< EMF manual manual 2.3.11.28 +#define U_SIZE_EMRSETWINDOWEXTEX (sizeof(U_EMRSETWINDOWEXTEX )) +#define U_SIZE_EMRSETVIEWPORTEXTEX (sizeof(U_EMRSETVIEWPORTEXTEX)) /* Index 10,12,13 */ /** EMF manual 2.3.11.31 @@ -2177,7 +2194,9 @@ typedef struct { *PU_EMRSETWINDOWORGEX, //!< EMF manual 2.3.11.31 *PU_EMRSETVIEWPORTORGEX, //!< EMF manual 2.3.11.29 *PU_EMRSETBRUSHORGEX; //!< EMF manual 2.3.11.12 - +#define U_SIZE_EMRSETWINDOWORGEX (sizeof(U_EMRSETWINDOWORGEX )) +#define U_SIZE_EMRSETVIEWPORTORGEX (sizeof(U_EMRSETVIEWPORTORGEX)) +#define U_SIZE_EMRSETBRUSHORGEX (sizeof(U_EMRSETBRUSHORGEX )) /* Index 14 */ /** EMF manual 3.2.4.1 @@ -2197,6 +2216,7 @@ typedef struct { U_OFFPLENTRIES offPalEntries; //!< Offset in bytes to array of palette entries } U_EMREOF, *PU_EMREOF; //!< EMF manual 3.2.4.1 +#define U_SIZE_EMREOF (sizeof(U_EMREOF)) /* Index 15 */ /** EMF manual 2.3.5.36 @@ -2207,6 +2227,7 @@ typedef struct { U_COLORREF crColor; //!< Pixel color } U_EMRSETPIXELV, *PU_EMRSETPIXELV; //!< EMF manual 2.3.5.36 +#define U_SIZE_EMRSETPIXELV (sizeof(U_EMRSETPIXELV)) /* Index 16 */ /** EMF manual 2.3.11.20 @@ -2216,6 +2237,7 @@ typedef struct { uint32_t dwFlags; //!< must be 1 } U_EMRSETMAPPERFLAGS, *PU_EMRSETMAPPERFLAGS; //!< EMF manual 2.3.11.20 +#define U_SIZE_EMRSETMAPPERFLAGS (sizeof(U_EMRSETMAPPERFLAGS)) /* Index 17,18,19,20,21,22,67,98,115 */ @@ -2243,6 +2265,16 @@ typedef struct { *PU_EMRSETICMMODE, //!< EMF manual 2.3.11.14 ICMMode Enumeration *PU_EMRSETLAYOUT; //!< EMF manual 2.3.11.17 Mirroring Enumeration +#define U_SIZE_EMRSETMAPMODE (sizeof(U_EMRSETMAPMODE )) +#define U_SIZE_EMRSETBKMODE (sizeof(U_EMRSETBKMODE )) +#define U_SIZE_EMRSETPOLYFILLMODE (sizeof(U_EMRSETPOLYFILLMODE )) +#define U_SIZE_EMRSETROP2 (sizeof(U_EMRSETROP2 )) +#define U_SIZE_EMRSETSTRETCHBLTMODE (sizeof(U_EMRSETSTRETCHBLTMODE)) +#define U_SIZE_EMRSETTEXTALIGN (sizeof(U_EMRSETTEXTALIGN )) +#define U_SIZE_EMRSELECTCLIPPATH (sizeof(U_EMRSELECTCLIPPATH )) +#define U_SIZE_EMRSETICMMODE (sizeof(U_EMRSETICMMODE )) +#define U_SIZE_EMRSETLAYOUT (sizeof(U_EMRSETLAYOUT )) + /* Index 23 */ /** EMF manual 2.3.11.13 */ @@ -2251,6 +2283,7 @@ typedef struct { U_COLORADJUSTMENT ColorAdjustment; //!< Color Adjustment } U_EMRSETCOLORADJUSTMENT, *PU_EMRSETCOLORADJUSTMENT; //!< EMF manual 2.3.11.13 +#define U_SIZE_EMRSETCOLORADJUSTMENT (sizeof(U_EMRSETCOLORADJUSTMENT)) /* Index 24, 25 */ /** EMF manual 2.3.11.26 @@ -2262,6 +2295,8 @@ typedef struct { U_EMRSETBKCOLOR, //!< EMF manual 2.3.11.10 *PU_EMRSETTEXTCOLOR, //!< EMF manual 2.3.11.26 *PU_EMRSETBKCOLOR; //!< EMF manual 2.3.11.10 +#define U_SIZE_EMRSETTEXTCOLOR (sizeof(U_EMRSETTEXTCOLOR)) +#define U_SIZE_EMRSETBKCOLOR (sizeof(U_EMRSETBKCOLOR )) /* Index 26 */ /** EMF manual 2.3.2.4 @@ -2271,6 +2306,7 @@ typedef struct { U_POINTL ptlOffset; //!< Clipping region } U_EMROFFSETCLIPRGN, *PU_EMROFFSETCLIPRGN; //!< EMF manual 2.3.2.4 +#define U_SIZE_EMROFFSETCLIPRGN (sizeof(U_EMROFFSETCLIPRGN)) /* Index 27, 54 */ /** @@ -2284,6 +2320,8 @@ typedef struct { U_EMRLINETO, //!< EMF manual 2.3.5.13 *PU_EMRMOVETOEX, //!< EMF manual 2.3.11.4 *PU_EMRLINETO; //!< EMF manual 2.3.5.13 +#define U_SIZE_EMRMOVETOEX (sizeof(U_EMRMOVETOEX)) +#define U_SIZE_EMRLINETO (sizeof(U_EMRLINETO )) /* Index 28,33,52,59,60,61,65,66,68 */ /** EMF manual 2.3.2 @@ -2309,6 +2347,15 @@ typedef struct { *PU_EMRFLATTENPATH, //!< EMF manual 2.3.10 *PU_EMRWIDENPATH, //!< EMF manual 2.3.10 *PU_EMRABORTPATH; //!< EMF manual 2.3.10 +#define U_SIZE_EMRSETMETARGN (sizeof(U_EMRSETMETARGN )) +#define U_SIZE_EMRSAVEDC (sizeof(U_EMRSAVEDC )) +#define U_SIZE_EMRREALIZEPALETTE (sizeof(U_EMRREALIZEPALETTE)) +#define U_SIZE_EMRBEGINPATH (sizeof(U_EMRBEGINPATH )) +#define U_SIZE_EMRENDPATH (sizeof(U_EMRENDPATH )) +#define U_SIZE_EMRCLOSEFIGURE (sizeof(U_EMRCLOSEFIGURE )) +#define U_SIZE_EMRFLATTENPATH (sizeof(U_EMRFLATTENPATH )) +#define U_SIZE_EMRWIDENPATH (sizeof(U_EMRWIDENPATH )) +#define U_SIZE_EMRABORTPATH (sizeof(U_EMRABORTPATH )) /* Index 29,30 */ /** EMF manual 2.3.2.1 @@ -2320,6 +2367,8 @@ typedef struct { U_EMRINTERSECTCLIPRECT, //!< EMF manual 2.3.2.3 *PU_EMREXCLUDECLIPRECT, //!< EMF manual 2.3.2.1 *PU_EMRINTERSECTCLIPRECT; //!< EMF manual 2.3.2.3 +#define U_SIZE_EMREXCLUDECLIPRECT (sizeof(U_EMREXCLUDECLIPRECT )) +#define U_SIZE_EMRINTERSECTCLIPRECT (sizeof(U_EMRINTERSECTCLIPRECT )) /* Index 31,32 */ /** EMF manual 2.3.11.7 @@ -2334,6 +2383,8 @@ typedef struct { U_EMRSCALEWINDOWEXTEX, //!< EMF manual 2.3.11.8 *PU_EMRSCALEVIEWPORTEXTEX, //!< EMF manual 2.3.11.7 *PU_EMRSCALEWINDOWEXTEX; //!< EMF manual 2.3.11.8 +#define U_SIZE_EMRSCALEVIEWPORTEXTEX (sizeof(U_EMRSCALEVIEWPORTEXTEX)) +#define U_SIZE_EMRSCALEWINDOWEXTEX (sizeof(U_EMRSCALEWINDOWEXTEX )) /* Index 33 (see 28) */ @@ -2345,6 +2396,7 @@ typedef struct { int32_t iRelative; //!< DC to restore. -1 is preceding } U_EMRRESTOREDC, *PU_EMRRESTOREDC; //!< EMF manual 2.3.11.6 +#define U_SIZE_EMRRESTOREDC (sizeof(U_EMRRESTOREDC)) /* Index 35 */ /** EMF manual 2.3.12.2 @@ -2354,6 +2406,7 @@ typedef struct { U_XFORM xform; //!< Transform } U_EMRSETWORLDTRANSFORM, *PU_EMRSETWORLDTRANSFORM; //!< EMF manual 2.3.12.2 +#define U_SIZE_EMRSETWORLDTRANSFORM (sizeof(U_EMRSETWORLDTRANSFORM)) /* Index 36 */ /** EMF manual 2.3.12.1 @@ -2364,6 +2417,7 @@ typedef struct { uint32_t iMode; //!< ModifyWorldTransformMode Enumeration } U_EMRMODIFYWORLDTRANSFORM, *PU_EMRMODIFYWORLDTRANSFORM; //!< EMF manual 2.3.12.1 +#define U_SIZE_EMRMODIFYWORLDTRANSFORM (sizeof(U_EMRMODIFYWORLDTRANSFORM)) /* Index 37,40 */ /** EMF manual 2.3.8.3 @@ -2375,6 +2429,8 @@ typedef struct { U_EMRSELECTOBJECT, //!< EMF manual 2.3.8.5 *PU_EMRDELETEOBJECT, //!< EMF manual 2.3.8.3 *PU_EMRSELECTOBJECT; //!< EMF manual 2.3.8.5 +#define U_SIZE_EMRDELETEOBJECT (sizeof(U_EMRDELETEOBJECT)) +#define U_SIZE_EMRSELECTOBJECT (sizeof(U_EMRSELECTOBJECT)) /* Index 38 */ /** EMF manual 2.3.7.7 @@ -2385,6 +2441,7 @@ typedef struct { U_LOGPEN lopn; //!< Pen properties } U_EMRCREATEPEN, *PU_EMRCREATEPEN; //!< EMF manual 2.3.7.7 +#define U_SIZE_EMRCREATEPEN (sizeof(U_EMRCREATEPEN)) /* Index 39 */ /** EMF manual 2.3.7.1 @@ -2395,6 +2452,7 @@ typedef struct { U_LOGBRUSH lb; //!< Brush properties } U_EMRCREATEBRUSHINDIRECT, *PU_EMRCREATEBRUSHINDIRECT; //!< EMF manual 2.3.7.1 +#define U_SIZE_EMRCREATEBRUSHINDIRECT (sizeof(U_EMRCREATEBRUSHINDIRECT)) /* Index 40 see 37 */ @@ -2409,6 +2467,7 @@ typedef struct { U_FLOAT eSweepAngle; //!< Sweep angle in degrees } U_EMRANGLEARC, *PU_EMRANGLEARC; //!< EMF manual 2.3.5.1 +#define U_SIZE_EMRANGLEARC (sizeof(U_EMRANGLEARC)) /* Index 42,43 */ /** EMF manual 2.3.5.5 @@ -2420,6 +2479,8 @@ typedef struct { U_EMRRECTANGLE, //!< EMF manual 2.3.5.5 *PU_EMRELLIPSE, //!< EMF manual 2.3.5.5 *PU_EMRRECTANGLE; //!< EMF manual 2.3.5.34 +#define U_SIZE_EMRELLIPSE (sizeof(U_EMRELLIPSE )) +#define U_SIZE_EMRRECTANGLE (sizeof(U_EMRRECTANGLE)) /* Index 44 */ /** EMF manual 2.3.5.35 @@ -2430,6 +2491,7 @@ typedef struct { U_SIZEL szlCorner; //!< W & H in logical units of ellipse used to round corner } U_EMRROUNDRECT, *PU_EMRROUNDRECT; //!< EMF manual 2.3.5.35 +#define U_SIZE_EMRROUNDRECT (sizeof(U_EMRROUNDRECT)) /* Index 45, 46 ,47, 55 */ /** EMF manual 2.3.5.2 @@ -2447,6 +2509,10 @@ typedef struct { *PU_EMRCHORD, //!< EMF manual 2.3.5.4 *PU_EMRPIE, //!< EMF manual 2.3.5.15 *PU_EMRARCTO; //!< EMF manual 2.3.5.3 +#define U_SIZE_EMRARC (sizeof(U_EMRARC )) +#define U_SIZE_EMRCHORD (sizeof(U_EMRCHORD)) +#define U_SIZE_EMRPIE (sizeof(U_EMRPIE )) +#define U_SIZE_EMRARCTO (sizeof(U_EMRARCTO)) /* Index 48 */ /** EMF manual 2.3.8.6 @@ -2456,6 +2522,7 @@ typedef struct { uint32_t ihPal; //!< Index of a Palette object in the EMF object table } U_EMRSELECTPALETTE, *PU_EMRSELECTPALETTE; //!< EMF manual 2.3.8.6 +#define U_SIZE_EMRSELECTPALETTE (sizeof(U_EMRSELECTPALETTE)) /* Index 49 */ /** EMF manual 2.3.7.6 @@ -2466,6 +2533,7 @@ typedef struct { U_LOGPALETTE lgpl; //!< Palette properties } U_EMRCREATEPALETTE, *PU_EMRCREATEPALETTE; //!< EMF manual 2.3.7.6 +#define U_SIZE_EMRCREATEPALETTE (sizeof(U_EMRCREATEPALETTE)) /* Index 50 */ /** EMF manual 2.3.8.8 @@ -2478,6 +2546,7 @@ typedef struct { U_LOGPLTNTRY aPalEntries[1]; //!< Values to set with } U_EMRSETPALETTEENTRIES, *PU_EMRSETPALETTEENTRIES; //!< EMF manual 2.3.8.8 +#define U_SIZE_EMRSETPALETTEENTRIES (sizeof(U_EMR) + 2*sizeof(uint32_t) + sizeof(U_NUM_LOGPLTNTRY)) /* Index 51 */ /** EMF manual 2.3.8.4 @@ -2488,6 +2557,7 @@ typedef struct { uint32_t cEntries; //!< Number to expand or truncate the Palette entry list to. } U_EMRRESIZEPALETTE, *PU_EMRRESIZEPALETTE; //!< EMF manual 2.3.8.4 +#define U_SIZE_EMRRESIZEPALETTE (sizeof(U_EMRRESIZEPALETTE)) /* Index 52 (see 28) */ @@ -2501,22 +2571,26 @@ typedef struct { uint32_t iMode; //!< FloodFill Enumeration } U_EMREXTFLOODFILL, *PU_EMREXTFLOODFILL; //!< EMF manual 2.3.5.6 +#define U_SIZE_EMREXTFLOODFILL (sizeof(U_EMREXTFLOODFILL)) /* Index 54 (see 27) */ /* Index 55 (see 45) */ /* Index 56 */ -/** EMF manual 2.3.5.20 +/** EMF manual 2.3.5.20 + + followed by + uint8_t abTypes[1]; //!< Array of Point Enumeration */ typedef struct { U_EMR emr; //!< U_EMR U_RECTL rclBounds; //!< Bounding rectangle in device units U_NUM_POINTL cptl; //!< Number of U_POINTL objects U_POINTL aptl[1]; //!< Array of U_POINTL objects - uint8_t abTypes[1]; //!< Array of Point Enumeration } U_EMRPOLYDRAW, *PU_EMRPOLYDRAW; //!< EMF manual 2.3.5.20 +#define U_SIZE_EMRPOLYDRAW (sizeof(U_EMR) + sizeof(U_RECTL) + sizeof(U_NUM_POINTL)) /* Index 57 */ /** EMF manual 2.3.11.9 @@ -2526,6 +2600,7 @@ typedef struct { uint32_t iArcDirection; //!< ArcDirection Enumeration } U_EMRSETARCDIRECTION, *PU_EMRSETARCDIRECTION; //!< EMF manual 2.3.11.9 +#define U_SIZE_EMRSETARCDIRECTION (sizeof(U_EMRSETARCDIRECTION)) /* Index 58 */ /** EMF manual 2.3.11.21 @@ -2538,6 +2613,7 @@ typedef struct { uint32_t eMiterLimit; //!< Miter limit (max value of mitered length / line width) } U_EMRSETMITERLIMIT, *PU_EMRSETMITERLIMIT; //!< EMF manual 2.3.11.21 +#define U_SIZE_EMRSETMITERLIMIT (sizeof(U_EMRSETMITERLIMIT)) /* Index 59,60,61 (see 28) */ @@ -2553,6 +2629,9 @@ typedef struct { *PU_EMRFILLPATH, //!< EMF manual 2.3.5.9 *PU_EMRSTROKEANDFILLPATH, //!< EMF manual 2.3.5.38 *PU_EMRSTROKEPATH; //!< EMF manual 2.3.5.39 +#define U_SIZE_EMRFILLPATH (sizeof(U_EMRFILLPATH )) +#define U_SIZE_EMRSTROKEANDFILLPATH (sizeof(U_EMRSTROKEANDFILLPATH)) +#define U_SIZE_EMRSTROKEPATH (sizeof(U_EMRSTROKEPATH )) /* Index 65,66 (see 28) */ /* Index 67 (see 17) */ @@ -2569,6 +2648,7 @@ typedef struct { uint8_t Data[1]; //!< Comment (any binary data, interpretation is program specific) } U_EMRCOMMENT, *PU_EMRCOMMENT; //!< EMF manual 2.3.3.1, AKA GDICOMMENT +#define U_SIZE_EMRCOMMENT (sizeof(U_EMR) + sizeof(U_CBDATA)) /* variant comment types */ /** EMF manual 2.3.3.2 @@ -2580,6 +2660,7 @@ typedef struct { uint8_t Data[1]; //!< EMF Plus record } U_EMRCOMMENT_EMFPLUS, *PU_EMRCOMMENT_EMFPLUS; //!< EMF manual 2.3.3.2, EMF Plus comment +#define U_SIZE_EMRCOMMENT_EMFPLUS (sizeof(U_EMR) + sizeof(U_CBDATA) + sizeof(uint32_t)) /** EMF manual 2.3.3.3 */ @@ -2591,6 +2672,7 @@ typedef struct { uint8_t Data[1]; //!< EMF Spool records } U_EMRCOMMENT_SPOOL, *PU_EMRCOMMENT_SPOOL; //!< EMF manual 2.3.3.3, EMF Spool comment +#define U_SIZE_EMRCOMMENT_SPOOL (sizeof(U_EMR) + sizeof(U_CBDATA) + 2*sizeof(uint32_t)) /** EMF manual 2.3.3.4 */ @@ -2602,9 +2684,11 @@ typedef struct { uint8_t Data[1]; //!< Public comment data } U_EMRCOMMENT_PUBLIC, *PU_EMRCOMMENT_PUBLIC; //!< EMF manual 2.3.3.4, EMF Public comment +#define U_SIZE_EMRCOMMENT_PUBLIC (sizeof(U_EMR) + sizeof(U_CBDATA) + 2*sizeof(uint32_t)) /* Index 71 */ -/** EMF manual 2.3.5.10 +/** EMF manual 2.3.5.10 + followed by a variable number of U_RECTLs */ typedef struct { U_EMR emr; //!< U_EMR @@ -2614,6 +2698,7 @@ typedef struct { U_RGNDATA RgnData[1]; //!< Variable size U_RGNDATA structure } U_EMRFILLRGN, *PU_EMRFILLRGN; //!< EMF manual 2.3.5.10 +#define U_SIZE_EMRFILLRGN (sizeof(U_EMR) + sizeof(U_RECTL) + sizeof(U_CBRGNDATA) + sizeof(uint32_t)) /* Index 72 */ /** EMF manual 2.3.5.11 @@ -2627,6 +2712,7 @@ typedef struct { U_RGNDATA RgnData[1]; //!< Variable size U_RGNDATA structure } U_EMRFRAMERGN, *PU_EMRFRAMERGN; //!< EMF manual 2.3.5.11 +#define U_SIZE_EMRFRAMERGN (sizeof(U_EMR) + sizeof(U_RECTL) + sizeof(U_CBRGNDATA) + sizeof(uint32_t) + sizeof(U_SIZEL)) /* Index 73,74 */ /** EMF manual 2.3.11.3 @@ -2640,6 +2726,8 @@ typedef struct { U_EMRPAINTRGN, //!< EMF manual 2.3.5.14 *PU_EMRINVERTRGN, //!< EMF manual 2.3.11.3 *PU_EMRPAINTRGN; //!< EMF manual 2.3.5.14 +#define U_SIZE_EMRINVERTRGN (sizeof(U_EMR) + sizeof(U_RECTL) + sizeof(U_CBRGNDATA)) +#define U_SIZE_EMRPAINTRGN U_SIZE_EMRINVERTRGN /* Index 75 */ /** EMF manual 2.3.2.2 @@ -2651,6 +2739,7 @@ typedef struct { U_RGNDATA RgnData[1]; //!< Variable size U_RGNDATA structure } U_EMREXTSELECTCLIPRGN, *PU_EMREXTSELECTCLIPRGN; //!< EMF manual 2.3.2.2 +#define U_SIZE_EMREXTSELECTCLIPRGN (sizeof(U_EMR) + sizeof(U_CBRGNDATA) + sizeof(uint32_t)) /* Index 76 */ /** EMF manual 2.3.1.2 @@ -2672,6 +2761,7 @@ typedef struct { //!< Record may include optional bitmapbuffer } U_EMRBITBLT, *PU_EMRBITBLT; //!< EMF manual 2.3.1.2 +#define U_SIZE_EMRBITBLT (sizeof(U_EMRBITBLT)) /* Index 77 */ /** EMF manual 2.3.1.6 @@ -2694,6 +2784,7 @@ typedef struct { //!< Record may include optional bitmapbuffer } U_EMRSTRETCHBLT, *PU_EMRSTRETCHBLT; //!< EMF manual 2.3.1.6 +#define U_SIZE_EMRSTRETCHBLT (sizeof(U_EMRSTRETCHBLT)) /* Index 78 */ /** EMF manual 2.3.1.3 @@ -2721,6 +2812,7 @@ typedef struct { //!< Record may include optional Source and mask bitmapbuffers } U_EMRMASKBLT, *PU_EMRMASKBLT; //!< EMF manual 2.3.1.3 +#define U_SIZE_EMRMASKBLT (sizeof(U_EMRMASKBLT)) /* Index 79 */ /** EMF manual 2.3.1.4 @@ -2747,6 +2839,7 @@ typedef struct { //!< Record may include optional Source and mask bitmapbuffers } U_EMRPLGBLT, *PU_EMRPLGBLT; //!< EMF manual 2.3.1.4 +#define U_SIZE_EMRPLGBLT (sizeof(U_EMRPLGBLT)) /* Index 80 */ /** EMF manual 2.3.1.5 @@ -2767,6 +2860,7 @@ typedef struct { //!< Record may includes optional bitmapbuffer } U_EMRSETDIBITSTODEVICE, *PU_EMRSETDIBITSTODEVICE; //!< EMF manual 2.3.1.5 +#define U_SIZE_EMRSETDIBITSTODEVICE (sizeof(U_EMRSETDIBITSTODEVICE)) /* Index 81 */ /** EMF manual 2.3.1.7 @@ -2787,6 +2881,7 @@ typedef struct { //!< Record may includes optional bitmapbuffer } U_EMRSTRETCHDIBITS, *PU_EMRSTRETCHDIBITS; //!< EMF manual 2.3.1.7 +#define U_SIZE_EMRSTRETCHDIBITS (sizeof(U_EMRSTRETCHDIBITS)) /* Index 82 */ /** EMF manual 2.3.7.8 @@ -2797,6 +2892,8 @@ typedef struct { U_LOGFONT_PANOSE elfw; //!< Font parameters, either U_LOGFONT or U_LOGFONT_PANOSE, the latter is bigger so use that type here } U_EMREXTCREATEFONTINDIRECTW, *PU_EMREXTCREATEFONTINDIRECTW; //!< EMF manual 2.3.7.8 +#define U_SIZE_EMREXTCREATEFONTINDIRECTW_LOGFONT_PANOSE (sizeof(U_EMR) + 4 + sizeof(U_LOGFONT_PANOSE)) +#define U_SIZE_EMREXTCREATEFONTINDIRECTW_LOGFONT (sizeof(U_EMR) + 4 + sizeof(U_LOGFONT)) /* Index 83,84 */ /** EMF manual 2.3.5.7 @@ -2820,6 +2917,8 @@ typedef struct { U_EMREXTTEXTOUTW, //!< EMF manual 2.3.5.8 *PU_EMREXTTEXTOUTA, //!< EMF manual 2.3.5.7 *PU_EMREXTTEXTOUTW; //!< EMF manual 2.3.5.8 +#define U_SIZE_EMREXTTEXTOUTA (sizeof(U_EMREXTTEXTOUTA)) +#define U_SIZE_EMREXTTEXTOUTW (sizeof(U_EMREXTTEXTOUTW)) /* Index 85,86,87,88,89 */ /** EMF manual 2.3.5.17 @@ -2839,9 +2938,16 @@ typedef struct { *PU_EMRPOLYLINE16, //!< EMF manual 2.3.5.25 *PU_EMRPOLYBEZIERTO16, //!< EMF manual 2.3.5.19 *PU_EMRPOLYLINETO16; //!< EMF manual 2.3.5.27 - +#define U_SIZE_EMRPOLYBEZIER16 (sizeof(U_EMR) + sizeof(U_RECTL) + sizeof(U_NUM_POINT16)) +#define U_SIZE_EMRPOLYGON16 U_SIZE_EMRPOLYBEZIER16 +#define U_SIZE_EMRPOLYLINE16 U_SIZE_EMRPOLYBEZIER16 +#define U_SIZE_EMRPOLYBEZIERTO16 U_SIZE_EMRPOLYBEZIER16 +#define U_SIZE_EMRPOLYLINETO16 U_SIZE_EMRPOLYBEZIER16 /* Index 90,91 */ -/** EMF manual 2.3.5.31 +/** EMF manual 2.3.5.31 + + followed by + U_POINT16 apts[1]; //!< array of point16 */ typedef struct { U_EMR emr; //!< U_EMR @@ -2849,24 +2955,28 @@ typedef struct { U_NUM_POLYCOUNTS nPolys; //!< Number of elements in aPolyCounts U_NUM_POINT16 cpts; //!< Total number of points (over all poly) U_POLYCOUNTS aPolyCounts[1]; //!< Number of points in each poly (sequential) -// This will appear somewhere but is not really part of the core structure. -// U_POINT16 apts[1]; //!< array of point16 } U_EMRPOLYPOLYLINE16, U_EMRPOLYPOLYGON16, //!< EMF manual 2.3.5.29 *PU_EMRPOLYPOLYLINE16, //!< EMF manual 2.3.5.31 *PU_EMRPOLYPOLYGON16; //!< EMF manual 2.3.5.29 +#define U_SIZE_EMRPOLYPOLYLINE16 (sizeof(U_EMR) + sizeof(U_RECTL) + sizeof(U_NUM_POLYCOUNTS) + sizeof(U_NUM_POINT16)) +#define U_SIZE_EMRPOLYPOLYGON16 U_SIZE_EMRPOLYPOLYLINE16 /* Index 92 */ -/** EMF manual 2.3.5.21 +/** EMF manual 2.3.5.21 + + followed by + uint8_t abTypes[1]; //!< Array of Point Enumeration + */ typedef struct { U_EMR emr; //!< U_EMR U_RECTL rclBounds; //!< Bounding rectangle in device units U_NUM_POINT16 cpts; //!< Total number of points (over all poly) U_POINT16 apts[1]; //!< array of points - uint8_t abTypes[1]; //!< Array of Point Enumeration } U_EMRPOLYDRAW16, *PU_EMRPOLYDRAW16; //!< EMF manual 2.3.5.21 +#define U_SIZE_EMRPOLYDRAW16 (sizeof(U_EMR) + sizeof(U_RECTL) + sizeof(U_NUM_POINT16)) /* Index 93 */ /** EMF manual 2.3.7.5 @@ -2882,6 +2992,7 @@ typedef struct { //!< Record may include optional DIB bitmapbuffer } U_EMRCREATEMONOBRUSH, *PU_EMRCREATEMONOBRUSH; //!< EMF manual 2.3.7.5 +#define U_SIZE_EMRCREATEMONOBRUSH (sizeof(U_EMRCREATEMONOBRUSH)) /* Index 94 */ /** EMF manual 2.3.7.4 @@ -2897,6 +3008,7 @@ typedef struct { //!< Record may include optional DIB bitmapbuffer } U_EMRCREATEDIBPATTERNBRUSHPT, *PU_EMRCREATEDIBPATTERNBRUSHPT; //!< EMF manual 2.3.7.4 +#define U_SIZE_EMRCREATEDIBPATTERNBRUSHPT (sizeof(U_EMRCREATEDIBPATTERNBRUSHPT)) /* Index 95 */ /** EMF manual 2.3.7.9 @@ -2912,6 +3024,7 @@ typedef struct { //!< Record may include optional DIB bitmap } U_EMREXTCREATEPEN, *PU_EMREXTCREATEPEN; //!< EMF manual 2.3.7.9 +#define U_SIZE_EMREXTCREATEPEN (sizeof(U_EMREXTCREATEPEN)) /* Index 96.97 */ /** EMF manual 2.3.5.32 @@ -2928,6 +3041,8 @@ typedef struct { U_EMRPOLYTEXTOUTW, //!< EMF manual 2.3.5.33 *PU_EMRPOLYTEXTOUTA, //!< EMF manual 2.3.5.32 *PU_EMRPOLYTEXTOUTW; //!< EMF manual 2.3.5.33 +#define U_SIZE_EMRPOLYTEXTOUTA (sizeof(U_EMR) + sizeof(U_RECTL) + sizeof(uint32_t) + 2*sizeof(U_FLOAT) + sizeof(U_NUM_EMRTEXT)) +#define U_SIZE_EMRPOLYTEXTOUTW U_SIZE_EMRPOLYTEXTOUTA /* Index 98 (see 17) */ @@ -2940,6 +3055,7 @@ typedef struct { U_LOGCOLORSPACEA lcs; //!< ColorSpace parameters } U_EMRCREATECOLORSPACE, *PU_EMRCREATECOLORSPACE; //!< EMF manual 2.3.7.2 +#define U_SIZE_EMRCREATECOLORSPACE (sizeof(U_EMRCREATECOLORSPACE)) /* Index 100,101 */ /** EMF manual 2.3.8.2 @@ -2951,6 +3067,8 @@ typedef struct { U_EMRSETCOLORSPACE, //!< EMF manual 2.3.8.7 *PU_EMRDELETECOLORSPACE, //!< EMF manual 2.3.8.2 *PU_EMRSETCOLORSPACE; //!< EMF manual 2.3.8.7 +#define U_SIZE_EMRDELETECOLORSPACE (sizeof(U_EMRDELETECOLORSPACE)) +#define U_SIZE_EMRSETCOLORSPACE (sizeof(U_EMRSETCOLORSPACE )) /* Index 102 */ /** EMF manual 2.3.9.2 @@ -2961,6 +3079,7 @@ typedef struct { U_DATA Data[1]; //!< OpenGL data } U_EMRGLSRECORD, *PU_EMRGLSRECORD; //!< EMF manual 2.3.9.2 +#define U_SIZE_EMRGLSRECORD (sizeof(U_EMRGLSRECORD)) /* Index 103 */ /** EMF manual 2.3.9.1 @@ -2972,6 +3091,7 @@ typedef struct { U_DATA Data[1]; //!< OpenGL data } U_EMRGLSBOUNDEDRECORD, *PU_EMRGLSBOUNDEDRECORD; //!< EMF manual 2.3.9.1 +#define U_SIZE_EMRGLSBOUNDEDRECORD (sizeof(U_EMR) + sizeof(U_RECTL) + sizeof(U_CBDATA)) /* Index 104 */ /** EMF manual 2.3.11.5 @@ -2981,6 +3101,7 @@ typedef struct { U_PIXELFORMATDESCRIPTOR pfd; //!< PixelFormatDescriptor } U_EMRPIXELFORMAT, *PU_EMRPIXELFORMAT; //!< EMF manual 2.3.11.5 +#define U_SIZE_EMRPIXELFORMAT (sizeof(U_EMRPIXELFORMAT)) /* Index 105 */ /** EMF manual 2.3.6.1 @@ -2991,6 +3112,7 @@ typedef struct { U_DATA Data[1]; //!< Data to send } U_EMRDRAWESCAPE, *PU_EMRDRAWESCAPE; //!< EMF manual 2.3.6.1 +#define U_SIZE_EMRDRAWESCAPE (sizeof(U_EMR) + sizeof(U_CBDATA)) /* Index 106 */ /** EMF manual 2.3.6.2 @@ -3001,6 +3123,7 @@ typedef struct { U_DATA Data[1]; //!< Data to send } U_EMREXTESCAPE, *PU_EMREXTESCAPE; //!< EMF manual 2.3.6.2 +#define U_SIZE_EMREXTESCAPE (sizeof(U_EMR) + sizeof(U_CBDATA)) /* Index 107 (not implemented ) */ @@ -3020,22 +3143,26 @@ typedef struct { //!< uint32_t TextString; text to output (fuOptions & ETO_SMALL_CHARS ? 8 bit : 16 bit) } U_EMRSMALLTEXTOUT, *PU_EMRSMALLTEXTOUT; //!< EMF manual 2.3.5.37 +#define U_SIZE_EMRSMALLTEXTOUT (sizeof(U_EMRSMALLTEXTOUT)) /* Index 109 (not implemented ) EMF manual 2.3.11.2 */ /* Index 110 */ -/** EMF manual 2.3.6.3 +/** EMF manual 2.3.6.3 + + followed by + uint8_t Data[1]; //!< Data for printer driver */ typedef struct { U_EMR emr; //!< U_EMR U_CBDATA cbDriver; //!< Number of bytes in driver name (note, BYTES, not CHARACTERS) U_CBDATA cbData; //!< Number of bytes in data uint16_t Driver[1]; //!< Driver name in uint16_t characters, null terminated - uint8_t Data[1]; //!< Data for printer driver } U_EMRNAMEDESCAPE, *PU_EMRNAMEDESCAPE; //!< EMF manual 2.3.6.3 +#define U_SIZE_EMRNAMEDESCAPE (sizeof(U_EMRNAMEDESCAPE)) /* Index 111-113 (not implemented ) EMF manual 2.3.8.1 @@ -3064,6 +3191,7 @@ typedef struct { //!< Record may include optional DIB bitmap } U_EMRALPHABLEND, *PU_EMRALPHABLEND; //!< EMF manual 2.3.1.1 +#define U_SIZE_EMRALPHABLEND (sizeof(U_EMRALPHABLEND)) /* Index 115 (see 17) */ @@ -3088,11 +3216,16 @@ typedef struct { //!< Record may includes optional bitmapbuffer } U_EMRTRANSPARENTBLT, *PU_EMRTRANSPARENTBLT; //!< EMF manual 2.3.1.8 +#define U_SIZE_EMRTRANSPARENTBLT (sizeof(U_EMRTRANSPARENTBLT)) /* Index 117 (not a defined U_EMR record type ) */ /* Index 118 */ -/** EMF manual 2.3.5.12 +/** EMF manual 2.3.5.12 + + followed by + U_TRIVERTEX TriVert[1]; Array of TriVertex objects + uint32_t GradObj[1]; Array of gradient objects (each has 2 or 3 indices into TriVert array) */ typedef struct { U_EMR emr; //!< U_EMR @@ -3100,11 +3233,9 @@ typedef struct { U_NUM_TRIVERTEX nTriVert; //!< Number of TriVertex objects U_NUM_GRADOBJ nGradObj; //!< Number of gradient triangle/rectangle objects uint32_t ulMode; //!< Gradientfill Enumeration (determines Triangle/Rectangle) -//parts that are required but which are not included in the core structure -// U_TRIVERTEX TriVert[1]; Array of TriVertex objects -// uint32_t GradObj[1]; Array of gradient objects (each has 2 or 3 indices into TriVert array) } U_EMRGRADIENTFILL, *PU_EMRGRADIENTFILL; //!< EMF manual 2.3.5.12 +#define U_SIZE_EMRGRADIENTFILL (sizeof(U_EMRGRADIENTFILL)) /* Index 119,120 (not implemented ) EMF manual 2.3.11.18 @@ -3123,6 +3254,7 @@ typedef struct { uint8_t Data[1]; //!< Data of size cbName+cbData: Name in UTF16 then color profile data } U_EMRCOLORMATCHTOTARGETW, *PU_EMRCOLORMATCHTOTARGETW; //!< EMF manual 2.3.11.1 +#define U_SIZE_EMRCOLORMATCHTOTARGETW (sizeof(U_EMR) + 2*sizeof(uint32_t) + sizeof(U_CBNAME) + sizeof(U_CBDATA)) /* Index 122 */ /** EMF manual 2.3.7.3 @@ -3136,6 +3268,10 @@ typedef struct { uint8_t Data[1]; //!< (Optional, dwFlags & 1) color profile data } U_EMRCREATECOLORSPACEW, *PU_EMRCREATECOLORSPACEW; //!< EMF manual 2.3.7.3 +#define U_SIZE_EMRCREATECOLORSPACEW (sizeof(U_EMR) + 2*sizeof(uint32_t) + sizeof(U_LOGCOLORSPACEW) + sizeof(U_CBDATA)) + +// records which are not documented, so we have no idea what to do with them +#define U_SIZE_EMRUNDEFINED 2048 // ************************************************************************************************ // Utility function structures @@ -3207,7 +3343,7 @@ int get_real_color_count(const char *Bmih); int get_real_color_icount(int Colors, int BitCount, int Width, int Height); int RGBA_to_DIB(char **px, uint32_t *cbPx, PU_RGBQUAD *ct, int *numCt, const char *rgba_px, int w, int h, int stride, uint32_t colortype, int use_ct, int invert); -int get_DIB_params( void *pEmr, uint32_t offBitsSrc, uint32_t offBmiSrc, +int get_DIB_params( const char *record, uint32_t offBitsSrc, uint32_t offBmiSrc, const char **px, const U_RGBQUAD **ct, uint32_t *numCt, uint32_t *width, uint32_t *height, uint32_t *colortype, uint32_t *invert ); int DIB_to_RGBA(const char *px, const U_RGBQUAD *ct, int numCt, @@ -3237,6 +3373,7 @@ int emf_htable_free(EMFHANDLES **eht); #define htable_free emf_htable_free U_RECTL rectl_set(U_POINTL ul, U_POINTL lr); +void rectli_set(PU_RECTL array, int index, U_POINTL ul, U_POINTL lr); U_SIZEL sizel_set(int32_t x, int32_t y); U_POINTL point32_set(int32_t x, int32_t y); #define point_set point32_set @@ -3463,6 +3600,7 @@ char *U_EMRSMALLTEXTOUT_set(const U_POINTL Dest, const U_NUM_STR cChars, const u // U_EMRSETICMPROFILEA_set 112 Not implemented // U_EMRSETICMPROFILEW_set 113 Not implemented + char *U_EMRALPHABLEND_set(const U_RECTL rclBounds, const U_POINTL Dest, const U_POINTL cDest, const U_POINTL Src, const U_POINTL cSrc, const U_XFORM xformSrc, const U_COLORREF crBkColorSrc, const uint32_t iUsageSrc, diff --git a/src/libuemf/uemf_endian.c b/src/libuemf/uemf_endian.c index 2d19361e1..f746553f1 100644 --- a/src/libuemf/uemf_endian.c +++ b/src/libuemf/uemf_endian.c @@ -19,11 +19,11 @@ /* File: uemf_endian.c -Version: 0.0.16 -Date: 27-MAR-2014 +Version: 0.0.21 +Date: 23-APR-2015 Author: David Mathog, Biology Division, Caltech email: mathog@caltech.edu -Copyright: 2014 David Mathog and California Institute of Technology (Caltech) +Copyright: 2015 David Mathog and California Institute of Technology (Caltech) */ #ifdef __cplusplus @@ -266,18 +266,91 @@ void bitmapinfoheader_swap( \param Bmi Pointer to a U_BITMAPINFO object */ void bitmapinfo_swap( - PU_BITMAPINFO Bmi + const char *Bmi ){ - bitmapinfoheader_swap(&(Bmi->bmiHeader)); // bmIHeader + PU_BITMAPINFO pBmi = (PU_BITMAPINFO)Bmi; + bitmapinfoheader_swap(&(pBmi->bmiHeader)); // bmIHeader // ordered bytes: bmiColors } +/** + \brief Swap the ordered bytes in a DIB and verify that the sizes are OK + + \return 1 on success, 0 on failure + \param record EMF record that contains a DIB pixel array + \param iUsage DIBcolors Enumeration + \param offBmi offset from the start of the record to the start of the bitmapinfo structure + \param cbBmi declared space for the bitmapinfo structure in the record + \param offBits offset from the start of the record to the start of the bitmap + \param cbBits declared space for the bitmap in the record (amount used may be less than this) + \param blimit one byte past the end of the record. + \param torev 1 for native to reversed, 0 for reversed to native + + This method can only test DIBs that hold Microsoft's various bitmap types. PNG or JPG is just a bag + of bytes, and there is no possible way to derive from the known width and height how big it should be. +*/ +int DIB_swap( + const char *record, + uint32_t iUsage, + uint32_t offBmi, + uint32_t cbBmi, + uint32_t offBits, + uint32_t cbBits, + const char *blimit, + int torev + ){ + int dibparams = U_BI_UNKNOWN; // type of image not yet determined + const char *px = NULL; // DIB pixels + const U_RGBQUAD *ct = NULL; // DIB color table + int bs; + int usedbytes; + + if(!cbBmi)return(1); // No DIB in a record where it is optional + if(IS_MEM_UNSAFE(record, offBmi + cbBmi, blimit))return(0); + if(cbBits && IS_MEM_UNSAFE(record, offBits + cbBits, blimit))return(0); + if(iUsage == U_DIB_RGB_COLORS){ + uint32_t width, height, colortype, numCt, invert; // these values will be set in get_DIB_params + // next call returns pointers and values, but allocates no memory + if(torev){ + dibparams = get_DIB_params(record, offBits, offBmi, &px, (const U_RGBQUAD **) &ct, + &numCt, &width, &height, &colortype, &invert); + } + bitmapinfo_swap(record + offBmi); // byte ordered fields in bitmapinfo + if(!torev){ + dibparams = get_DIB_params(record, offBits, offBmi, &px, (const U_RGBQUAD **) &ct, + &numCt, &width, &height, &colortype, &invert); + } + + // sanity checking + if(numCt && colortype >= U_BCBM_COLOR16)return(0); //color tables not used above 16 bit pixels + if(!numCt && colortype < U_BCBM_COLOR16)return(0); //color tables mandatory for < 16 bit + + if(dibparams ==U_BI_RGB){ + // this is the only DIB type where we can calculate how big it should be when stored in the EMF file + bs = colortype/8; + if(bs<1){ + usedbytes = (width*colortype + 7)/8; // width of line in fully and partially occupied bytes + } + else { + usedbytes = width*bs; + } + if(IS_MEM_UNSAFE(record+offBits, usedbytes, blimit))return(0); + } + } + else { + bitmapinfo_swap(record + offBmi); + } + return(1); +} + /** \brief Convert a pointer to a U_EXTLOGPEN object. - \param elp PU_EXTLOGPEN object + \param elp PU_EXTLOGPEN object + \param blimit one byte past the end of the record */ -void extlogpen_swap( +int extlogpen_swap( PU_EXTLOGPEN elp, + const char *blimit, int torev ){ int count=0; @@ -290,7 +363,9 @@ void extlogpen_swap( if(!torev){ count = elp->elpNumEntries; } + if(IS_MEM_UNSAFE(&(elp->elpStyleEntry), count*4, blimit))return(0); U_swap4(&(elp->elpStyleEntry),count); // elpStyleEntry[] + return(1); } /** @@ -330,15 +405,27 @@ void rgndataheader_swap( } /** + \return 1 on success, 0 on failure \brief Convert a pointer to a U_RGNDATA object. - \param rgd pointer to a U_RGNDATA object. + \param rd pointer to a U_RGNDATA object. + \param cbRgnData size of the U_RGNDATA object. */ -void rgndata_swap( - PU_RGNDATA rd +int rgndata_swap( + PU_RGNDATA rd, + int cbRgnData, + int torev ){ - int count = rd->rdh.nCount; + int count = 0; + if(torev){ + count = rd->rdh.nCount; + } rgndataheader_swap(&(rd->rdh)); + if(!torev){ + count = rd->rdh.nCount; + } + if(4*count + (int)sizeof(U_RGNDATAHEADER) > cbRgnData)return(0); U_swap4(rd->Buffer,4*count); + return(1); } /** @@ -368,12 +455,14 @@ void pixelformatdescriptor_swap( \brief Convert a Pointer to a U_EMRTEXT record \param pemt Pointer to a U_EMRTEXT record \param record Pointer to the start of the record which contains this U_EMRTEXT + \param blimit one byte past the end of the record. \param torev 1 for native to reversed, 0 for reversed to native */ -void emrtext_swap( - PU_EMRTEXT pemt, - char *record, - int torev +int emrtext_swap( + PU_EMRTEXT pemt, + char *record, + const char *blimit, + int torev ){ int off; uint32_t count=0; @@ -391,6 +480,7 @@ void emrtext_swap( } off = sizeof(U_EMRTEXT); if(!(fOptions & U_ETO_NO_RECT)){ + if(IS_MEM_UNSAFE(pemt, sizeof(U_RECTL), blimit))return(0); rectl_swap((PU_RECTL)((char *)pemt + off),1); // optional rectangle off+=sizeof(U_RECTL); } @@ -398,11 +488,14 @@ void emrtext_swap( offDx = *(uint32_t *)((char *)pemt +off); } // ordered bytes OR UTF16-LE: the string at offString + if(IS_MEM_UNSAFE(pemt, off + 4, blimit))return(0); U_swap4(((char *)pemt+off),1); // offDx if(!torev){ offDx = *(uint32_t *)((char *)pemt +off); } - U_swap4((record+offDx),count); // Dx[], offset with respect to the Record, NOT the object + if(IS_MEM_UNSAFE(record, count*4, blimit))return(0); + U_swap4((record + offDx),count); // Dx[], offset with respect to the Record, NOT the object + return(1); } @@ -424,182 +517,236 @@ by end user code and to further that end prototypes are NOT provided and they ar // all core*_swap call this, U_EMRSETMARGN_swap and some others all it directly // numbered as core5 to be consistent with uemf.c, but must appear before the others as there is no prototype -void core5_swap(char *record, int torev){ +int core5_swap(char *record, int torev){ UNUSED_PARAMETER(torev); - PU_ENHMETARECORD pEMR = (PU_ENHMETARECORD)(record); - U_swap4(pEMR,2); // iType nSize + if(!record)return(0); + PU_EMR pEmr = (PU_EMR)(record); + U_swap4(pEmr,2); // iType nSize + return(1); } // Functions with the same form starting with U_EMRPOLYBEZIER_swap -void core1_swap(char *record, int torev){ +int core1_swap(char *record, int torev){ int count=0; + const char *blimit = NULL; PU_EMRPOLYLINETO pEmr = (PU_EMRPOLYLINETO) (record); if(torev){ count = pEmr->cptl; + blimit = record + pEmr->emr.nSize; } - core5_swap(record, torev); + if(!core5_swap(record, torev))return(0); rectl_swap(&(pEmr->rclBounds),1 ); // rclBounds U_swap4(&(pEmr->cptl),1); // cptl if(!torev){ count = pEmr->cptl; + blimit = record + pEmr->emr.nSize; } + if(IS_MEM_UNSAFE((pEmr->aptl), count*sizeof(U_POINTL), blimit))return(0); pointl_swap((pEmr->aptl),count); // aptl[] + return(1); } // Functions with the same form starting with U_EMRPOLYPOLYLINE_swap -void core2_swap(char *record, int torev){ +int core2_swap(char *record, int torev){ int count=0; int nPolys=0; + const char *blimit = NULL; PU_EMRPOLYPOLYLINE pEmr = (PU_EMRPOLYPOLYLINE) (record); if(torev){ count = pEmr->cptl; nPolys = pEmr->nPolys; + blimit = record + pEmr->emr.nSize; } - core5_swap(record, torev); + if(!core5_swap(record, torev))return(0); rectl_swap(&(pEmr->rclBounds),1); // rclBounds U_swap4(&(pEmr->nPolys),2); // nPolys cptl if(!torev){ count = pEmr->cptl; nPolys = pEmr->nPolys; + blimit = record + pEmr->emr.nSize; } + if(IS_MEM_UNSAFE((pEmr->aPolyCounts), nPolys*4, blimit))return(0); U_swap4(pEmr->aPolyCounts,nPolys); // aPolyCounts[] - pointl_swap((PU_POINT)(record + sizeof(U_EMRPOLYPOLYLINE) - 4 + sizeof(uint32_t)* nPolys), count); // paptl[] + record += sizeof(U_EMRPOLYPOLYLINE) - 4 + sizeof(uint32_t)* nPolys; + if(IS_MEM_UNSAFE(record, count*sizeof(U_POINTL), blimit))return(0); + pointl_swap((PU_POINT)(record), count); // paptl[] + return(1); } // Functions with the same form starting with U_EMRSETMAPMODE_swap -void core3_swap(char *record, int torev){ +int core3_swap(char *record, int torev){ PU_EMRSETMAPMODE pEmr = (PU_EMRSETMAPMODE)(record); - core5_swap(record, torev); + if(!core5_swap(record, torev))return(0); U_swap4(&(pEmr->iMode),1); // iMode + return(1); } // Functions taking a single U_RECT or U_RECTL, starting with U_EMRELLIPSE_swap, also U_EMRFILLPATH_swap, -void core4_swap(char *record, int torev){ +int core4_swap(char *record, int torev){ PU_EMRELLIPSE pEmr = (PU_EMRELLIPSE)( record); - core5_swap(record, torev); + if(!core5_swap(record, torev))return(0); rectl_swap(&(pEmr->rclBox),1); // rclBox + return(1); } // Functions with the same form starting with U_EMRPOLYBEZIER16_swap -void core6_swap(char *record, int torev){ +int core6_swap(char *record, int torev){ int count=0; + const char *blimit = NULL; PU_EMRPOLYBEZIER16 pEmr = (PU_EMRPOLYBEZIER16) (record); if(torev){ count = pEmr->cpts; + blimit = record + pEmr->emr.nSize; } - core5_swap(record, torev); + if(!core5_swap(record, torev))return(0); rectl_swap(&(pEmr->rclBounds),1); // rclBounds U_swap4(&(pEmr->cpts),1); // cpts if(!torev){ count = pEmr->cpts; + blimit = record + pEmr->emr.nSize; } + if(IS_MEM_UNSAFE((pEmr->apts), count*sizeof(U_POINT16), blimit))return(0); point16_swap((pEmr->apts),count); // apts[] + return(1); } // Records with the same form starting with U_EMRSETWINDOWEXTEX_swap, that is, all with two uint32_t values after the emr -void core7_swap(char *record, int torev){ +int core7_swap(char *record, int torev){ PU_EMRGENERICPAIR pEmr = (PU_EMRGENERICPAIR) (record); - core5_swap(record, torev); + if(!core5_swap(record, torev))return(0); U_swap4(&(pEmr->pair),2); + return(1); } // For U_EMREXTTEXTOUTA and U_EMREXTTEXTOUTW, type=0 for the first one -void core8_swap(char *record, int torev){ +int core8_swap(char *record, int torev){ + const char *blimit = NULL; PU_EMREXTTEXTOUTA pEmr = (PU_EMREXTTEXTOUTA) (record); - emrtext_swap(&(pEmr->emrtext),record,torev); - core5_swap(record, torev); + if(torev){ + blimit = record + pEmr->emr.nSize; + } + if(!core5_swap(record, torev))return(0); U_swap4(&(pEmr->iGraphicsMode),1); // iGraphicsMode rectl_swap(&(pEmr->rclBounds),1); // rclBounds U_swap4(&(pEmr->exScale),2); // exScale eyScale + if(!torev){ + blimit = record + pEmr->emr.nSize; + } + if(!emrtext_swap(&(pEmr->emrtext),record,blimit,torev))return(0); + return(1); } // Functions that take a rect and a pair of points, starting with U_EMRARC_swap -void core9_swap(char *record, int torev){ +int core9_swap(char *record, int torev){ PU_EMRARC pEmr = (PU_EMRARC) (record); - core5_swap(record, torev); + if(!core5_swap(record, torev))return(0); rectl_swap(&(pEmr->rclBox),1); // rclBox U_swap4(&(pEmr->ptlStart),4); // ptlStart ptlEnd + return(1); } // Functions with the same form starting with U_EMRPOLYPOLYLINE16_swap -void core10_swap(char *record, int torev){ +int core10_swap(char *record, int torev){ int count=0; int nPolys=0; + const char *blimit = NULL; PU_EMRPOLYPOLYLINE16 pEmr = (PU_EMRPOLYPOLYLINE16) (record); if(torev){ count = pEmr->cpts; nPolys = pEmr->nPolys; + blimit = record + pEmr->emr.nSize; } - core5_swap(record, torev); + if(!core5_swap(record, torev))return(0); rectl_swap(&(pEmr->rclBounds),1); // rclBounds U_swap4(&(pEmr->nPolys),2); // nPolys cpts if(!torev){ count = pEmr->cpts; nPolys = pEmr->nPolys; + blimit = record + pEmr->emr.nSize; } + if(IS_MEM_UNSAFE((pEmr->aPolyCounts), nPolys*4, blimit))return(0); U_swap4(pEmr->aPolyCounts,nPolys); // aPolyCounts[] - point16_swap((PU_POINT16)(record + sizeof(U_EMRPOLYPOLYLINE16) - 4 + sizeof(uint32_t)* nPolys), count); // apts[] + record += sizeof(U_EMRPOLYPOLYLINE16) - 4 + sizeof(uint32_t)* nPolys; + if(IS_MEM_UNSAFE(record, count*sizeof(U_POINT16), blimit))return(0); + point16_swap((PU_POINT16)(record), count); // apts[] + return(1); } // Functions with the same form starting with U_EMRINVERTRGN_swap and U_EMRPAINTRGN_swap, -void core11_swap(char *record, int torev){ - int roff=0; - int nextroff=0; - int limit=0; - PU_EMRINVERTRGN pEmr = (PU_EMRINVERTRGN) (record); - roff = 0; +int core11_swap(char *record, int torev){ + int cbRgnData=0; + const char *blimit = NULL; + PU_EMRINVERTRGN pEmr = (PU_EMRINVERTRGN)(record); if(torev){ - limit = pEmr->emr.nSize; - nextroff = 0; - } - core5_swap(record, torev); - if(!torev){ - limit = pEmr->emr.nSize; + cbRgnData= pEmr->cbRgnData; + blimit = record + pEmr->emr.nSize; } + if(!core5_swap(record, torev))return(0); rectl_swap(&(pEmr->rclBounds),1); // rclBounds U_swap4(&(pEmr->cbRgnData),1); // cbRgnData if(!torev){ - limit = pEmr->emr.nSize; - } - // This one is a pain since each RGNDATA may be a different size, so it isn't possible to index through them. - char *prd = (char *) &(pEmr->RgnData); - while(roff + 28 < limit){ // up to the end of the record - if(torev){ - nextroff += (((PU_RGNDATA)prd)->rdh.dwSize + ((PU_RGNDATA)prd)->rdh.nRgnSize - 16); - rgndata_swap((PU_RGNDATA) (prd + roff)); - roff = nextroff; - } - else { - rgndata_swap((PU_RGNDATA) (prd + roff)); - roff += (((PU_RGNDATA)prd)->rdh.dwSize + ((PU_RGNDATA)prd)->rdh.nRgnSize - 16); - } + cbRgnData= pEmr->cbRgnData; + blimit = record + pEmr->emr.nSize; } + if(IS_MEM_UNSAFE(pEmr->RgnData, cbRgnData, blimit))return(0); + return(rgndata_swap(pEmr->RgnData, cbRgnData, torev)); } // common code for U_EMRCREATEMONOBRUSH_swap and U_EMRCREATEDIBPATTERNBRUSHPT_swap, -void core12_swap(char *record, int torev){ +int core12_swap(char *record, int torev){ + const char *blimit = NULL; + U_OFFBMI offBmi = 0; + U_CBBMI cbBmi = 0; + U_OFFBITS offBits = 0; + U_CBBITS cbBits = 0; + uint32_t iUsage = 0; PU_EMRCREATEMONOBRUSH pEmr = (PU_EMRCREATEMONOBRUSH) (record); - if(torev && pEmr->cbBmi){ - bitmapinfo_swap((PU_BITMAPINFO)(record + pEmr->offBmi)); // Bmi - } - core5_swap(record, torev); + if(torev){ + offBmi = pEmr->offBmi; + cbBmi = pEmr->cbBmi; + offBits = pEmr->offBits; + cbBits = pEmr->cbBits; + iUsage = pEmr->iUsage; + blimit = record + pEmr->emr.nSize; + if(!DIB_swap(record, iUsage, offBmi, cbBmi, offBits, cbBits, blimit, torev))return(0); + } + if(!core5_swap(record, torev))return(0); U_swap4(&(pEmr->ihBrush),6); // ihBrush iUsage offBmi cbBmi offBits cbBits - // ordered bytes: bitmap (including 16 bit 5bit/channel color mode, which is done bytewise). - if(!torev && pEmr->cbBmi){ - bitmapinfo_swap((PU_BITMAPINFO)(record + pEmr->offBmi)); // Bmi + if(!torev){ + offBmi = pEmr->offBmi; + cbBmi = pEmr->cbBmi; + offBits = pEmr->offBits; + cbBits = pEmr->cbBits; + iUsage = pEmr->iUsage; + blimit = record + pEmr->emr.nSize; + if(!DIB_swap(record, iUsage, offBmi, cbBmi, offBits, cbBits, blimit, torev))return(0); } + // ordered bytes: bitmap (including 16 bit 5bit/channel color mode, which is done bytewise). + return(1); } // common code for U_EMRALPHABLEND_swap and U_EMRTRANSPARENTBLT_swap, -void core13_swap(char *record, int torev){ +int core13_swap(char *record, int torev){ + const char *blimit = NULL; + U_OFFBMISRC offBmiSrc = 0; + U_CBBMISRC cbBmiSrc = 0; + U_OFFBITSSRC offBitsSrc = 0; + U_CBBITSSRC cbBitsSrc = 0; + uint32_t iUsageSrc = 0; PU_EMRALPHABLEND pEmr = (PU_EMRALPHABLEND) (record); - if(torev && pEmr->cbBmiSrc){ - bitmapinfo_swap((PU_BITMAPINFO)(record + pEmr->offBmiSrc)); - } - core5_swap(record, torev); + if(torev){ + offBmiSrc = pEmr->offBmiSrc; + cbBmiSrc = pEmr->cbBmiSrc; + offBitsSrc = pEmr->offBitsSrc; + cbBitsSrc = pEmr->cbBitsSrc; + iUsageSrc = pEmr->iUsageSrc; + blimit = record + pEmr->emr.nSize; + if(!DIB_swap(record, iUsageSrc, offBmiSrc, cbBmiSrc, offBitsSrc, cbBitsSrc, blimit, torev))return(0); + } + if(!core5_swap(record, torev))return(0); rectl_swap(&(pEmr->rclBounds),1); // rclBounds pointl_swap(&(pEmr->Dest),2); // Dest cDest pointl_swap(&(pEmr->Dest),2); // Dest cDest @@ -608,15 +755,25 @@ void core13_swap(char *record, int torev){ xform_swap( &(pEmr->xformSrc)); // xformSrc // ordered bytes: crBkColorSrc U_swap4(&(pEmr->iUsageSrc),5); // iUsageSrc offBmiSrc cbBmiSrc offBitsSrc cbBitsSrc - // ordered bytes: bitmap (including 16 bit 5bit/channel color mode, which is done bytewise). - if(!torev && pEmr->cbBmiSrc){ - bitmapinfo_swap((PU_BITMAPINFO)(record + pEmr->offBmiSrc)); + if(!torev){ + offBmiSrc = pEmr->offBmiSrc; + cbBmiSrc = pEmr->cbBmiSrc; + offBitsSrc = pEmr->offBitsSrc; + cbBitsSrc = pEmr->cbBitsSrc; + iUsageSrc = pEmr->iUsageSrc; + blimit = record + pEmr->emr.nSize; + if(!DIB_swap(record, iUsageSrc, offBmiSrc, cbBmiSrc, offBitsSrc, cbBitsSrc, blimit, torev))return(0); } + // ordered bytes: bitmap (including 16 bit 5bit/channel color mode, which is done bytewise). + return(1); } /* ********************************************************************************************** -These are the core EMR functions, each creates a particular type of record. -All return these records via a char* pointer, which is NULL if the call failed. +These are the core EMR_swap functions, each converts a particular type of record. +All operate in place on the chunk of memory holding that record. +Some of these have offsets or counts which, if corrupt or evil would result in access outside + the record. These cases return a status value of 0 if that happens, 1 on success. Other + records which do not have these issues do not return a status value. They are listed in order by the corresponding U_EMR_* index number. *********************************************************************************************** */ @@ -626,37 +783,31 @@ They are listed in order by the corresponding U_EMR_* index number. \param record pointer to a buffer holding the EMR record \param torev 1 for native to reversed, 0 for reversed to native */ -void U_EMRNOTIMPLEMENTED_swap(char *record, int torev){ - core5_swap(record, torev); - printf("WARNING: could not convert data in record type that has not been implemented!\n"); +int U_EMRNOTIMPLEMENTED_swap(char *record, int torev){ + fprintf(stderr,"EMF WARNING: could not swap data bytes on record because that type has not been implemented!\n"); + return(core5_swap(record, torev)); } // U_EMRHEADER 1 -void U_EMRHEADER_swap(char *record, int torev){ +int U_EMRHEADER_swap(char *record, int torev){ int nDesc,offDesc,nSize,cbPix,offPix; + nDesc = offDesc = nSize = cbPix = offPix = 0; PU_EMRHEADER pEmr = (PU_EMRHEADER)(record); if(torev){ nSize = pEmr->emr.nSize; - core5_swap(record, torev); - } - else { - core5_swap(record, torev); - nSize = pEmr->emr.nSize; + nDesc = pEmr->nDescription; + offDesc = pEmr->offDescription; } - + if(!core5_swap(record, torev))return(0); rectl_swap(&(pEmr->rclBounds),2); // rclBounds rclFrame U_swap4(&(pEmr->dSignature), 4); // dSignature nVersion nBytes nRecords U_swap2(&(pEmr->nHandles), 2); // nHandlessReserved - if(torev){ - nDesc = pEmr->nDescription; - offDesc = pEmr->offDescription; - U_swap4(&(pEmr->nDescription), 3); // nDescription offDescription nPalEntries - } - else { - U_swap4(&(pEmr->nDescription), 3); // nDescription offDescription nPalEntries - nDesc = pEmr->nDescription; - offDesc = pEmr->offDescription; - } + U_swap4(&(pEmr->nDescription), 3); // nDescription offDescription nPalEntries + if(!torev){ + nSize = pEmr->emr.nSize; + nDesc = pEmr->nDescription; + offDesc = pEmr->offDescription; + } // UTF16-LE Description sizel_swap(&(pEmr->szlDevice), 2); // szlDevice szlMillimeters if((nDesc && (offDesc >= 100)) || @@ -665,16 +816,14 @@ void U_EMRHEADER_swap(char *record, int torev){ if(torev){ cbPix = pEmr->cbPixelFormat; offPix = pEmr->offPixelFormat; - if(cbPix)pixelformatdescriptor_swap( (PU_PIXELFORMATDESCRIPTOR) (record + pEmr->offPixelFormat)); - U_swap4(&(pEmr->cbPixelFormat), 2); // cbPixelFormat offPixelFormat } - else { - U_swap4(&(pEmr->cbPixelFormat), 2); // cbPixelFormat offPixelFormat + U_swap4(&(pEmr->cbPixelFormat), 2); // cbPixelFormat offPixelFormat + U_swap4(&(pEmr->bOpenGL), 1); // bOpenGL + if(!torev){ cbPix = pEmr->cbPixelFormat; offPix = pEmr->offPixelFormat; - if(cbPix)pixelformatdescriptor_swap( (PU_PIXELFORMATDESCRIPTOR) (record + pEmr->offPixelFormat)); } - U_swap4(&(pEmr->bOpenGL), 1); // bOpenGL + if(cbPix)pixelformatdescriptor_swap( (PU_PIXELFORMATDESCRIPTOR) (record + pEmr->offPixelFormat)); if((nDesc && (offDesc >= 108)) || (cbPix && (offPix >=108)) || (!offDesc && !cbPix && nSize >= 108) @@ -682,543 +831,557 @@ void U_EMRHEADER_swap(char *record, int torev){ sizel_swap(&(pEmr->szlMicrometers), 1); // szlMicrometers } } + return(1); } // U_EMRPOLYBEZIER 2 -void U_EMRPOLYBEZIER_swap(char *record, int torev){ - core1_swap(record, torev); +int U_EMRPOLYBEZIER_swap(char *record, int torev){ + return(core1_swap(record, torev)); } // U_EMRPOLYGON 3 -void U_EMRPOLYGON_swap(char *record, int torev){ - core1_swap(record, torev); +int U_EMRPOLYGON_swap(char *record, int torev){ + return(core1_swap(record, torev)); } // U_EMRPOLYLINE 4 -void U_EMRPOLYLINE_swap(char *record, int torev){ - core1_swap(record, torev); +int U_EMRPOLYLINE_swap(char *record, int torev){ + return(core1_swap(record, torev)); } // U_EMRPOLYBEZIERTO 5 -void U_EMRPOLYBEZIERTO_swap(char *record, int torev){ - core1_swap(record, torev); +int U_EMRPOLYBEZIERTO_swap(char *record, int torev){ + return(core1_swap(record, torev)); } // U_EMRPOLYLINETO 6 -void U_EMRPOLYLINETO_swap(char *record, int torev){ - core1_swap(record, torev); +int U_EMRPOLYLINETO_swap(char *record, int torev){ + return(core1_swap(record, torev)); } // U_EMRPOLYPOLYLINE 7 -void U_EMRPOLYPOLYLINE_swap(char *record, int torev){ - core2_swap(record, torev); +int U_EMRPOLYPOLYLINE_swap(char *record, int torev){ + return(core2_swap(record, torev)); } // U_EMRPOLYPOLYGON 8 -void U_EMRPOLYPOLYGON_swap(char *record, int torev){ - core2_swap(record, torev); +int U_EMRPOLYPOLYGON_swap(char *record, int torev){ + return(core2_swap(record, torev)); } // U_EMRSETWINDOWEXTEX 9 -void U_EMRSETWINDOWEXTEX_swap(char *record, int torev){ - core7_swap(record, torev); +int U_EMRSETWINDOWEXTEX_swap(char *record, int torev){ + return(core7_swap(record, torev)); } // U_EMRSETWINDOWORGEX 10 -void U_EMRSETWINDOWORGEX_swap(char *record, int torev){ - core7_swap(record, torev); +int U_EMRSETWINDOWORGEX_swap(char *record, int torev){ + return(core7_swap(record, torev)); } // U_EMRSETVIEWPORTEXTEX 11 -void U_EMRSETVIEWPORTEXTEX_swap(char *record, int torev){ - core7_swap(record, torev); +int U_EMRSETVIEWPORTEXTEX_swap(char *record, int torev){ + return(core7_swap(record, torev)); } // U_EMRSETVIEWPORTORGEX 12 -void U_EMRSETVIEWPORTORGEX_swap(char *record, int torev){ - core7_swap(record, torev); +int U_EMRSETVIEWPORTORGEX_swap(char *record, int torev){ + return(core7_swap(record, torev)); } // U_EMRSETBRUSHORGEX 13 -void U_EMRSETBRUSHORGEX_swap(char *record, int torev){ - core7_swap(record, torev); +int U_EMRSETBRUSHORGEX_swap(char *record, int torev){ + return(core7_swap(record, torev)); } // U_EMREOF 14 -void U_EMREOF_swap(char *record, int torev){ +int U_EMREOF_swap(char *record, int torev){ int off=0; int cbPalEntries=0; - core5_swap(record, torev); + const char *blimit = NULL; PU_EMREOF pEmr = (PU_EMREOF)(record); if(torev){ + blimit = record + pEmr->emr.nSize; cbPalEntries = pEmr->cbPalEntries; - if(cbPalEntries){ - logpalette_swap( (PU_LOGPALETTE)(record + pEmr->offPalEntries)); - } } + if(!core5_swap(record, torev))return(0); U_swap4(&(pEmr->cbPalEntries),2); // cbPalEntries offPalEntries if(!torev){ + blimit = record + pEmr->emr.nSize; cbPalEntries = pEmr->cbPalEntries; - if(cbPalEntries){ - logpalette_swap( (PU_LOGPALETTE)(record + pEmr->offPalEntries)); - } + } + if(cbPalEntries){ + if(IS_MEM_UNSAFE(record, pEmr->offPalEntries + 2*2, blimit))return(0); // 2 16 bit values in U_LOGPALLETE + logpalette_swap( (PU_LOGPALETTE)(record + pEmr->offPalEntries)); + // U_LOGPLTNTRY values in pallette are ordered data } off = sizeof(U_EMREOF) + 4 * cbPalEntries; + if(IS_MEM_UNSAFE(record, off + 4, blimit))return(0); U_swap4(record + off,1); // nSizeLast + return(1); } // U_EMRSETPIXELV 15 -void U_EMRSETPIXELV_swap(char *record, int torev){ - core5_swap(record, torev); +int U_EMRSETPIXELV_swap(char *record, int torev){ + if(!core5_swap(record, torev))return(0); PU_EMRSETPIXELV pEmr = (PU_EMRSETPIXELV)(record); pointl_swap(&(pEmr->ptlPixel),1); // ptlPixel // ordered bytes: crColor + return(1); } // U_EMRSETMAPPERFLAGS 16 -void U_EMRSETMAPPERFLAGS_swap(char *record, int torev){ - core5_swap(record, torev); +int U_EMRSETMAPPERFLAGS_swap(char *record, int torev){ + if(!core5_swap(record, torev))return(0); PU_EMRSETMAPPERFLAGS pEmr = (PU_EMRSETMAPPERFLAGS)(record); U_swap4(&(pEmr->dwFlags),1); // dwFlags + return(1); } // U_EMRSETMAPMODE 17 -void U_EMRSETMAPMODE_swap(char *record, int torev){ - core3_swap(record, torev); +int U_EMRSETMAPMODE_swap(char *record, int torev){ + return(core3_swap(record, torev)); } // U_EMRSETBKMODE 18 -void U_EMRSETBKMODE_swap(char *record, int torev){ - core3_swap(record, torev); +int U_EMRSETBKMODE_swap(char *record, int torev){ + return(core3_swap(record, torev)); } // U_EMRSETPOLYFILLMODE 19 -void U_EMRSETPOLYFILLMODE_swap(char *record, int torev){ - core3_swap(record, torev); +int U_EMRSETPOLYFILLMODE_swap(char *record, int torev){ + return(core3_swap(record, torev)); } // U_EMRSETROP2 20 -void U_EMRSETROP2_swap(char *record, int torev){ - core3_swap(record, torev); +int U_EMRSETROP2_swap(char *record, int torev){ + return(core3_swap(record, torev)); } // U_EMRSETSTRETCHBLTMODE 21 -void U_EMRSETSTRETCHBLTMODE_swap(char *record, int torev){ - core3_swap(record, torev); +int U_EMRSETSTRETCHBLTMODE_swap(char *record, int torev){ + return(core3_swap(record, torev)); } // U_EMRSETTEXTALIGN 22 -void U_EMRSETTEXTALIGN_swap(char *record, int torev){ - core3_swap(record, torev); +int U_EMRSETTEXTALIGN_swap(char *record, int torev){ + return(core3_swap(record, torev)); } // U_EMRSETCOLORADJUSTMENT 23 -void U_EMRSETCOLORADJUSTMENT_swap(char *record, int torev){ - core5_swap(record, torev); +int U_EMRSETCOLORADJUSTMENT_swap(char *record, int torev){ + if(!core5_swap(record, torev))return(0); PU_EMRSETCOLORADJUSTMENT pEmr = (PU_EMRSETCOLORADJUSTMENT)(record); coloradjustment_swap(&(pEmr->ColorAdjustment)); + return(1); } // U_EMRSETTEXTCOLOR 24 -void U_EMRSETTEXTCOLOR_swap(char *record, int torev){ - core5_swap(record, torev); +int U_EMRSETTEXTCOLOR_swap(char *record, int torev){ + if(!core5_swap(record, torev))return(0); // ordered bytes: crColor + return(1); } // U_EMRSETBKCOLOR 25 -void U_EMRSETBKCOLOR_swap(char *record, int torev){ - core5_swap(record, torev); +int U_EMRSETBKCOLOR_swap(char *record, int torev){ + if(!core5_swap(record, torev))return(0); // ordered bytes: crColor + return(1); } // U_EMROFFSETCLIPRGN 26 -void U_EMROFFSETCLIPRGN_swap(char *record, int torev){ - core7_swap(record, torev); +int U_EMROFFSETCLIPRGN_swap(char *record, int torev){ + return(core7_swap(record, torev)); } // U_EMRMOVETOEX 27 -void U_EMRMOVETOEX_swap(char *record, int torev){ - core7_swap(record, torev); +int U_EMRMOVETOEX_swap(char *record, int torev){ + return(core7_swap(record, torev)); } // U_EMRSETMETARGN 28 -void U_EMRSETMETARGN_swap(char *record, int torev){ - core5_swap(record, torev); +int U_EMRSETMETARGN_swap(char *record, int torev){ + return(core5_swap(record, torev)); } // U_EMREXCLUDECLIPRECT 29 -void U_EMREXCLUDECLIPRECT_swap(char *record, int torev){ - core4_swap(record, torev); +int U_EMREXCLUDECLIPRECT_swap(char *record, int torev){ + return(core4_swap(record, torev)); } // U_EMRINTERSECTCLIPRECT 30 -void U_EMRINTERSECTCLIPRECT_swap(char *record, int torev){ - core4_swap(record, torev); +int U_EMRINTERSECTCLIPRECT_swap(char *record, int torev){ + return(core4_swap(record, torev)); } // U_EMRSCALEVIEWPORTEXTEX 31 -void U_EMRSCALEVIEWPORTEXTEX_swap(char *record, int torev){ - core4_swap(record, torev); +int U_EMRSCALEVIEWPORTEXTEX_swap(char *record, int torev){ + return(core4_swap(record, torev)); } - // U_EMRSCALEWINDOWEXTEX 32 -void U_EMRSCALEWINDOWEXTEX_swap(char *record, int torev){ - core4_swap(record, torev); +int U_EMRSCALEWINDOWEXTEX_swap(char *record, int torev){ + return(core4_swap(record, torev)); } // U_EMRSAVEDC 33 -void U_EMRSAVEDC_swap(char *record, int torev){ - core5_swap(record, torev); +int U_EMRSAVEDC_swap(char *record, int torev){ + return(core5_swap(record, torev)); } // U_EMRRESTOREDC 34 -void U_EMRRESTOREDC_swap(char *record, int torev){ - core3_swap(record, torev); +int U_EMRRESTOREDC_swap(char *record, int torev){ + return(core3_swap(record, torev)); } // U_EMRSETWORLDTRANSFORM 35 -void U_EMRSETWORLDTRANSFORM_swap(char *record, int torev){ - core5_swap(record, torev); +int U_EMRSETWORLDTRANSFORM_swap(char *record, int torev){ + if(!core5_swap(record, torev))return(0); PU_EMRSETWORLDTRANSFORM pEmr = (PU_EMRSETWORLDTRANSFORM)(record); xform_swap(&(pEmr->xform)); + return(1); } // U_EMRMODIFYWORLDTRANSFORM 36 -void U_EMRMODIFYWORLDTRANSFORM_swap(char *record, int torev){ - core5_swap(record, torev); +int U_EMRMODIFYWORLDTRANSFORM_swap(char *record, int torev){ + if(!core5_swap(record, torev))return(0); PU_EMRMODIFYWORLDTRANSFORM pEmr = (PU_EMRMODIFYWORLDTRANSFORM)(record); xform_swap(&(pEmr->xform)); // xform U_swap4(&(pEmr->iMode),1); // iMode + return(1); } // U_EMRSELECTOBJECT 37 -void U_EMRSELECTOBJECT_swap(char *record, int torev){ - core5_swap(record, torev); +int U_EMRSELECTOBJECT_swap(char *record, int torev){ + if(!core5_swap(record, torev))return(0); PU_EMRSELECTOBJECT pEmr = (PU_EMRSELECTOBJECT)(record); U_swap4(&(pEmr->ihObject),1); // ihObject + return(1); } // U_EMRCREATEPEN 38 -void U_EMRCREATEPEN_swap(char *record, int torev){ - core5_swap(record, torev); +int U_EMRCREATEPEN_swap(char *record, int torev){ + if(!core5_swap(record, torev))return(0); PU_EMRCREATEPEN pEmr = (PU_EMRCREATEPEN)(record); U_swap4(&(pEmr->ihPen),1); // ihPen logpen_swap(&(pEmr->lopn)); // lopn + return(1); } // U_EMRCREATEBRUSHINDIRECT 39 -void U_EMRCREATEBRUSHINDIRECT_swap(char *record, int torev){ - core5_swap(record, torev); +int U_EMRCREATEBRUSHINDIRECT_swap(char *record, int torev){ + if(!core5_swap(record, torev))return(0); PU_EMRCREATEBRUSHINDIRECT pEmr = (PU_EMRCREATEBRUSHINDIRECT)(record); U_swap4(&(pEmr->ihBrush),1); // ihBrush logbrush_swap(&(pEmr->lb)); // lb + return(1); } // U_EMRDELETEOBJECT 40 -void U_EMRDELETEOBJECT_swap(char *record, int torev){ - core5_swap(record, torev); +int U_EMRDELETEOBJECT_swap(char *record, int torev){ + if(!core5_swap(record, torev))return(0); PU_EMRDELETEOBJECT pEmr = (PU_EMRDELETEOBJECT)(record); U_swap4(&(pEmr->ihObject),1); // ihObject + return(1); } // U_EMRANGLEARC 41 -void U_EMRANGLEARC_swap(char *record, int torev){ - core5_swap(record, torev); +int U_EMRANGLEARC_swap(char *record, int torev){ + if(!core5_swap(record, torev))return(0); PU_EMRANGLEARC pEmr = (PU_EMRANGLEARC)(record); pointl_swap(&(pEmr->ptlCenter),1); // ptlCenter U_swap4(&(pEmr->nRadius),3); // nRadius eStartAngle eSweepAngle + return(1); } // U_EMRELLIPSE 42 -void U_EMRELLIPSE_swap(char *record, int torev){ - core4_swap(record, torev); +int U_EMRELLIPSE_swap(char *record, int torev){ + return(core4_swap(record, torev)); } // U_EMRRECTANGLE 43 -void U_EMRRECTANGLE_swap(char *record, int torev){ - core4_swap(record, torev); +int U_EMRRECTANGLE_swap(char *record, int torev){ + return(core4_swap(record, torev)); } // U_EMRROUNDRECT 44 -void U_EMRROUNDRECT_swap(char *record, int torev){ - core5_swap(record, torev); +int U_EMRROUNDRECT_swap(char *record, int torev){ + if(!core5_swap(record, torev))return(0); PU_EMRROUNDRECT pEmr = (PU_EMRROUNDRECT)(record); rectl_swap(&(pEmr->rclBox),1); // rclBox sizel_swap(&(pEmr->szlCorner), 1); // szlCorner + return(1); } // U_EMRARC 45 -void U_EMRARC_swap(char *record, int torev){ - core9_swap(record, torev); +int U_EMRARC_swap(char *record, int torev){ + return(core9_swap(record, torev)); } // U_EMRCHORD 46 -void U_EMRCHORD_swap(char *record, int torev){ - core9_swap(record, torev); +int U_EMRCHORD_swap(char *record, int torev){ + return(core9_swap(record, torev)); } // U_EMRPIE 47 -void U_EMRPIE_swap(char *record, int torev){ - core9_swap(record, torev); +int U_EMRPIE_swap(char *record, int torev){ + return(core9_swap(record, torev)); } // U_EMRSELECTPALETTE 48 -void U_EMRSELECTPALETTE_swap(char *record, int torev){ - core3_swap(record, torev); +int U_EMRSELECTPALETTE_swap(char *record, int torev){ + return(core3_swap(record, torev)); } // U_EMRCREATEPALETTE 49 -void U_EMRCREATEPALETTE_swap(char *record, int torev){ - core5_swap(record, torev); +int U_EMRCREATEPALETTE_swap(char *record, int torev){ + if(!core5_swap(record, torev))return(0); PU_EMRCREATEPALETTE pEmr = (PU_EMRCREATEPALETTE)(record); U_swap4(&(pEmr->ihPal),1); // ihPal logpalette_swap( (PU_LOGPALETTE)&(pEmr->lgpl) ); // lgpl + return(1); } // U_EMRSETPALETTEENTRIES 50 -void U_EMRSETPALETTEENTRIES_swap(char *record, int torev){ - core5_swap(record, torev); +int U_EMRSETPALETTEENTRIES_swap(char *record, int torev){ + if(!core5_swap(record, torev))return(0); PU_EMRSETPALETTEENTRIES pEmr = (PU_EMRSETPALETTEENTRIES)(record); U_swap4(&(pEmr->ihPal),3); // ihPal iStart cEntries // ordered bytes: aPalEntries[] + return(1); } // U_EMRRESIZEPALETTE 51 -void U_EMRRESIZEPALETTE_swap(char *record, int torev){ - core7_swap(record, torev); +int U_EMRRESIZEPALETTE_swap(char *record, int torev){ + return(core7_swap(record, torev)); } // U_EMRREALIZEPALETTE 52 -void U_EMRREALIZEPALETTE_swap(char *record, int torev){ - core5_swap(record, torev); +int U_EMRREALIZEPALETTE_swap(char *record, int torev){ + return(core5_swap(record, torev)); } // U_EMREXTFLOODFILL 53 -void U_EMREXTFLOODFILL_swap(char *record, int torev){ - core5_swap(record, torev); +int U_EMREXTFLOODFILL_swap(char *record, int torev){ + if(!core5_swap(record, torev))return(0); PU_EMREXTFLOODFILL pEmr = (PU_EMREXTFLOODFILL)(record); pointl_swap(&(pEmr->ptlStart),1); // ptlStart // ordered bytes: crColor U_swap4(&(pEmr->iMode),1); // iMode + return(1); } // U_EMRLINETO 54 -void U_EMRLINETO_swap(char *record, int torev){ - core7_swap(record, torev); +int U_EMRLINETO_swap(char *record, int torev){ + return(core7_swap(record, torev)); } // U_EMRARCTO 55 -void U_EMRARCTO_swap(char *record, int torev){ - core9_swap(record, torev); +int U_EMRARCTO_swap(char *record, int torev){ + return(core9_swap(record, torev)); } // U_EMRPOLYDRAW 56 -void U_EMRPOLYDRAW_swap(char *record, int torev){ +int U_EMRPOLYDRAW_swap(char *record, int torev){ int count=0; - core5_swap(record, torev); + const char *blimit = NULL; PU_EMRPOLYDRAW pEmr = (PU_EMRPOLYDRAW)(record); if(torev){ count = pEmr->cptl; + blimit = record + pEmr->emr.nSize; } + if(!core5_swap(record, torev))return(0); rectl_swap(&(pEmr->rclBounds),1); // rclBounds U_swap4(&(pEmr->cptl),1); // cptl if(!torev){ count = pEmr->cptl; + blimit = record + pEmr->emr.nSize; } + if(IS_MEM_UNSAFE((pEmr->aptl), count*sizeof(U_POINTL), blimit))return(0); pointl_swap(pEmr->aptl,count); // aptl[] - U_swap4(pEmr->abTypes,count); // abTypes[] + // single byte data abTypes + return(1); } // U_EMRSETARCDIRECTION 57 -void U_EMRSETARCDIRECTION_swap(char *record, int torev){ - core3_swap(record, torev); +int U_EMRSETARCDIRECTION_swap(char *record, int torev){ + return(core3_swap(record, torev)); } // U_EMRSETMITERLIMIT 58 -void U_EMRSETMITERLIMIT_swap(char *record, int torev){ - core3_swap(record, torev); +int U_EMRSETMITERLIMIT_swap(char *record, int torev){ + return(core3_swap(record, torev)); } // U_EMRBEGINPATH 59 -void U_EMRBEGINPATH_swap(char *record, int torev){ - core5_swap(record, torev); +int U_EMRBEGINPATH_swap(char *record, int torev){ + return(core5_swap(record, torev)); } // U_EMRENDPATH 60 -void U_EMRENDPATH_swap(char *record, int torev){ - core5_swap(record, torev); +int U_EMRENDPATH_swap(char *record, int torev){ + return(core5_swap(record, torev)); } // U_EMRCLOSEFIGURE 61 -void U_EMRCLOSEFIGURE_swap(char *record, int torev){ - core5_swap(record, torev); +int U_EMRCLOSEFIGURE_swap(char *record, int torev){ + return(core5_swap(record, torev)); } // U_EMRFILLPATH 62 -void U_EMRFILLPATH_swap(char *record, int torev){ - core4_swap(record, torev); +int U_EMRFILLPATH_swap(char *record, int torev){ + return(core4_swap(record, torev)); } // U_EMRSTROKEANDFILLPATH 63 -void U_EMRSTROKEANDFILLPATH_swap(char *record, int torev){ - core4_swap(record, torev); +int U_EMRSTROKEANDFILLPATH_swap(char *record, int torev){ + return(core4_swap(record, torev)); } // U_EMRSTROKEPATH 64 -void U_EMRSTROKEPATH_swap(char *record, int torev){ - core4_swap(record, torev); +int U_EMRSTROKEPATH_swap(char *record, int torev){ + return(core4_swap(record, torev)); } // U_EMRFLATTENPATH 65 -void U_EMRFLATTENPATH_swap(char *record, int torev){ - core5_swap(record, torev); +int U_EMRFLATTENPATH_swap(char *record, int torev){ + return(core5_swap(record, torev)); } // U_EMRWIDENPATH 66 -void U_EMRWIDENPATH_swap(char *record, int torev){ - core5_swap(record, torev); +int U_EMRWIDENPATH_swap(char *record, int torev){ + return(core5_swap(record, torev)); } // U_EMRSELECTCLIPPATH 67 -void U_EMRSELECTCLIPPATH_swap(char *record, int torev){ - core3_swap(record, torev); +int U_EMRSELECTCLIPPATH_swap(char *record, int torev){ + return(core3_swap(record, torev)); } // U_EMRABORTPATH 68 -void U_EMRABORTPATH_swap(char *record, int torev){ - core5_swap(record, torev); +int U_EMRABORTPATH_swap(char *record, int torev){ + return(core5_swap(record, torev)); } // U_EMRUNDEF69 69 #define U_EMRUNDEF69_swap(A,B) U_EMRNOTIMPLEMENTED_swap(A,B) //!< Not implemented. // U_EMRCOMMENT 70 Comment (any binary data, interpretation is program specific) -void U_EMRCOMMENT_swap(char *record, int torev){ - core5_swap(record, torev); +int U_EMRCOMMENT_swap(char *record, int torev){ + int cbData = 0; + const char *blimit = NULL; PU_EMRCOMMENT pEmr = (PU_EMRCOMMENT)(record); + if(torev){ + cbData = pEmr->cbData; + blimit = record + pEmr->emr.nSize; + } + if(!core5_swap(record, torev))return(0); U_swap4(&(pEmr->cbData),1); // cbData + if(!torev){ + cbData = pEmr->cbData; + blimit = record + pEmr->emr.nSize; + } + if(IS_MEM_UNSAFE(record, cbData + sizeof(U_SIZE_EMRCOMMENT), blimit))return(0); // program specific data, presumably byte ordered, otherwise, not portable + return(1); } // U_EMRFILLRGN 71 -void U_EMRFILLRGN_swap(char *record, int torev){ - int roff=0; - int nextroff=0; - int limit=0; - roff=0; +int U_EMRFILLRGN_swap(char *record, int torev){ + int cbRgnData=0; + const char *blimit = NULL; PU_EMRFILLRGN pEmr = (PU_EMRFILLRGN)(record); if(torev){ - limit = pEmr->emr.nSize; - nextroff = 0; - } - core5_swap(record, torev); - if(!torev){ - limit = pEmr->emr.nSize; + cbRgnData= pEmr->cbRgnData; + blimit = record + pEmr->emr.nSize; } + if(!core5_swap(record, torev))return(0); rectl_swap(&(pEmr->rclBounds),1); // rclBounds U_swap4(&(pEmr->cbRgnData),2); // cbRgnData ihBrush - // This one is a pain since each RGNDATA may be a different size, so it isn't possible to index through them. - char *prd = (char *) &(pEmr->RgnData); - while(roff + 28 < limit){ // up to the end of the record - if(torev){ - nextroff += (((PU_RGNDATA)prd)->rdh.dwSize + ((PU_RGNDATA)prd)->rdh.nRgnSize - 16); - rgndata_swap((PU_RGNDATA) (prd + roff)); - roff = nextroff; - } - else { - rgndata_swap((PU_RGNDATA) (prd + roff)); - roff += (((PU_RGNDATA)prd)->rdh.dwSize + ((PU_RGNDATA)prd)->rdh.nRgnSize - 16); - } + if(!torev){ + cbRgnData= pEmr->cbRgnData; + blimit = record + pEmr->emr.nSize; } + if(IS_MEM_UNSAFE(pEmr->RgnData, cbRgnData, blimit))return(0); + return(rgndata_swap(pEmr->RgnData, cbRgnData, torev)); } // U_EMRFRAMERGN 72 -void U_EMRFRAMERGN_swap(char *record, int torev){ - int roff=0; - int nextroff=0; - int limit=0; +int U_EMRFRAMERGN_swap(char *record, int torev){ + int cbRgnData=0; + const char *blimit = NULL; PU_EMRFRAMERGN pEmr = (PU_EMRFRAMERGN)(record); - roff = 0; if(torev){ - limit = pEmr->emr.nSize; - nextroff = 0; - } - core5_swap(record, torev); - if(!torev){ - limit = pEmr->emr.nSize; + cbRgnData= pEmr->cbRgnData; + blimit = record + pEmr->emr.nSize; } + if(!core5_swap(record, torev))return(0); rectl_swap(&(pEmr->rclBounds),1); // rclBounds U_swap4(&(pEmr->cbRgnData),2); // cbRgnData ihBrush - sizel_swap(&(pEmr->szlStroke), 2); // szlStroke - // This one is a pain since each RGNDATA may be a different size, so it isn't possible to index through them. - char *prd = (char *) &(pEmr->RgnData); - while(roff + 28 < limit){ // up to the end of the record - if(torev){ - nextroff += (((PU_RGNDATA)prd)->rdh.dwSize + ((PU_RGNDATA)prd)->rdh.nRgnSize - 16); - rgndata_swap((PU_RGNDATA) (prd + roff)); - roff = nextroff; - } - else { - rgndata_swap((PU_RGNDATA) (prd + roff)); - roff += (((PU_RGNDATA)prd)->rdh.dwSize + ((PU_RGNDATA)prd)->rdh.nRgnSize - 16); - } + sizel_swap(&(pEmr->szlStroke), 1); // szlStroke + if(!torev){ + cbRgnData= pEmr->cbRgnData; + blimit = record + pEmr->emr.nSize; } + if(IS_MEM_UNSAFE(pEmr->RgnData, cbRgnData, blimit))return(0); + return(rgndata_swap(pEmr->RgnData, cbRgnData, torev)); } // U_EMRINVERTRGN 73 -void U_EMRINVERTRGN_swap(char *record, int torev){ - core11_swap(record, torev); +int U_EMRINVERTRGN_swap(char *record, int torev){ + return(core11_swap(record, torev)); } // U_EMRPAINTRGN 74 -void U_EMRPAINTRGN_swap(char *record, int torev){ - core11_swap(record, torev); +int U_EMRPAINTRGN_swap(char *record, int torev){ + return(core11_swap(record, torev)); } // U_EMREXTSELECTCLIPRGN 75 -void U_EMREXTSELECTCLIPRGN_swap(char *record, int torev){ - int roff=0; - int nextroff=0; - int limit=0; - PU_EMREXTSELECTCLIPRGN pEmr = (PU_EMREXTSELECTCLIPRGN) (record); +int U_EMREXTSELECTCLIPRGN_swap(char *record, int torev){ + int cbRgnData=0; + const char *blimit = NULL; + PU_EMREXTSELECTCLIPRGN pEmr = (PU_EMREXTSELECTCLIPRGN)(record); if(torev){ - limit = pEmr->emr.nSize; - } - core5_swap(record, torev); - if(!torev){ - limit = pEmr->emr.nSize; + cbRgnData= pEmr->cbRgnData; + blimit = record + pEmr->emr.nSize; } + if(!core5_swap(record, torev))return(0); U_swap4(&(pEmr->cbRgnData),2); // cbRgnData iMode - // This one is a pain since each RGNDATA may be a different size, so it isn't possible to index through them. - char *prd = (char *) &(pEmr->RgnData); - nextroff = roff = 0; - while(roff + 16 < limit){ // up to the end of the record - if(torev){ - nextroff += (((PU_RGNDATA)prd)->rdh.dwSize + ((PU_RGNDATA)prd)->rdh.nRgnSize - 16); - rgndata_swap((PU_RGNDATA) (prd + roff)); - roff = nextroff; - } - else { - rgndata_swap((PU_RGNDATA) (prd + roff)); - roff += (((PU_RGNDATA)prd)->rdh.dwSize + ((PU_RGNDATA)prd)->rdh.nRgnSize - 16); - } + if(!torev){ + cbRgnData= pEmr->cbRgnData; + blimit = record + pEmr->emr.nSize; } + if(IS_MEM_UNSAFE(pEmr->RgnData, cbRgnData, blimit))return(0); + return(rgndata_swap(pEmr->RgnData, cbRgnData, torev)); } // U_EMRBITBLT 76 -void U_EMRBITBLT_swap(char *record, int torev){ - core5_swap(record, torev); +int U_EMRBITBLT_swap(char *record, int torev){ + const char *blimit = NULL; + U_OFFBMISRC offBmiSrc = 0; + U_CBBMISRC cbBmiSrc = 0; + U_OFFBITSSRC offBitsSrc = 0; + U_CBBITSSRC cbBitsSrc = 0; + uint32_t iUsageSrc = 0; PU_EMRBITBLT pEmr = (PU_EMRBITBLT) (record); - if(torev && pEmr->cbBmiSrc){ - bitmapinfo_swap((PU_BITMAPINFO)(record + pEmr->offBmiSrc)); - } + if(torev){ + offBmiSrc = pEmr->offBmiSrc; + cbBmiSrc = pEmr->cbBmiSrc; + offBitsSrc = pEmr->offBitsSrc; + cbBitsSrc = pEmr->cbBitsSrc; + iUsageSrc = pEmr->iUsageSrc; + blimit = record + pEmr->emr.nSize; + if(!DIB_swap(record, iUsageSrc, offBmiSrc, cbBmiSrc, offBitsSrc, cbBitsSrc, blimit, torev))return(0); + } + if(!core5_swap(record, torev))return(0); rectl_swap(&(pEmr->rclBounds),1); // rclBounds pointl_swap(&(pEmr->Dest),2); // Dest cDest U_swap4(&(pEmr->dwRop),1); // dwRop @@ -1226,42 +1389,89 @@ void U_EMRBITBLT_swap(char *record, int torev){ xform_swap(&(pEmr->xformSrc)); // xformSrc // ordered bytes: crBkColorSrc U_swap4(&(pEmr->iUsageSrc),5); // iUsageSrc offBmiSrc cbBmiSrc offBitsSrc cbBitsSrc - // ordered bytes: bitmap (including 16 bit 5bit/channel color mode, which is done bytewise). - if(!torev && pEmr->cbBmiSrc){ - bitmapinfo_swap((PU_BITMAPINFO)(record + pEmr->offBmiSrc)); + if(!torev){ + offBmiSrc = pEmr->offBmiSrc; + cbBmiSrc = pEmr->cbBmiSrc; + offBitsSrc = pEmr->offBitsSrc; + cbBitsSrc = pEmr->cbBitsSrc; + iUsageSrc = pEmr->iUsageSrc; + blimit = record + pEmr->emr.nSize; + if(!DIB_swap(record, iUsageSrc, offBmiSrc, cbBmiSrc, offBitsSrc, cbBitsSrc, blimit, torev))return(0); } + // ordered bytes: bitmap (including 16 bit 5bit/channel color mode, which is done bytewise). + return(1); } // U_EMRSTRETCHBLT 77 -void U_EMRSTRETCHBLT_swap(char *record, int torev){ +int U_EMRSTRETCHBLT_swap(char *record, int torev){ + const char *blimit = NULL; + U_OFFBMISRC offBmiSrc = 0; + U_CBBMISRC cbBmiSrc = 0; + U_OFFBITSSRC offBitsSrc = 0; + U_CBBITSSRC cbBitsSrc = 0; + uint32_t iUsageSrc = 0; PU_EMRSTRETCHBLT pEmr = (PU_EMRSTRETCHBLT) (record); - core5_swap(record, torev); + if(torev){ + offBmiSrc = pEmr->offBmiSrc; + cbBmiSrc = pEmr->cbBmiSrc; + offBitsSrc = pEmr->offBitsSrc; + cbBitsSrc = pEmr->cbBitsSrc; + iUsageSrc = pEmr->iUsageSrc; + blimit = record + pEmr->emr.nSize; + if(!DIB_swap(record, iUsageSrc, offBmiSrc, cbBmiSrc, offBitsSrc, cbBitsSrc, blimit, torev))return(0); + } + if(!core5_swap(record, torev))return(0); rectl_swap(&(pEmr->rclBounds),1); // rclBounds pointl_swap(&(pEmr->Dest),2); // Dest cDest U_swap4(&(pEmr->dwRop),1); // dwRop pointl_swap(&(pEmr->Src),1); // Src xform_swap(&(pEmr->xformSrc)); // xformSrc // ordered bytes: crBkColorSrc - if(torev && pEmr->cbBmiSrc){ - bitmapinfo_swap((PU_BITMAPINFO)(record + pEmr->offBmiSrc)); - } U_swap4(&(pEmr->iUsageSrc),5); // iUsageSrc offBmiSrc cbBmiSrc offBitsSrc cbBitsSrc pointl_swap(&(pEmr->cSrc),1); // cSrc - if(!torev && pEmr->cbBmiSrc){ - bitmapinfo_swap((PU_BITMAPINFO)(record + pEmr->offBmiSrc)); + if(!torev){ + offBmiSrc = pEmr->offBmiSrc; + cbBmiSrc = pEmr->cbBmiSrc; + offBitsSrc = pEmr->offBitsSrc; + cbBitsSrc = pEmr->cbBitsSrc; + iUsageSrc = pEmr->iUsageSrc; + blimit = record + pEmr->emr.nSize; + if(!DIB_swap(record, iUsageSrc, offBmiSrc, cbBmiSrc, offBitsSrc, cbBitsSrc, blimit, torev))return(0); } + // ordered bytes: bitmap (including 16 bit 5bit/channel color mode, which is done bytewise). + return(1); } // U_EMRMASKBLT 78 -void U_EMRMASKBLT_swap(char *record, int torev){ +int U_EMRMASKBLT_swap(char *record, int torev){ + const char *blimit = NULL; + U_OFFBMISRC offBmiSrc = 0; + U_CBBMISRC cbBmiSrc = 0; + U_OFFBITSSRC offBitsSrc = 0; + U_CBBITSSRC cbBitsSrc = 0; + uint32_t iUsageSrc = 0; + U_OFFBMIMSK offBmiMask = 0; + U_CBBMIMSK cbBmiMask = 0; + U_OFFBITSMSK offBitsMask = 0; + U_CBBITSMSK cbBitsMask = 0; + uint32_t iUsageMask = 0; PU_EMRMASKBLT pEmr = (PU_EMRMASKBLT) (record); - core5_swap(record, torev); - if(torev && pEmr->cbBmiSrc){ - bitmapinfo_swap((PU_BITMAPINFO)(record + pEmr->offBmiSrc)); - } - if(torev && pEmr->cbBmiMask){ - bitmapinfo_swap((PU_BITMAPINFO)(record + pEmr->offBmiMask)); - } + if(torev){ + offBmiSrc = pEmr->offBmiSrc; + cbBmiSrc = pEmr->cbBmiSrc; + offBitsSrc = pEmr->offBitsSrc; + cbBitsSrc = pEmr->cbBitsSrc; + iUsageSrc = pEmr->iUsageSrc; + offBmiMask = pEmr->offBmiMask; + cbBmiMask = pEmr->cbBmiMask; + offBitsMask = pEmr->offBitsMask; + cbBitsMask = pEmr->cbBitsMask; + iUsageMask = pEmr->iUsageMask; + blimit = record + pEmr->emr.nSize; + if(!DIB_swap(record, iUsageSrc, offBmiSrc, cbBmiSrc, offBitsSrc, cbBitsSrc, blimit, torev))return(0); + if(!DIB_swap(record, iUsageMask, offBmiMask, cbBmiMask, offBitsMask, cbBitsMask, blimit, torev))return(0); + } + if(!core5_swap(record, torev))return(0); rectl_swap(&(pEmr->rclBounds),1); // rclBounds pointl_swap(&(pEmr->Dest),2); // Dest cDest U_swap4(&(pEmr->dwRop),1); // dwRop @@ -1271,24 +1481,54 @@ void U_EMRMASKBLT_swap(char *record, int torev){ U_swap4(&(pEmr->iUsageSrc),5); // iUsageSrc offBmiSrc cbBmiSrc offBitsSrc cbBitsSrc pointl_swap(&(pEmr->Mask),1); // Mask U_swap4(&(pEmr->iUsageMask),5); // iUsageMask offBmiMask cbBmiMask offBitsMask cbBitsMask - if(!torev && pEmr->cbBmiSrc){ - bitmapinfo_swap((PU_BITMAPINFO)(record + pEmr->offBmiSrc)); - } - if(!torev && pEmr->cbBmiMask){ - bitmapinfo_swap((PU_BITMAPINFO)(record + pEmr->offBmiMask)); - } + if(!torev){ + offBmiSrc = pEmr->offBmiSrc; + cbBmiSrc = pEmr->cbBmiSrc; + offBitsSrc = pEmr->offBitsSrc; + cbBitsSrc = pEmr->cbBitsSrc; + iUsageSrc = pEmr->iUsageSrc; + offBmiMask = pEmr->offBmiMask; + cbBmiMask = pEmr->cbBmiMask; + offBitsMask = pEmr->offBitsMask; + cbBitsMask = pEmr->cbBitsMask; + iUsageMask = pEmr->iUsageMask; + blimit = record + pEmr->emr.nSize; + if(!DIB_swap(record, iUsageSrc, offBmiSrc, cbBmiSrc, offBitsSrc, cbBitsSrc, blimit, torev))return(0); + if(!DIB_swap(record, iUsageMask, offBmiMask, cbBmiMask, offBitsMask, cbBitsMask, blimit, torev))return(0); + } + return(1); } // U_EMRPLGBLT 79 -void U_EMRPLGBLT_swap(char *record, int torev){ +int U_EMRPLGBLT_swap(char *record, int torev){ + const char *blimit = NULL; + U_OFFBMISRC offBmiSrc = 0; + U_CBBMISRC cbBmiSrc = 0; + U_OFFBITSSRC offBitsSrc = 0; + U_CBBITSSRC cbBitsSrc = 0; + uint32_t iUsageSrc = 0; + U_OFFBMIMSK offBmiMask = 0; + U_CBBMIMSK cbBmiMask = 0; + U_OFFBITSMSK offBitsMask = 0; + U_CBBITSMSK cbBitsMask = 0; + uint32_t iUsageMask = 0; PU_EMRPLGBLT pEmr = (PU_EMRPLGBLT) (record); - core5_swap(record, torev); - if(torev && pEmr->cbBmiSrc){ - bitmapinfo_swap((PU_BITMAPINFO)(record + pEmr->offBmiSrc)); - } - if(torev && pEmr->cbBmiMask){ - bitmapinfo_swap((PU_BITMAPINFO)(record + pEmr->offBmiMask)); - } + if(torev){ + offBmiSrc = pEmr->offBmiSrc; + cbBmiSrc = pEmr->cbBmiSrc; + offBitsSrc = pEmr->offBitsSrc; + cbBitsSrc = pEmr->cbBitsSrc; + iUsageSrc = pEmr->iUsageSrc; + offBmiMask = pEmr->offBmiMask; + cbBmiMask = pEmr->cbBmiMask; + offBitsMask = pEmr->offBitsMask; + cbBitsMask = pEmr->cbBitsMask; + iUsageMask = pEmr->iUsageMask; + blimit = record + pEmr->emr.nSize; + if(!DIB_swap(record, iUsageSrc, offBmiSrc, cbBmiSrc, offBitsSrc, cbBitsSrc, blimit, torev))return(0); + if(!DIB_swap(record, iUsageMask, offBmiMask, cbBmiMask, offBitsMask, cbBitsMask, blimit, torev))return(0); + } + if(!core5_swap(record, torev))return(0); rectl_swap(&(pEmr->rclBounds),1); // rclBounds pointl_swap(pEmr->aptlDst,3); // aptlDst[] pointl_swap(&(pEmr->Src),2); // Src cSrc @@ -1297,78 +1537,124 @@ void U_EMRPLGBLT_swap(char *record, int torev){ U_swap4(&(pEmr->iUsageSrc),5); // iUsageSrc offBmiSrc cbBmiSrc offBitsSrc cbBitsSrc pointl_swap(&(pEmr->Mask),1); // Mask U_swap4(&(pEmr->iUsageMask),5); // iUsageMask offBmiMask cbBmiMask offBitsMask cbBitsMask - if(!torev && pEmr->cbBmiSrc){ - bitmapinfo_swap((PU_BITMAPINFO)(record + pEmr->offBmiSrc)); - } - if(!torev && pEmr->cbBmiMask){ - bitmapinfo_swap((PU_BITMAPINFO)(record + pEmr->offBmiMask)); - } + if(!torev){ + offBmiSrc = pEmr->offBmiSrc; + cbBmiSrc = pEmr->cbBmiSrc; + offBitsSrc = pEmr->offBitsSrc; + cbBitsSrc = pEmr->cbBitsSrc; + iUsageSrc = pEmr->iUsageSrc; + offBmiMask = pEmr->offBmiMask; + cbBmiMask = pEmr->cbBmiMask; + offBitsMask = pEmr->offBitsMask; + cbBitsMask = pEmr->cbBitsMask; + iUsageMask = pEmr->iUsageMask; + blimit = record + pEmr->emr.nSize; + if(!DIB_swap(record, iUsageSrc, offBmiSrc, cbBmiSrc, offBitsSrc, cbBitsSrc, blimit, torev))return(0); + if(!DIB_swap(record, iUsageMask, offBmiMask, cbBmiMask, offBitsMask, cbBitsMask, blimit, torev))return(0); + } + return(1); } // U_EMRSETDIBITSTODEVICE 80 -void U_EMRSETDIBITSTODEVICE_swap(char *record, int torev){ +int U_EMRSETDIBITSTODEVICE_swap(char *record, int torev){ + const char *blimit = NULL; + U_OFFBMISRC offBmiSrc = 0; + U_CBBMISRC cbBmiSrc = 0; + U_OFFBITSSRC offBitsSrc = 0; + U_CBBITSSRC cbBitsSrc = 0; + uint32_t iUsageSrc = 0; PU_EMRSETDIBITSTODEVICE pEmr = (PU_EMRSETDIBITSTODEVICE) (record); - core5_swap(record, torev); - if(torev && pEmr->cbBmiSrc){ - bitmapinfo_swap((PU_BITMAPINFO)(record + pEmr->offBmiSrc)); - } + if(torev){ + offBmiSrc = pEmr->offBmiSrc; + cbBmiSrc = pEmr->cbBmiSrc; + offBitsSrc = pEmr->offBitsSrc; + cbBitsSrc = pEmr->cbBitsSrc; + iUsageSrc = pEmr->iUsageSrc; + blimit = record + pEmr->emr.nSize; + if(!DIB_swap(record, iUsageSrc, offBmiSrc, cbBmiSrc, offBitsSrc, cbBitsSrc, blimit, torev))return(0); + } + if(!core5_swap(record, torev))return(0); rectl_swap(&(pEmr->rclBounds),1); // rclBounds pointl_swap(&(pEmr->Dest),1); // Dest pointl_swap(&(pEmr->Src),2); // Src cSrc U_swap4(&(pEmr->offBmiSrc),7); // offBmiSrc cbBmiSrc offBitsSrc cbBitsSrc iUsageSrc iStartScan cScans - if(!torev && pEmr->cbBmiSrc){ - bitmapinfo_swap((PU_BITMAPINFO)(record + pEmr->offBmiSrc)); + if(!torev){ + offBmiSrc = pEmr->offBmiSrc; + cbBmiSrc = pEmr->cbBmiSrc; + offBitsSrc = pEmr->offBitsSrc; + cbBitsSrc = pEmr->cbBitsSrc; + iUsageSrc = pEmr->iUsageSrc; + blimit = record + pEmr->emr.nSize; + if(!DIB_swap(record, iUsageSrc, offBmiSrc, cbBmiSrc, offBitsSrc, cbBitsSrc, blimit, torev))return(0); } + return(1); } // U_EMRSTRETCHDIBITS 81 -void U_EMRSTRETCHDIBITS_swap(char *record, int torev){ +int U_EMRSTRETCHDIBITS_swap(char *record, int torev){ + const char *blimit = NULL; + U_OFFBMISRC offBmiSrc = 0; + U_CBBMISRC cbBmiSrc = 0; + U_OFFBITSSRC offBitsSrc = 0; + U_CBBITSSRC cbBitsSrc = 0; + uint32_t iUsageSrc = 0; PU_EMRSTRETCHDIBITS pEmr = (PU_EMRSTRETCHDIBITS) (record); - core5_swap(record, torev); - if(torev && pEmr->cbBmiSrc){ - bitmapinfo_swap((PU_BITMAPINFO)(record + pEmr->offBmiSrc)); - } + if(torev){ + offBmiSrc = pEmr->offBmiSrc; + cbBmiSrc = pEmr->cbBmiSrc; + offBitsSrc = pEmr->offBitsSrc; + cbBitsSrc = pEmr->cbBitsSrc; + iUsageSrc = pEmr->iUsageSrc; + blimit = record + pEmr->emr.nSize; + if(!DIB_swap(record, iUsageSrc, offBmiSrc, cbBmiSrc, offBitsSrc, cbBitsSrc, blimit, torev))return(0); + } + if(!core5_swap(record, torev))return(0); rectl_swap(&(pEmr->rclBounds),1); // rclBounds pointl_swap(&(pEmr->Dest),1); // Dest pointl_swap(&(pEmr->Src),2); // Src cSrc U_swap4(&(pEmr->offBmiSrc),6); // offBmiSrc cbBmiSrc offBitsSrc cbBitsSrc iUsageSrc dwRop pointl_swap(&(pEmr->cDest),1); // cDest - if(!torev && pEmr->cbBmiSrc){ - bitmapinfo_swap((PU_BITMAPINFO)(record + pEmr->offBmiSrc)); + if(!torev){ + offBmiSrc = pEmr->offBmiSrc; + cbBmiSrc = pEmr->cbBmiSrc; + offBitsSrc = pEmr->offBitsSrc; + cbBitsSrc = pEmr->cbBitsSrc; + iUsageSrc = pEmr->iUsageSrc; + blimit = record + pEmr->emr.nSize; + if(!DIB_swap(record, iUsageSrc, offBmiSrc, cbBmiSrc, offBitsSrc, cbBitsSrc, blimit, torev))return(0); } + return(1); } -// U_EMREXTCREATEFONTINDIRECTW_swap 82 -void U_EMREXTCREATEFONTINDIRECTW_swap(char *record, int torev){ +// U_EMREXTCREATEFONTINDIRECTW 82 +int U_EMREXTCREATEFONTINDIRECTW_swap(char *record, int torev){ + int nSize = 0; PU_EMREXTCREATEFONTINDIRECTW pEmr = (PU_EMREXTCREATEFONTINDIRECTW) (record); if(torev){ - if(pEmr->emr.nSize == sizeof(U_EMREXTCREATEFONTINDIRECTW)){ - logfont_panose_swap(&(pEmr->elfw)); - } - else { - logfont_swap( (PU_LOGFONT) &(pEmr->elfw)); - } + nSize = pEmr->emr.nSize; } - core5_swap(record, torev); + if(!core5_swap(record, torev))return(0); + U_swap4(&(pEmr->ihFont),1); // ihFont if(!torev){ - if(pEmr->emr.nSize == sizeof(U_EMREXTCREATEFONTINDIRECTW)){ - logfont_panose_swap(&(pEmr->elfw)); - } - else { - logfont_swap( (PU_LOGFONT) &(pEmr->elfw)); - } + nSize = pEmr->emr.nSize; } - U_swap4(&(pEmr->ihFont),1); // ihFont + if(nSize == U_SIZE_EMREXTCREATEFONTINDIRECTW_LOGFONT_PANOSE){ + logfont_panose_swap(&(pEmr->elfw)); + } + else { // logfont or logfontExDv (which starts with logfont, which can be swapped, and the rest is already in byte order + logfont_swap( (PU_LOGFONT) &(pEmr->elfw)); + } + return(1); } // U_EMREXTTEXTOUTA 83 -void U_EMREXTTEXTOUTA_swap(char *record, int torev){ - core8_swap(record, torev); +int U_EMREXTTEXTOUTA_swap(char *record, int torev){ + return(core8_swap(record, torev)); } // U_EMREXTTEXTOUTW 84 -void U_EMREXTTEXTOUTW_swap(char *record, int torev){ - core8_swap(record, torev); +int U_EMREXTTEXTOUTW_swap(char *record, int torev){ + return(core8_swap(record, torev)); } // U_EMRPOLYBEZIER16 85 @@ -1376,23 +1662,23 @@ void U_EMREXTTEXTOUTW_swap(char *record, int torev){ \brief Convert a pointer to a U_EMR_POLYBEZIER16 record. \param record pointer to a buffer holding the EMR record */ -void U_EMRPOLYBEZIER16_swap(char *record, int torev){ - core6_swap(record, torev); +int U_EMRPOLYBEZIER16_swap(char *record, int torev){ + return(core6_swap(record, torev)); } // U_EMRPOLYGON16 86 -void U_EMRPOLYGON16_swap(char *record, int torev){ - core6_swap(record, torev); +int U_EMRPOLYGON16_swap(char *record, int torev){ + return(core6_swap(record, torev)); } // U_EMRPOLYLINE16 87 -void U_EMRPOLYLINE16_swap(char *record, int torev){ - core6_swap(record, torev); +int U_EMRPOLYLINE16_swap(char *record, int torev){ + return(core6_swap(record, torev)); } // U_EMRPOLYBEZIERTO16 88 -void U_EMRPOLYBEZIERTO16_swap(char *record, int torev){ - core6_swap(record, torev); +int U_EMRPOLYBEZIERTO16_swap(char *record, int torev){ + return(core6_swap(record, torev)); } // U_EMRPOLYLINETO16 89 @@ -1400,61 +1686,81 @@ void U_EMRPOLYBEZIERTO16_swap(char *record, int torev){ \brief Convert a pointer to a U_EMR_POLYLINETO16 record. \param record pointer to a buffer holding the EMR record */ -void U_EMRPOLYLINETO16_swap(char *record, int torev){ - core6_swap(record, torev); +int U_EMRPOLYLINETO16_swap(char *record, int torev){ + return(core6_swap(record, torev)); } // U_EMRPOLYPOLYLINE16 90 -void U_EMRPOLYPOLYLINE16_swap(char *record, int torev){ - core10_swap(record, torev); +int U_EMRPOLYPOLYLINE16_swap(char *record, int torev){ + return(core10_swap(record, torev)); } // U_EMRPOLYPOLYGON16 91 -void U_EMRPOLYPOLYGON16_swap(char *record, int torev){ - core10_swap(record, torev); +int U_EMRPOLYPOLYGON16_swap(char *record, int torev){ + return(core10_swap(record, torev)); } // U_EMRPOLYDRAW16 92 -void U_EMRPOLYDRAW16_swap(char *record, int torev){ +int U_EMRPOLYDRAW16_swap(char *record, int torev){ int count=0; - core5_swap(record, torev); + const char *blimit = NULL; PU_EMRPOLYDRAW16 pEmr = (PU_EMRPOLYDRAW16)(record); if(torev){ count = pEmr->cpts; + blimit = record + pEmr->emr.nSize; } + if(!core5_swap(record, torev))return(0); rectl_swap(&(pEmr->rclBounds),1); // rclBounds U_swap4(&(pEmr->cpts),1); // cpts if(!torev){ count = pEmr->cpts; + blimit = record + pEmr->emr.nSize; } + if(IS_MEM_UNSAFE((pEmr->apts), count*sizeof(U_POINT16), blimit))return(0); point16_swap(pEmr->apts,count); // apts[] - U_swap4(pEmr->abTypes,count); // abTypes[] + // single byte data abTypes + return(1); } // U_EMRCREATEMONOBRUSH 93 -void U_EMRCREATEMONOBRUSH_swap(char *record, int torev){ - core12_swap(record, torev); +int U_EMRCREATEMONOBRUSH_swap(char *record, int torev){ + return(core12_swap(record, torev)); } // U_EMRCREATEDIBPATTERNBRUSHPT_swap 94 -void U_EMRCREATEDIBPATTERNBRUSHPT_swap(char *record, int torev){ - core12_swap(record, torev); +int U_EMRCREATEDIBPATTERNBRUSHPT_swap(char *record, int torev){ + return(core12_swap(record, torev)); } // U_EMREXTCREATEPEN 95 -void U_EMREXTCREATEPEN_swap(char *record, int torev){ - core5_swap(record, torev); +int U_EMREXTCREATEPEN_swap(char *record, int torev){ + const char *blimit = NULL; + U_OFFBMI offBmi = 0; + U_CBBMI cbBmi = 0; + U_OFFBITS offBits = 0; + U_CBBITS cbBits = 0; PU_EMREXTCREATEPEN pEmr = (PU_EMREXTCREATEPEN)(record); - if(torev && pEmr->cbBmi){ - bitmapinfo_swap((PU_BITMAPINFO)(record + pEmr->offBmi)); - } + if(torev){ + offBmi = pEmr->offBmi; + cbBmi = pEmr->cbBmi; + offBits = pEmr->offBits; + cbBits = pEmr->cbBits; + blimit = record + pEmr->emr.nSize; + if(!DIB_swap(record, U_DIB_RGB_COLORS, offBmi, cbBmi, offBits, cbBits, blimit, torev))return(0); + } + if(!core5_swap(record, torev))return(0); U_swap4(&(pEmr->ihPen),5); // ihPen offBmi cbBmi offBits cbBits - if(!torev && pEmr->cbBmi){ - bitmapinfo_swap((PU_BITMAPINFO)(record + pEmr->offBmi)); + if(!torev){ + offBmi = pEmr->offBmi; + cbBmi = pEmr->cbBmi; + offBits = pEmr->offBits; + cbBits = pEmr->cbBits; + blimit = record + pEmr->emr.nSize; + if(!DIB_swap(record, U_DIB_RGB_COLORS, offBmi, cbBmi, offBits, cbBits, blimit, torev))return(0); } - extlogpen_swap((PU_EXTLOGPEN) &(pEmr->elp), torev); + return(extlogpen_swap((PU_EXTLOGPEN) &(pEmr->elp), blimit, torev)); } // U_EMRPOLYTEXTOUTA 96 NOT IMPLEMENTED, denigrated after Windows NT @@ -1463,26 +1769,27 @@ void U_EMREXTCREATEPEN_swap(char *record, int torev){ #define U_EMRPOLYTEXTOUTW_swap(A,B) U_EMRNOTIMPLEMENTED_swap(A,B) //!< Not implemented. // U_EMRSETICMMODE 98 -void U_EMRSETICMMODE_swap(char *record, int torev){ - core3_swap(record, torev); +int U_EMRSETICMMODE_swap(char *record, int torev){ + return(core3_swap(record, torev)); } // U_EMRCREATECOLORSPACE 99 -void U_EMRCREATECOLORSPACE_swap(char *record, int torev){ - core5_swap(record, torev); +int U_EMRCREATECOLORSPACE_swap(char *record, int torev){ + if(!core5_swap(record, torev))return(0); PU_EMRCREATECOLORSPACE pEmr = (PU_EMRCREATECOLORSPACE)(record); U_swap4(&(pEmr->ihCS),1); // ihCS logcolorspacea_swap(&(pEmr->lcs)); // lcs + return(1); } // U_EMRSETCOLORSPACE 100 -void U_EMRSETCOLORSPACE_swap(char *record, int torev){ - core3_swap(record, torev); +int U_EMRSETCOLORSPACE_swap(char *record, int torev){ + return(core3_swap(record, torev)); } // U_EMRDELETECOLORSPACE 101 -void U_EMRDELETECOLORSPACE_swap(char *record, int torev){ - core3_swap(record, torev); +int U_EMRDELETECOLORSPACE_swap(char *record, int torev){ + return(core3_swap(record, torev)); } // U_EMRGLSRECORD 102 Not implemented @@ -1491,10 +1798,11 @@ void U_EMRDELETECOLORSPACE_swap(char *record, int torev){ #define U_EMRGLSBOUNDEDRECORD_swap(A,B) U_EMRNOTIMPLEMENTED_swap(A,B) //!< Not implemented. // U_EMRPIXELFORMAT 104 -void U_EMRPIXELFORMAT_swap(char *record, int torev){ - core5_swap(record, torev); +int U_EMRPIXELFORMAT_swap(char *record, int torev){ + if(!core5_swap(record, torev))return(0); PU_EMRPIXELFORMAT pEmr = (PU_EMRPIXELFORMAT)(record); pixelformatdescriptor_swap(&(pEmr->pfd)); // pfd + return(1); } // U_EMRDRAWESCAPE 105 Not implemented @@ -1505,24 +1813,32 @@ void U_EMRPIXELFORMAT_swap(char *record, int torev){ #define U_EMRUNDEF107_swap(A,B) U_EMRNOTIMPLEMENTED_swap(A,B) //!< Not implemented. // U_EMRSMALLTEXTOUT 108 -void U_EMRSMALLTEXTOUT_swap(char *record, int torev){ - int roff=0; - int fuOptions=0; - core5_swap(record, torev); +int U_EMRSMALLTEXTOUT_swap(char *record, int torev){ + int roff=sizeof(U_EMRSMALLTEXTOUT); // offset to the start of the variable fields + int fuOptions = 0; + int cChars = 0; + const char *blimit = NULL; PU_EMRSMALLTEXTOUT pEmr = (PU_EMRSMALLTEXTOUT)(record); if(torev){ fuOptions = pEmr->fuOptions; + cChars = pEmr->cChars; + blimit = record + pEmr->emr.nSize; } + if(!core5_swap(record, torev))return(0); pointl_swap(&(pEmr->Dest),1); // Dest U_swap4(&(pEmr->cChars),5); // cChars fuOptions iGraphicsMode exScale eyScale if(!torev){ fuOptions = pEmr->fuOptions; + cChars = pEmr->cChars; + blimit = record + pEmr->emr.nSize; } - roff = sizeof(U_EMRSMALLTEXTOUT); // offset to the start of the variable fields if(!(fuOptions & U_ETO_NO_RECT)){ + if(IS_MEM_UNSAFE(record, roff + sizeof(U_RECTL), blimit))return(0); rectl_swap( (PU_RECTL) (record + roff),1); // rclBounds } + if(IS_MEM_UNSAFE(record, roff + sizeof(U_RECTL) + cChars, blimit))return(0); // ordered bytes or UTF16-LE TextString + return(1); } // U_EMRFORCEUFIMAPPING 109 Not implemented @@ -1537,55 +1853,62 @@ void U_EMRSMALLTEXTOUT_swap(char *record, int torev){ #define U_EMRSETICMPROFILEW_swap(A,B) U_EMRNOTIMPLEMENTED_swap(A,B) //!< Not implemented. // U_EMRALPHABLEND 114 -void U_EMRALPHABLEND_swap(char *record, int torev){ - core13_swap(record, torev); +int U_EMRALPHABLEND_swap(char *record, int torev){ + return(core13_swap(record, torev)); } // U_EMRSETLAYOUT 115 -void U_EMRSETLAYOUT_swap(char *record, int torev){ - core3_swap(record, torev); +int U_EMRSETLAYOUT_swap(char *record, int torev){ + return(core3_swap(record, torev)); } // U_EMRTRANSPARENTBLT 116 -void U_EMRTRANSPARENTBLT_swap(char *record, int torev){ - core13_swap(record, torev); +int U_EMRTRANSPARENTBLT_swap(char *record, int torev){ + return(core13_swap(record, torev)); } // U_EMRUNDEF117 117 Not implemented #define U_EMRUNDEF117_swap(A,B) U_EMRNOTIMPLEMENTED_swap(A,B) //!< Not implemented. // U_EMRGRADIENTFILL 118 -void U_EMRGRADIENTFILL_swap(char *record, int torev){ +int U_EMRGRADIENTFILL_swap(char *record, int torev){ int nTriVert=0; int nGradObj=0; int ulMode=0; - core5_swap(record, torev); + const char *blimit = NULL; PU_EMRGRADIENTFILL pEmr = (PU_EMRGRADIENTFILL)(record); if(torev){ nTriVert = pEmr->nTriVert; nGradObj = pEmr->nGradObj; ulMode = pEmr->ulMode; + blimit = record + pEmr->emr.nSize; } + if(!core5_swap(record, torev))return(0); rectl_swap(&(pEmr->rclBounds),1); // rclBounds U_swap4(&(pEmr->nTriVert),3); // nTriVert nGradObj ulMode if(!torev){ nTriVert = pEmr->nTriVert; nGradObj = pEmr->nGradObj; ulMode = pEmr->ulMode; + blimit = record + pEmr->emr.nSize; } record += sizeof(U_EMRGRADIENTFILL); + if(IS_MEM_UNSAFE(record, nTriVert*sizeof(U_TRIVERTEX), blimit))return(0); if(nTriVert){ trivertex_swap((PU_TRIVERTEX)(record),nTriVert); // TriVert[] } record += nTriVert * sizeof(U_TRIVERTEX); if(nGradObj){ if( ulMode == U_GRADIENT_FILL_TRIANGLE){ + if(IS_MEM_UNSAFE(record, nGradObj*sizeof(U_GRADIENT3), blimit))return(0); gradient3_swap((PU_GRADIENT3)(record), nGradObj); // GradObj[] } else if(ulMode == U_GRADIENT_FILL_RECT_H || ulMode == U_GRADIENT_FILL_RECT_V){ + if(IS_MEM_UNSAFE(record, nGradObj*sizeof(U_GRADIENT4), blimit))return(0); gradient4_swap((PU_GRADIENT4)(record), nGradObj); // GradObj[] } } + return(1); } // U_EMRSETLINKEDUFIS 119 Not implemented @@ -1596,17 +1919,185 @@ void U_EMRGRADIENTFILL_swap(char *record, int torev){ #define U_EMRCOLORMATCHTOTARGETW_swap(A,B) U_EMRNOTIMPLEMENTED_swap(A,B) //!< Not implemented. // U_EMRCREATECOLORSPACEW 122 -void U_EMRCREATECOLORSPACEW_swap(char *record, int torev){ - core5_swap(record, torev); +int U_EMRCREATECOLORSPACEW_swap(char *record, int torev){ PU_EMRCREATECOLORSPACEW pEmr = (PU_EMRCREATECOLORSPACEW)(record); + if(!core5_swap(record, torev))return(0); U_swap4(&(pEmr->ihCS),1); // ihCS logcolorspacew_swap(&(pEmr->lcs)); // lcs U_swap4(&(pEmr->dwFlags),2); // dwFlags cbData // ordered bytes: Data + return(1); } //! \endcond +/** + \brief Checks the declared size of a record for consistency + \return 0 on failure, 1 on success + \param record pointer to the start of the EMF record in memory + \param blimit pointer to one byte after the EMF record in memory + \param nSize number of bytes in the record, read from the record + \param iType type of the record, read from the record + \param torev 1 for native to reversed, 0 for reversed to native + + Normally this would be called immediately after reading the data from a file. + Verifies that the declared size is consistent with this type of record. +*/ +int U_emf_record_sizeok(const char *record, const char *blimit, uint32_t *nSize, uint32_t *iType, int torev){ + uint32_t rsize=0; + if(!nSize || !iType)return(0); // programming error + + /* Check that COMMON data in record can be touched without an access violation. If it cannot be + this is either a corrupt EMF or one engineered to cause a buffer overflow. Pointer math + could wrap so check both sides of the range, and fail any indications of such a wrap. + */ + if(IS_MEM_UNSAFE(record, sizeof(U_EMR), blimit))return(0); + + PU_ENHMETARECORD pEmr = (PU_ENHMETARECORD)(record); + *iType = pEmr->iType; + *nSize = pEmr->nSize; + if(!torev){ + U_swap4(iType,1); + U_swap4(nSize,1); + } + + /* Check that the FULL record size is OK, abort if not. */ + if(IS_MEM_UNSAFE(record, *nSize, blimit))return(0); + + switch (*iType) + { + // next line, ancient EMF files used a smaller header, to be safe, test for that + case U_EMR_HEADER: rsize = U_SIZE_EMRHEADER_MIN; break; + case U_EMR_POLYBEZIER: rsize = U_SIZE_EMRPOLYBEZIER; break; + case U_EMR_POLYGON: rsize = U_SIZE_EMRPOLYGON; break; + case U_EMR_POLYLINE: rsize = U_SIZE_EMRPOLYLINE; break; + case U_EMR_POLYBEZIERTO: rsize = U_SIZE_EMRPOLYBEZIERTO; break; + case U_EMR_POLYLINETO: rsize = U_SIZE_EMRPOLYLINETO; break; + case U_EMR_POLYPOLYLINE: rsize = U_SIZE_EMRPOLYPOLYLINE; break; + case U_EMR_POLYPOLYGON: rsize = U_SIZE_EMRPOLYPOLYGON; break; + case U_EMR_SETWINDOWEXTEX: rsize = U_SIZE_EMRSETWINDOWEXTEX; break; + case U_EMR_SETWINDOWORGEX: rsize = U_SIZE_EMRSETWINDOWORGEX; break; + case U_EMR_SETVIEWPORTEXTEX: rsize = U_SIZE_EMRSETVIEWPORTEXTEX; break; + case U_EMR_SETVIEWPORTORGEX: rsize = U_SIZE_EMRSETVIEWPORTORGEX; break; + case U_EMR_SETBRUSHORGEX: rsize = U_SIZE_EMRSETBRUSHORGEX; break; + case U_EMR_EOF: rsize = U_SIZE_EMREOF; break; + case U_EMR_SETPIXELV: rsize = U_SIZE_EMRSETPIXELV; break; + case U_EMR_SETMAPPERFLAGS: rsize = U_SIZE_EMRSETMAPPERFLAGS; break; + case U_EMR_SETMAPMODE: rsize = U_SIZE_EMRSETMAPMODE; break; + case U_EMR_SETBKMODE: rsize = U_SIZE_EMRSETBKMODE; break; + case U_EMR_SETPOLYFILLMODE: rsize = U_SIZE_EMRSETPOLYFILLMODE; break; + case U_EMR_SETROP2: rsize = U_SIZE_EMRSETROP2; break; + case U_EMR_SETSTRETCHBLTMODE: rsize = U_SIZE_EMRSETSTRETCHBLTMODE; break; + case U_EMR_SETTEXTALIGN: rsize = U_SIZE_EMRSETTEXTALIGN; break; + case U_EMR_SETCOLORADJUSTMENT: rsize = U_SIZE_EMRSETCOLORADJUSTMENT; break; + case U_EMR_SETTEXTCOLOR: rsize = U_SIZE_EMRSETTEXTCOLOR; break; + case U_EMR_SETBKCOLOR: rsize = U_SIZE_EMRSETBKCOLOR; break; + case U_EMR_OFFSETCLIPRGN: rsize = U_SIZE_EMROFFSETCLIPRGN; break; + case U_EMR_MOVETOEX: rsize = U_SIZE_EMRMOVETOEX; break; + case U_EMR_SETMETARGN: rsize = U_SIZE_EMRSETMETARGN; break; + case U_EMR_EXCLUDECLIPRECT: rsize = U_SIZE_EMREXCLUDECLIPRECT; break; + case U_EMR_INTERSECTCLIPRECT: rsize = U_SIZE_EMRINTERSECTCLIPRECT; break; + case U_EMR_SCALEVIEWPORTEXTEX: rsize = U_SIZE_EMRSCALEVIEWPORTEXTEX; break; + case U_EMR_SCALEWINDOWEXTEX: rsize = U_SIZE_EMRSCALEWINDOWEXTEX; break; + case U_EMR_SAVEDC: rsize = U_SIZE_EMRSAVEDC; break; + case U_EMR_RESTOREDC: rsize = U_SIZE_EMRRESTOREDC; break; + case U_EMR_SETWORLDTRANSFORM: rsize = U_SIZE_EMRSETWORLDTRANSFORM; break; + case U_EMR_MODIFYWORLDTRANSFORM: rsize = U_SIZE_EMRMODIFYWORLDTRANSFORM; break; + case U_EMR_SELECTOBJECT: rsize = U_SIZE_EMRSELECTOBJECT; break; + case U_EMR_CREATEPEN: rsize = U_SIZE_EMRCREATEPEN; break; + case U_EMR_CREATEBRUSHINDIRECT: rsize = U_SIZE_EMRCREATEBRUSHINDIRECT; break; + case U_EMR_DELETEOBJECT: rsize = U_SIZE_EMRDELETEOBJECT; break; + case U_EMR_ANGLEARC: rsize = U_SIZE_EMRANGLEARC; break; + case U_EMR_ELLIPSE: rsize = U_SIZE_EMRELLIPSE; break; + case U_EMR_RECTANGLE: rsize = U_SIZE_EMRRECTANGLE; break; + case U_EMR_ROUNDRECT: rsize = U_SIZE_EMRROUNDRECT; break; + case U_EMR_ARC: rsize = U_SIZE_EMRARC; break; + case U_EMR_CHORD: rsize = U_SIZE_EMRCHORD; break; + case U_EMR_PIE: rsize = U_SIZE_EMRPIE; break; + case U_EMR_SELECTPALETTE: rsize = U_SIZE_EMRSELECTPALETTE; break; + case U_EMR_CREATEPALETTE: rsize = U_SIZE_EMRCREATEPALETTE; break; + case U_EMR_SETPALETTEENTRIES: rsize = U_SIZE_EMRSETPALETTEENTRIES; break; + case U_EMR_RESIZEPALETTE: rsize = U_SIZE_EMRRESIZEPALETTE; break; + case U_EMR_REALIZEPALETTE: rsize = U_SIZE_EMRREALIZEPALETTE; break; + case U_EMR_EXTFLOODFILL: rsize = U_SIZE_EMREXTFLOODFILL; break; + case U_EMR_LINETO: rsize = U_SIZE_EMRLINETO; break; + case U_EMR_ARCTO: rsize = U_SIZE_EMRARCTO; break; + case U_EMR_POLYDRAW: rsize = U_SIZE_EMRPOLYDRAW; break; + case U_EMR_SETARCDIRECTION: rsize = U_SIZE_EMRSETARCDIRECTION; break; + case U_EMR_SETMITERLIMIT: rsize = U_SIZE_EMRSETMITERLIMIT; break; + case U_EMR_BEGINPATH: rsize = U_SIZE_EMRBEGINPATH; break; + case U_EMR_ENDPATH: rsize = U_SIZE_EMRENDPATH; break; + case U_EMR_CLOSEFIGURE: rsize = U_SIZE_EMRCLOSEFIGURE; break; + case U_EMR_FILLPATH: rsize = U_SIZE_EMRFILLPATH; break; + case U_EMR_STROKEANDFILLPATH: rsize = U_SIZE_EMRSTROKEANDFILLPATH; break; + case U_EMR_STROKEPATH: rsize = U_SIZE_EMRSTROKEPATH; break; + case U_EMR_FLATTENPATH: rsize = U_SIZE_EMRFLATTENPATH; break; + case U_EMR_WIDENPATH: rsize = U_SIZE_EMRWIDENPATH; break; + case U_EMR_SELECTCLIPPATH: rsize = U_SIZE_EMRSELECTCLIPPATH; break; + case U_EMR_ABORTPATH: rsize = U_SIZE_EMRABORTPATH; break; + case U_EMR_UNDEF69: rsize = U_SIZE_EMRUNDEFINED; break; + case U_EMR_COMMENT: rsize = U_SIZE_EMRCOMMENT; break; + case U_EMR_FILLRGN: rsize = U_SIZE_EMRFILLRGN; break; + case U_EMR_FRAMERGN: rsize = U_SIZE_EMRFRAMERGN; break; + case U_EMR_INVERTRGN: rsize = U_SIZE_EMRINVERTRGN; break; + case U_EMR_PAINTRGN: rsize = U_SIZE_EMRPAINTRGN; break; + case U_EMR_EXTSELECTCLIPRGN: rsize = U_SIZE_EMREXTSELECTCLIPRGN; break; + case U_EMR_BITBLT: rsize = U_SIZE_EMRBITBLT; break; + case U_EMR_STRETCHBLT: rsize = U_SIZE_EMRSTRETCHBLT; break; + case U_EMR_MASKBLT: rsize = U_SIZE_EMRMASKBLT; break; + case U_EMR_PLGBLT: rsize = U_SIZE_EMRPLGBLT; break; + case U_EMR_SETDIBITSTODEVICE: rsize = U_SIZE_EMRSETDIBITSTODEVICE; break; + case U_EMR_STRETCHDIBITS: rsize = U_SIZE_EMRSTRETCHDIBITS; break; + case U_EMR_EXTCREATEFONTINDIRECTW: rsize = U_SIZE_EMREXTCREATEFONTINDIRECTW_LOGFONT; break; + case U_EMR_EXTTEXTOUTA: rsize = U_SIZE_EMREXTTEXTOUTA; break; + case U_EMR_EXTTEXTOUTW: rsize = U_SIZE_EMREXTTEXTOUTW; break; + case U_EMR_POLYBEZIER16: rsize = U_SIZE_EMRPOLYBEZIER16; break; + case U_EMR_POLYGON16: rsize = U_SIZE_EMRPOLYGON16; break; + case U_EMR_POLYLINE16: rsize = U_SIZE_EMRPOLYLINE16; break; + case U_EMR_POLYBEZIERTO16: rsize = U_SIZE_EMRPOLYBEZIERTO16; break; + case U_EMR_POLYLINETO16: rsize = U_SIZE_EMRPOLYLINETO16; break; + case U_EMR_POLYPOLYLINE16: rsize = U_SIZE_EMRPOLYPOLYLINE16; break; + case U_EMR_POLYPOLYGON16: rsize = U_SIZE_EMRPOLYPOLYGON16; break; + case U_EMR_POLYDRAW16: rsize = U_SIZE_EMRPOLYDRAW16; break; + case U_EMR_CREATEMONOBRUSH: rsize = U_SIZE_EMRCREATEMONOBRUSH; break; + case U_EMR_CREATEDIBPATTERNBRUSHPT: rsize = U_SIZE_EMRCREATEDIBPATTERNBRUSHPT; break; + case U_EMR_EXTCREATEPEN: rsize = U_SIZE_EMREXTCREATEPEN; break; + case U_EMR_POLYTEXTOUTA: rsize = U_SIZE_EMRPOLYTEXTOUTA; break; + case U_EMR_POLYTEXTOUTW: rsize = U_SIZE_EMRPOLYTEXTOUTW; break; + case U_EMR_SETICMMODE: rsize = U_SIZE_EMRSETICMMODE; break; + case U_EMR_CREATECOLORSPACE: rsize = U_SIZE_EMRCREATECOLORSPACE; break; + case U_EMR_SETCOLORSPACE: rsize = U_SIZE_EMRSETCOLORSPACE; break; + case U_EMR_DELETECOLORSPACE: rsize = U_SIZE_EMRDELETECOLORSPACE; break; + case U_EMR_GLSRECORD: rsize = U_SIZE_EMRGLSRECORD; break; + case U_EMR_GLSBOUNDEDRECORD: rsize = U_SIZE_EMRGLSBOUNDEDRECORD; break; + case U_EMR_PIXELFORMAT: rsize = U_SIZE_EMRPIXELFORMAT; break; + case U_EMR_DRAWESCAPE: rsize = U_SIZE_EMRDRAWESCAPE; break; + case U_EMR_EXTESCAPE: rsize = U_SIZE_EMREXTESCAPE; break; + case U_EMR_UNDEF107: rsize = U_SIZE_EMRUNDEFINED; break; + case U_EMR_SMALLTEXTOUT: rsize = U_SIZE_EMRSMALLTEXTOUT; break; +// case U_EMR_FORCEUFIMAPPING: rsize = U_SIZE_EMRFORCEUFIMAPPING; break; + case U_EMR_NAMEDESCAPE: rsize = U_SIZE_EMRNAMEDESCAPE; break; +// case U_EMR_COLORCORRECTPALETTE: rsize = U_SIZE_EMRCOLORCORRECTPALETTE; break; +// case U_EMR_SETICMPROFILEA: rsize = U_SIZE_EMRSETICMPROFILEA; break; +// case U_EMR_SETICMPROFILEW: rsize = U_SIZE_EMRSETICMPROFILEW; break; + case U_EMR_ALPHABLEND: rsize = U_SIZE_EMRALPHABLEND; break; + case U_EMR_SETLAYOUT: rsize = U_SIZE_EMRSETLAYOUT; break; + case U_EMR_TRANSPARENTBLT: rsize = U_SIZE_EMRTRANSPARENTBLT; break; + case U_EMR_UNDEF117: rsize = U_SIZE_EMRUNDEFINED; break; + case U_EMR_GRADIENTFILL: rsize = U_SIZE_EMRGRADIENTFILL; break; +// case U_EMR_SETLINKEDUFIS: rsize = U_SIZE_EMRSETLINKEDUFIS; break; +// case U_EMR_SETTEXTJUSTIFICATION: rsize = U_SIZE_EMRSETTEXTJUSTIFICATION; break; + case U_EMR_COLORMATCHTOTARGETW: rsize = U_SIZE_EMRCOLORMATCHTOTARGETW; break; + case U_EMR_CREATECOLORSPACEW: rsize = U_SIZE_EMRCREATECOLORSPACEW; break; + default: rsize = U_SIZE_EMRNOTIMPLEMENTED; break; + } //end of switch + // record's declared size must be more than the minimum size for this type of record + if(*nSize < rsize){ + return(0); + } + return(1); +} + /** \brief Convert an entire EMF in memory from Big Endian to Little Endian. @@ -1622,155 +2113,151 @@ int U_emf_endian(char *contents, size_t length, int torev){ uint32_t off; uint32_t OK, recnum, iType; char *record; - PU_ENHMETARECORD pEmr; + const char *blimit = contents + length; /* should never wrap since it describes a structure in memory */ + int rstatus=1; record = contents; OK = 1; off = 0; recnum = 0; while(OK){ - if(record > contents + length){ // this is most likely a corrupt EMF - return(0); - } - pEmr = (PU_ENHMETARECORD)(record); - - iType = pEmr->iType; - off = pEmr->nSize; - if(!torev){ - U_swap4(&iType,1); - U_swap4(&off,1); + if(!U_emf_record_sizeok(record, blimit, &off, &iType, torev)){ + return(0); } switch (iType) { - case U_EMR_HEADER: U_EMRHEADER_swap(record, torev); break; - case U_EMR_POLYBEZIER: U_EMRPOLYBEZIER_swap(record, torev); break; - case U_EMR_POLYGON: U_EMRPOLYGON_swap(record, torev); break; - case U_EMR_POLYLINE: U_EMRPOLYLINE_swap(record, torev); break; - case U_EMR_POLYBEZIERTO: U_EMRPOLYBEZIERTO_swap(record, torev); break; - case U_EMR_POLYLINETO: U_EMRPOLYLINETO_swap(record, torev); break; - case U_EMR_POLYPOLYLINE: U_EMRPOLYPOLYLINE_swap(record, torev); break; - case U_EMR_POLYPOLYGON: U_EMRPOLYPOLYGON_swap(record, torev); break; - case U_EMR_SETWINDOWEXTEX: U_EMRSETWINDOWEXTEX_swap(record, torev); break; - case U_EMR_SETWINDOWORGEX: U_EMRSETWINDOWORGEX_swap(record, torev); break; - case U_EMR_SETVIEWPORTEXTEX: U_EMRSETVIEWPORTEXTEX_swap(record, torev); break; - case U_EMR_SETVIEWPORTORGEX: U_EMRSETVIEWPORTORGEX_swap(record, torev); break; - case U_EMR_SETBRUSHORGEX: U_EMRSETBRUSHORGEX_swap(record, torev); break; + case U_EMR_HEADER: rstatus=U_EMRHEADER_swap(record, torev); break; + case U_EMR_POLYBEZIER: rstatus=U_EMRPOLYBEZIER_swap(record, torev); break; + case U_EMR_POLYGON: rstatus=U_EMRPOLYGON_swap(record, torev); break; + case U_EMR_POLYLINE: rstatus=U_EMRPOLYLINE_swap(record, torev); break; + case U_EMR_POLYBEZIERTO: rstatus=U_EMRPOLYBEZIERTO_swap(record, torev); break; + case U_EMR_POLYLINETO: rstatus=U_EMRPOLYLINETO_swap(record, torev); break; + case U_EMR_POLYPOLYLINE: rstatus=U_EMRPOLYPOLYLINE_swap(record, torev); break; + case U_EMR_POLYPOLYGON: rstatus=U_EMRPOLYPOLYGON_swap(record, torev); break; + case U_EMR_SETWINDOWEXTEX: rstatus=U_EMRSETWINDOWEXTEX_swap(record, torev); break; + case U_EMR_SETWINDOWORGEX: rstatus=U_EMRSETWINDOWORGEX_swap(record, torev); break; + case U_EMR_SETVIEWPORTEXTEX: rstatus=U_EMRSETVIEWPORTEXTEX_swap(record, torev); break; + case U_EMR_SETVIEWPORTORGEX: rstatus=U_EMRSETVIEWPORTORGEX_swap(record, torev); break; + case U_EMR_SETBRUSHORGEX: rstatus=U_EMRSETBRUSHORGEX_swap(record, torev); break; case U_EMR_EOF: - U_EMREOF_swap(record, torev); + rstatus=U_EMREOF_swap(record, torev); OK = 0; /* Exit triggered here */ break; - case U_EMR_SETPIXELV: U_EMRSETPIXELV_swap(record, torev); break; - case U_EMR_SETMAPPERFLAGS: U_EMRSETMAPPERFLAGS_swap(record, torev); break; - case U_EMR_SETMAPMODE: U_EMRSETMAPMODE_swap(record, torev); break; - case U_EMR_SETBKMODE: U_EMRSETBKMODE_swap(record, torev); break; - case U_EMR_SETPOLYFILLMODE: U_EMRSETPOLYFILLMODE_swap(record, torev); break; - case U_EMR_SETROP2: U_EMRSETROP2_swap(record, torev); break; - case U_EMR_SETSTRETCHBLTMODE: U_EMRSETSTRETCHBLTMODE_swap(record, torev); break; - case U_EMR_SETTEXTALIGN: U_EMRSETTEXTALIGN_swap(record, torev); break; - case U_EMR_SETCOLORADJUSTMENT: U_EMRSETCOLORADJUSTMENT_swap(record, torev); break; - case U_EMR_SETTEXTCOLOR: U_EMRSETTEXTCOLOR_swap(record, torev); break; - case U_EMR_SETBKCOLOR: U_EMRSETBKCOLOR_swap(record, torev); break; - case U_EMR_OFFSETCLIPRGN: U_EMROFFSETCLIPRGN_swap(record, torev); break; - case U_EMR_MOVETOEX: U_EMRMOVETOEX_swap(record, torev); break; - case U_EMR_SETMETARGN: U_EMRSETMETARGN_swap(record, torev); break; - case U_EMR_EXCLUDECLIPRECT: U_EMREXCLUDECLIPRECT_swap(record, torev); break; - case U_EMR_INTERSECTCLIPRECT: U_EMRINTERSECTCLIPRECT_swap(record, torev); break; - case U_EMR_SCALEVIEWPORTEXTEX: U_EMRSCALEVIEWPORTEXTEX_swap(record, torev); break; - case U_EMR_SCALEWINDOWEXTEX: U_EMRSCALEWINDOWEXTEX_swap(record, torev); break; - case U_EMR_SAVEDC: U_EMRSAVEDC_swap(record, torev); break; - case U_EMR_RESTOREDC: U_EMRRESTOREDC_swap(record, torev); break; - case U_EMR_SETWORLDTRANSFORM: U_EMRSETWORLDTRANSFORM_swap(record, torev); break; - case U_EMR_MODIFYWORLDTRANSFORM: U_EMRMODIFYWORLDTRANSFORM_swap(record, torev); break; - case U_EMR_SELECTOBJECT: U_EMRSELECTOBJECT_swap(record, torev); break; - case U_EMR_CREATEPEN: U_EMRCREATEPEN_swap(record, torev); break; - case U_EMR_CREATEBRUSHINDIRECT: U_EMRCREATEBRUSHINDIRECT_swap(record, torev); break; - case U_EMR_DELETEOBJECT: U_EMRDELETEOBJECT_swap(record, torev); break; - case U_EMR_ANGLEARC: U_EMRANGLEARC_swap(record, torev); break; - case U_EMR_ELLIPSE: U_EMRELLIPSE_swap(record, torev); break; - case U_EMR_RECTANGLE: U_EMRRECTANGLE_swap(record, torev); break; - case U_EMR_ROUNDRECT: U_EMRROUNDRECT_swap(record, torev); break; - case U_EMR_ARC: U_EMRARC_swap(record, torev); break; - case U_EMR_CHORD: U_EMRCHORD_swap(record, torev); break; - case U_EMR_PIE: U_EMRPIE_swap(record, torev); break; - case U_EMR_SELECTPALETTE: U_EMRSELECTPALETTE_swap(record, torev); break; - case U_EMR_CREATEPALETTE: U_EMRCREATEPALETTE_swap(record, torev); break; - case U_EMR_SETPALETTEENTRIES: U_EMRSETPALETTEENTRIES_swap(record, torev); break; - case U_EMR_RESIZEPALETTE: U_EMRRESIZEPALETTE_swap(record, torev); break; - case U_EMR_REALIZEPALETTE: U_EMRREALIZEPALETTE_swap(record, torev); break; - case U_EMR_EXTFLOODFILL: U_EMREXTFLOODFILL_swap(record, torev); break; - case U_EMR_LINETO: U_EMRLINETO_swap(record, torev); break; - case U_EMR_ARCTO: U_EMRARCTO_swap(record, torev); break; - case U_EMR_POLYDRAW: U_EMRPOLYDRAW_swap(record, torev); break; - case U_EMR_SETARCDIRECTION: U_EMRSETARCDIRECTION_swap(record, torev); break; - case U_EMR_SETMITERLIMIT: U_EMRSETMITERLIMIT_swap(record, torev); break; - case U_EMR_BEGINPATH: U_EMRBEGINPATH_swap(record, torev); break; - case U_EMR_ENDPATH: U_EMRENDPATH_swap(record, torev); break; - case U_EMR_CLOSEFIGURE: U_EMRCLOSEFIGURE_swap(record, torev); break; - case U_EMR_FILLPATH: U_EMRFILLPATH_swap(record, torev); break; - case U_EMR_STROKEANDFILLPATH: U_EMRSTROKEANDFILLPATH_swap(record, torev); break; - case U_EMR_STROKEPATH: U_EMRSTROKEPATH_swap(record, torev); break; - case U_EMR_FLATTENPATH: U_EMRFLATTENPATH_swap(record, torev); break; - case U_EMR_WIDENPATH: U_EMRWIDENPATH_swap(record, torev); break; - case U_EMR_SELECTCLIPPATH: U_EMRSELECTCLIPPATH_swap(record, torev); break; - case U_EMR_ABORTPATH: U_EMRABORTPATH_swap(record, torev); break; - case U_EMR_UNDEF69: U_EMRUNDEF69_swap(record, torev); break; - case U_EMR_COMMENT: U_EMRCOMMENT_swap(record, torev); break; - case U_EMR_FILLRGN: U_EMRFILLRGN_swap(record, torev); break; - case U_EMR_FRAMERGN: U_EMRFRAMERGN_swap(record, torev); break; - case U_EMR_INVERTRGN: U_EMRINVERTRGN_swap(record, torev); break; - case U_EMR_PAINTRGN: U_EMRPAINTRGN_swap(record, torev); break; - case U_EMR_EXTSELECTCLIPRGN: U_EMREXTSELECTCLIPRGN_swap(record, torev); break; - case U_EMR_BITBLT: U_EMRBITBLT_swap(record, torev); break; - case U_EMR_STRETCHBLT: U_EMRSTRETCHBLT_swap(record, torev); break; - case U_EMR_MASKBLT: U_EMRMASKBLT_swap(record, torev); break; - case U_EMR_PLGBLT: U_EMRPLGBLT_swap(record, torev); break; - case U_EMR_SETDIBITSTODEVICE: U_EMRSETDIBITSTODEVICE_swap(record, torev); break; - case U_EMR_STRETCHDIBITS: U_EMRSTRETCHDIBITS_swap(record, torev); break; - case U_EMR_EXTCREATEFONTINDIRECTW: U_EMREXTCREATEFONTINDIRECTW_swap(record, torev); break; - case U_EMR_EXTTEXTOUTA: U_EMREXTTEXTOUTA_swap(record, torev); break; - case U_EMR_EXTTEXTOUTW: U_EMREXTTEXTOUTW_swap(record, torev); break; - case U_EMR_POLYBEZIER16: U_EMRPOLYBEZIER16_swap(record, torev); break; - case U_EMR_POLYGON16: U_EMRPOLYGON16_swap(record, torev); break; - case U_EMR_POLYLINE16: U_EMRPOLYLINE16_swap(record, torev); break; - case U_EMR_POLYBEZIERTO16: U_EMRPOLYBEZIERTO16_swap(record, torev); break; - case U_EMR_POLYLINETO16: U_EMRPOLYLINETO16_swap(record, torev); break; - case U_EMR_POLYPOLYLINE16: U_EMRPOLYPOLYLINE16_swap(record, torev); break; - case U_EMR_POLYPOLYGON16: U_EMRPOLYPOLYGON16_swap(record, torev); break; - case U_EMR_POLYDRAW16: U_EMRPOLYDRAW16_swap(record, torev); break; - case U_EMR_CREATEMONOBRUSH: U_EMRCREATEMONOBRUSH_swap(record, torev); break; - case U_EMR_CREATEDIBPATTERNBRUSHPT: U_EMRCREATEDIBPATTERNBRUSHPT_swap(record, torev); break; - case U_EMR_EXTCREATEPEN: U_EMREXTCREATEPEN_swap(record, torev); break; - case U_EMR_POLYTEXTOUTA: U_EMRPOLYTEXTOUTA_swap(record, torev); break; - case U_EMR_POLYTEXTOUTW: U_EMRPOLYTEXTOUTW_swap(record, torev); break; - case U_EMR_SETICMMODE: U_EMRSETICMMODE_swap(record, torev); break; - case U_EMR_CREATECOLORSPACE: U_EMRCREATECOLORSPACE_swap(record, torev); break; - case U_EMR_SETCOLORSPACE: U_EMRSETCOLORSPACE_swap(record, torev); break; - case U_EMR_DELETECOLORSPACE: U_EMRDELETECOLORSPACE_swap(record, torev); break; - case U_EMR_GLSRECORD: U_EMRGLSRECORD_swap(record, torev); break; - case U_EMR_GLSBOUNDEDRECORD: U_EMRGLSBOUNDEDRECORD_swap(record, torev); break; - case U_EMR_PIXELFORMAT: U_EMRPIXELFORMAT_swap(record, torev); break; - case U_EMR_DRAWESCAPE: U_EMRDRAWESCAPE_swap(record, torev); break; - case U_EMR_EXTESCAPE: U_EMREXTESCAPE_swap(record, torev); break; - case U_EMR_UNDEF107: U_EMRUNDEF107_swap(record, torev); break; - case U_EMR_SMALLTEXTOUT: U_EMRSMALLTEXTOUT_swap(record, torev); break; - case U_EMR_FORCEUFIMAPPING: U_EMRFORCEUFIMAPPING_swap(record, torev); break; - case U_EMR_NAMEDESCAPE: U_EMRNAMEDESCAPE_swap(record, torev); break; - case U_EMR_COLORCORRECTPALETTE: U_EMRCOLORCORRECTPALETTE_swap(record, torev); break; - case U_EMR_SETICMPROFILEA: U_EMRSETICMPROFILEA_swap(record, torev); break; - case U_EMR_SETICMPROFILEW: U_EMRSETICMPROFILEW_swap(record, torev); break; - case U_EMR_ALPHABLEND: U_EMRALPHABLEND_swap(record, torev); break; - case U_EMR_SETLAYOUT: U_EMRSETLAYOUT_swap(record, torev); break; - case U_EMR_TRANSPARENTBLT: U_EMRTRANSPARENTBLT_swap(record, torev); break; - case U_EMR_UNDEF117: U_EMRUNDEF117_swap(record, torev); break; - case U_EMR_GRADIENTFILL: U_EMRGRADIENTFILL_swap(record, torev); break; - case U_EMR_SETLINKEDUFIS: U_EMRSETLINKEDUFIS_swap(record, torev); break; - case U_EMR_SETTEXTJUSTIFICATION: U_EMRSETTEXTJUSTIFICATION_swap(record, torev); break; - case U_EMR_COLORMATCHTOTARGETW: U_EMRCOLORMATCHTOTARGETW_swap(record, torev); break; - case U_EMR_CREATECOLORSPACEW: U_EMRCREATECOLORSPACEW_swap(record, torev); break; - default: U_EMRNOTIMPLEMENTED_swap(record, torev); break; + case U_EMR_SETPIXELV: rstatus=U_EMRSETPIXELV_swap(record, torev); break; + case U_EMR_SETMAPPERFLAGS: rstatus=U_EMRSETMAPPERFLAGS_swap(record, torev); break; + case U_EMR_SETMAPMODE: rstatus=U_EMRSETMAPMODE_swap(record, torev); break; + case U_EMR_SETBKMODE: rstatus=U_EMRSETBKMODE_swap(record, torev); break; + case U_EMR_SETPOLYFILLMODE: rstatus=U_EMRSETPOLYFILLMODE_swap(record, torev); break; + case U_EMR_SETROP2: rstatus=U_EMRSETROP2_swap(record, torev); break; + case U_EMR_SETSTRETCHBLTMODE: rstatus=U_EMRSETSTRETCHBLTMODE_swap(record, torev); break; + case U_EMR_SETTEXTALIGN: rstatus=U_EMRSETTEXTALIGN_swap(record, torev); break; + case U_EMR_SETCOLORADJUSTMENT: rstatus=U_EMRSETCOLORADJUSTMENT_swap(record, torev); break; + case U_EMR_SETTEXTCOLOR: rstatus=U_EMRSETTEXTCOLOR_swap(record, torev); break; + case U_EMR_SETBKCOLOR: rstatus=U_EMRSETBKCOLOR_swap(record, torev); break; + case U_EMR_OFFSETCLIPRGN: rstatus=U_EMROFFSETCLIPRGN_swap(record, torev); break; + case U_EMR_MOVETOEX: rstatus=U_EMRMOVETOEX_swap(record, torev); break; + case U_EMR_SETMETARGN: rstatus=U_EMRSETMETARGN_swap(record, torev); break; + case U_EMR_EXCLUDECLIPRECT: rstatus=U_EMREXCLUDECLIPRECT_swap(record, torev); break; + case U_EMR_INTERSECTCLIPRECT: rstatus=U_EMRINTERSECTCLIPRECT_swap(record, torev); break; + case U_EMR_SCALEVIEWPORTEXTEX: rstatus=U_EMRSCALEVIEWPORTEXTEX_swap(record, torev); break; + case U_EMR_SCALEWINDOWEXTEX: rstatus=U_EMRSCALEWINDOWEXTEX_swap(record, torev); break; + case U_EMR_SAVEDC: rstatus=U_EMRSAVEDC_swap(record, torev); break; + case U_EMR_RESTOREDC: rstatus=U_EMRRESTOREDC_swap(record, torev); break; + case U_EMR_SETWORLDTRANSFORM: rstatus=U_EMRSETWORLDTRANSFORM_swap(record, torev); break; + case U_EMR_MODIFYWORLDTRANSFORM: rstatus=U_EMRMODIFYWORLDTRANSFORM_swap(record, torev); break; + case U_EMR_SELECTOBJECT: rstatus=U_EMRSELECTOBJECT_swap(record, torev); break; + case U_EMR_CREATEPEN: rstatus=U_EMRCREATEPEN_swap(record, torev); break; + case U_EMR_CREATEBRUSHINDIRECT: rstatus=U_EMRCREATEBRUSHINDIRECT_swap(record, torev); break; + case U_EMR_DELETEOBJECT: rstatus=U_EMRDELETEOBJECT_swap(record, torev); break; + case U_EMR_ANGLEARC: rstatus=U_EMRANGLEARC_swap(record, torev); break; + case U_EMR_ELLIPSE: rstatus=U_EMRELLIPSE_swap(record, torev); break; + case U_EMR_RECTANGLE: rstatus=U_EMRRECTANGLE_swap(record, torev); break; + case U_EMR_ROUNDRECT: rstatus=U_EMRROUNDRECT_swap(record, torev); break; + case U_EMR_ARC: rstatus=U_EMRARC_swap(record, torev); break; + case U_EMR_CHORD: rstatus=U_EMRCHORD_swap(record, torev); break; + case U_EMR_PIE: rstatus=U_EMRPIE_swap(record, torev); break; + case U_EMR_SELECTPALETTE: rstatus=U_EMRSELECTPALETTE_swap(record, torev); break; + case U_EMR_CREATEPALETTE: rstatus=U_EMRCREATEPALETTE_swap(record, torev); break; + case U_EMR_SETPALETTEENTRIES: rstatus=U_EMRSETPALETTEENTRIES_swap(record, torev); break; + case U_EMR_RESIZEPALETTE: rstatus=U_EMRRESIZEPALETTE_swap(record, torev); break; + case U_EMR_REALIZEPALETTE: rstatus=U_EMRREALIZEPALETTE_swap(record, torev); break; + case U_EMR_EXTFLOODFILL: rstatus=U_EMREXTFLOODFILL_swap(record, torev); break; + case U_EMR_LINETO: rstatus=U_EMRLINETO_swap(record, torev); break; + case U_EMR_ARCTO: rstatus=U_EMRARCTO_swap(record, torev); break; + case U_EMR_POLYDRAW: rstatus=U_EMRPOLYDRAW_swap(record, torev); break; + case U_EMR_SETARCDIRECTION: rstatus=U_EMRSETARCDIRECTION_swap(record, torev); break; + case U_EMR_SETMITERLIMIT: rstatus=U_EMRSETMITERLIMIT_swap(record, torev); break; + case U_EMR_BEGINPATH: rstatus=U_EMRBEGINPATH_swap(record, torev); break; + case U_EMR_ENDPATH: rstatus=U_EMRENDPATH_swap(record, torev); break; + case U_EMR_CLOSEFIGURE: rstatus=U_EMRCLOSEFIGURE_swap(record, torev); break; + case U_EMR_FILLPATH: rstatus=U_EMRFILLPATH_swap(record, torev); break; + case U_EMR_STROKEANDFILLPATH: rstatus=U_EMRSTROKEANDFILLPATH_swap(record, torev); break; + case U_EMR_STROKEPATH: rstatus=U_EMRSTROKEPATH_swap(record, torev); break; + case U_EMR_FLATTENPATH: rstatus=U_EMRFLATTENPATH_swap(record, torev); break; + case U_EMR_WIDENPATH: rstatus=U_EMRWIDENPATH_swap(record, torev); break; + case U_EMR_SELECTCLIPPATH: rstatus=U_EMRSELECTCLIPPATH_swap(record, torev); break; + case U_EMR_ABORTPATH: rstatus=U_EMRABORTPATH_swap(record, torev); break; + case U_EMR_UNDEF69: rstatus=U_EMRUNDEF69_swap(record, torev); break; + case U_EMR_COMMENT: rstatus=U_EMRCOMMENT_swap(record, torev); break; + case U_EMR_FILLRGN: rstatus=U_EMRFILLRGN_swap(record, torev); break; + case U_EMR_FRAMERGN: rstatus=U_EMRFRAMERGN_swap(record, torev); break; + case U_EMR_INVERTRGN: rstatus=U_EMRINVERTRGN_swap(record, torev); break; + case U_EMR_PAINTRGN: rstatus=U_EMRPAINTRGN_swap(record, torev); break; + case U_EMR_EXTSELECTCLIPRGN: rstatus=U_EMREXTSELECTCLIPRGN_swap(record, torev);break; + case U_EMR_BITBLT: rstatus=U_EMRBITBLT_swap(record, torev); break; + case U_EMR_STRETCHBLT: rstatus=U_EMRSTRETCHBLT_swap(record, torev); break; + case U_EMR_MASKBLT: rstatus=U_EMRMASKBLT_swap(record, torev); break; + case U_EMR_PLGBLT: rstatus=U_EMRPLGBLT_swap(record, torev); break; + case U_EMR_SETDIBITSTODEVICE: rstatus=U_EMRSETDIBITSTODEVICE_swap(record, torev); break; + case U_EMR_STRETCHDIBITS: rstatus=U_EMRSTRETCHDIBITS_swap(record, torev); break; + case U_EMR_EXTCREATEFONTINDIRECTW: rstatus=U_EMREXTCREATEFONTINDIRECTW_swap(record, torev); break; + case U_EMR_EXTTEXTOUTA: rstatus=U_EMREXTTEXTOUTA_swap(record, torev); break; + case U_EMR_EXTTEXTOUTW: rstatus=U_EMREXTTEXTOUTW_swap(record, torev); break; + case U_EMR_POLYBEZIER16: rstatus=U_EMRPOLYBEZIER16_swap(record, torev); break; + case U_EMR_POLYGON16: rstatus=U_EMRPOLYGON16_swap(record, torev); break; + case U_EMR_POLYLINE16: rstatus=U_EMRPOLYLINE16_swap(record, torev); break; + case U_EMR_POLYBEZIERTO16: rstatus=U_EMRPOLYBEZIERTO16_swap(record, torev); break; + case U_EMR_POLYLINETO16: rstatus=U_EMRPOLYLINETO16_swap(record, torev); break; + case U_EMR_POLYPOLYLINE16: rstatus=U_EMRPOLYPOLYLINE16_swap(record, torev); break; + case U_EMR_POLYPOLYGON16: rstatus=U_EMRPOLYPOLYGON16_swap(record, torev); break; + case U_EMR_POLYDRAW16: rstatus=U_EMRPOLYDRAW16_swap(record, torev); break; + case U_EMR_CREATEMONOBRUSH: rstatus=U_EMRCREATEMONOBRUSH_swap(record, torev); break; + case U_EMR_CREATEDIBPATTERNBRUSHPT: rstatus=U_EMRCREATEDIBPATTERNBRUSHPT_swap(record, torev); break; + case U_EMR_EXTCREATEPEN: rstatus=U_EMREXTCREATEPEN_swap(record, torev); break; + case U_EMR_POLYTEXTOUTA: rstatus=U_EMRPOLYTEXTOUTA_swap(record, torev); break; + case U_EMR_POLYTEXTOUTW: rstatus=U_EMRPOLYTEXTOUTW_swap(record, torev); break; + case U_EMR_SETICMMODE: rstatus=U_EMRSETICMMODE_swap(record, torev); break; + case U_EMR_CREATECOLORSPACE: rstatus=U_EMRCREATECOLORSPACE_swap(record, torev); break; + case U_EMR_SETCOLORSPACE: rstatus=U_EMRSETCOLORSPACE_swap(record, torev); break; + case U_EMR_DELETECOLORSPACE: rstatus=U_EMRDELETECOLORSPACE_swap(record, torev); break; + case U_EMR_GLSRECORD: rstatus=U_EMRGLSRECORD_swap(record, torev); break; + case U_EMR_GLSBOUNDEDRECORD: rstatus=U_EMRGLSBOUNDEDRECORD_swap(record, torev); break; + case U_EMR_PIXELFORMAT: rstatus=U_EMRPIXELFORMAT_swap(record, torev); break; + case U_EMR_DRAWESCAPE: rstatus=U_EMRDRAWESCAPE_swap(record, torev); break; + case U_EMR_EXTESCAPE: rstatus=U_EMREXTESCAPE_swap(record, torev); break; + case U_EMR_UNDEF107: rstatus=U_EMRUNDEF107_swap(record, torev); break; + case U_EMR_SMALLTEXTOUT: rstatus=U_EMRSMALLTEXTOUT_swap(record, torev); break; + case U_EMR_FORCEUFIMAPPING: rstatus=U_EMRFORCEUFIMAPPING_swap(record, torev); break; + case U_EMR_NAMEDESCAPE: rstatus=U_EMRNAMEDESCAPE_swap(record, torev); break; + case U_EMR_COLORCORRECTPALETTE: rstatus=U_EMRCOLORCORRECTPALETTE_swap(record, torev); break; + case U_EMR_SETICMPROFILEA: rstatus=U_EMRSETICMPROFILEA_swap(record, torev); break; + case U_EMR_SETICMPROFILEW: rstatus=U_EMRSETICMPROFILEW_swap(record, torev); break; + case U_EMR_ALPHABLEND: rstatus=U_EMRALPHABLEND_swap(record, torev); break; + case U_EMR_SETLAYOUT: rstatus=U_EMRSETLAYOUT_swap(record, torev); break; + case U_EMR_TRANSPARENTBLT: rstatus=U_EMRTRANSPARENTBLT_swap(record, torev); break; + case U_EMR_UNDEF117: rstatus=U_EMRUNDEF117_swap(record, torev); break; + case U_EMR_GRADIENTFILL: rstatus=U_EMRGRADIENTFILL_swap(record, torev); break; + case U_EMR_SETLINKEDUFIS: rstatus=U_EMRSETLINKEDUFIS_swap(record, torev); break; + case U_EMR_SETTEXTJUSTIFICATION: rstatus=U_EMRSETTEXTJUSTIFICATION_swap(record, torev); break; + case U_EMR_COLORMATCHTOTARGETW: rstatus=U_EMRCOLORMATCHTOTARGETW_swap(record, torev); break; + case U_EMR_CREATECOLORSPACEW: rstatus=U_EMRCREATECOLORSPACEW_swap(record, torev); break; + default: rstatus=U_EMRNOTIMPLEMENTED_swap(record, torev); break; } //end of switch + if(!rstatus){ + return(rstatus); + } record += off; recnum++; } //end of while diff --git a/src/libuemf/uemf_endian.h b/src/libuemf/uemf_endian.h index 317968c34..9dbcec455 100644 --- a/src/libuemf/uemf_endian.h +++ b/src/libuemf/uemf_endian.h @@ -6,11 +6,11 @@ /* File: uemf_endian.h -Version: 0.0.3 -Date: 24-JUL-2012 +Version: 0.0.4 +Date: 24-MAR-2015 Author: David Mathog, Biology Division, Caltech email: mathog@caltech.edu -Copyright: 2012 David Mathog and California Institute of Technology (Caltech) +Copyright: 2015 David Mathog and California Institute of Technology (Caltech) */ #ifndef _UEMF_ENDIAN_ @@ -49,6 +49,7 @@ extern "C" { //! \cond // prototypes int U_emf_endian(char *contents, size_t length, int torev); +int U_emf_record_sizeok(const char *record, const char *blimit, uint32_t *nSize, uint32_t *iType, int torev); //! \endcond #ifdef __cplusplus diff --git a/src/libuemf/uemf_print.c b/src/libuemf/uemf_print.c index aa574bd73..adcf54c0f 100644 --- a/src/libuemf/uemf_print.c +++ b/src/libuemf/uemf_print.c @@ -6,11 +6,11 @@ /* File: uemf_print.c -Version: 0.0.15 -Date: 17-OCT-2013 +Version: 0.0.18 +Date: 25-MAR-2015 Author: David Mathog, Biology Division, Caltech email: mathog@caltech.edu -Copyright: 2013 David Mathog and California Institute of Technology (Caltech) +Copyright: 2015 David Mathog and California Institute of Technology (Caltech) */ #ifdef __cplusplus @@ -23,9 +23,12 @@ extern "C" { #include #include "uemf.h" #include "upmf_print.h" +#include "uemf_safe.h" //! \cond #define UNUSED(x) (void)(x) +/* This bit of code is used all over the place, so reduce it to a DEFINITION */ +#define IF_MEM_UNSAFE_PRINT_AND_RETURN(A,B,C) if(IS_MEM_UNSAFE(A,B,C)){printf(" record corruption HERE\n"); return; } /* one needed prototype */ void U_swap4(void *ul, unsigned int count); @@ -364,24 +367,28 @@ int bitmapinfoheader_print( /** \brief Print a Pointer to a U_BITMAPINFO object. \param Bmi Pointer to a U_BITMAPINFO object + \param blimit Pointer to the first byte after after this record This may be called from WMF _print routines, where problems could occur if the data was passed as the struct or a pointer to the struct, as the struct may not be aligned in memory. */ void bitmapinfo_print( - const char *Bmi + const char *Bmi, + const char *blimit ){ int i,k; int ClrUsed; U_RGBQUAD BmiColor; printf("BmiHeader: "); + IF_MEM_UNSAFE_PRINT_AND_RETURN(Bmi, offsetof(U_BITMAPINFO,bmiHeader) + sizeof(U_BITMAPINFOHEADER), blimit); ClrUsed = bitmapinfoheader_print(Bmi + offsetof(U_BITMAPINFO,bmiHeader)); if(ClrUsed){ - k= offsetof(U_BITMAPINFO,bmiColors); - for(i=0; irdh ); + IF_MEM_UNSAFE_PRINT_AND_RETURN(rd, sizeof(U_RGNDATAHEADER), blimit); + printf("rdh: "); rgndataheader_print(rd->rdh ); printf(" rects: "); if(rd->rdh.nCount){ rects = (PU_RECTL) &(rd->Buffer); + IF_MEM_UNSAFE_PRINT_AND_RETURN(rects, rd->rdh.nCount * sizeof(U_RECTL), blimit); for(i=0;irdh.nCount;i++){ printf("%d:",i); rectl_print(rects[i]); } @@ -559,11 +570,13 @@ void pixelformatdescriptor_print( \brief Print a Pointer to a U_EMRTEXT record \param emt Pointer to a U_EMRTEXT record \param record Pointer to the start of the record which contains this U_ERMTEXT + \param blimit Pointer to the first byte after after this record \param type 0 for 8 bit character, anything else for 16 */ void emrtext_print( const char *emt, const char *record, + const char *blimit, int type ){ unsigned int i,off; @@ -575,9 +588,11 @@ void emrtext_print( printf("offString:%u " ,pemt->offString ); if(pemt->offString){ if(!type){ + IF_MEM_UNSAFE_PRINT_AND_RETURN(record, pemt->offString + pemt->nChars*sizeof(char), blimit); printf("string8:<%s> ",record + pemt->offString); } else { + IF_MEM_UNSAFE_PRINT_AND_RETURN(record, pemt->offString + pemt->nChars*2*sizeof(char), blimit); string = U_Utf16leToUtf8((uint16_t *)(record + pemt->offString), pemt->nChars, NULL); printf("string16:<%s> ",string); free(string); @@ -622,9 +637,15 @@ void core1_print(const char *name, const char *contents){ unsigned int i; UNUSED(name); PU_EMRPOLYLINETO pEmr = (PU_EMRPOLYLINETO) (contents); + if(pEmr->emr.nSize < sizeof(U_EMRPOLYBEZIER)){ + printf(" record corruption HERE\n"); + return; + } + const char *blimit = contents + pEmr->emr.nSize; printf(" rclBounds: "); rectl_print(pEmr->rclBounds); printf("\n"); printf(" cptl: %d\n",pEmr->cptl ); printf(" Points: "); + IF_MEM_UNSAFE_PRINT_AND_RETURN(pEmr->aptl, pEmr->cptl*sizeof(U_POINTL), blimit); for(i=0;icptl; i++){ printf("[%d]:",i); pointl_print(pEmr->aptl[i]); } @@ -636,16 +657,23 @@ void core2_print(const char *name, const char *contents){ unsigned int i; UNUSED(name); PU_EMRPOLYPOLYGON pEmr = (PU_EMRPOLYPOLYGON) (contents); + if(pEmr->emr.nSize < sizeof(U_EMRPOLYPOLYGON)){ + printf(" record corruption HERE\n"); + return; + } + const char *blimit = contents + pEmr->emr.nSize; printf(" rclBounds: "); rectl_print(pEmr->rclBounds); printf("\n"); printf(" nPolys: %d\n",pEmr->nPolys ); printf(" cptl: %d\n",pEmr->cptl ); printf(" Counts: "); + IF_MEM_UNSAFE_PRINT_AND_RETURN(pEmr->aPolyCounts, pEmr->nPolys*sizeof(U_POLYCOUNTS), blimit); for(i=0;inPolys; i++){ printf(" [%d]:%d ",i,pEmr->aPolyCounts[i] ); } printf("\n"); PU_POINTL paptl = (PU_POINTL)((char *)pEmr->aPolyCounts + sizeof(uint32_t)* pEmr->nPolys); printf(" Points: "); + IF_MEM_UNSAFE_PRINT_AND_RETURN(paptl, pEmr->cptl*sizeof(U_POINTL), blimit); for(i=0;icptl; i++){ printf(" [%d]:",i); pointl_print(paptl[i]); } @@ -656,7 +684,12 @@ void core2_print(const char *name, const char *contents){ // Functions with the same form starting with U_EMRSETMAPMODE_print void core3_print(const char *name, const char *label, const char *contents){ UNUSED(name); + /* access violation is impossible for these because there are no counts or offsets */ PU_EMRSETMAPMODE pEmr = (PU_EMRSETMAPMODE)(contents); + if(pEmr->emr.nSize < sizeof(U_EMRSETMAPMODE)){ + printf(" record corruption HERE\n"); + return; + } if(!strcmp(label,"crColor:")){ printf(" %-15s ",label); colorref_print(*(U_COLORREF *)&(pEmr->iMode)); printf("\n"); } @@ -672,6 +705,10 @@ void core3_print(const char *name, const char *label, const char *contents){ void core4_print(const char *name, const char *contents){ UNUSED(name); PU_EMRELLIPSE pEmr = (PU_EMRELLIPSE)( contents); + if(pEmr->emr.nSize < sizeof(U_EMRELLIPSE)){ + printf(" record corruption HERE\n"); + return; + } printf(" rclBox: "); rectl_print(pEmr->rclBox); printf("\n"); } @@ -680,10 +717,16 @@ void core6_print(const char *name, const char *contents){ UNUSED(name); unsigned int i; PU_EMRPOLYBEZIER16 pEmr = (PU_EMRPOLYBEZIER16) (contents); + if(pEmr->emr.nSize < sizeof(U_EMRPOLYBEZIER16)){ + printf(" record corruption HERE\n"); + return; + } + const char *blimit = contents + pEmr->emr.nSize; printf(" rclBounds: "); rectl_print(pEmr->rclBounds); printf("\n"); printf(" cpts: %d\n",pEmr->cpts ); printf(" Points: "); PU_POINT16 papts = (PU_POINT16)(&(pEmr->apts)); + IF_MEM_UNSAFE_PRINT_AND_RETURN(papts, pEmr->cpts*sizeof(U_POINT16), blimit); for(i=0; icpts; i++){ printf(" [%d]:",i); point16_print(papts[i]); } @@ -698,6 +741,10 @@ void core6_print(const char *name, const char *contents){ void core7_print(const char *name, const char *field1, const char *field2, const char *contents){ UNUSED(name); PU_EMRGENERICPAIR pEmr = (PU_EMRGENERICPAIR) (contents); + if(pEmr->emr.nSize < sizeof(U_EMRGENERICPAIR)){ + printf(" record corruption HERE\n"); + return; + } if(*field2){ printf(" %-15s %d\n",field1,pEmr->pair.x); printf(" %-15s %d\n",field2,pEmr->pair.y); @@ -711,12 +758,13 @@ void core7_print(const char *name, const char *field1, const char *field2, const void core8_print(const char *name, const char *contents, int type){ UNUSED(name); PU_EMREXTTEXTOUTA pEmr = (PU_EMREXTTEXTOUTA) (contents); + const char *blimit = contents + pEmr->emr.nSize; printf(" iGraphicsMode: %u\n",pEmr->iGraphicsMode ); printf(" rclBounds: "); rectl_print(pEmr->rclBounds); printf("\n"); printf(" exScale: %f\n",pEmr->exScale ); printf(" eyScale: %f\n",pEmr->eyScale ); printf(" emrtext: "); - emrtext_print(contents + sizeof(U_EMREXTTEXTOUTA) - sizeof(U_EMRTEXT),contents,type); + emrtext_print(contents + sizeof(U_EMREXTTEXTOUTA) - sizeof(U_EMRTEXT),contents,blimit,type); printf("\n"); } @@ -724,6 +772,10 @@ void core8_print(const char *name, const char *contents, int type){ void core9_print(const char *name, const char *contents){ UNUSED(name); PU_EMRARC pEmr = (PU_EMRARC) (contents); + if(pEmr->emr.nSize < sizeof(U_EMRARC)){ + printf(" record corruption HERE\n"); + return; + } printf(" rclBox: "); rectl_print(pEmr->rclBox); printf("\n"); printf(" ptlStart: "); pointl_print(pEmr->ptlStart); printf("\n"); printf(" ptlEnd: "); pointl_print(pEmr->ptlEnd); printf("\n"); @@ -734,16 +786,23 @@ void core10_print(const char *name, const char *contents){ UNUSED(name); unsigned int i; PU_EMRPOLYPOLYLINE16 pEmr = (PU_EMRPOLYPOLYLINE16) (contents); + if(pEmr->emr.nSize < sizeof(U_EMRPOLYPOLYLINE16)){ + printf(" record corruption HERE\n"); + return; + } + const char *blimit = contents + pEmr->emr.nSize; printf(" rclBounds: "); rectl_print(pEmr->rclBounds); printf("\n"); printf(" nPolys: %d\n",pEmr->nPolys ); printf(" cpts: %d\n",pEmr->cpts ); printf(" Counts: "); + IF_MEM_UNSAFE_PRINT_AND_RETURN(&(pEmr->aPolyCounts), pEmr->nPolys*sizeof(U_POLYCOUNTS), blimit); for(i=0;inPolys; i++){ printf(" [%d]:%d ",i,pEmr->aPolyCounts[i] ); } printf("\n"); printf(" Points: "); - PU_POINT16 papts = (PU_POINT16)((char *)pEmr->aPolyCounts + sizeof(uint32_t)* pEmr->nPolys); + PU_POINT16 papts = (PU_POINT16)((char *)pEmr->aPolyCounts + pEmr->nPolys*sizeof(U_POLYCOUNTS) ); + IF_MEM_UNSAFE_PRINT_AND_RETURN(papts, pEmr->cpts*sizeof(U_POINT16), blimit); for(i=0; icpts; i++){ printf(" [%d]:",i); point16_print(papts[i]); } @@ -754,20 +813,18 @@ void core10_print(const char *name, const char *contents){ // Functions with the same form starting with U_EMRINVERTRGN_print and U_EMRPAINTRGN_print, void core11_print(const char *name, const char *contents){ UNUSED(name); - unsigned int i,roff; PU_EMRINVERTRGN pEmr = (PU_EMRINVERTRGN) (contents); + if(pEmr->emr.nSize < sizeof(U_EMRINVERTRGN)){ + printf(" record corruption HERE\n"); + return; + } + const char *blimit = contents + pEmr->emr.nSize; printf(" rclBounds: "); rectl_print(pEmr->rclBounds); printf("\n"); printf(" cbRgnData: %d\n",pEmr->cbRgnData); - // This one is a pain since each RGNDATA may be a different size, so it isn't possible to index through them. - roff=0; - i=1; - char *prd = (char *) &(pEmr->RgnData); - while(roff + sizeof(U_RGNDATAHEADER) < pEmr->cbRgnData){ // stop at end of the record 4*4 = header + 4*4=rect - printf(" RegionData:%d",i); - rgndata_print((PU_RGNDATA) (prd + roff)); - roff += (((PU_RGNDATA)prd)->rdh.dwSize + ((PU_RGNDATA)prd)->rdh.nRgnSize - 16); - printf("\n"); - } + printf(" RegionData:"); + const char *minptr = MAKE_MIN_PTR(((const char *) &pEmr->RgnData + pEmr->cbRgnData),blimit); + rgndata_print(pEmr->RgnData, minptr); + printf("\n"); } @@ -775,13 +832,18 @@ void core11_print(const char *name, const char *contents){ void core12_print(const char *name, const char *contents){ UNUSED(name); PU_EMRCREATEMONOBRUSH pEmr = (PU_EMRCREATEMONOBRUSH) (contents); + if(pEmr->emr.nSize < sizeof(U_EMRCREATEMONOBRUSH)){ + printf(" record corruption HERE\n"); + return; + } + const char *blimit = contents + pEmr->emr.nSize; printf(" ihBrush: %u\n",pEmr->ihBrush ); printf(" iUsage : %u\n",pEmr->iUsage ); printf(" offBmi : %u\n",pEmr->offBmi ); printf(" cbBmi : %u\n",pEmr->cbBmi ); if(pEmr->cbBmi){ printf(" bitmap:"); - bitmapinfo_print(contents + pEmr->offBmi); + bitmapinfo_print(contents + pEmr->offBmi, blimit); printf("\n"); } printf(" offBits: %u\n",pEmr->offBits ); @@ -792,6 +854,11 @@ void core12_print(const char *name, const char *contents){ void core13_print(const char *name, const char *contents){ UNUSED(name); PU_EMRALPHABLEND pEmr = (PU_EMRALPHABLEND) (contents); + if(pEmr->emr.nSize < sizeof(U_EMRALPHABLEND)){ + printf(" record corruption HERE\n"); + return; + } + const char *blimit = contents + pEmr->emr.nSize; printf(" rclBounds: "); rectl_print( pEmr->rclBounds); printf("\n"); printf(" Dest: "); pointl_print(pEmr->Dest); printf("\n"); printf(" cDest: "); pointl_print(pEmr->cDest); printf("\n"); @@ -804,7 +871,7 @@ void core13_print(const char *name, const char *contents){ printf(" cbBmiSrc: %u\n",pEmr->cbBmiSrc ); if(pEmr->cbBmiSrc){ printf(" bitmap:"); - bitmapinfo_print(contents + pEmr->offBmiSrc); + bitmapinfo_print(contents + pEmr->offBmiSrc, blimit); printf("\n"); } printf(" offBitsSrc: %u\n",pEmr->offBitsSrc ); @@ -839,6 +906,11 @@ void U_EMRHEADER_print(const char *contents){ int p1len; PU_EMRHEADER pEmr = (PU_EMRHEADER)(contents); + if(pEmr->emr.nSize < sizeof(U_EMRHEADER)){ + printf(" record corruption HERE\n"); + return; + } + const char *blimit = contents + pEmr->emr.nSize; printf(" rclBounds: "); rectl_print( pEmr->rclBounds); printf("\n"); printf(" rclFrame: "); rectl_print( pEmr->rclFrame); printf("\n"); printf(" dSignature: 0x%8.8X\n", pEmr->dSignature ); @@ -850,6 +922,7 @@ void U_EMRHEADER_print(const char *contents){ printf(" nDescription: %d\n", pEmr->nDescription ); printf(" offDescription: %d\n", pEmr->offDescription); if(pEmr->offDescription){ + IF_MEM_UNSAFE_PRINT_AND_RETURN(contents, pEmr->offDescription + pEmr->nDescription*2*sizeof(char), blimit); string = U_Utf16leToUtf8((uint16_t *)((char *) pEmr + pEmr->offDescription), pEmr->nDescription, NULL); printf(" Desc. A: %s\n",string); free(string); @@ -868,6 +941,7 @@ void U_EMRHEADER_print(const char *contents){ printf(" offPixelFormat: %d\n", pEmr->offPixelFormat); if(pEmr->cbPixelFormat){ printf(" PFD:"); + IF_MEM_UNSAFE_PRINT_AND_RETURN(contents, pEmr->offPixelFormat + sizeof(U_PIXELFORMATDESCRIPTOR), blimit); pixelformatdescriptor_print( *(PU_PIXELFORMATDESCRIPTOR) (contents + pEmr->offPixelFormat)); printf("\n"); } @@ -997,6 +1071,10 @@ void U_EMRSETBRUSHORGEX_print(const char *contents){ */ void U_EMREOF_print(const char *contents){ PU_EMREOF pEmr = (PU_EMREOF)(contents); + if(pEmr->emr.nSize < sizeof(U_EMREOF)){ + printf(" record corruption HERE\n"); + return; + } printf(" cbPalEntries: %u\n", pEmr->cbPalEntries ); printf(" offPalEntries: %u\n", pEmr->offPalEntries); if(pEmr->cbPalEntries){ @@ -1014,6 +1092,10 @@ void U_EMREOF_print(const char *contents){ */ void U_EMRSETPIXELV_print(const char *contents){ PU_EMRSETPIXELV pEmr = (PU_EMRSETPIXELV)(contents); + if(pEmr->emr.nSize < sizeof(U_EMRSETPIXELV)){ + printf(" record corruption HERE\n"); + return; + } printf(" ptlPixel: "); pointl_print( pEmr->ptlPixel); printf("\n"); printf(" crColor: "); colorref_print(pEmr->crColor); printf("\n"); } @@ -1026,6 +1108,10 @@ void U_EMRSETPIXELV_print(const char *contents){ */ void U_EMRSETMAPPERFLAGS_print(const char *contents){ PU_EMRSETMAPPERFLAGS pEmr = (PU_EMRSETMAPPERFLAGS)(contents); + if(pEmr->emr.nSize < sizeof(U_EMRSETMAPPERFLAGS)){ + printf(" record corruption HERE\n"); + return; + } printf(" dwFlags: 0x%8.8X\n",pEmr->dwFlags); } @@ -1091,6 +1177,10 @@ void U_EMRSETTEXTALIGN_print(const char *contents){ */ void U_EMRSETCOLORADJUSTMENT_print(const char *contents){ PU_EMRSETCOLORADJUSTMENT pEmr = (PU_EMRSETCOLORADJUSTMENT)(contents); + if(pEmr->emr.nSize < sizeof(U_EMRSETCOLORADJUSTMENT)){ + printf(" record corruption HERE\n"); + return; + } printf(" ColorAdjustment:"); coloradjustment_print(pEmr->ColorAdjustment); printf("\n"); @@ -1203,6 +1293,10 @@ void U_EMRRESTOREDC_print(const char *contents){ */ void U_EMRSETWORLDTRANSFORM_print(const char *contents){ PU_EMRSETWORLDTRANSFORM pEmr = (PU_EMRSETWORLDTRANSFORM)(contents); + if(pEmr->emr.nSize < sizeof(U_EMRSETWORLDTRANSFORM)){ + printf(" record corruption HERE\n"); + return; + } printf(" xform:"); xform_print(pEmr->xform); printf("\n"); @@ -1215,6 +1309,10 @@ void U_EMRSETWORLDTRANSFORM_print(const char *contents){ */ void U_EMRMODIFYWORLDTRANSFORM_print(const char *contents){ PU_EMRMODIFYWORLDTRANSFORM pEmr = (PU_EMRMODIFYWORLDTRANSFORM)(contents); + if(pEmr->emr.nSize < sizeof(U_EMRMODIFYWORLDTRANSFORM)){ + printf(" record corruption HERE\n"); + return; + } printf(" xform:"); xform_print(pEmr->xform); printf("\n"); @@ -1228,6 +1326,10 @@ void U_EMRMODIFYWORLDTRANSFORM_print(const char *contents){ */ void U_EMRSELECTOBJECT_print(const char *contents){ PU_EMRSELECTOBJECT pEmr = (PU_EMRSELECTOBJECT)(contents); + if(pEmr->emr.nSize < sizeof(U_EMRSELECTOBJECT)){ + printf(" record corruption HERE\n"); + return; + } if(pEmr->ihObject & U_STOCK_OBJECT){ printf(" StockObject: 0x%8.8X\n", pEmr->ihObject ); } @@ -1243,6 +1345,10 @@ void U_EMRSELECTOBJECT_print(const char *contents){ */ void U_EMRCREATEPEN_print(const char *contents){ PU_EMRCREATEPEN pEmr = (PU_EMRCREATEPEN)(contents); + if(pEmr->emr.nSize < sizeof(U_EMRCREATEPEN)){ + printf(" record corruption HERE\n"); + return; + } printf(" ihPen: %u\n", pEmr->ihPen ); printf(" lopn: "); logpen_print(pEmr->lopn); printf("\n"); } @@ -1254,6 +1360,10 @@ void U_EMRCREATEPEN_print(const char *contents){ */ void U_EMRCREATEBRUSHINDIRECT_print(const char *contents){ PU_EMRCREATEBRUSHINDIRECT pEmr = (PU_EMRCREATEBRUSHINDIRECT)(contents); + if(pEmr->emr.nSize < sizeof(U_EMRCREATEBRUSHINDIRECT)){ + printf(" record corruption HERE\n"); + return; + } printf(" ihBrush: %u\n", pEmr->ihBrush ); printf(" lb: "); logbrush_print(pEmr->lb); printf("\n"); } @@ -1265,6 +1375,10 @@ void U_EMRCREATEBRUSHINDIRECT_print(const char *contents){ */ void U_EMRDELETEOBJECT_print(const char *contents){ PU_EMRDELETEOBJECT pEmr = (PU_EMRDELETEOBJECT)(contents); + if(pEmr->emr.nSize < sizeof(U_EMRDELETEOBJECT)){ + printf(" record corruption HERE\n"); + return; + } printf(" ihObject: %u\n", pEmr->ihObject ); } @@ -1275,6 +1389,10 @@ void U_EMRDELETEOBJECT_print(const char *contents){ */ void U_EMRANGLEARC_print(const char *contents){ PU_EMRANGLEARC pEmr = (PU_EMRANGLEARC)(contents); + if(pEmr->emr.nSize < sizeof(U_EMRANGLEARC)){ + printf(" record corruption HERE\n"); + return; + } printf(" ptlCenter: "), pointl_print(pEmr->ptlCenter ); printf("\n"); printf(" nRadius: %u\n", pEmr->nRadius ); printf(" eStartAngle: %f\n", pEmr->eStartAngle ); @@ -1306,6 +1424,10 @@ void U_EMRRECTANGLE_print(const char *contents){ */ void U_EMRROUNDRECT_print(const char *contents){ PU_EMRROUNDRECT pEmr = (PU_EMRROUNDRECT)(contents); + if(pEmr->emr.nSize < sizeof(U_EMRROUNDRECT)){ + printf(" record corruption HERE\n"); + return; + } printf(" rclBox: "), rectl_print(pEmr->rclBox ); printf("\n"); printf(" szlCorner: "), sizel_print(pEmr->szlCorner ); printf("\n"); } @@ -1353,6 +1475,10 @@ void U_EMRSELECTPALETTE_print(const char *contents){ */ void U_EMRCREATEPALETTE_print(const char *contents){ PU_EMRCREATEPALETTE pEmr = (PU_EMRCREATEPALETTE)(contents); + if(pEmr->emr.nSize < sizeof(U_EMRCREATEPALETTE)){ + printf(" record corruption HERE\n"); + return; + } printf(" ihPal: %u\n",pEmr->ihPal); printf(" lgpl: "), logpalette_print( (PU_LOGPALETTE)&(pEmr->lgpl) ); printf("\n"); } @@ -1365,12 +1491,18 @@ void U_EMRCREATEPALETTE_print(const char *contents){ void U_EMRSETPALETTEENTRIES_print(const char *contents){ unsigned int i; PU_EMRSETPALETTEENTRIES pEmr = (PU_EMRSETPALETTEENTRIES)(contents); + if(pEmr->emr.nSize < sizeof(U_EMRSETPALETTEENTRIES)){ + printf(" record corruption HERE\n"); + return; + } + const char *blimit = contents + pEmr->emr.nSize; printf(" ihPal: %u\n",pEmr->ihPal); printf(" iStart: %u\n",pEmr->iStart); printf(" cEntries: %u\n",pEmr->cEntries); if(pEmr->cEntries){ printf(" PLTEntries:"); PU_LOGPLTNTRY aPalEntries = (PU_LOGPLTNTRY) &(pEmr->aPalEntries); + IF_MEM_UNSAFE_PRINT_AND_RETURN(aPalEntries, pEmr->cEntries*sizeof(U_LOGPLTNTRY), blimit); for(i=0; icEntries; i++){ printf("%d:",i); logpltntry_print(aPalEntries[i]); } @@ -1403,6 +1535,10 @@ void U_EMRREALIZEPALETTE_print(const char *contents){ */ void U_EMREXTFLOODFILL_print(const char *contents){ PU_EMREXTFLOODFILL pEmr = (PU_EMREXTFLOODFILL)(contents); + if(pEmr->emr.nSize < sizeof(U_EMREXTFLOODFILL)){ + printf(" record corruption HERE\n"); + return; + } printf(" ptlStart: "); pointl_print(pEmr->ptlStart); printf("\n"); printf(" crColor: "); colorref_print(pEmr->crColor); printf("\n"); printf(" iMode: %u\n",pEmr->iMode); @@ -1434,17 +1570,25 @@ void U_EMRARCTO_print(const char *contents){ void U_EMRPOLYDRAW_print(const char *contents){ unsigned int i; PU_EMRPOLYDRAW pEmr = (PU_EMRPOLYDRAW)(contents); + if(pEmr->emr.nSize < sizeof(U_EMRPOLYDRAW)){ + printf(" record corruption HERE\n"); + return; + } + const char *blimit = contents + pEmr->emr.nSize; printf(" rclBounds: "); rectl_print( pEmr->rclBounds); printf("\n"); printf(" cptl: %d\n",pEmr->cptl ); printf(" Points: "); + IF_MEM_UNSAFE_PRINT_AND_RETURN(pEmr->aptl, pEmr->cptl*sizeof(U_POINTL), blimit); for(i=0;icptl; i++){ printf(" [%d]:",i); pointl_print(pEmr->aptl[i]); } printf("\n"); printf(" Types: "); + const char *abTypes = (const char *) pEmr->aptl + pEmr->cptl*sizeof(U_POINTL); + IF_MEM_UNSAFE_PRINT_AND_RETURN(abTypes, pEmr->cptl, blimit); for(i=0;icptl; i++){ - printf(" [%d]:%u ",i,pEmr->abTypes[i]); + printf(" [%d]:%u ",i,((uint8_t *)abTypes)[i]); } printf("\n"); } @@ -1565,12 +1709,11 @@ void U_EMRABORTPATH_print(const char *contents){ /** \brief Print a pointer to a U_EMR_COMMENT record. \param contents pointer to a location in memory holding the comment record - \param blimit size in bytes of the comment record - \param off offset in bytes to the first byte in this record + \param off offset in bytes to the first byte in this record (needed for EMF+ record printing) EMF+ records, if any, are stored in EMF comment records. */ -void U_EMRCOMMENT_print(const char *contents, const char *blimit, size_t off){ +void U_EMRCOMMENT_print(const char *contents, size_t off){ char *string; char *src; uint32_t cIdent,cIdent2,cbData; @@ -1579,21 +1722,30 @@ void U_EMRCOMMENT_print(const char *contents, const char *blimit, size_t off){ static int recnum=0; PU_EMRCOMMENT pEmr = (PU_EMRCOMMENT)(contents); + if(pEmr->emr.nSize < sizeof(U_EMRCOMMENT)){ + printf(" record corruption HERE\n"); + return; + } + const char *blimit = contents + pEmr->emr.nSize; /* There are several different types of comments */ + IF_MEM_UNSAFE_PRINT_AND_RETURN(contents, sizeof(U_EMRCOMMENT), blimit); cbData = pEmr->cbData; printf(" cbData: %d\n",cbData ); + IF_MEM_UNSAFE_PRINT_AND_RETURN(contents, sizeof(U_EMR) + sizeof(U_CBDATA) + cbData, blimit); src = (char *)&(pEmr->Data); // default if(cbData >= 4){ /* Since the comment is just a big bag of bytes the emf endian code cannot safely touch - any of its payload. This is the only record type with that limitation. Try to determine + any of its payload. This is the only record type with that limitation. So the record + may appear at this stage with the wrong endianness. Try to determine what the contents are even if more byte swapping is required. */ cIdent = *(uint32_t *)(src); if(U_BYTE_SWAP){ U_swap4(&(cIdent),1); } if( cIdent == U_EMR_COMMENT_PUBLIC ){ printf(" cIdent: Public\n"); PU_EMRCOMMENT_PUBLIC pEmrp = (PU_EMRCOMMENT_PUBLIC) pEmr; + IF_MEM_UNSAFE_PRINT_AND_RETURN(contents, sizeof(U_EMRCOMMENT_PUBLIC), blimit); cIdent2 = pEmrp->pcIdent; if(U_BYTE_SWAP){ U_swap4(&(cIdent2),1); } printf(" pcIdent: 0x%8.8x\n",cIdent2); @@ -1603,6 +1755,7 @@ void U_EMRCOMMENT_print(const char *contents, const char *blimit, size_t off){ else if(cIdent == U_EMR_COMMENT_SPOOL ){ printf(" cIdent: Spool\n"); PU_EMRCOMMENT_SPOOL pEmrs = (PU_EMRCOMMENT_SPOOL) pEmr; + IF_MEM_UNSAFE_PRINT_AND_RETURN(contents, sizeof(U_EMRCOMMENT_SPOOL), blimit); cIdent2 = pEmrs->esrIdent; if(U_BYTE_SWAP){ U_swap4(&(cIdent2),1); } printf(" esrIdent: 0x%8.8x\n",cIdent2); @@ -1612,11 +1765,16 @@ void U_EMRCOMMENT_print(const char *contents, const char *blimit, size_t off){ else if(cIdent == U_EMR_COMMENT_EMFPLUSRECORD){ printf(" cIdent: EMF+\n"); PU_EMRCOMMENT_EMFPLUS pEmrpl = (PU_EMRCOMMENT_EMFPLUS) pEmr; + IF_MEM_UNSAFE_PRINT_AND_RETURN(contents, sizeof(U_EMRCOMMENT_EMFPLUS), blimit); src = (char *)&(pEmrpl->Data); loff = 16; /* Header size of the header part of an EMF+ comment record */ while(loff < cbData + 12){ // EMF+ records may not fill the entire comment, cbData value includes cIdent, but not U_EMR or cbData recsize = U_pmf_onerec_print(src, blimit, recnum, loff + off); - if(recsize<=0)break; + if(recsize==0){ break; } + else if(recsize<0){ + printf(" record corruption HERE\n"); + return; + } loff += recsize; src += recsize; recnum++; @@ -1642,19 +1800,17 @@ void U_EMRCOMMENT_print(const char *contents, const char *blimit, size_t off){ \param contents pointer to a buffer holding all EMR records */ void U_EMRFILLRGN_print(const char *contents){ - int i,roff; PU_EMRFILLRGN pEmr = (PU_EMRFILLRGN)(contents); + if(pEmr->emr.nSize < sizeof(U_EMRFILLRGN)){ + printf(" record corruption HERE\n"); + return; + } + const char *blimit = contents + pEmr->emr.nSize; printf(" rclBounds: "); rectl_print(pEmr->rclBounds); printf("\n"); printf(" cbRgnData: %u\n",pEmr->cbRgnData); printf(" ihBrush: %u\n",pEmr->ihBrush); - // This one is a pain since each RGNDATA may be a different size, so it isn't possible to index through them. - roff=0; - i=1; - char *prd = (char *) &(pEmr->RgnData); - while(roff + sizeof(U_RGNDATAHEADER) < pEmr->emr.nSize){ // up to the end of the record - printf(" RegionData[%d]: ",i); rgndata_print((PU_RGNDATA) (prd + roff)); printf("\n"); - roff += (((PU_RGNDATA)prd)->rdh.dwSize + ((PU_RGNDATA)prd)->rdh.nRgnSize - 16); - } + const char *minptr = MAKE_MIN_PTR(((const char *) &pEmr->RgnData + pEmr->cbRgnData + sizeof(U_RGNDATAHEADER)),blimit); + printf(" RegionData: "); rgndata_print(pEmr->RgnData, minptr); printf("\n"); } // U_EMRFRAMERGN 72 @@ -1663,20 +1819,18 @@ void U_EMRFILLRGN_print(const char *contents){ \param contents pointer to a buffer holding all EMR records */ void U_EMRFRAMERGN_print(const char *contents){ - int i,roff; PU_EMRFRAMERGN pEmr = (PU_EMRFRAMERGN)(contents); + if(pEmr->emr.nSize < sizeof(U_EMRFRAMERGN)){ + printf(" record corruption HERE\n"); + return; + } + const char *blimit = contents + pEmr->emr.nSize; printf(" rclBounds: "); rectl_print(pEmr->rclBounds); printf("\n"); printf(" cbRgnData: %u\n",pEmr->cbRgnData); printf(" ihBrush: %u\n",pEmr->ihBrush); printf(" szlStroke: "), sizel_print(pEmr->szlStroke ); printf("\n"); - // This one is a pain since each RGNDATA may be a different size, so it isn't possible to index through them. - roff=0; - i=1; - char *prd = (char *) &(pEmr->RgnData); - while(roff + sizeof(U_RGNDATAHEADER) < pEmr->emr.nSize){ // up to the end of the record - printf(" RegionData[%d]: ",i); rgndata_print((PU_RGNDATA) (prd + roff)); printf("\n"); - roff += (((PU_RGNDATA)prd)->rdh.dwSize + ((PU_RGNDATA)prd)->rdh.nRgnSize - 16); - } + const char *minptr = MAKE_MIN_PTR(((const char *) &pEmr->RgnData + pEmr->cbRgnData),blimit); + printf(" RegionData: "); rgndata_print(pEmr->RgnData, minptr); printf("\n"); } // U_EMRINVERTRGN 73 @@ -1703,17 +1857,16 @@ void U_EMRPAINTRGN_print(const char *contents){ \param contents pointer to a buffer holding all EMR records */ void U_EMREXTSELECTCLIPRGN_print(const char *contents){ - int i,roff; PU_EMREXTSELECTCLIPRGN pEmr = (PU_EMREXTSELECTCLIPRGN) (contents); + if(pEmr->emr.nSize < sizeof(U_EMREXTSELECTCLIPRGN)){ + printf(" record corruption HERE\n"); + return; + } + const char *blimit = contents + pEmr->emr.nSize; printf(" cbRgnData: %u\n",pEmr->cbRgnData); printf(" iMode: %u\n",pEmr->iMode); - // This one is a pain since each RGNDATA may be a different size, so it isn't possible to index through them. - char *prd = (char *) &(pEmr->RgnData); - i=roff=0; - while(roff + sizeof(U_RGNDATAHEADER) < pEmr->cbRgnData){ // stop at end of the record 4*4 = header + 4*4=rect - printf(" RegionData[%d]: ",i++); rgndata_print((PU_RGNDATA) (prd + roff)); printf("\n"); - roff += (((PU_RGNDATA)prd)->rdh.dwSize + ((PU_RGNDATA)prd)->rdh.nRgnSize - 16); - } + const char *minptr = MAKE_MIN_PTR(((const char *) &pEmr->RgnData + pEmr->cbRgnData),blimit); + printf(" RegionData: "); rgndata_print(pEmr->RgnData, minptr); printf("\n"); } // U_EMRBITBLT 76 @@ -1723,6 +1876,11 @@ void U_EMREXTSELECTCLIPRGN_print(const char *contents){ */ void U_EMRBITBLT_print(const char *contents){ PU_EMRBITBLT pEmr = (PU_EMRBITBLT) (contents); + if(pEmr->emr.nSize < sizeof(U_EMRBITBLT)){ + printf(" record corruption HERE\n"); + return; + } + const char *blimit = contents + pEmr->emr.nSize; printf(" rclBounds: "); rectl_print( pEmr->rclBounds); printf("\n"); printf(" Dest: "); pointl_print(pEmr->Dest); printf("\n"); printf(" cDest: "); pointl_print(pEmr->cDest); printf("\n"); @@ -1735,7 +1893,7 @@ void U_EMRBITBLT_print(const char *contents){ printf(" cbBmiSrc: %u\n", pEmr->cbBmiSrc ); if(pEmr->cbBmiSrc){ printf(" bitmap: "); - bitmapinfo_print(contents + pEmr->offBmiSrc); + bitmapinfo_print(contents + pEmr->offBmiSrc, blimit); printf("\n"); } printf(" offBitsSrc: %u\n", pEmr->offBitsSrc ); @@ -1749,6 +1907,11 @@ void U_EMRBITBLT_print(const char *contents){ */ void U_EMRSTRETCHBLT_print(const char *contents){ PU_EMRSTRETCHBLT pEmr = (PU_EMRSTRETCHBLT) (contents); + if(pEmr->emr.nSize < sizeof(U_EMRSTRETCHBLT)){ + printf(" record corruption HERE\n"); + return; + } + const char *blimit = contents + pEmr->emr.nSize; printf(" rclBounds: "); rectl_print( pEmr->rclBounds); printf("\n"); printf(" Dest: "); pointl_print(pEmr->Dest); printf("\n"); printf(" cDest: "); pointl_print(pEmr->cDest); printf("\n"); @@ -1761,7 +1924,7 @@ void U_EMRSTRETCHBLT_print(const char *contents){ printf(" cbBmiSrc: %u\n", pEmr->cbBmiSrc ); if(pEmr->cbBmiSrc){ printf(" bitmap: "); - bitmapinfo_print(contents + pEmr->offBmiSrc); + bitmapinfo_print(contents + pEmr->offBmiSrc, blimit); printf("\n"); } printf(" offBitsSrc: %u\n", pEmr->offBitsSrc ); @@ -1776,6 +1939,11 @@ void U_EMRSTRETCHBLT_print(const char *contents){ */ void U_EMRMASKBLT_print(const char *contents){ PU_EMRMASKBLT pEmr = (PU_EMRMASKBLT) (contents); + if(pEmr->emr.nSize < sizeof(U_EMRMASKBLT)){ + printf(" record corruption HERE\n"); + return; + } + const char *blimit = contents + pEmr->emr.nSize; printf(" rclBounds: "); rectl_print( pEmr->rclBounds); printf("\n"); printf(" Dest: "); pointl_print(pEmr->Dest); printf("\n"); printf(" cDest: "); pointl_print(pEmr->cDest); printf("\n"); @@ -1788,7 +1956,7 @@ void U_EMRMASKBLT_print(const char *contents){ printf(" cbBmiSrc: %u\n", pEmr->cbBmiSrc ); if(pEmr->cbBmiSrc){ printf(" Src bitmap: "); - bitmapinfo_print(contents + pEmr->offBmiSrc); + bitmapinfo_print(contents + pEmr->offBmiSrc, blimit); printf("\n"); } printf(" offBitsSrc: %u\n", pEmr->offBitsSrc ); @@ -1799,7 +1967,7 @@ void U_EMRMASKBLT_print(const char *contents){ printf(" cbBmiMask: %u\n", pEmr->cbBmiMask ); if(pEmr->cbBmiMask){ printf(" Mask bitmap: "); - bitmapinfo_print(contents + pEmr->offBmiMask); + bitmapinfo_print(contents + pEmr->offBmiMask, blimit); printf("\n"); } printf(" offBitsMask: %u\n", pEmr->offBitsMask ); @@ -1813,6 +1981,11 @@ void U_EMRMASKBLT_print(const char *contents){ */ void U_EMRPLGBLT_print(const char *contents){ PU_EMRPLGBLT pEmr = (PU_EMRPLGBLT) (contents); + if(pEmr->emr.nSize < sizeof(U_EMRPLGBLT)){ + printf(" record corruption HERE\n"); + return; + } + const char *blimit = contents + pEmr->emr.nSize; printf(" rclBounds: "); rectl_print( pEmr->rclBounds); printf("\n"); printf(" aptlDst(UL): "); pointl_print(pEmr->aptlDst[0]); printf("\n"); printf(" aptlDst(UR): "); pointl_print(pEmr->aptlDst[1]); printf("\n"); @@ -1826,7 +1999,7 @@ void U_EMRPLGBLT_print(const char *contents){ printf(" cbBmiSrc: %u\n", pEmr->cbBmiSrc ); if(pEmr->cbBmiSrc){ printf(" Src bitmap: "); - bitmapinfo_print(contents + pEmr->offBmiSrc); + bitmapinfo_print(contents + pEmr->offBmiSrc, blimit); printf("\n"); } printf(" offBitsSrc: %u\n", pEmr->offBitsSrc ); @@ -1837,7 +2010,7 @@ void U_EMRPLGBLT_print(const char *contents){ printf(" cbBmiMask: %u\n", pEmr->cbBmiMask ); if(pEmr->cbBmiMask){ printf(" Mask bitmap: "); - bitmapinfo_print(contents + pEmr->offBmiMask); + bitmapinfo_print(contents + pEmr->offBmiMask, blimit); printf("\n"); } printf(" offBitsMask: %u\n", pEmr->offBitsMask ); @@ -1851,6 +2024,11 @@ void U_EMRPLGBLT_print(const char *contents){ */ void U_EMRSETDIBITSTODEVICE_print(const char *contents){ PU_EMRSETDIBITSTODEVICE pEmr = (PU_EMRSETDIBITSTODEVICE) (contents); + if(pEmr->emr.nSize < sizeof(U_EMRSETDIBITSTODEVICE)){ + printf(" record corruption HERE\n"); + return; + } + const char *blimit = contents + pEmr->emr.nSize; printf(" rclBounds: "); rectl_print( pEmr->rclBounds); printf("\n"); printf(" Dest: "); pointl_print(pEmr->Dest); printf("\n"); printf(" Src: "); pointl_print(pEmr->Src); printf("\n"); @@ -1859,7 +2037,7 @@ void U_EMRSETDIBITSTODEVICE_print(const char *contents){ printf(" cbBmiSrc: %u\n", pEmr->cbBmiSrc ); if(pEmr->cbBmiSrc){ printf(" Src bitmap: "); - bitmapinfo_print(contents + pEmr->offBmiSrc); + bitmapinfo_print(contents + pEmr->offBmiSrc, blimit); printf("\n"); } printf(" offBitsSrc: %u\n", pEmr->offBitsSrc ); @@ -1876,6 +2054,11 @@ void U_EMRSETDIBITSTODEVICE_print(const char *contents){ */ void U_EMRSTRETCHDIBITS_print(const char *contents){ PU_EMRSTRETCHDIBITS pEmr = (PU_EMRSTRETCHDIBITS) (contents); + if(pEmr->emr.nSize < sizeof(U_EMRSTRETCHDIBITS)){ + printf(" record corruption HERE\n"); + return; + } + const char *blimit = contents + pEmr->emr.nSize; printf(" rclBounds: "); rectl_print( pEmr->rclBounds); printf("\n"); printf(" Dest: "); pointl_print(pEmr->Dest); printf("\n"); printf(" Src: "); pointl_print(pEmr->Src); printf("\n"); @@ -1884,7 +2067,7 @@ void U_EMRSTRETCHDIBITS_print(const char *contents){ printf(" cbBmiSrc: %u\n", pEmr->cbBmiSrc ); if(pEmr->cbBmiSrc){ printf(" Src bitmap: "); - bitmapinfo_print(contents + pEmr->offBmiSrc); + bitmapinfo_print(contents + pEmr->offBmiSrc, blimit); printf("\n"); } printf(" offBitsSrc: %u\n", pEmr->offBitsSrc ); @@ -1901,12 +2084,19 @@ void U_EMRSTRETCHDIBITS_print(const char *contents){ */ void U_EMREXTCREATEFONTINDIRECTW_print(const char *contents){ PU_EMREXTCREATEFONTINDIRECTW pEmr = (PU_EMREXTCREATEFONTINDIRECTW) (contents); + if(pEmr->emr.nSize < U_SIZE_EMREXTCREATEFONTINDIRECTW_LOGFONT){ // smallest variant + printf(" record corruption HERE\n"); + return; + } + const char *blimit = contents + pEmr->emr.nSize; printf(" ihFont: %u\n",pEmr->ihFont ); printf(" Font: "); - if(pEmr->emr.nSize == sizeof(U_EMREXTCREATEFONTINDIRECTW)){ // holds logfont_panose + if(pEmr->emr.nSize == U_SIZE_EMREXTCREATEFONTINDIRECTW_LOGFONT_PANOSE){ // holds logfont_panose + IF_MEM_UNSAFE_PRINT_AND_RETURN(&(pEmr->elfw), sizeof(U_PANOSE), blimit); logfont_panose_print(pEmr->elfw); } - else { // holds logfont + else { // holds logfont or logfontExDv. The latter isn't supported but it starts with logfont, so use that + IF_MEM_UNSAFE_PRINT_AND_RETURN(&(pEmr->elfw), sizeof(U_LOGFONT), blimit); logfont_print( *(PU_LOGFONT) &(pEmr->elfw)); } printf("\n"); @@ -2002,17 +2192,25 @@ void U_EMRPOLYPOLYGON16_print(const char *contents){ void U_EMRPOLYDRAW16_print(const char *contents){ unsigned int i; PU_EMRPOLYDRAW16 pEmr = (PU_EMRPOLYDRAW16)(contents); + if(pEmr->emr.nSize < sizeof(U_EMRPOLYDRAW16)){ + printf(" record corruption HERE\n"); + return; + } + const char *blimit = contents + pEmr->emr.nSize; printf(" rclBounds: "); rectl_print( pEmr->rclBounds); printf("\n"); printf(" cpts: %d\n",pEmr->cpts ); printf(" Points: "); + IF_MEM_UNSAFE_PRINT_AND_RETURN(pEmr->apts, pEmr->cpts*sizeof(U_POINT16), blimit); for(i=0;icpts; i++){ printf(" [%d]:",i); point16_print(pEmr->apts[i]); } printf("\n"); printf(" Types: "); + const char *abTypes = (const char *) pEmr->apts + pEmr->cpts*sizeof(U_POINT16); + IF_MEM_UNSAFE_PRINT_AND_RETURN(abTypes, pEmr->cpts, blimit); for(i=0;icpts; i++){ - printf(" [%d]:%u ",i,pEmr->abTypes[i]); + printf(" [%d]:%u ",i,((uint8_t *)abTypes)[i]); } printf("\n"); } @@ -2043,12 +2241,17 @@ void U_EMRCREATEDIBPATTERNBRUSHPT_print(const char *contents){ */ void U_EMREXTCREATEPEN_print(const char *contents){ PU_EMREXTCREATEPEN pEmr = (PU_EMREXTCREATEPEN)(contents); + if(pEmr->emr.nSize < sizeof(U_EMREXTCREATEPEN)){ + printf(" record corruption HERE\n"); + return; + } + const char *blimit = contents + pEmr->emr.nSize; printf(" ihPen: %u\n", pEmr->ihPen ); printf(" offBmi: %u\n", pEmr->offBmi ); printf(" cbBmi: %u\n", pEmr->cbBmi ); if(pEmr->cbBmi){ printf(" bitmap: "); - bitmapinfo_print(contents + pEmr->offBmi); + bitmapinfo_print(contents + pEmr->offBmi, blimit); printf("\n"); } printf(" offBits: %u\n", pEmr->offBits ); @@ -2077,6 +2280,10 @@ void U_EMRSETICMMODE_print(const char *contents){ */ void U_EMRCREATECOLORSPACE_print(const char *contents){ PU_EMRCREATECOLORSPACE pEmr = (PU_EMRCREATECOLORSPACE)(contents); + if(pEmr->emr.nSize < sizeof(U_EMRCREATECOLORSPACE)){ + printf(" record corruption HERE\n"); + return; + } printf(" ihCS: %u\n", pEmr->ihCS ); printf(" ColorSpace: "); logcolorspacea_print(pEmr->lcs); printf("\n"); } @@ -2111,6 +2318,12 @@ void U_EMRDELETECOLORSPACE_print(const char *contents){ */ void U_EMRPIXELFORMAT_print(const char *contents){ PU_EMRPIXELFORMAT pEmr = (PU_EMRPIXELFORMAT)(contents); + if(pEmr->emr.nSize < sizeof(U_EMRPIXELFORMAT)){ + printf(" record corruption HERE\n"); + return; + } + const char *blimit = contents + pEmr->emr.nSize; + IF_MEM_UNSAFE_PRINT_AND_RETURN(&(pEmr->pfd), sizeof(U_PIXELFORMATDESCRIPTOR), blimit); printf(" Pfd: "); pixelformatdescriptor_print(pEmr->pfd); printf("\n"); } @@ -2130,6 +2343,11 @@ void U_EMRSMALLTEXTOUT_print(const char *contents){ int roff; char *string; PU_EMRSMALLTEXTOUT pEmr = (PU_EMRSMALLTEXTOUT)(contents); + if(pEmr->emr.nSize < sizeof(U_EMRSMALLTEXTOUT)){ + printf(" record corruption HERE\n"); + return; + } + const char *blimit = contents + pEmr->emr.nSize; printf(" Dest: "); pointl_print(pEmr->Dest); printf("\n"); printf(" cChars: %u\n", pEmr->cChars ); printf(" fuOptions: 0x%8.8X\n", pEmr->fuOptions ); @@ -2138,14 +2356,17 @@ void U_EMRSMALLTEXTOUT_print(const char *contents){ printf(" eyScale: %f\n", pEmr->eyScale ); roff = sizeof(U_EMRSMALLTEXTOUT); //offset to the start of the variable fields if(!(pEmr->fuOptions & U_ETO_NO_RECT)){ + IF_MEM_UNSAFE_PRINT_AND_RETURN(contents, roff, blimit); printf(" rclBounds: "); rectl_print( *(PU_RECTL) (contents + roff)); printf("\n"); roff += sizeof(U_RECTL); } if(pEmr->fuOptions & U_ETO_SMALL_CHARS){ + IF_MEM_UNSAFE_PRINT_AND_RETURN(contents, roff + pEmr->cChars*sizeof(char), blimit); printf(" Text8: <%.*s>\n",pEmr->cChars,contents+roff); /* May not be null terminated */ } else { string = U_Utf16leToUtf8((uint16_t *)(contents+roff), pEmr->cChars, NULL); + IF_MEM_UNSAFE_PRINT_AND_RETURN(contents, roff + pEmr->cChars*2*sizeof(char), blimit); printf(" Text16: <%s>\n",contents+roff); free(string); } @@ -2199,12 +2420,18 @@ void U_EMRTRANSPARENTBLT_print(const char *contents){ void U_EMRGRADIENTFILL_print(const char *contents){ unsigned int i; PU_EMRGRADIENTFILL pEmr = (PU_EMRGRADIENTFILL)(contents); + if(pEmr->emr.nSize < sizeof(U_EMRGRADIENTFILL)){ + printf(" record corruption HERE\n"); + return; + } + const char *blimit = contents + pEmr->emr.nSize; printf(" rclBounds: "); rectl_print( pEmr->rclBounds); printf("\n"); printf(" nTriVert: %u\n", pEmr->nTriVert ); printf(" nGradObj: %u\n", pEmr->nGradObj ); printf(" ulMode: %u\n", pEmr->ulMode ); contents += sizeof(U_EMRGRADIENTFILL); if(pEmr->nTriVert){ + IF_MEM_UNSAFE_PRINT_AND_RETURN(contents, pEmr->nTriVert*sizeof(U_TRIVERTEX), blimit); printf(" TriVert: "); for(i=0; inTriVert; i++, contents+=sizeof(U_TRIVERTEX)){ trivertex_print(*(PU_TRIVERTEX)(contents)); @@ -2214,12 +2441,14 @@ void U_EMRGRADIENTFILL_print(const char *contents){ if(pEmr->nGradObj){ printf(" GradObj: "); if( pEmr->ulMode == U_GRADIENT_FILL_TRIANGLE){ + IF_MEM_UNSAFE_PRINT_AND_RETURN(contents, pEmr->nGradObj*sizeof(U_GRADIENT3), blimit); for(i=0; inGradObj; i++, contents+=sizeof(U_GRADIENT3)){ gradient3_print(*(PU_GRADIENT3)(contents)); } } else if(pEmr->ulMode == U_GRADIENT_FILL_RECT_H || pEmr->ulMode == U_GRADIENT_FILL_RECT_V){ + IF_MEM_UNSAFE_PRINT_AND_RETURN(contents, pEmr->nGradObj*sizeof(U_GRADIENT4), blimit); for(i=0; inGradObj; i++, contents+=sizeof(U_GRADIENT4)){ gradient4_print(*(PU_GRADIENT4)(contents)); } @@ -2244,12 +2473,18 @@ void U_EMRGRADIENTFILL_print(const char *contents){ void U_EMRCREATECOLORSPACEW_print(const char *contents){ unsigned int i; PU_EMRCREATECOLORSPACEW pEmr = (PU_EMRCREATECOLORSPACEW)(contents); + if(pEmr->emr.nSize < sizeof(U_EMRCREATECOLORSPACEW)){ + printf(" record corruption HERE\n"); + return; + } + const char *blimit = contents + pEmr->emr.nSize; printf(" ihCS: %u\n", pEmr->ihCS ); printf(" ColorSpace: "); logcolorspacew_print(pEmr->lcs); printf("\n"); printf(" dwFlags: 0x%8.8X\n", pEmr->dwFlags ); printf(" cbData: %u\n", pEmr->cbData ); printf(" Data(hexvalues):"); if(pEmr->dwFlags & 1){ + IF_MEM_UNSAFE_PRINT_AND_RETURN(contents, pEmr->cbData, blimit); for(i=0; icbData; i++){ printf("[%d]:%2.2X ",i,pEmr->Data[i]); } @@ -2267,145 +2502,154 @@ void U_EMRCREATECOLORSPACEW_print(const char *contents){ */ int U_emf_onerec_print(const char *contents, const char *blimit, int recnum, size_t off){ PU_ENHMETARECORD lpEMFR = (PU_ENHMETARECORD)(contents + off); - unsigned int size; - - printf("%-30srecord:%5d type:%-4d offset:%8d rsize:%8d\n",U_emr_names(lpEMFR->iType),recnum,lpEMFR->iType,(int) off,lpEMFR->nSize); - size = lpEMFR->nSize; - contents += off; + uint32_t nSize; + uint32_t iType; + const char *record = contents + off; - /* Check that the record size is OK, abort if not. - Pointer math might wrap, so check both sides of the range */ - if(size < sizeof(U_EMR) || - contents + size - 1 >= blimit || - contents + size - 1 < contents)return(-1); + if(record < contents)return(-1); // offset wrapped + /* Check that COMMON data in record can be touched without an access violation. If it cannot be + this is either a corrupt EMF or one engineered to cause a buffer overflow. Pointer math + could wrap so check both sides of the range. + */ + if(!U_emf_record_sizeok(record, blimit, &nSize, &iType, 1))return(-1); + + printf("%-30srecord:%5d type:%-4d offset:%8d rsize:%8d\n",U_emr_names(iType),recnum,iType,(int) off,nSize); + fflush(stdout); + + /* print the record header before checking further. + Note if this is a corrupt record, but continue anyway. + The _print routines will stop at the actual problem and print another corrupt message. + */ + if(!U_emf_record_safe(record)){printf("WARNING: Corrupt record. Emitting fields above the problem.\n");} + switch (lpEMFR->iType) { - case U_EMR_HEADER: U_EMRHEADER_print(contents); break; - case U_EMR_POLYBEZIER: U_EMRPOLYBEZIER_print(contents); break; - case U_EMR_POLYGON: U_EMRPOLYGON_print(contents); break; - case U_EMR_POLYLINE: U_EMRPOLYLINE_print(contents); break; - case U_EMR_POLYBEZIERTO: U_EMRPOLYBEZIERTO_print(contents); break; - case U_EMR_POLYLINETO: U_EMRPOLYLINETO_print(contents); break; - case U_EMR_POLYPOLYLINE: U_EMRPOLYPOLYLINE_print(contents); break; - case U_EMR_POLYPOLYGON: U_EMRPOLYPOLYGON_print(contents); break; - case U_EMR_SETWINDOWEXTEX: U_EMRSETWINDOWEXTEX_print(contents); break; - case U_EMR_SETWINDOWORGEX: U_EMRSETWINDOWORGEX_print(contents); break; - case U_EMR_SETVIEWPORTEXTEX: U_EMRSETVIEWPORTEXTEX_print(contents); break; - case U_EMR_SETVIEWPORTORGEX: U_EMRSETVIEWPORTORGEX_print(contents); break; - case U_EMR_SETBRUSHORGEX: U_EMRSETBRUSHORGEX_print(contents); break; - case U_EMR_EOF: U_EMREOF_print(contents); size=0; break; - case U_EMR_SETPIXELV: U_EMRSETPIXELV_print(contents); break; - case U_EMR_SETMAPPERFLAGS: U_EMRSETMAPPERFLAGS_print(contents); break; - case U_EMR_SETMAPMODE: U_EMRSETMAPMODE_print(contents); break; - case U_EMR_SETBKMODE: U_EMRSETBKMODE_print(contents); break; - case U_EMR_SETPOLYFILLMODE: U_EMRSETPOLYFILLMODE_print(contents); break; - case U_EMR_SETROP2: U_EMRSETROP2_print(contents); break; - case U_EMR_SETSTRETCHBLTMODE: U_EMRSETSTRETCHBLTMODE_print(contents); break; - case U_EMR_SETTEXTALIGN: U_EMRSETTEXTALIGN_print(contents); break; - case U_EMR_SETCOLORADJUSTMENT: U_EMRSETCOLORADJUSTMENT_print(contents); break; - case U_EMR_SETTEXTCOLOR: U_EMRSETTEXTCOLOR_print(contents); break; - case U_EMR_SETBKCOLOR: U_EMRSETBKCOLOR_print(contents); break; - case U_EMR_OFFSETCLIPRGN: U_EMROFFSETCLIPRGN_print(contents); break; - case U_EMR_MOVETOEX: U_EMRMOVETOEX_print(contents); break; - case U_EMR_SETMETARGN: U_EMRSETMETARGN_print(contents); break; - case U_EMR_EXCLUDECLIPRECT: U_EMREXCLUDECLIPRECT_print(contents); break; - case U_EMR_INTERSECTCLIPRECT: U_EMRINTERSECTCLIPRECT_print(contents); break; - case U_EMR_SCALEVIEWPORTEXTEX: U_EMRSCALEVIEWPORTEXTEX_print(contents); break; - case U_EMR_SCALEWINDOWEXTEX: U_EMRSCALEWINDOWEXTEX_print(contents); break; - case U_EMR_SAVEDC: U_EMRSAVEDC_print(contents); break; - case U_EMR_RESTOREDC: U_EMRRESTOREDC_print(contents); break; - case U_EMR_SETWORLDTRANSFORM: U_EMRSETWORLDTRANSFORM_print(contents); break; - case U_EMR_MODIFYWORLDTRANSFORM: U_EMRMODIFYWORLDTRANSFORM_print(contents); break; - case U_EMR_SELECTOBJECT: U_EMRSELECTOBJECT_print(contents); break; - case U_EMR_CREATEPEN: U_EMRCREATEPEN_print(contents); break; - case U_EMR_CREATEBRUSHINDIRECT: U_EMRCREATEBRUSHINDIRECT_print(contents); break; - case U_EMR_DELETEOBJECT: U_EMRDELETEOBJECT_print(contents); break; - case U_EMR_ANGLEARC: U_EMRANGLEARC_print(contents); break; - case U_EMR_ELLIPSE: U_EMRELLIPSE_print(contents); break; - case U_EMR_RECTANGLE: U_EMRRECTANGLE_print(contents); break; - case U_EMR_ROUNDRECT: U_EMRROUNDRECT_print(contents); break; - case U_EMR_ARC: U_EMRARC_print(contents); break; - case U_EMR_CHORD: U_EMRCHORD_print(contents); break; - case U_EMR_PIE: U_EMRPIE_print(contents); break; - case U_EMR_SELECTPALETTE: U_EMRSELECTPALETTE_print(contents); break; - case U_EMR_CREATEPALETTE: U_EMRCREATEPALETTE_print(contents); break; - case U_EMR_SETPALETTEENTRIES: U_EMRSETPALETTEENTRIES_print(contents); break; - case U_EMR_RESIZEPALETTE: U_EMRRESIZEPALETTE_print(contents); break; - case U_EMR_REALIZEPALETTE: U_EMRREALIZEPALETTE_print(contents); break; - case U_EMR_EXTFLOODFILL: U_EMREXTFLOODFILL_print(contents); break; - case U_EMR_LINETO: U_EMRLINETO_print(contents); break; - case U_EMR_ARCTO: U_EMRARCTO_print(contents); break; - case U_EMR_POLYDRAW: U_EMRPOLYDRAW_print(contents); break; - case U_EMR_SETARCDIRECTION: U_EMRSETARCDIRECTION_print(contents); break; - case U_EMR_SETMITERLIMIT: U_EMRSETMITERLIMIT_print(contents); break; - case U_EMR_BEGINPATH: U_EMRBEGINPATH_print(contents); break; - case U_EMR_ENDPATH: U_EMRENDPATH_print(contents); break; - case U_EMR_CLOSEFIGURE: U_EMRCLOSEFIGURE_print(contents); break; - case U_EMR_FILLPATH: U_EMRFILLPATH_print(contents); break; - case U_EMR_STROKEANDFILLPATH: U_EMRSTROKEANDFILLPATH_print(contents); break; - case U_EMR_STROKEPATH: U_EMRSTROKEPATH_print(contents); break; - case U_EMR_FLATTENPATH: U_EMRFLATTENPATH_print(contents); break; - case U_EMR_WIDENPATH: U_EMRWIDENPATH_print(contents); break; - case U_EMR_SELECTCLIPPATH: U_EMRSELECTCLIPPATH_print(contents); break; - case U_EMR_ABORTPATH: U_EMRABORTPATH_print(contents); break; - case U_EMR_UNDEF69: U_EMRUNDEF69_print(contents); break; - case U_EMR_COMMENT: U_EMRCOMMENT_print(contents, blimit, off); break; - case U_EMR_FILLRGN: U_EMRFILLRGN_print(contents); break; - case U_EMR_FRAMERGN: U_EMRFRAMERGN_print(contents); break; - case U_EMR_INVERTRGN: U_EMRINVERTRGN_print(contents); break; - case U_EMR_PAINTRGN: U_EMRPAINTRGN_print(contents); break; - case U_EMR_EXTSELECTCLIPRGN: U_EMREXTSELECTCLIPRGN_print(contents); break; - case U_EMR_BITBLT: U_EMRBITBLT_print(contents); break; - case U_EMR_STRETCHBLT: U_EMRSTRETCHBLT_print(contents); break; - case U_EMR_MASKBLT: U_EMRMASKBLT_print(contents); break; - case U_EMR_PLGBLT: U_EMRPLGBLT_print(contents); break; - case U_EMR_SETDIBITSTODEVICE: U_EMRSETDIBITSTODEVICE_print(contents); break; - case U_EMR_STRETCHDIBITS: U_EMRSTRETCHDIBITS_print(contents); break; - case U_EMR_EXTCREATEFONTINDIRECTW: U_EMREXTCREATEFONTINDIRECTW_print(contents); break; - case U_EMR_EXTTEXTOUTA: U_EMREXTTEXTOUTA_print(contents); break; - case U_EMR_EXTTEXTOUTW: U_EMREXTTEXTOUTW_print(contents); break; - case U_EMR_POLYBEZIER16: U_EMRPOLYBEZIER16_print(contents); break; - case U_EMR_POLYGON16: U_EMRPOLYGON16_print(contents); break; - case U_EMR_POLYLINE16: U_EMRPOLYLINE16_print(contents); break; - case U_EMR_POLYBEZIERTO16: U_EMRPOLYBEZIERTO16_print(contents); break; - case U_EMR_POLYLINETO16: U_EMRPOLYLINETO16_print(contents); break; - case U_EMR_POLYPOLYLINE16: U_EMRPOLYPOLYLINE16_print(contents); break; - case U_EMR_POLYPOLYGON16: U_EMRPOLYPOLYGON16_print(contents); break; - case U_EMR_POLYDRAW16: U_EMRPOLYDRAW16_print(contents); break; - case U_EMR_CREATEMONOBRUSH: U_EMRCREATEMONOBRUSH_print(contents); break; - case U_EMR_CREATEDIBPATTERNBRUSHPT: U_EMRCREATEDIBPATTERNBRUSHPT_print(contents); break; - case U_EMR_EXTCREATEPEN: U_EMREXTCREATEPEN_print(contents); break; - case U_EMR_POLYTEXTOUTA: U_EMRPOLYTEXTOUTA_print(contents); break; - case U_EMR_POLYTEXTOUTW: U_EMRPOLYTEXTOUTW_print(contents); break; - case U_EMR_SETICMMODE: U_EMRSETICMMODE_print(contents); break; - case U_EMR_CREATECOLORSPACE: U_EMRCREATECOLORSPACE_print(contents); break; - case U_EMR_SETCOLORSPACE: U_EMRSETCOLORSPACE_print(contents); break; - case U_EMR_DELETECOLORSPACE: U_EMRDELETECOLORSPACE_print(contents); break; - case U_EMR_GLSRECORD: U_EMRGLSRECORD_print(contents); break; - case U_EMR_GLSBOUNDEDRECORD: U_EMRGLSBOUNDEDRECORD_print(contents); break; - case U_EMR_PIXELFORMAT: U_EMRPIXELFORMAT_print(contents); break; - case U_EMR_DRAWESCAPE: U_EMRDRAWESCAPE_print(contents); break; - case U_EMR_EXTESCAPE: U_EMREXTESCAPE_print(contents); break; - case U_EMR_UNDEF107: U_EMRUNDEF107_print(contents); break; - case U_EMR_SMALLTEXTOUT: U_EMRSMALLTEXTOUT_print(contents); break; - case U_EMR_FORCEUFIMAPPING: U_EMRFORCEUFIMAPPING_print(contents); break; - case U_EMR_NAMEDESCAPE: U_EMRNAMEDESCAPE_print(contents); break; - case U_EMR_COLORCORRECTPALETTE: U_EMRCOLORCORRECTPALETTE_print(contents); break; - case U_EMR_SETICMPROFILEA: U_EMRSETICMPROFILEA_print(contents); break; - case U_EMR_SETICMPROFILEW: U_EMRSETICMPROFILEW_print(contents); break; - case U_EMR_ALPHABLEND: U_EMRALPHABLEND_print(contents); break; - case U_EMR_SETLAYOUT: U_EMRSETLAYOUT_print(contents); break; - case U_EMR_TRANSPARENTBLT: U_EMRTRANSPARENTBLT_print(contents); break; - case U_EMR_UNDEF117: U_EMRUNDEF117_print(contents); break; - case U_EMR_GRADIENTFILL: U_EMRGRADIENTFILL_print(contents); break; - case U_EMR_SETLINKEDUFIS: U_EMRSETLINKEDUFIS_print(contents); break; - case U_EMR_SETTEXTJUSTIFICATION: U_EMRSETTEXTJUSTIFICATION_print(contents); break; - case U_EMR_COLORMATCHTOTARGETW: U_EMRCOLORMATCHTOTARGETW_print(contents); break; - case U_EMR_CREATECOLORSPACEW: U_EMRCREATECOLORSPACEW_print(contents); break; - default: U_EMRNOTIMPLEMENTED_print("?",contents); break; + case U_EMR_HEADER: U_EMRHEADER_print(record); break; + case U_EMR_POLYBEZIER: U_EMRPOLYBEZIER_print(record); break; + case U_EMR_POLYGON: U_EMRPOLYGON_print(record); break; + case U_EMR_POLYLINE: U_EMRPOLYLINE_print(record); break; + case U_EMR_POLYBEZIERTO: U_EMRPOLYBEZIERTO_print(record); break; + case U_EMR_POLYLINETO: U_EMRPOLYLINETO_print(record); break; + case U_EMR_POLYPOLYLINE: U_EMRPOLYPOLYLINE_print(record); break; + case U_EMR_POLYPOLYGON: U_EMRPOLYPOLYGON_print(record); break; + case U_EMR_SETWINDOWEXTEX: U_EMRSETWINDOWEXTEX_print(record); break; + case U_EMR_SETWINDOWORGEX: U_EMRSETWINDOWORGEX_print(record); break; + case U_EMR_SETVIEWPORTEXTEX: U_EMRSETVIEWPORTEXTEX_print(record); break; + case U_EMR_SETVIEWPORTORGEX: U_EMRSETVIEWPORTORGEX_print(record); break; + case U_EMR_SETBRUSHORGEX: U_EMRSETBRUSHORGEX_print(record); break; + case U_EMR_EOF: U_EMREOF_print(record); nSize=0; break; + case U_EMR_SETPIXELV: U_EMRSETPIXELV_print(record); break; + case U_EMR_SETMAPPERFLAGS: U_EMRSETMAPPERFLAGS_print(record); break; + case U_EMR_SETMAPMODE: U_EMRSETMAPMODE_print(record); break; + case U_EMR_SETBKMODE: U_EMRSETBKMODE_print(record); break; + case U_EMR_SETPOLYFILLMODE: U_EMRSETPOLYFILLMODE_print(record); break; + case U_EMR_SETROP2: U_EMRSETROP2_print(record); break; + case U_EMR_SETSTRETCHBLTMODE: U_EMRSETSTRETCHBLTMODE_print(record); break; + case U_EMR_SETTEXTALIGN: U_EMRSETTEXTALIGN_print(record); break; + case U_EMR_SETCOLORADJUSTMENT: U_EMRSETCOLORADJUSTMENT_print(record); break; + case U_EMR_SETTEXTCOLOR: U_EMRSETTEXTCOLOR_print(record); break; + case U_EMR_SETBKCOLOR: U_EMRSETBKCOLOR_print(record); break; + case U_EMR_OFFSETCLIPRGN: U_EMROFFSETCLIPRGN_print(record); break; + case U_EMR_MOVETOEX: U_EMRMOVETOEX_print(record); break; + case U_EMR_SETMETARGN: U_EMRSETMETARGN_print(record); break; + case U_EMR_EXCLUDECLIPRECT: U_EMREXCLUDECLIPRECT_print(record); break; + case U_EMR_INTERSECTCLIPRECT: U_EMRINTERSECTCLIPRECT_print(record); break; + case U_EMR_SCALEVIEWPORTEXTEX: U_EMRSCALEVIEWPORTEXTEX_print(record); break; + case U_EMR_SCALEWINDOWEXTEX: U_EMRSCALEWINDOWEXTEX_print(record); break; + case U_EMR_SAVEDC: U_EMRSAVEDC_print(record); break; + case U_EMR_RESTOREDC: U_EMRRESTOREDC_print(record); break; + case U_EMR_SETWORLDTRANSFORM: U_EMRSETWORLDTRANSFORM_print(record); break; + case U_EMR_MODIFYWORLDTRANSFORM: U_EMRMODIFYWORLDTRANSFORM_print(record); break; + case U_EMR_SELECTOBJECT: U_EMRSELECTOBJECT_print(record); break; + case U_EMR_CREATEPEN: U_EMRCREATEPEN_print(record); break; + case U_EMR_CREATEBRUSHINDIRECT: U_EMRCREATEBRUSHINDIRECT_print(record); break; + case U_EMR_DELETEOBJECT: U_EMRDELETEOBJECT_print(record); break; + case U_EMR_ANGLEARC: U_EMRANGLEARC_print(record); break; + case U_EMR_ELLIPSE: U_EMRELLIPSE_print(record); break; + case U_EMR_RECTANGLE: U_EMRRECTANGLE_print(record); break; + case U_EMR_ROUNDRECT: U_EMRROUNDRECT_print(record); break; + case U_EMR_ARC: U_EMRARC_print(record); break; + case U_EMR_CHORD: U_EMRCHORD_print(record); break; + case U_EMR_PIE: U_EMRPIE_print(record); break; + case U_EMR_SELECTPALETTE: U_EMRSELECTPALETTE_print(record); break; + case U_EMR_CREATEPALETTE: U_EMRCREATEPALETTE_print(record); break; + case U_EMR_SETPALETTEENTRIES: U_EMRSETPALETTEENTRIES_print(record); break; + case U_EMR_RESIZEPALETTE: U_EMRRESIZEPALETTE_print(record); break; + case U_EMR_REALIZEPALETTE: U_EMRREALIZEPALETTE_print(record); break; + case U_EMR_EXTFLOODFILL: U_EMREXTFLOODFILL_print(record); break; + case U_EMR_LINETO: U_EMRLINETO_print(record); break; + case U_EMR_ARCTO: U_EMRARCTO_print(record); break; + case U_EMR_POLYDRAW: U_EMRPOLYDRAW_print(record); break; + case U_EMR_SETARCDIRECTION: U_EMRSETARCDIRECTION_print(record); break; + case U_EMR_SETMITERLIMIT: U_EMRSETMITERLIMIT_print(record); break; + case U_EMR_BEGINPATH: U_EMRBEGINPATH_print(record); break; + case U_EMR_ENDPATH: U_EMRENDPATH_print(record); break; + case U_EMR_CLOSEFIGURE: U_EMRCLOSEFIGURE_print(record); break; + case U_EMR_FILLPATH: U_EMRFILLPATH_print(record); break; + case U_EMR_STROKEANDFILLPATH: U_EMRSTROKEANDFILLPATH_print(record); break; + case U_EMR_STROKEPATH: U_EMRSTROKEPATH_print(record); break; + case U_EMR_FLATTENPATH: U_EMRFLATTENPATH_print(record); break; + case U_EMR_WIDENPATH: U_EMRWIDENPATH_print(record); break; + case U_EMR_SELECTCLIPPATH: U_EMRSELECTCLIPPATH_print(record); break; + case U_EMR_ABORTPATH: U_EMRABORTPATH_print(record); break; + case U_EMR_UNDEF69: U_EMRUNDEF69_print(record); break; + case U_EMR_COMMENT: U_EMRCOMMENT_print(record, off); break; + case U_EMR_FILLRGN: U_EMRFILLRGN_print(record); break; + case U_EMR_FRAMERGN: U_EMRFRAMERGN_print(record); break; + case U_EMR_INVERTRGN: U_EMRINVERTRGN_print(record); break; + case U_EMR_PAINTRGN: U_EMRPAINTRGN_print(record); break; + case U_EMR_EXTSELECTCLIPRGN: U_EMREXTSELECTCLIPRGN_print(record); break; + case U_EMR_BITBLT: U_EMRBITBLT_print(record); break; + case U_EMR_STRETCHBLT: U_EMRSTRETCHBLT_print(record); break; + case U_EMR_MASKBLT: U_EMRMASKBLT_print(record); break; + case U_EMR_PLGBLT: U_EMRPLGBLT_print(record); break; + case U_EMR_SETDIBITSTODEVICE: U_EMRSETDIBITSTODEVICE_print(record); break; + case U_EMR_STRETCHDIBITS: U_EMRSTRETCHDIBITS_print(record); break; + case U_EMR_EXTCREATEFONTINDIRECTW: U_EMREXTCREATEFONTINDIRECTW_print(record); break; + case U_EMR_EXTTEXTOUTA: U_EMREXTTEXTOUTA_print(record); break; + case U_EMR_EXTTEXTOUTW: U_EMREXTTEXTOUTW_print(record); break; + case U_EMR_POLYBEZIER16: U_EMRPOLYBEZIER16_print(record); break; + case U_EMR_POLYGON16: U_EMRPOLYGON16_print(record); break; + case U_EMR_POLYLINE16: U_EMRPOLYLINE16_print(record); break; + case U_EMR_POLYBEZIERTO16: U_EMRPOLYBEZIERTO16_print(record); break; + case U_EMR_POLYLINETO16: U_EMRPOLYLINETO16_print(record); break; + case U_EMR_POLYPOLYLINE16: U_EMRPOLYPOLYLINE16_print(record); break; + case U_EMR_POLYPOLYGON16: U_EMRPOLYPOLYGON16_print(record); break; + case U_EMR_POLYDRAW16: U_EMRPOLYDRAW16_print(record); break; + case U_EMR_CREATEMONOBRUSH: U_EMRCREATEMONOBRUSH_print(record); break; + case U_EMR_CREATEDIBPATTERNBRUSHPT: U_EMRCREATEDIBPATTERNBRUSHPT_print(record); break; + case U_EMR_EXTCREATEPEN: U_EMREXTCREATEPEN_print(record); break; + case U_EMR_POLYTEXTOUTA: U_EMRPOLYTEXTOUTA_print(record); break; + case U_EMR_POLYTEXTOUTW: U_EMRPOLYTEXTOUTW_print(record); break; + case U_EMR_SETICMMODE: U_EMRSETICMMODE_print(record); break; + case U_EMR_CREATECOLORSPACE: U_EMRCREATECOLORSPACE_print(record); break; + case U_EMR_SETCOLORSPACE: U_EMRSETCOLORSPACE_print(record); break; + case U_EMR_DELETECOLORSPACE: U_EMRDELETECOLORSPACE_print(record); break; + case U_EMR_GLSRECORD: U_EMRGLSRECORD_print(record); break; + case U_EMR_GLSBOUNDEDRECORD: U_EMRGLSBOUNDEDRECORD_print(record); break; + case U_EMR_PIXELFORMAT: U_EMRPIXELFORMAT_print(record); break; + case U_EMR_DRAWESCAPE: U_EMRDRAWESCAPE_print(record); break; + case U_EMR_EXTESCAPE: U_EMREXTESCAPE_print(record); break; + case U_EMR_UNDEF107: U_EMRUNDEF107_print(record); break; + case U_EMR_SMALLTEXTOUT: U_EMRSMALLTEXTOUT_print(record); break; + case U_EMR_FORCEUFIMAPPING: U_EMRFORCEUFIMAPPING_print(record); break; + case U_EMR_NAMEDESCAPE: U_EMRNAMEDESCAPE_print(record); break; + case U_EMR_COLORCORRECTPALETTE: U_EMRCOLORCORRECTPALETTE_print(record); break; + case U_EMR_SETICMPROFILEA: U_EMRSETICMPROFILEA_print(record); break; + case U_EMR_SETICMPROFILEW: U_EMRSETICMPROFILEW_print(record); break; + case U_EMR_ALPHABLEND: U_EMRALPHABLEND_print(record); break; + case U_EMR_SETLAYOUT: U_EMRSETLAYOUT_print(record); break; + case U_EMR_TRANSPARENTBLT: U_EMRTRANSPARENTBLT_print(record); break; + case U_EMR_UNDEF117: U_EMRUNDEF117_print(record); break; + case U_EMR_GRADIENTFILL: U_EMRGRADIENTFILL_print(record); break; + case U_EMR_SETLINKEDUFIS: U_EMRSETLINKEDUFIS_print(record); break; + case U_EMR_SETTEXTJUSTIFICATION: U_EMRSETTEXTJUSTIFICATION_print(record); break; + case U_EMR_COLORMATCHTOTARGETW: U_EMRCOLORMATCHTOTARGETW_print(record); break; + case U_EMR_CREATECOLORSPACEW: U_EMRCREATECOLORSPACEW_print(record); break; + default: U_EMRNOTIMPLEMENTED_print("?",record); break; } //end of switch - return(size); + return(nSize); } diff --git a/src/libuemf/uemf_print.h b/src/libuemf/uemf_print.h index 896de659e..6568b4cfa 100644 --- a/src/libuemf/uemf_print.h +++ b/src/libuemf/uemf_print.h @@ -6,11 +6,11 @@ /* File: uemf_print.h -Version: 0.0.5 -Date: 14-FEB-2013 +Version: 0.0.7 +Date: 24-MAR-2015 Author: David Mathog, Biology Division, Caltech email: mathog@caltech.edu -Copyright: 2013 David Mathog and California Institute of Technology (Caltech) +Copyright: 2015 David Mathog and California Institute of Technology (Caltech) */ #ifndef _UEMF_PRINT_ @@ -44,17 +44,17 @@ void panose_print(U_PANOSE panose); void logfont_print(U_LOGFONT lf); void logfont_panose_print(U_LOGFONT_PANOSE lfp); void bitmapinfoheader_print(const char *Bmih); -void bitmapinfo_print(const char *Bmi); +void bitmapinfo_print(const char *Bmi, const char *blimit); void blend_print(U_BLEND blend); void extlogpen_print(const PU_EXTLOGPEN elp); void logpen_print(U_LOGPEN lp); void logpltntry_print(U_LOGPLTNTRY lpny); void logpalette_print(const PU_LOGPALETTE lp); void rgndataheader_print(U_RGNDATAHEADER rdh); -void rgndata_print(const PU_RGNDATA rd); +void rgndata_print(const PU_RGNDATA rd, const char *blimit); void coloradjustment_print(U_COLORADJUSTMENT ca); void pixelformatdescriptor_print(U_PIXELFORMATDESCRIPTOR pfd); -void emrtext_print(const char *emt, const char *record, int type); +void emrtext_print(const char *emt, const char *record, const char *blimit, int type); /* prototypes for EMR records */ void U_EMRNOTIMPLEMENTED_print(const char *name, const char *contents, int recnum, int off); @@ -126,7 +126,7 @@ void U_EMRFLATTENPATH_print(const char *contents); void U_EMRWIDENPATH_print(const char *contents); void U_EMRSELECTCLIPPATH_print(const char *contents); void U_EMRABORTPATH_print(const char *contents); -void U_EMRCOMMENT_print(const char *contents, const char *blimit, size_t off); +void U_EMRCOMMENT_print(const char *contents, size_t off); void U_EMRFILLRGN_print(const char *contents); void U_EMRFRAMERGN_print(const char *contents); void U_EMRINVERTRGN_print(const char *contents); diff --git a/src/libuemf/upmf.c b/src/libuemf/upmf.c index 01f7ba3a4..7d6349185 100644 --- a/src/libuemf/upmf.c +++ b/src/libuemf/upmf.c @@ -21,11 +21,11 @@ /* File: upmf.c -Version: 0.0.6 -Date: 26-MAR-2014 +Version: 0.0.9 +Date: 25-MAR-2015 Author: David Mathog, Biology Division, Caltech email: mathog@caltech.edu -Copyright: 2014 David Mathog and California Institute of Technology (Caltech) +Copyright: 2015 David Mathog and California Institute of Technology (Caltech) */ #ifdef __cplusplus @@ -1459,11 +1459,18 @@ int U_PMF_PTRSAV_COND(const char **Dst, const char *Src, int Doit){ else { *Dst = NULL; } return(1); } +/* + + ===================================================================================== + start of U_PMF_*_get() functions + +*/ /** \brief Get the 16 bit unsigned Flags field from a header. \param contents Record from which to extract data, will be incremented by header size. \return Flags field + In many records the only value needed from the header is Flags. Rather than mapping the entire Header and returning it, in these instances this function may be called to just get this one value. @@ -1515,6 +1522,19 @@ int U_PMF_CMN_HDR_get(const char **contents, U_PMF_CMN_HDR *Header){ return(1); } +/** + \brief return the size in bytes of the EMF+ record + \param contents Record from which to extract data, will not be modified. + \returns size, or 0 if contents is Null +*/ +int U_PMF_RECORD_SIZE_get(const char *contents){ + if(!contents){ return(0); } + int Size; + const char *from = contents + 4; + U_PMF_SERIAL_get(&from, &Size, 4, 1, U_LE); + return(Size); +} + /** \brief Return the size of a PenData object from an EMF+ record. \param PenData Address in memory where the PenData object starts. @@ -5362,6 +5382,17 @@ U_PSEUDO_OBJ *U_PMR_TRANSLATEWORLDTRANSFORM_set(int xmtype, U_FLOAT Dx, U_FLOAT return(po); } +/* + + end of U_PMF_*_set() functions + ===================================================================================== + start of U_PMF_*_get() functions + + These functions all take a blimit value so that they can check if the data description in the fields + they process extend beyond the end of the record. + +*/ + //! \cond /* core _get functions, not accessed outside of this routine */ @@ -5387,11 +5418,15 @@ int U_PMF_CORE1_get(const char *contents, void *v1, void *v2, void *v3, void *v4 \param Version EmfPlusGraphicsVersion object \param Type BrushType Enumeration \param Data one of the 5 types of Brush data + \param blimit one byte past the end of data EMF+ manual 2.2.1.1, Microsoft name: EmfPlusBrush Object + + Caller must check Data for possible memory access violations. */ -int U_PMF_BRUSH_get(const char *contents, uint32_t *Version, uint32_t *Type, const char **Data){ - if(!contents || !Version || !Type || !Data){ return(0); } +int U_PMF_BRUSH_get(const char *contents, uint32_t *Version, uint32_t *Type, const char **Data, const char *blimit){ + if(!contents || !Version || !Type || !Data || !blimit){ return(0); } + if(IS_MEM_UNSAFE(contents,sizeof(U_PMF_BRUSH), blimit))return(0); U_PMF_SERIAL_get(&contents, Version, 4, 1, U_LE); U_PMF_SERIAL_get(&contents, Type, 4, 1, U_LE); U_PMF_PTRSAV_SHIFT(Data, &contents, 0); @@ -5405,11 +5440,15 @@ int U_PMF_BRUSH_get(const char *contents, uint32_t *Version, uint32_t *Type, con \param Version EmfPlusGraphicsVersion object \param Type CustomLineCapData Enumeration \param Data one of the 2 types of Linecap data + \param blimit one byte past the end of data EMF+ manual 2.2.1.2, Microsoft name: EmfPlusCustomLineCap Object + + Caller must check Data for possible memory access violations. */ -int U_PMF_CUSTOMLINECAP_get(const char *contents, uint32_t *Version, uint32_t *Type, const char **Data){ - if(!contents || !Version || !Type || !Data){ return(0); } +int U_PMF_CUSTOMLINECAP_get(const char *contents, uint32_t *Version, uint32_t *Type, const char **Data, const char *blimit){ + if(!contents || !Version || !Type || !Data || !blimit){ return(0); } + if(IS_MEM_UNSAFE(contents, sizeof(U_PMF_CUSTOMLINECAP), blimit))return(0); U_PMF_SERIAL_get(&contents, Version, 4, 1, U_LE); U_PMF_SERIAL_get(&contents, Type, 4, 1, U_LE); U_PMF_PTRSAV_SHIFT(Data, &contents, 0); @@ -5428,10 +5467,13 @@ int U_PMF_CUSTOMLINECAP_get(const char *contents, uint32_t *Version, uint32_t *T \param Data Unicode (UTF-16LE) name of font family EMF+ manual 2.2.1.3, Microsoft name: EmfPlusFont Object + + Caller must check Data for possible memory access violations. */ int U_PMF_FONT_get(const char *contents, uint32_t *Version, U_FLOAT *EmSize, uint32_t *SizeUnit, - int32_t *FSFlags, uint32_t *Length, const char **Data){ - if(!contents || !Version || !EmSize || !SizeUnit || !FSFlags || !Length || !Data){ return(0); } + int32_t *FSFlags, uint32_t *Length, const char **Data, const char *blimit){ + if(!contents || !Version || !EmSize || !SizeUnit || !FSFlags || !Length || !Data || !blimit){ return(0); } + if(IS_MEM_UNSAFE(contents, sizeof(U_PMF_FONT), blimit))return(0); U_PMF_SERIAL_get(&contents, Version, 4, 1, U_LE); U_PMF_SERIAL_get(&contents, EmSize, 4, 1, U_LE); U_PMF_SERIAL_get(&contents, SizeUnit, 4, 1, U_LE); @@ -5452,9 +5494,12 @@ int U_PMF_FONT_get(const char *contents, uint32_t *Version, U_FLOAT *EmSize, uin \param Data one of the 2 types of image data EMF+ manual 2.2.1.4, Microsoft name: EmfPlusImage Object + + Caller must check Data for possible memory access violations. */ -int U_PMF_IMAGE_get(const char *contents, uint32_t *Version, uint32_t *Type, const char **Data){ - if(!contents || !Version || !Type){ return(0); } +int U_PMF_IMAGE_get(const char *contents, uint32_t *Version, uint32_t *Type, const char **Data, const char *blimit){ + if(!contents || !Version || !Type || !blimit){ return(0); } + if(IS_MEM_UNSAFE(contents, sizeof(U_PMF_IMAGE), blimit))return(0); U_PMF_SERIAL_get(&contents, Version, 4, 1, U_LE); U_PMF_SERIAL_get(&contents, Type, 4, 1, U_LE); U_PMF_PTRSAV_SHIFT(Data, &contents, 0); @@ -5472,8 +5517,10 @@ int U_PMF_IMAGE_get(const char *contents, uint32_t *Version, uint32_t *Type, con EMF+ manual 2.2.1.5, Microsoft name: EmfPlusImageAttributes Object */ -int U_PMF_IMAGEATTRIBUTES_get(const char *contents, uint32_t *Version, uint32_t *WrapMode, uint32_t *ClampColor, uint32_t *ObjectClamp){ - if(!contents || !Version || !WrapMode || !ClampColor || !ObjectClamp){ return(0); } +int U_PMF_IMAGEATTRIBUTES_get(const char *contents, uint32_t *Version, uint32_t *WrapMode, uint32_t *ClampColor, + uint32_t *ObjectClamp, const char *blimit){ + if(!contents || !Version || !WrapMode || !ClampColor || !ObjectClamp || !blimit){ return(0); } + if(IS_MEM_UNSAFE(contents, sizeof(U_PMF_IMAGEATTRIBUTES), blimit))return(0); U_PMF_SERIAL_get(&contents, Version, 4, 1, U_LE); contents += 4; /* Skip Reserved 1*/ U_PMF_SERIAL_get(&contents, WrapMode, 4, 1, U_LE); @@ -5494,21 +5541,31 @@ int U_PMF_IMAGEATTRIBUTES_get(const char *contents, uint32_t *Version, uint32_t \param Types array of U_PMF_PATHPOINTTYPERLE and/or U_PMF_PATHPOINTTYPE EMF+ manual 2.2.1.6, Microsoft name: EmfPlusPath Object + + Caller must check Types for possible memory access violations if type can be U_PMF_PATHPOINTTYPERLE. */ -int U_PMF_PATH_get(const char *contents, uint32_t *Version, uint32_t *Count, uint16_t *Flags, const char **Points, const char **Types){ - if(!contents || !Version || !Count || !Flags || !Points || !Types){ return(0); } +int U_PMF_PATH_get(const char *contents, uint32_t *Version, uint32_t *Count, uint16_t *Flags, + const char **Points, const char **Types, const char *blimit){ + if(!contents || !Version || !Count || !Flags || !Points || !Types || !blimit){ return(0); } + if(IS_MEM_UNSAFE(contents, sizeof(U_PMF_PATH), blimit))return(0); U_PMF_SERIAL_get(&contents, Version, 4, 1, U_LE); U_PMF_SERIAL_get(&contents, Count, 4, 1, U_LE); U_PMF_SERIAL_get(&contents, Flags, 2, 1, U_LE); contents+=2; /* reserved */ - U_PMF_PTRSAV_SHIFT(Points, &contents, 0); + uint32_t sizeP, sizeT; if(*Flags & U_PPF_P){ - int killme = U_PMF_LEN_REL715(contents,*Count); //DEBUG - printf("DEBUG U_PMF_PATH_get count:%d LENREL715:%d\n",*Count,killme);fflush(stdout); - contents += killme; + sizeP = U_PMF_LEN_REL715(contents,*Count); //DEBUG + printf("DEBUG U_PMF_PATH_get count:%d LENREL715:%d\n",*Count,sizeP);fflush(stdout); } - else if(*Flags & U_PPF_C){ contents += *Count * sizeof(U_PMF_POINT); } - else { contents += *Count * sizeof(U_PMF_POINTF); } + else if(*Flags & U_PPF_C){ sizeP = *Count * sizeof(U_PMF_POINT); } + else { sizeP = *Count * sizeof(U_PMF_POINTF); } + if(IS_MEM_UNSAFE(contents, sizeP, blimit))return(0); + U_PMF_PTRSAV_SHIFT(Points, &contents, 0); + contents += sizeP; + /* this limit is correct if there are only U_PMF_PATHPOINTTYPE PointTypes, it is a lower bound if + there can also be U_PMF_PATHPOINTTYPERLE */ + sizeT = *Count * sizeof(U_PMF_PATHPOINTTYPE); + if(IS_MEM_UNSAFE(contents, sizeT, blimit))return(0); U_PMF_PTRSAV_SHIFT(Types, &contents, 0); return(1); } @@ -5523,9 +5580,12 @@ int U_PMF_PATH_get(const char *contents, uint32_t *Version, uint32_t *Count, uin \param Brush Brush Description EMF+ manual 2.2.1.7, Microsoft name: EmfPlusPen Object + + Caller must check Brush and PenData for possible memory access violations. */ -int U_PMF_PEN_get(const char *contents, uint32_t *Version, uint32_t *Type, const char **PenData, const char **Brush){ - if(!contents || !Type || !PenData || !Brush){ return(0); } +int U_PMF_PEN_get(const char *contents, uint32_t *Version, uint32_t *Type, const char **PenData, const char **Brush, const char *blimit){ + if(!contents || !Type || !PenData || !Brush || !blimit){ return(0); } + if(IS_MEM_UNSAFE(contents, sizeof(U_PMF_PEN), blimit))return(0); U_PMF_SERIAL_get(&contents, Version, 4, 1, U_LE); U_PMF_SERIAL_get(&contents, Type, 4, 1, U_LE); U_PMF_PTRSAV_SHIFT(PenData, &contents, 0); @@ -5543,8 +5603,9 @@ int U_PMF_PEN_get(const char *contents, uint32_t *Version, uint32_t *Type, const EMF+ manual 2.2.1.8, Microsoft name: EmfPlusRegion Object */ -int U_PMF_REGION_get(const char *contents, uint32_t *Version, uint32_t *Count, const char **Nodes){ - if(!contents || !Version || !Count || !Nodes){ return(0); } +int U_PMF_REGION_get(const char *contents, uint32_t *Version, uint32_t *Count, const char **Nodes, const char *blimit){ + if(!contents || !Version || !Count || !Nodes || !blimit){ return(0); } + if(IS_MEM_UNSAFE(contents, sizeof(U_PMF_REGION), blimit))return(0); U_PMF_SERIAL_get(&contents, Version, 4, 1, U_LE); U_PMF_SERIAL_get(&contents, Count, 4, 1, U_LE); U_PMF_PTRSAV_SHIFT(Nodes, &contents, 0); @@ -5560,8 +5621,9 @@ int U_PMF_REGION_get(const char *contents, uint32_t *Version, uint32_t *Count, c EMF+ manual 2.2.1.9, Microsoft name: EmfPlusStringFormat Object */ -int U_PMF_STRINGFORMAT_get(const char *contents, U_PMF_STRINGFORMAT *Sfs, const char **Data){ - if(!contents || !Sfs || !Data){ return(0); } +int U_PMF_STRINGFORMAT_get(const char *contents, U_PMF_STRINGFORMAT *Sfs, const char **Data, const char *blimit){ + if(!contents || !Sfs || !Data || !blimit){ return(0); } + if(IS_MEM_UNSAFE(contents, sizeof(U_PMF_STRINGFORMAT), blimit))return(0); U_PMF_SERIAL_get(&contents, Sfs, 4, 15, U_LE); *Data = contents; return(1); @@ -5578,8 +5640,9 @@ int U_PMF_STRINGFORMAT_get(const char *contents, U_PMF_STRINGFORMAT *Sfs, const EMF+ manual 2.2.2.1, Microsoft name: EmfPlusARGB Object */ -int U_PMF_ARGB_get(const char *contents, uint8_t *Blue, uint8_t *Green, uint8_t *Red, uint8_t *Alpha){ - if(!contents || !Blue || !Green || !Red || !Alpha){ return(0); } +int U_PMF_ARGB_get(const char *contents, uint8_t *Blue, uint8_t *Green, uint8_t *Red, uint8_t *Alpha, const char *blimit){ + if(!contents || !Blue || !Green || !Red || !Alpha || !blimit){ return(0); } + if(IS_MEM_UNSAFE(contents, sizeof(U_PMF_ARGB), blimit))return(0); U_PMF_SERIAL_get(&contents, Blue, 1, 1, U_XE); U_PMF_SERIAL_get(&contents, Green, 1, 1, U_XE); U_PMF_SERIAL_get(&contents, Red, 1, 1, U_XE); @@ -5595,11 +5658,14 @@ int U_PMF_ARGB_get(const char *contents, uint8_t *Blue, uint8_t *Green, uint8_t \param Data pointer to variable part EMF+ manual 2.2.2.2, Microsoft name: EmfPlusBitmap Object + + Caller must check Data for possible memory access violations. */ -int U_PMF_BITMAP_get(const char *contents, U_PMF_BITMAP *Bs, const char **Data){ - if(!contents || !Bs || !Data){ return(0); } - U_PMF_SERIAL_get(&contents, Bs, 4, 5, U_LE); - U_PMF_PTRSAV_SHIFT(Data, &contents, 0); +int U_PMF_BITMAP_get(const char *contents, U_PMF_BITMAP *Bs, const char **Data, const char *blimit){ + if(!contents || !Bs || !Data || !blimit){ return(0); } + if(IS_MEM_UNSAFE(contents, sizeof(U_PMF_BITMAP), blimit))return(0); + U_PMF_SERIAL_get(&contents, Bs, 4, 5, U_LE); // width, height, stride, pixelformat, type + U_PMF_PTRSAV_SHIFT(Data, &contents, 0); // bitmapdata return(1); } @@ -5612,11 +5678,16 @@ int U_PMF_BITMAP_get(const char *contents, U_PMF_BITMAP *Bs, const char **Data){ \param Data An array of bytes, meaning depends on fields in U_PMF_BITMAP object and the PixelFormat enumeration. EMF+ manual 2.2.2.3, Microsoft name: EmfPlusBitmapData Object + + Caller must check Data for possible memory access violations. */ -int U_PMF_BITMAPDATA_get(const char *contents, U_PMF_PALETTE *Ps, const char **Colors, const char **Data){ - if(!contents || !Ps || !Colors || !Data ){ return(0); } +int U_PMF_BITMAPDATA_get(const char *contents, U_PMF_PALETTE *Ps, const char **Colors, const char **Data, const char *blimit){ + if(!contents || !Ps || !Colors || !Data || !blimit){ return(0); } + /* this structure is entirely optional */ + if(IS_MEM_UNSAFE(contents, 4*2, blimit))return(0); U_PMF_SERIAL_get(&contents, Ps, 4, 2, U_LE); U_PMF_PTRSAV_SHIFT(Colors, &contents, Ps->Elements * sizeof(U_PMF_ARGB)); + /* difficult to know how big the actual bitmap will be, just return the pointer to it untested */ U_PMF_PTRSAV_SHIFT(Data, &contents, 0); return(1); } @@ -5627,13 +5698,15 @@ int U_PMF_BITMAPDATA_get(const char *contents, U_PMF_PALETTE *Ps, const char **C \param contents Record from which to extract data \param Elements Number of members in Positions and Colors \param Positions Caller must free. Pointer to memory holding positions along gradient line. - \param Colors Caller must NOT free memory ,Pointer to memory holding colors at positions on gradient line. + \param Colors Caller must NOT free memory, Pointer to memory holding colors at positions on gradient line. EMF+ manual 2.2.2.4, Microsoft name: EmfPlusBlendColors Object */ -int U_PMF_BLENDCOLORS_get(const char *contents, uint32_t *Elements, U_FLOAT **Positions, const char **Colors){ - if(!contents || !Positions || !Colors){ return(0); } +int U_PMF_BLENDCOLORS_get(const char *contents, uint32_t *Elements, U_FLOAT **Positions, const char **Colors, const char *blimit){ + if(!contents || !Positions || !Colors || !blimit){ return(0); } + if(IS_MEM_UNSAFE(contents, sizeof(U_PMF_BLENDCOLORS), blimit))return(0); U_PMF_SERIAL_get(&contents, Elements, 4, 1, U_LE); + if(IS_MEM_UNSAFE(contents, *Elements * 4, blimit))return(0); if(!U_PMF_SERIAL_array_copy_get(&contents, (void **)Positions, 4, *Elements, U_LE,1)){ return(0); } U_PMF_PTRSAV_SHIFT(Colors, &contents, 0); return(1); @@ -5649,9 +5722,11 @@ int U_PMF_BLENDCOLORS_get(const char *contents, uint32_t *Elements, U_FLOAT **Po EMF+ manual 2.2.2.5, Microsoft name: EmfPlusBlendFactors Object */ -int U_PMF_BLENDFACTORS_get(const char *contents, uint32_t *Elements, U_FLOAT **Positions, U_FLOAT **Factors){ - if(!contents || !Elements || !Positions || !Factors){ return(0); } +int U_PMF_BLENDFACTORS_get(const char *contents, uint32_t *Elements, U_FLOAT **Positions, U_FLOAT **Factors, const char *blimit){ + if(!contents || !Elements || !Positions || !Factors || !blimit){ return(0); } + if(IS_MEM_UNSAFE(contents, sizeof(U_PMF_BLENDFACTORS), blimit))return(0); U_PMF_SERIAL_get(&contents, Elements, 4, 1, U_LE); + if(IS_MEM_UNSAFE(contents, *Elements * 4 * 2, blimit))return(0); if(!U_PMF_SERIAL_array_copy_get(&contents, (void **)Positions, 4, *Elements, U_LE, 1)){ return(0); } if(!U_PMF_SERIAL_array_copy_get(&contents, (void **)Factors, 4, *Elements, U_LE, 1)){ free(*Positions); @@ -5668,9 +5743,12 @@ int U_PMF_BLENDFACTORS_get(const char *contents, uint32_t *Elements, U_FLOAT **P \param Data boundary of the brush EMF+ manual 2.2.2.6, Microsoft name: EmfPlusBoundaryPathData Object + + Caller must check Data for possible memory access violations. */ -int U_PMF_BOUNDARYPATHDATA_get(const char *contents, int32_t *Size, const char **Data){ - if(!contents || !Size || !Data){ return(0); } +int U_PMF_BOUNDARYPATHDATA_get(const char *contents, int32_t *Size, const char **Data, const char *blimit){ + if(!contents || !Size || !Data || !blimit){ return(0); } + if(IS_MEM_UNSAFE(contents, sizeof(U_PMF_BOUNDARYPATHDATA), blimit))return(0); U_PMF_SERIAL_get(&contents, Size, 4, 1, U_LE); U_PMF_PTRSAV_SHIFT(Data, &contents, 0); return(1); @@ -5680,14 +5758,16 @@ int U_PMF_BOUNDARYPATHDATA_get(const char *contents, int32_t *Size, const char * \brief Get data from a U_PMF_BOUNDARYPOINTDATA object \return 1 on success, 0 on error \param contents Record from which to extract data - \param Elements Members in POints + \param Elements Members in Points \param Points Caller must free. Pointer to memory holding points along gradient line. Boundary of the brush. EMF+ manual 2.2.2.7, Microsoft name: EmfPlusBoundaryPointData Object */ -int U_PMF_BOUNDARYPOINTDATA_get(const char *contents, int32_t *Elements, U_PMF_POINTF **Points){ - if(!contents || !Elements || !Points){ return(0); } +int U_PMF_BOUNDARYPOINTDATA_get(const char *contents, int32_t *Elements, U_PMF_POINTF **Points, const char *blimit){ + if(!contents || !Elements || !Points || !blimit){ return(0); } + if(IS_MEM_UNSAFE(contents, sizeof(U_PMF_BOUNDARYPOINTDATA), blimit))return(0); U_PMF_SERIAL_get(&contents, Elements, 4, 1, U_LE); + if(IS_MEM_UNSAFE(contents, *Elements * 2, blimit))return(0); if(!U_PMF_SERIAL_array_copy_get(&contents, (void **)Points, 4, *Elements * 2, U_LE, 1)){ return(0); } return(1); } @@ -5701,8 +5781,9 @@ int U_PMF_BOUNDARYPOINTDATA_get(const char *contents, int32_t *Elements, U_PMF_P EMF+ manual 2.2.2.8, Microsoft name: EmfPlusCharacterRange Object */ -int U_PMF_CHARACTERRANGE_get(const char *contents, int32_t *First, int32_t *Length){ - if(!contents || !First || !Length){ return(0); } +int U_PMF_CHARACTERRANGE_get(const char *contents, int32_t *First, int32_t *Length, const char *blimit){ + if(!contents || !First || !Length || !blimit){ return(0); } + if(IS_MEM_UNSAFE(contents, sizeof(U_PMF_CHARACTERRANGE), blimit))return(0); U_PMF_SERIAL_get(&contents, First, 4, 1, U_LE); U_PMF_SERIAL_get(&contents, Length, 4, 1, U_LE); return(1); @@ -5717,9 +5798,11 @@ int U_PMF_CHARACTERRANGE_get(const char *contents, int32_t *First, int32_t *Leng EMF+ manual 2.2.2.9, Microsoft name: EmfPlusCompoundLineData Object */ -int U_PMF_COMPOUNDLINEDATA_get(const char *contents, int32_t *Elements, U_FLOAT **Widths){ - if(!contents || !Elements || !Widths){ return(0); } +int U_PMF_COMPOUNDLINEDATA_get(const char *contents, int32_t *Elements, U_FLOAT **Widths, const char *blimit){ + if(!contents || !Elements || !Widths || !blimit){ return(0); } + if(IS_MEM_UNSAFE(contents, sizeof(U_PMF_COMPOUNDLINEDATA), blimit))return(0); U_PMF_SERIAL_get(&contents, Elements, 4, 1, U_LE); + if(IS_MEM_UNSAFE(contents, *Elements * sizeof(U_FLOAT), blimit))return(0); *Widths = (U_FLOAT *)malloc(*Elements * sizeof(U_FLOAT)); if(!*Widths){ return(0); } U_PMF_SERIAL_get(&contents, *Widths, 4, *Elements, U_LE); @@ -5736,9 +5819,12 @@ int U_PMF_COMPOUNDLINEDATA_get(const char *contents, int32_t *Elements, U_FLOAT This function does not do anything useful, but it is included so that all objects have a corresponding _get(). + + Caller must check Data for possible memory access violations. */ -int U_PMF_COMPRESSEDIMAGE_get(const char *contents, const char **Data){ - if(!contents || !Data){ return(0); } +int U_PMF_COMPRESSEDIMAGE_get(const char *contents, const char **Data, const char *blimit){ + if(!contents || !Data || !blimit){ return(0); } + if(contents >= blimit)return(0); U_PMF_PTRSAV_SHIFT(Data, &contents, 0); return(1); } @@ -5751,9 +5837,12 @@ int U_PMF_COMPRESSEDIMAGE_get(const char *contents, const char **Data){ \param Data Description of linecap EMF+ manual 2.2.2.11, Microsoft name: EmfPlusCustomEndCapData Object + + Caller must check Data for possible memory access violations. */ -int U_PMF_CUSTOMENDCAPDATA_get(const char *contents, int32_t *Size, const char **Data){ - if(!contents || !Size || !Data){ return(0); } +int U_PMF_CUSTOMENDCAPDATA_get(const char *contents, int32_t *Size, const char **Data, const char *blimit){ + if(!contents || !Size || !Data || !blimit){ return(0); } + if(IS_MEM_UNSAFE(contents, sizeof(U_PMF_CUSTOMENDCAPDATA), blimit))return(0); U_PMF_SERIAL_get(&contents, Size, 4, 1, U_LE); U_PMF_PTRSAV_SHIFT(Data, &contents, 0); return(1); @@ -5767,8 +5856,9 @@ int U_PMF_CUSTOMENDCAPDATA_get(const char *contents, int32_t *Size, const char * EMF+ manual 2.2.2.12, Microsoft name: EmfPlusCustomLineCapArrowData Object */ -int U_PMF_CUSTOMLINECAPARROWDATA_get(const char *contents, U_PMF_CUSTOMLINECAPARROWDATA *Ccad){ - if(!contents || !Ccad){ return(0); } +int U_PMF_CUSTOMLINECAPARROWDATA_get(const char *contents, U_PMF_CUSTOMLINECAPARROWDATA *Ccad, const char *blimit){ + if(!contents || !Ccad || !blimit){ return(0); } + if(IS_MEM_UNSAFE(contents, sizeof(U_PMF_CUSTOMLINECAPARROWDATA), blimit))return(0); U_PMF_SERIAL_get(&contents, Ccad, 4, 13, U_LE); return(1); } @@ -5781,9 +5871,12 @@ int U_PMF_CUSTOMLINECAPARROWDATA_get(const char *contents, U_PMF_CUSTOMLINECAPAR \param Data variable part of U_PMF_CUSTOMLINECAPDATA EMF+ manual 2.2.2.13, Microsoft name: EmfPlusCustomLineCapData Object + + Caller must check Data for possible memory access violations. */ -int U_PMF_CUSTOMLINECAPDATA_get(const char *contents, U_PMF_CUSTOMLINECAPDATA *Clcd, const char **Data){ - if(!contents || !Clcd){ return(0); } +int U_PMF_CUSTOMLINECAPDATA_get(const char *contents, U_PMF_CUSTOMLINECAPDATA *Clcd, const char **Data, const char *blimit){ + if(!contents || !Clcd || !blimit){ return(0); } + if(IS_MEM_UNSAFE(contents, sizeof(U_PMF_CUSTOMLINECAPDATA), blimit))return(0); U_PMF_SERIAL_get(&contents, Clcd, 4, 12, U_LE); U_PMF_PTRSAV_SHIFT(Data, &contents, 0); return(1); @@ -5798,14 +5891,19 @@ int U_PMF_CUSTOMLINECAPDATA_get(const char *contents, U_PMF_CUSTOMLINECAPDATA *C \param LineData Path to stroke (optional) EMF+ manual 2.2.2.14, Microsoft name: EmfPlusCustomLineCapOptionalData Object + + Caller must check LineData for possible memory access violations. */ -int U_PMF_CUSTOMLINECAPOPTIONALDATA_get(const char *contents, uint32_t Flags, const char **FillData, const char **LineData){ +int U_PMF_CUSTOMLINECAPOPTIONALDATA_get(const char *contents, uint32_t Flags, const char **FillData, const char **LineData, const char *blimit){ uint32_t length; int status = 1; - if(!contents){ return(0); } + if(!contents || !*FillData || !*LineData || !blimit){ return(0); } + /* this structure is entirely optional */ if(Flags & U_CLCD_FillPath){ if(!FillData){ return(0); } + if(IS_MEM_UNSAFE(contents, 4, blimit))return(0); U_PMF_SERIAL_get(&contents, &length, 4, 1, U_LE); + if(IS_MEM_UNSAFE(contents, length, blimit))return(0); contents -= 4; /* undo the unneeded shift from preceding */ U_PMF_PTRSAV_SHIFT(FillData, &contents, 4 + length); status += 2; @@ -5814,6 +5912,10 @@ int U_PMF_CUSTOMLINECAPOPTIONALDATA_get(const char *contents, uint32_t Flags, co if(Flags & U_CLCD_LinePath){ if(!LineData){ return(0); } + if(IS_MEM_UNSAFE(contents, 4, blimit))return(0); + U_PMF_SERIAL_get(&contents, &length, 4, 1, U_LE); + if(IS_MEM_UNSAFE(contents, length, blimit))return(0); + contents -= 4; /* undo the unneeded shift from preceding */ U_PMF_PTRSAV_SHIFT(LineData, &contents, 0); status += 4; } @@ -5829,9 +5931,12 @@ int U_PMF_CUSTOMLINECAPOPTIONALDATA_get(const char *contents, uint32_t Flags, co \param Data Description of linecap EMF+ manual 2.2.2.15, Microsoft name: EmfPlusCustomStartCapData Object + + Caller must check Data for possible memory access violations. */ -int U_PMF_CUSTOMSTARTCAPDATA_get(const char *contents, int32_t *Size, const char **Data){ - if(!contents || !Size || !Data){ return(0); } +int U_PMF_CUSTOMSTARTCAPDATA_get(const char *contents, int32_t *Size, const char **Data, const char *blimit){ + if(!contents || !Size || !Data || !blimit){ return(0); } + if(IS_MEM_UNSAFE(contents, sizeof(U_PMF_CUSTOMSTARTCAPDATA), blimit))return(0); U_PMF_SERIAL_get(&contents, Size, 4, 1, U_LE); U_PMF_PTRSAV_SHIFT(Data, &contents, 0); return(1); @@ -5846,9 +5951,11 @@ int U_PMF_CUSTOMSTARTCAPDATA_get(const char *contents, int32_t *Size, const char EMF+ manual 2.2.2.16, Microsoft name: EmfPlusDashedLineData Object */ -int U_PMF_DASHEDLINEDATA_get(const char *contents, int32_t *Elements, U_FLOAT **Lengths){ - if(!contents || !Elements || !Lengths){ return(0); } +int U_PMF_DASHEDLINEDATA_get(const char *contents, int32_t *Elements, U_FLOAT **Lengths, const char *blimit){ + if(!contents || !Elements || !Lengths || !blimit){ return(0); } + if(IS_MEM_UNSAFE(contents, sizeof(U_PMF_DASHEDLINEDATA), blimit))return(0); U_PMF_SERIAL_get(&contents, Elements, 4, 1, U_LE); + if(IS_MEM_UNSAFE(contents, *Elements * sizeof(U_FLOAT), blimit))return(0); *Lengths = (U_FLOAT *)malloc(*Elements * sizeof(U_FLOAT)); if(!*Lengths){ return(0); } U_PMF_SERIAL_get(&contents, *Lengths, 4, *Elements, U_LE); @@ -5863,9 +5970,12 @@ int U_PMF_DASHEDLINEDATA_get(const char *contents, int32_t *Elements, U_FLOAT ** \param Data Path specification EMF+ manual 2.2.2.17, Microsoft name: EmfPlusFillPath Object + + Caller must check Data for possible memory access violations. */ -int U_PMF_FILLPATHOBJ_get(const char *contents, int32_t *Size, const char **Data){ - if(!contents || !Size || !Data){ return(0); } +int U_PMF_FILLPATHOBJ_get(const char *contents, int32_t *Size, const char **Data, const char *blimit){ + if(!contents || !Size || !Data || !blimit){ return(0); } + if(IS_MEM_UNSAFE(contents, sizeof(U_PMF_FILLPATHO), blimit))return(0); U_PMF_SERIAL_get(&contents, Size, 4, 1, U_LE); U_PMF_PTRSAV_SHIFT(Data, &contents, 0); return(1); @@ -5881,8 +5991,9 @@ int U_PMF_FILLPATHOBJ_get(const char *contents, int32_t *Size, const char **Data EMF+ manual 2.2.2.18, Microsoft name: EmfPlusFocusScaleData Object */ -int U_PMF_FOCUSSCALEDATA_get(const char *contents, uint32_t *Count, U_FLOAT *ScaleX, U_FLOAT *ScaleY){ - if(!contents || !Count || !ScaleX || !ScaleY){ return(0); } +int U_PMF_FOCUSSCALEDATA_get(const char *contents, uint32_t *Count, U_FLOAT *ScaleX, U_FLOAT *ScaleY, const char *blimit){ + if(!contents || !Count || !ScaleX || !ScaleY || !blimit){ return(0); } + if(IS_MEM_UNSAFE(contents, sizeof(U_PMF_FOCUSSCALEDATA), blimit))return(0); U_PMF_SERIAL_get(&contents, Count, 4, 1, U_LE); if(*Count != 2){ return(0); } U_PMF_SERIAL_get(&contents, ScaleX, 4, 1, U_LE); @@ -5899,9 +6010,10 @@ int U_PMF_FOCUSSCALEDATA_get(const char *contents, uint32_t *Count, U_FLOAT *Sca EMF+ manual 2.2.2.19, Microsoft name: EmfPlusGraphicsVersion Object */ -int U_PMF_GRAPHICSVERSION_get(const char *contents, int *Signature, int *GrfVersion){ - if(!contents || !Signature || !GrfVersion){ return(0); } +int U_PMF_GRAPHICSVERSION_get(const char *contents, int *Signature, int *GrfVersion, const char *blimit){ uint32_t tmp; + if(!contents || !Signature || !GrfVersion || !blimit){ return(0); } + if(IS_MEM_UNSAFE(contents, sizeof(U_PMF_GRAPHICSVERSION), blimit))return(0); memcpy(&tmp, contents, 4); *Signature = tmp >> 12; *GrfVersion = tmp & U_GFVR_MASKLO; @@ -5918,8 +6030,9 @@ int U_PMF_GRAPHICSVERSION_get(const char *contents, int *Signature, int *GrfVers EMF+ manual 2.2.2.20, Microsoft name: EmfPlusHatchBrushData Object */ -int U_PMF_HATCHBRUSHDATA_get(const char *contents, uint32_t *Style, U_PMF_ARGB *Foreground, U_PMF_ARGB *Background){ - if(!contents || !Style || !Foreground || !Background){ return(0); } +int U_PMF_HATCHBRUSHDATA_get(const char *contents, uint32_t *Style, U_PMF_ARGB *Foreground, U_PMF_ARGB *Background, const char *blimit){ + if(!contents || !Style || !Foreground || !Background || !blimit){ return(0); } + if(IS_MEM_UNSAFE(contents, sizeof(U_PMF_HATCHBRUSHDATA), blimit))return(0); U_PMF_SERIAL_get(&contents, Style, 4, 1, U_LE); U_PMF_SERIAL_get(&contents, Foreground, 4, 1, U_XE); U_PMF_SERIAL_get(&contents, Background, 4, 1, U_XE); @@ -5931,12 +6044,14 @@ int U_PMF_HATCHBRUSHDATA_get(const char *contents, uint32_t *Style, U_PMF_ARGB * \return 1 on success, 0 on error \param contents Record from which to extract data \param Value 7 bit signed integer (stored in an integer) + \param blimit one byte past the end of data EMF+ manual 2.2.2.21, Microsoft name: EmfPlusInteger7 Object */ -int U_PMF_INTEGER7_get(const char **contents, U_FLOAT *Value){ - if(!contents || !*contents || !Value){ return(0); } +int U_PMF_INTEGER7_get(const char **contents, U_FLOAT *Value, const char *blimit){ uint8_t tmp; + if(!contents || !*contents || !Value || !blimit){ return(0); } + if(IS_MEM_UNSAFE(*contents, 1, blimit))return(0); /* past end of buffer */ if(**contents & U_TEST_INT7)return(0); /* this bit must be 0 in this object type */ U_PMF_SERIAL_get(contents, &tmp, 1, 1, U_XE); if(tmp & U_SIGN_INT7){ @@ -5954,12 +6069,14 @@ int U_PMF_INTEGER7_get(const char **contents, U_FLOAT *Value){ \return 1 on success, 0 on error \param contents Record from which to extract data \param Value 15 bit signed integer (stored in an integer) + \param blimit one byte past the end of data EMF+ manual 2.2.2.22, Microsoft name: EmfPlusInteger15 Object */ -int U_PMF_INTEGER15_get(const char **contents, U_FLOAT *Value){ - if(!contents || !*contents || !Value){ return(0); } +int U_PMF_INTEGER15_get(const char **contents, U_FLOAT *Value, const char *blimit){ + if(!contents || !*contents || !Value || !blimit){ return(0); } uint16_t tmp; + if(IS_MEM_UNSAFE(*contents, 2, blimit))return(0); /* past end of buffer */ if(!(**contents & U_TEST_INT7))return(0); /* this bit must be 1 in this object type */ U_PMF_SERIAL_get(contents, &tmp, 2, 1, U_BE); tmp &= U_MASK_INT15; /* drop the 7/15 flag from the most significant bit */ @@ -6000,11 +6117,15 @@ int U_PMF_LANGUAGEIDENTIFIER_get(U_PMF_LANGUAGEIDENTIFIER LId, int *SubLId, int \param contents Record from which to extract data \param Lgbd U_PMF_LINEARGRADIENTBRUSHDATA structure, with no variable part \param Data variable part of U_PMF_LINEARGRADIENTBRUSHDATA + \param blimit one byte past the end of data EMF+ manual 2.2.2.24, Microsoft name: EmfPlusLinearGradientBrushData Object + + Caller must check Data for possible memory access violations. */ -int U_PMF_LINEARGRADIENTBRUSHDATA_get(const char *contents, U_PMF_LINEARGRADIENTBRUSHDATA *Lgbd, const char **Data){ - if(!contents || !Lgbd || !Data){ return(0); } +int U_PMF_LINEARGRADIENTBRUSHDATA_get(const char *contents, U_PMF_LINEARGRADIENTBRUSHDATA *Lgbd, const char **Data, const char *blimit){ + if(!contents || !Lgbd || !Data || !blimit){ return(0); } + if(IS_MEM_UNSAFE(contents, sizeof(U_PMF_LINEARGRADIENTBRUSHDATA), blimit))return(0); U_PMF_SERIAL_get(&contents, Lgbd, 4, 6, U_LE); /* Flags, WrapMode, RectF*/ U_PMF_SERIAL_get(&contents, &(Lgbd->StartColor), 4, 4, U_XE); /* StartColor, EndColor, Reserved1 & 2 */ U_PMF_PTRSAV_SHIFT(Data, &contents, 0); @@ -6020,27 +6141,42 @@ int U_PMF_LINEARGRADIENTBRUSHDATA_get(const char *contents, U_PMF_LINEARGRADIENT \param Bc U_PMF_BLENDCOLORS object or NULL \param BfH U_PMF_BLENDFACTORS (H) object or NULL \param BfV U_PMF_BLENDFACTORS (V) object or NULL (WARNING, GDI+ defines this field but does not render it. DO NOT USE.) + \param blimit one byte past the end of data EMF+ manual 2.2.2.25, Microsoft name: EmfPlusLinearGradientBrushOptionalData Object + */ int U_PMF_LINEARGRADIENTBRUSHOPTIONALDATA_get(const char *contents, uint32_t Flags, U_PMF_TRANSFORMMATRIX *Tm, - const char **Bc, const char **BfH, const char **BfV){ + const char **Bc, const char **BfH, const char **BfV, const char *blimit){ uint32_t Elements; - if(!contents || !Tm|| !Bc || !BfH || !BfV){ return(0); } + if(!contents || !Tm|| !Bc || !BfH || !BfV || !blimit){ return(0); } + /* all of the fields are optional! */ *Bc = *BfH = *BfV = NULL; - if(Flags & U_BD_Transform)U_PMF_SERIAL_get(&contents, Tm, 4, 6, U_LE); + if(Flags & U_BD_Transform){ + if(IS_MEM_UNSAFE(contents, sizeof(U_PMF_ROTMATRIX), blimit))return(0); + U_PMF_SERIAL_get(&contents, Tm, 4, 6, U_LE); + } if(Flags & U_BD_PresetColors){ + if(IS_MEM_UNSAFE(contents, 4, blimit))return(0); + U_PMF_SERIAL_get(&contents, &Elements, 4, 1, U_LE); /* starts with a 4 byte count*/ + if(IS_MEM_UNSAFE(contents, Elements * ( sizeof(U_FLOAT) + sizeof(U_PMF_ARGB)), blimit))return(0); + contents-=4; /* back up to the front of the count, as it is part of the data field */ U_PMF_PTRSAV_SHIFT(Bc, &contents, 0); } else if(Flags & U_BD_BlendFactorsH){ U_PMF_SERIAL_get(&contents, &Elements, 4, 1, U_LE); /* starts with a 4 byte count*/ + if(IS_MEM_UNSAFE(contents, Elements * 2 * sizeof(U_FLOAT), blimit))return(0); contents-=4; /* back up to the front of the count, as it is part of the data field */ - U_PMF_PTRSAV_SHIFT(BfH, &contents, 4 + 8*Elements); /* 4 byte count + 2 * 4bytes * Elements */ + U_PMF_PTRSAV_SHIFT(BfH, &contents, 4 + (Elements * 2 * sizeof(U_FLOAT))); /* 4 byte count + 2 * 4bytes * Elements */ if(Flags & U_BD_BlendFactorsV){ + if(IS_MEM_UNSAFE(contents, Elements * 2 * sizeof(U_FLOAT), blimit))return(0); U_PMF_PTRSAV_SHIFT(BfV, &contents, 0); } } else if(Flags & U_BD_BlendFactorsV){ + U_PMF_SERIAL_get(&contents, &Elements, 4, 1, U_LE); /* starts with a 4 byte count*/ + if(IS_MEM_UNSAFE(contents, Elements * 2 * sizeof(U_FLOAT), blimit))return(0); + contents-=4; /* back up to the front of the count, as it is part of the data field */ U_PMF_PTRSAV_SHIFT(BfV, &contents, 0); } return(1); @@ -6052,11 +6188,15 @@ int U_PMF_LINEARGRADIENTBRUSHOPTIONALDATA_get(const char *contents, uint32_t Fla \param contents Record from which to extract data \param Size Bytes in Data \param Data Outline path + \param blimit one byte past the end of data EMF+ manual 2.2.2.26, Microsoft name: EmfPlusLinePath Object + + Caller must check Data for possible memory access violations. */ -int U_PMF_LINEPATH_get(const char *contents, int32_t *Size, const char **Data){ - if(!contents || !Size || !Data){ return(0); } +int U_PMF_LINEPATH_get(const char *contents, int32_t *Size, const char **Data, const char *blimit){ + if(!contents || !Size || !Data || !blimit){ return(0); } + if(IS_MEM_UNSAFE(contents, sizeof(U_PMF_LINEPATH), blimit))return(0); U_PMF_SERIAL_get(&contents, Size, 4, 1, U_LE); U_PMF_PTRSAV_SHIFT(Data, &contents, 0); return(1); @@ -6069,11 +6209,15 @@ int U_PMF_LINEPATH_get(const char *contents, int32_t *Size, const char **Data){ \param Type \param Size Bytes in Data \param Data Various types of data, like an EMF metafile, WMF metafile, another EMF+ metafile + \param blimit one byte past the end of data EMF+ manual 2.2.2.27, Microsoft name: EmfPlusMetafile Object + + Caller must check Data for possible memory access violations. */ -int U_PMF_METAFILE_get(const char *contents, uint32_t *Type, uint32_t *Size, const char **Data){ - if(!contents || !Type || !Size || !Data){ return(0); } +int U_PMF_METAFILE_get(const char *contents, uint32_t *Type, uint32_t *Size, const char **Data, const char *blimit){ + if(!contents || !Type || !Size || !Data || !blimit){ return(0); } + if(IS_MEM_UNSAFE(contents, sizeof(U_PMF_METAFILE), blimit))return(0); U_PMF_SERIAL_get(&contents, &Type, 4, 1, U_LE); U_PMF_SERIAL_get(&contents, &Size, 4, 1, U_LE); U_PMF_PTRSAV_SHIFT(Data, &contents, 0); @@ -6087,13 +6231,16 @@ int U_PMF_METAFILE_get(const char *contents, uint32_t *Type, uint32_t *Size, con \param Flags PaletteStyle flags \param Elements Members in the array \param Colors Palette data (array of colors) + \param blimit one byte past the end of data EMF+ manual 2.2.2.28, Microsoft name: EmfPlusPalette Object */ -int U_PMF_PALETTE_get(const char *contents, uint32_t *Flags, uint32_t *Elements, const char **Colors){ - if(!contents || !Flags || !Elements || !Colors){ return(0); } +int U_PMF_PALETTE_get(const char *contents, uint32_t *Flags, uint32_t *Elements, const char **Colors, const char *blimit){ + if(!contents || !Flags || !Elements || !Colors || !blimit){ return(0); } + if(IS_MEM_UNSAFE(contents, sizeof(U_PMF_PALETTE), blimit))return(0); U_PMF_SERIAL_get(&contents, &Flags, 4, 1, U_LE); U_PMF_SERIAL_get(&contents, &Elements, 4, 1, U_LE); + if(IS_MEM_UNSAFE(contents, *Elements*sizeof(U_RGBQUAD), blimit))return(0); U_PMF_PTRSAV_SHIFT(Colors, &contents, 0); return(1); @@ -6107,21 +6254,32 @@ int U_PMF_PALETTE_get(const char *contents, uint32_t *Flags, uint32_t *Elements, \param Gradient variable part of U_PMF_LINEARGRADIENTBRUSHDATA, Color Gradient with Elements members \param Boundary variable part of U_PMF_LINEARGRADIENTBRUSHDATA, U_PMF_BOUNDARYPATHDATA object if BrushDataPath bit set in Flag, else U_PMF_BOUNDARYPOINTDATA object \param Data variable part of U_PMF_LINEARGRADIENTBRUSHDATA, exact composition depends on Flags + \param blimit one byte past the end of data EMF+ manual 2.2.2.29, Microsoft name: EmfPlusPathGradientBrushData Object + + Caller must check Data for possible memory access violations. + */ -int U_PMF_PATHGRADIENTBRUSHDATA_get(const char *contents, U_PMF_PATHGRADIENTBRUSHDATA *Pgbd, const char **Gradient, const char **Boundary, const char **Data){ - if(!contents || !Pgbd || !Gradient || !Boundary || !Data){ return(0); } +int U_PMF_PATHGRADIENTBRUSHDATA_get(const char *contents, U_PMF_PATHGRADIENTBRUSHDATA *Pgbd, const char **Gradient, + const char **Boundary, const char **Data, const char *blimit){ + if(!contents || !Pgbd || !Gradient || !Boundary || !Data || !blimit){ return(0); } + if(IS_MEM_UNSAFE(contents, sizeof(U_PMF_PATHGRADIENTBRUSHDATA), blimit))return(0); uint32_t Size; U_PMF_SERIAL_get(&contents, Pgbd, 4, 2, U_LE); /* Flags and WrapMode*/ U_PMF_SERIAL_get(&contents, &(Pgbd->CenterColor), 4, 1, U_XE); U_PMF_SERIAL_get(&contents, &(Pgbd->Center), 4, 3, U_LE); /* Center and Elements */ + if(IS_MEM_UNSAFE(contents, Pgbd->Elements * sizeof(U_PMF_ARGB), blimit))return(0); U_PMF_PTRSAV_SHIFT(Gradient, &contents, Pgbd->Elements * sizeof(U_PMF_ARGB)); U_PMF_PTRSAV_SHIFT(Boundary, &contents, 0); U_PMF_SERIAL_get(&contents, &Size, 4, 1, U_LE); /* The first 4 bytes of the Boundary are always a size */ if(Pgbd->Flags & U_BD_Path){ contents += Size; } // U_PMF_BOUNDARYPATHDATA else { contents += Size*2*sizeof(U_FLOAT); } // U_PMF_BOUNDARYPOINTDATA - U_PMF_PTRSAV_SHIFT(Data, &contents, 0); + if(Pgbd->Flags & (U_BD_Transform |U_BD_PresetColors | U_BD_BlendFactorsH| U_BD_FocusScales)){ // optional data present + if(contents >= blimit)return(0); // the size is variable but this must still hold + U_PMF_PTRSAV_SHIFT(Data, &contents, 0); + } + else { *Data = NULL; } // no optional data present return(1); } @@ -6133,15 +6291,34 @@ int U_PMF_PATHGRADIENTBRUSHDATA_get(const char *contents, U_PMF_PATHGRADIENTBRUS \param Matrix Transformation matrix \param Pattern Blend Pattern \param Data Focus scales for the brush + \param blimit one byte past the end of data EMF+ manual 2.2.2.30, Microsoft name: EmfPlusPathGradientBrushOptionalData Object */ -int U_PMF_PATHGRADIENTBRUSHOPTIONALDATA_get(const char *contents, uint32_t Flags, U_PMF_TRANSFORMMATRIX *Matrix, const char **Pattern, const char **Data){ - if(!contents || !Flags || !Matrix || !Pattern || !Data){ return(0); } - U_PMF_SERIAL_get(&contents, &Flags, 4, 1, U_LE); - U_PMF_SERIAL_get(&contents, Matrix, 4, 6, U_LE); - U_PMF_PTRSAV_COND(Data, contents, (Flags & (U_BD_PresetColors | U_BD_BlendFactorsH))); - U_PMF_PTRSAV_COND(Data, contents, (Flags & U_BD_FocusScales)); +int U_PMF_PATHGRADIENTBRUSHOPTIONALDATA_get(const char *contents, uint32_t Flags, U_PMF_TRANSFORMMATRIX *Matrix, + const char **Pattern, const char **Data, const char *blimit){ + int varsize; + if(!contents || !Flags || !Matrix || !Pattern || !Data || !blimit){ return(0); } + /* this structure is entirely optional */ + if(Flags & U_BD_Transform){ + if(IS_MEM_UNSAFE(contents, sizeof(U_PMF_TRANSFORMMATRIX), blimit))return(0); + U_PMF_SERIAL_get(&contents, Matrix, 4, 6, U_LE); + } + if(Flags & (U_BD_PresetColors | U_BD_BlendFactorsH)){ + if(IS_MEM_UNSAFE(contents, 4, blimit))return(0); + uint32_t Elements; + U_PMF_SERIAL_get(&contents, &Elements, 4, 1, U_LE); + contents -= 4; + varsize=(Elements * 4 * (Flags & U_BD_BlendFactorsH ? 2 :1)); + if(IS_MEM_UNSAFE(contents, varsize, blimit))return(0); + U_PMF_PTRSAV_SHIFT(Pattern, &contents, varsize); + } + else { *Pattern=NULL; } + if(Flags & U_BD_FocusScales){ + if(IS_MEM_UNSAFE(contents, sizeof(U_PMF_FOCUSSCALEDATA), blimit))return(0); + U_PMF_PTRSAV_SHIFT(Data, &contents, sizeof(U_PMF_FOCUSSCALEDATA)); + } + else { *Data=NULL; } return(1); } @@ -6151,14 +6328,16 @@ int U_PMF_PATHGRADIENTBRUSHOPTIONALDATA_get(const char *contents, uint32_t Flags \param contents Record from which to extract data \param Flags PathPointType flags \param Type PathPointType enumeration + \param blimit one byte past the end of data EMF+ manual 2.2.2.31, Microsoft name: EmfPlusPathPointType Object Note: order of 4bit fields appears to be shown in the LE column, not as documented in the BE column. */ -int U_PMF_PATHPOINTTYPE_get(const char *contents, int *Flags, int *Type){ - if(!contents || !Flags || !Type){ return(0); } +int U_PMF_PATHPOINTTYPE_get(const char *contents, int *Flags, int *Type, const char *blimit){ + if(!contents || !Flags || !Type || !blimit){ return(0); } + if(IS_MEM_UNSAFE(contents, 1, blimit))return(0); uint8_t tmp; memcpy(&tmp, contents, 1); *Flags =(tmp & U_PTP_MASK) >> U_PTP_SHIFT; @@ -6172,13 +6351,15 @@ int U_PMF_PATHPOINTTYPE_get(const char *contents, int *Flags, int *Type){ \param contents Record from which to extract data \param Bezier Set: Bezier curve, Clear: straight line \param RL Run Length - \param Ppt PathPointType enumeration + \param Ppt PathPointType enumeration + \param blimit one byte past the end of data EMF+ manual 2.2.2.32, Microsoft name: EmfPlusPathPointTypeRLE Object */ -int U_PMF_PATHPOINTTYPERLE_get(const char *contents, int *Bezier, int *RL, int *Ppt){ - if(!contents || !Bezier || !RL || !Ppt){ return(0); } +int U_PMF_PATHPOINTTYPERLE_get(const char *contents, int *Bezier, int *RL, int *Ppt, const char *blimit){ + if(!contents || !Bezier || !RL || !Ppt || !blimit){ return(0); } uint16_t tmp; + if(IS_MEM_UNSAFE(contents, 2, blimit))return(0); U_PMF_SERIAL_get(&contents, &tmp, 2, 1, U_LE); *Bezier = tmp & U_PPF_BZ; *RL = (tmp >> U_FF_SHFT_RL) & U_FF_MASK_RL; @@ -6194,14 +6375,17 @@ int U_PMF_PATHPOINTTYPERLE_get(const char *contents, int *Bezier, int *RL, int * \param Unit UnitType enumeration \param Width Width in units set by Unit \param Data Optional pen data, exact composition depends on Flags + \param blimit one byte past the end of data EMF+ manual 2.2.2.33, Microsoft name: EmfPlusPenData Object */ -int U_PMF_PENDATA_get(const char *contents, uint32_t *Flags, uint32_t *Unit, U_FLOAT *Width, const char **Data){ - if(!contents || !Flags || !Unit || !Width || !Data){ return(0); } +int U_PMF_PENDATA_get(const char *contents, uint32_t *Flags, uint32_t *Unit, U_FLOAT *Width, const char **Data, const char *blimit){ + if(!contents || !Flags || !Unit || !Width || !Data || !blimit){ return(0); } + if(IS_MEM_UNSAFE(contents, 3*4, blimit))return(0); U_PMF_SERIAL_get(&contents, Flags, 4, 1, U_LE); U_PMF_SERIAL_get(&contents, Unit, 4, 1, U_LE); U_PMF_SERIAL_get(&contents, Width, 4, 1, U_LE); + if(contents >= blimit)return(0); // variable data will extend farther, but this much at least must be true U_PMF_PTRSAV_SHIFT(Data, &contents, 0); return(1); } @@ -6224,6 +6408,7 @@ int U_PMF_PENDATA_get(const char *contents, uint32_t *Flags, uint32_t *Unit, U_F \param CmpndLineData Compount Line (parallel lines drawn instead of one) \param CSCapData Custom start cap \param CECapData Custom end cap + \param blimit one byte past the end of data EMF+ manual 2.2.2.34, Microsoft name: EmfPlusPenOptionalData Object @@ -6245,26 +6430,56 @@ int U_PMF_PENOPTIONALDATA_get( int32_t *Alignment, const char **CmpndLineData, const char **CSCapData, - const char **CECapData){ + const char **CECapData, + const char *blimit){ if(!contents || !Flags || !Matrix || !StartCap || !EndCap || !Join || !MiterLimit || !Style || !DLCap || !DLOffset || !DLData || !Alignment || !CmpndLineData || - !CSCapData || !CECapData){ return(0); } - - if(Flags & U_PD_Transform){ U_PMF_SERIAL_get(&contents, Matrix, 4, 6, U_LE); } - if(Flags & U_PD_StartCap){ U_PMF_SERIAL_get(&contents, StartCap, 4, 1, U_LE); } - if(Flags & U_PD_EndCap){ U_PMF_SERIAL_get(&contents, EndCap, 4, 1, U_LE); } - if(Flags & U_PD_Join){ U_PMF_SERIAL_get(&contents, Join, 4, 1, U_LE); } - if(Flags & U_PD_MiterLimit){ U_PMF_SERIAL_get(&contents, MiterLimit, 4, 1, U_LE); } - if(Flags & U_PD_LineStyle){ U_PMF_SERIAL_get(&contents, Style, 4, 1, U_LE); } - if(Flags & U_PD_DLCap){ U_PMF_SERIAL_get(&contents, DLCap, 4, 1, U_LE); } - if(Flags & U_PD_DLOffset){ U_PMF_SERIAL_get(&contents, DLOffset, 4, 1, U_LE); } - if(Flags & U_PD_DLData){ U_PMF_PTRSAV_SHIFT( DLData, &contents, U_PMF_LEN_FLOATDATA(contents)); } - if(Flags & U_PD_NonCenter){ U_PMF_SERIAL_get(&contents, Alignment, 4, 1, U_LE); } - if(Flags & U_PD_CLData){ U_PMF_PTRSAV_SHIFT( CmpndLineData, &contents, U_PMF_LEN_FLOATDATA(contents)); } - if(Flags & U_PD_CustomStartCap){ U_PMF_PTRSAV_SHIFT( CSCapData, &contents, U_PMF_LEN_BYTEDATA(contents)); } - if(Flags & U_PD_CustomEndCap){ U_PMF_PTRSAV_SHIFT( CECapData, &contents, U_PMF_LEN_BYTEDATA(contents)); } + !CSCapData || !CECapData || !blimit){ return(0); } + + if(Flags & U_PD_Transform){ if(IS_MEM_UNSAFE(contents, 4*6, blimit))return(0); + U_PMF_SERIAL_get(&contents, Matrix, 4, 6, U_LE); + } + if(Flags & U_PD_StartCap){ if(IS_MEM_UNSAFE(contents, 4, blimit))return(0); + U_PMF_SERIAL_get(&contents, StartCap, 4, 1, U_LE); + } + if(Flags & U_PD_EndCap){ if(IS_MEM_UNSAFE(contents, 4, blimit))return(0); + U_PMF_SERIAL_get(&contents, EndCap, 4, 1, U_LE); + } + if(Flags & U_PD_Join){ if(IS_MEM_UNSAFE(contents, 4, blimit))return(0); + U_PMF_SERIAL_get(&contents, Join, 4, 1, U_LE); + } + if(Flags & U_PD_MiterLimit){ if(IS_MEM_UNSAFE(contents, 4, blimit))return(0); + U_PMF_SERIAL_get(&contents, MiterLimit, 4, 1, U_LE); + } + if(Flags & U_PD_LineStyle){ if(IS_MEM_UNSAFE(contents, 4, blimit))return(0); + U_PMF_SERIAL_get(&contents, Style, 4, 1, U_LE); + } + if(Flags & U_PD_DLCap){ if(IS_MEM_UNSAFE(contents, 4, blimit))return(0); + U_PMF_SERIAL_get(&contents, DLCap, 4, 1, U_LE); + } + if(Flags & U_PD_DLOffset){ if(IS_MEM_UNSAFE(contents, 4, blimit))return(0); + U_PMF_SERIAL_get(&contents, DLOffset, 4, 1, U_LE); + } + if(Flags & U_PD_DLData){ if(IS_MEM_UNSAFE(contents, 4, blimit))return(0); + if(IS_MEM_UNSAFE(contents, U_PMF_LEN_FLOATDATA(contents), blimit))return(0); + U_PMF_PTRSAV_SHIFT( DLData, &contents, U_PMF_LEN_FLOATDATA(contents)); + } + if(Flags & U_PD_NonCenter){ if(IS_MEM_UNSAFE(contents, 4, blimit))return(0); + U_PMF_SERIAL_get(&contents, Alignment, 4, 1, U_LE); } + if(Flags & U_PD_CLData){ if(IS_MEM_UNSAFE(contents, 4, blimit))return(0); + if(IS_MEM_UNSAFE(contents, U_PMF_LEN_FLOATDATA(contents), blimit))return(0); + U_PMF_PTRSAV_SHIFT( CmpndLineData, &contents, U_PMF_LEN_FLOATDATA(contents)); + } + if(Flags & U_PD_CustomStartCap){ if(IS_MEM_UNSAFE(contents, 4, blimit))return(0); + if(IS_MEM_UNSAFE(contents, U_PMF_LEN_BYTEDATA(contents), blimit))return(0); + U_PMF_PTRSAV_SHIFT( CSCapData, &contents, U_PMF_LEN_BYTEDATA(contents)); + } + if(Flags & U_PD_CustomEndCap){ if(IS_MEM_UNSAFE(contents, 4, blimit))return(0); + if(IS_MEM_UNSAFE(contents, U_PMF_LEN_BYTEDATA(contents), blimit))return(0); + U_PMF_PTRSAV_SHIFT( CECapData, &contents, U_PMF_LEN_BYTEDATA(contents)); + } return(1); } @@ -6274,12 +6489,14 @@ int U_PMF_PENOPTIONALDATA_get( \param contents Record from which to extract data. On return position is offset by sizeof(U_PMF_POINT). \param X X coordinate \param Y Y coordinate + \param blimit one byte past the end of data EMF+ manual 2.2.2.35, Microsoft name: EmfPlusPoint Object */ -int U_PMF_POINT_get(const char **contents, U_FLOAT *X, U_FLOAT *Y){ - if(!contents || !X || !Y){ return(0); } +int U_PMF_POINT_get(const char **contents, U_FLOAT *X, U_FLOAT *Y, const char *blimit){ + if(!contents || !X || !Y || !blimit){ return(0); } int16_t tmp; + if(IS_MEM_UNSAFE(*contents, 2*2, blimit))return(0); U_PMF_SERIAL_get(contents, &tmp, 2, 1, U_LE); *X = tmp; U_PMF_SERIAL_get(contents, &tmp, 2, 1, U_LE); *Y = tmp; return(1); @@ -6291,11 +6508,13 @@ int U_PMF_POINT_get(const char **contents, U_FLOAT *X, U_FLOAT *Y){ \param contents Record from which to extract data. On return position is offset by sizeof(U_PMF_POINTF). \param X X coordinate \param Y Y coordinate + \param blimit one byte past the end of data EMF+ manual 2.2.2.36, Microsoft name: EmfPlusPointF Object */ -int U_PMF_POINTF_get(const char **contents, U_FLOAT *X, U_FLOAT *Y){ - if(!contents || !X || !Y){ return(0); } +int U_PMF_POINTF_get(const char **contents, U_FLOAT *X, U_FLOAT *Y, const char *blimit){ + if(!contents || !X || !Y || !blimit){ return(0); } + if(IS_MEM_UNSAFE(*contents, 4*2, blimit))return(0); U_PMF_SERIAL_get(contents, X, 4, 1, U_LE); U_PMF_SERIAL_get(contents, Y, 4, 1, U_LE); return(1); @@ -6307,19 +6526,20 @@ int U_PMF_POINTF_get(const char **contents, U_FLOAT *X, U_FLOAT *Y){ \param contents Record from which to extract data. On return position is offset by returned size. \param X X coordinate \param Y Y coordinate + \param blimit one byte past the end of data EMF+ manual 2.2.2.37, Microsoft name: EmfPlusPointR Object */ -int U_PMF_POINTR_get(const char **contents, U_FLOAT *X, U_FLOAT *Y){ - if(!contents || !*contents | !X || !Y){ return(0); } +int U_PMF_POINTR_get(const char **contents, U_FLOAT *X, U_FLOAT *Y, const char *blimit){ + if(!contents || !*contents | !X || !Y || !blimit){ return(0); } int size=0; - if( U_PMF_INTEGER7_get( contents, X)){ size +=1; } - else if(U_PMF_INTEGER15_get(contents, X)){ size +=2; } + if( U_PMF_INTEGER7_get( contents, X, blimit)){ size +=1; } + else if(U_PMF_INTEGER15_get(contents, X, blimit)){ size +=2; } else { return(0); } - if( U_PMF_INTEGER7_get( contents, Y)){ size +=1; } - else if(U_PMF_INTEGER15_get(contents, Y)){ size +=2; } + if( U_PMF_INTEGER7_get( contents, Y, blimit)){ size +=1; } + else if(U_PMF_INTEGER15_get(contents, Y, blimit)){ size +=2; } else { return(0); } return(size); @@ -6332,31 +6552,38 @@ int U_PMF_POINTR_get(const char **contents, U_FLOAT *X, U_FLOAT *Y){ \param Flags Record flags (bits U_PPF_C and U_PPF_P are referenced) \param Elements Number of points to retrieve. \param Points Caller must free. Array of U_PMF_POINTF coordinates. + \param blimit one byte past the end of data + + This function should never be called directly by end user code. */ -int U_PMF_VARPOINTS_get(const char **contents, uint16_t Flags, int Elements, U_PMF_POINTF **Points){ +int U_PMF_VARPOINTS_get(const char *contents, uint16_t Flags, int Elements, U_PMF_POINTF **Points, const char *blimit){ int status = 0; - if(!contents || !*contents || !Points || !Elements){ return(status); } + if(!contents || !Points || !Elements || !blimit){ return(status); } U_PMF_POINTF *pts = (U_PMF_POINTF *)malloc(Elements * sizeof(U_PMF_POINTF)); if(!pts){ return(status); } *Points = pts; U_FLOAT XF, YF; U_FLOAT XFS, YFS; - for(XFS = YFS = 0.0; Elements; Elements--, pts++){ - if(Flags & U_PPF_P){ - if(!U_PMF_POINTR_get(contents, &XF, &YF))break; /* this should never happen */ + if(Flags & U_PPF_P){ + for(XFS = YFS = 0.0; Elements; Elements--, pts++){ + if(!U_PMF_POINTR_get(&contents, &XF, &YF, blimit))return(0); /* this should never happen */ XFS += XF; /* position relative to previous point, first point is always 0,0 */ YFS += YF; pts->X = XFS; pts->Y = YFS; } - else if(Flags & U_PPF_C){ - if(!U_PMF_POINT_get(contents, &XF, &XF))break; /* this should never happen */ + } + else if(Flags & U_PPF_C){ + for(XFS = YFS = 0.0; Elements; Elements--, pts++){ + if(!U_PMF_POINT_get(&contents, &XF, &XF, blimit))break; /* this should never happen */ pts->X = XF; pts->Y = YF; } - else { - (void) U_PMF_POINTF_get(contents, &(pts->X), &(pts->Y)); + } + else { + for(XFS = YFS = 0.0; Elements; Elements--, pts++){ + (void) U_PMF_POINTF_get(&contents, &(pts->X), &(pts->Y), blimit); } } if(Elements){ /* some error in the preceding */ @@ -6377,11 +6604,13 @@ int U_PMF_VARPOINTS_get(const char **contents, uint16_t Flags, int Elements, U_P \param Y UL Y value \param Width Width \param Height Height + \param blimit one byte past the end of data EMF+ manual 2.2.2.38, Microsoft name: EmfPlusRect Object */ -int U_PMF_RECT_get(const char **contents, int16_t *X, int16_t *Y, int16_t *Width, int16_t *Height){ +int U_PMF_RECT_get(const char **contents, int16_t *X, int16_t *Y, int16_t *Width, int16_t *Height, const char *blimit){ if(!contents || !X || !Y|| !Width || !Height){ return(0); } + if(IS_MEM_UNSAFE(*contents, 2*4, blimit))return(0); U_PMF_SERIAL_get(contents, X, 2, 1, U_LE); U_PMF_SERIAL_get(contents, Y, 2, 1, U_LE); U_PMF_SERIAL_get(contents, Width, 2, 1, U_LE); @@ -6397,11 +6626,13 @@ int U_PMF_RECT_get(const char **contents, int16_t *X, int16_t *Y, int16_t *Width \param Y UL Y value \param Width Width \param Height Height + \param blimit one byte past the end of data EMF+ manual 2.2.2.39, Microsoft name: EmfPlusRectF Object */ -int U_PMF_RECTF_get(const char **contents, U_FLOAT *X, U_FLOAT *Y, U_FLOAT *Width, U_FLOAT *Height){ +int U_PMF_RECTF_get(const char **contents, U_FLOAT *X, U_FLOAT *Y, U_FLOAT *Width, U_FLOAT *Height, const char *blimit){ if(!contents || !X || !Y|| !Width || !Height){ return(0); } + if(IS_MEM_UNSAFE(*contents, 4*4, blimit))return(0); U_PMF_SERIAL_get(contents, X, 4, 1, U_LE); U_PMF_SERIAL_get(contents, Y, 4, 1, U_LE); U_PMF_SERIAL_get(contents, Width, 4, 1, U_LE); @@ -6416,13 +6647,14 @@ int U_PMF_RECTF_get(const char **contents, U_FLOAT *X, U_FLOAT *Y, U_FLOAT *Widt \param Flags Record flags (bit U_PPF_C is referenced) \param Elements Number of rects to retrieve. \param Rects Caller must free. Array of U_PMF_RECTF coordinates. + \param blimit one byte past the end of data Rects in record may be either U_PMF_RECT or U_PMF_RECTF, but this function always returns U_PMF_RECTF */ -int U_PMF_VARRECTS_get(const char **contents, uint16_t Flags, int Elements, U_PMF_RECTF **Rects){ +int U_PMF_VARRECTS_get(const char **contents, uint16_t Flags, int Elements, U_PMF_RECTF **Rects, const char *blimit){ int16_t X16, Y16, Width, Height; - if(!contents || !*contents || !Rects){ return(0); } + if(!contents || !*contents || !Rects || !blimit){ return(0); } U_PMF_RECTF *rts = (U_PMF_RECTF *)malloc(Elements * sizeof(U_PMF_RECTF)); if(!rts){ *Rects = NULL; @@ -6430,16 +6662,28 @@ int U_PMF_VARRECTS_get(const char **contents, uint16_t Flags, int Elements, U_PM } *Rects = rts; + if(Flags & U_PPF_C){ + if(IS_MEM_UNSAFE(*contents, Elements*sizeof(U_PMF_RECT), blimit)){ + free(rts); + return(0); + } + } + else { + if(IS_MEM_UNSAFE(*contents, Elements*sizeof(U_PMF_RECT), blimit)){ + free(rts); + return(0); + } + } for(; Elements; Elements--, rts++){ if(Flags & U_PPF_C){ - (void) U_PMF_RECT_get(contents, &X16, &Y16, &Width, &Height); + (void) U_PMF_RECT_get(contents, &X16, &Y16, &Width, &Height, blimit); rts->X = X16; rts->Y = Y16; rts->Width = Width; rts->Height = Height; } else { - (void) U_PMF_RECTF_get(contents, &(rts->X), &(rts->Y), &(rts->Width), &(rts->Height)); + (void) U_PMF_RECTF_get(contents, &(rts->X), &(rts->Y), &(rts->Width), &(rts->Height), blimit); } } return(1); @@ -6451,13 +6695,18 @@ int U_PMF_VARRECTS_get(const char **contents, uint16_t Flags, int Elements, U_PM \param contents Record from which to extract data \param Type RegionNodeDataType \param Data Depending on Type: U_PMF_REGIONNODEPATH, U_PMF_RECTF, or U_PMF_REGIONNODECHILDNODES - + \param blimit one byte past the end of data EMF+ manual 2.2.2.40, Microsoft name: EmfPlusRegionNode Object + + Caller must check Data for possible memory access violations. */ -int U_PMF_REGIONNODE_get(const char *contents, uint32_t *Type, const char **Data){ - if(!contents || !Type|| !Data){ return(0); } +int U_PMF_REGIONNODE_get(const char *contents, uint32_t *Type, const char **Data, const char *blimit){ + if(!contents || !Type || !Data || !blimit){ return(0); } + /* Important! This only checks the constant part, the caller must check that returned data doesn't exceed blimit */ + if(IS_MEM_UNSAFE(contents, sizeof(U_PMF_REGIONNODE), blimit))return(0); U_PMF_SERIAL_get(&contents, Type, 4, 1, U_LE); + if(contents >= blimit)return(0); // returned Data is variable size, this much at least must be true U_PMF_PTRSAV_COND(Data, contents, !(*Type == U_RNDT_Empty || *Type == U_RNDT_Infinite )); return(1); } @@ -6481,12 +6730,16 @@ int U_PMF_REGIONNODE_get(const char *contents, uint32_t *Type, const char **Data \param contents Record from which to extract data \param Size Bytes in Data \param Data Boundary of region node + \param blimit one byte past the end of data EMF+ manual 2.2.2.42, Microsoft name: EmfPlusRegionNodePath Object */ -int U_PMF_REGIONNODEPATH_get(const char *contents, int32_t *Size, const char **Data){ - if(!contents || !Size || !Data){ return(0); } +int U_PMF_REGIONNODEPATH_get(const char *contents, int32_t *Size, const char **Data, const char *blimit){ + if(!contents || !Size || !Data || !blimit){ return(0); } + /* Important! This only checks the constant part, the caller must check that returned data doesn't exceed blimit */ + if(IS_MEM_UNSAFE(contents, sizeof(U_PMF_REGIONNODEPATH), blimit))return(0); U_PMF_SERIAL_get(&contents, Size, 4, 1, U_LE); + if(contents >= blimit)return(0); // returned Data is variable size, this much at least must be true U_PMF_PTRSAV_SHIFT(Data, &contents, 0); return(1); } @@ -6496,11 +6749,13 @@ int U_PMF_REGIONNODEPATH_get(const char *contents, int32_t *Size, const char **D \return 1 on success, 0 on error \param contents Record from which to extract data \param Color Color of brush + \param blimit one byte past the end of data EMF+ manual 2.2.2.43, Microsoft name: EmfPlusSolidBrushData Object */ -int U_PMF_SOLIDBRUSHDATA_get(const char *contents, U_PMF_ARGB *Color){ - if(!contents || !Color){ return(0); } +int U_PMF_SOLIDBRUSHDATA_get(const char *contents, U_PMF_ARGB *Color, const char *blimit){ + if(!contents || !Color || !blimit){ return(0); } + if(IS_MEM_UNSAFE(contents, sizeof(U_PMF_SOLIDBRUSHDATA), blimit))return(0); U_PMF_SERIAL_get(&contents, Color, 4, 1, U_XE); return(1); } @@ -6513,12 +6768,14 @@ int U_PMF_SOLIDBRUSHDATA_get(const char *contents, U_PMF_ARGB *Color){ \param RangeCount Entries in CharRange array \param TabStops Array of tabstop locations \param CharRange Array of character ranges in the text + \param blimit one byte past the end of data EMF+ manual 2.2.2.44, Microsoft name: EmfPlusStringFormatData Object */ int U_PMF_STRINGFORMATDATA_get(const char *contents, uint32_t TabStopCount, uint32_t RangeCount, - const U_FLOAT **TabStops, const U_PMF_CHARACTERRANGE **CharRange){ - if(!contents || !TabStops|| !CharRange){ return(0); } + const U_FLOAT **TabStops, const U_PMF_CHARACTERRANGE **CharRange, const char *blimit){ + if(!contents || !TabStops|| !CharRange || !blimit){ return(0); } + if(IS_MEM_UNSAFE(contents, (TabStopCount + 2*RangeCount)*4, blimit))return(0); *TabStops = NULL; if(TabStopCount > 0){ U_PMF_SERIAL_get(&contents, TabStops, 4, TabStopCount, U_LE); } *CharRange = NULL; @@ -6533,13 +6790,19 @@ int U_PMF_STRINGFORMATDATA_get(const char *contents, uint32_t TabStopCount, uint \param Flags BrushData flags \param WrapMode WrapMode enumeration \param Data Optional texture data + \param blimit one byte past the end of data EMF+ manual 2.2.2.45, Microsoft name: EmfPlusTextureBrushData Object + + Caller must check Data for possible memory access violations. */ -int U_PMF_TEXTUREBRUSHDATA_get(const char *contents, uint32_t *Flags, int32_t *WrapMode, const char **Data){ - if(!contents || !Flags || !WrapMode || !Data){ return(0); } +int U_PMF_TEXTUREBRUSHDATA_get(const char *contents, uint32_t *Flags, int32_t *WrapMode, const char **Data, const char *blimit){ + if(!contents || !Flags || !WrapMode || !Data || !blimit){ return(0); } + /* Important! This only checks the constant part, the caller must check that returned data doesn't exceed blimit */ + if(IS_MEM_UNSAFE(contents, sizeof(U_PMF_TEXTUREBRUSHDATA), blimit))return(0); U_PMF_SERIAL_get(&contents, Flags, 4, 1, U_LE); U_PMF_SERIAL_get(&contents, WrapMode, 4, 1, U_LE); + if(contents >= blimit)return(0); // returned Data is variable size, this much at least must be true U_PMF_PTRSAV_SHIFT(Data, &contents, 0); return(1); } @@ -6549,16 +6812,25 @@ int U_PMF_TEXTUREBRUSHDATA_get(const char *contents, uint32_t *Flags, int32_t *W \return 1 on success, 0 on error \param contents Record from which to extract data \param HasImage True if this object has an Image - \param Matrix Transformation matrix, present if Flag BrushDataTransform is set. + \param Matrix Transformation matrix, NULL if Flag BrushDataTransform is not set. \param Image Image that contains the texture. - + \param blimit one byte past the end of data EMF+ manual 2.2.2.46, Microsoft name: EmfPlusTextureBrushOptionalData Object + + Caller must check Image for possible memory access violations. */ -int U_PMF_TEXTUREBRUSHOPTIONALDATA_get(const char *contents, int HasImage, U_PMF_TRANSFORMMATRIX *Matrix, const char **Image){ - if(!contents || !Matrix || !Image){ return(0); } - U_PMF_SERIAL_get(&contents, Matrix, 4, 6, U_LE); - U_PMF_PTRSAV_COND(Image, contents, HasImage); +int U_PMF_TEXTUREBRUSHOPTIONALDATA_get(const char *contents, int HasImage, U_PMF_TRANSFORMMATRIX *Matrix, + const char **Image, const char *blimit){ + if(!contents || !Image || !blimit){ return(0); } + if(Matrix){ + if(IS_MEM_UNSAFE(contents, sizeof(U_PMF_TRANSFORMMATRIX), blimit))return(0); + U_PMF_SERIAL_get(&contents, Matrix, 4, 6, U_LE); + } + if(HasImage){ + if(contents >= blimit)return(0); // returned Data is variable size, this much at least must be true + U_PMF_PTRSAV_COND(Image, contents, HasImage); + } return(1); } @@ -6567,11 +6839,13 @@ int U_PMF_TEXTUREBRUSHOPTIONALDATA_get(const char *contents, int HasImage, U_PMF \return 1 on success, 0 on error \param contents Record from which to extract data \param Matrix Transformation matrix, present if Flag BrushDataTransform is set. + \param blimit one byte past the end of data EMF+ manual 2.2.2.47, Microsoft name: EmfPlusTransformMatrix Object */ -int U_PMF_TRANSFORMMATRIX_get(const char *contents, U_PMF_TRANSFORMMATRIX *Matrix){ - if(!contents || !Matrix){ return(0); } +int U_PMF_TRANSFORMMATRIX_get(const char *contents, U_PMF_TRANSFORMMATRIX *Matrix, const char *blimit){ + if(!contents || !Matrix || !blimit){ return(0); } + if(IS_MEM_UNSAFE(contents, sizeof(U_PMF_TRANSFORMMATRIX), blimit))return(0); U_PMF_SERIAL_get(&contents, Matrix, 4, 6, U_LE); return(1); } @@ -6582,11 +6856,13 @@ int U_PMF_TRANSFORMMATRIX_get(const char *contents, U_PMF_TRANSFORMMATRIX *Matri \param contents Record from which to extract data \param Radius Blur radius in pixels \param ExpandEdge 1: expand bitmap by Radius; 0: bitmap size unchanged + \param blimit one byte past the end of data EMF+ manual 2.2.3.1, Microsoft name: BlurEffect Object */ -int U_PMF_IE_BLUR_get(const char *contents, U_FLOAT *Radius, uint32_t *ExpandEdge){ - if(!contents || !Radius || !ExpandEdge){ return(0); } +int U_PMF_IE_BLUR_get(const char *contents, U_FLOAT *Radius, uint32_t *ExpandEdge, const char *blimit){ + if(!contents || !Radius || !ExpandEdge || !blimit){ return(0); } + if(IS_MEM_UNSAFE(contents, sizeof(U_PMF_IE_BLUR), blimit))return(0); U_PMF_SERIAL_get(&contents, Radius, 4, 1, U_LE); U_PMF_SERIAL_get(&contents, ExpandEdge, 4, 1, U_LE); return(1); @@ -6598,11 +6874,13 @@ int U_PMF_IE_BLUR_get(const char *contents, U_FLOAT *Radius, uint32_t *ExpandEdg \param contents Record from which to extract data \param Brightness -255 to 255, 0 is unchanged, positive increases, negative decreases \param Contrast -100 to 100, 0 is unchanged, positive increases, negative decreases + \param blimit one byte past the end of data EMF+ manual 2.2.3.2, Microsoft name: BrightnessContrastEffect Object */ -int U_PMF_IE_BRIGHTNESSCONTRAST_get(const char *contents, int32_t *Brightness, int32_t *Contrast){ - if(!contents || !Brightness || !Contrast){ return(0); } +int U_PMF_IE_BRIGHTNESSCONTRAST_get(const char *contents, int32_t *Brightness, int32_t *Contrast, const char *blimit){ + if(!contents || !Brightness || !Contrast || !blimit){ return(0); } + if(IS_MEM_UNSAFE(contents, sizeof(U_PMF_IE_BRIGHTNESSCONTRAST), blimit))return(0); U_PMF_SERIAL_get(&contents, Brightness, 4, 1, U_LE); U_PMF_SERIAL_get(&contents, Contrast, 4, 1, U_LE); return(1); @@ -6615,11 +6893,13 @@ int U_PMF_IE_BRIGHTNESSCONTRAST_get(const char *contents, int32_t *Brightness, i \param CyanRed -100 to 100, 0 is unchanged, positive increases Red & decreases Cyan, negative is opposite \param MagentaGreen -100 to 100, 0 is unchanged, positive increases Green & decreases Magenta, negative is opposite \param YellowBlue -100 to 100, 0 is unchanged, positive increases Blue & decreases Yellow, negative is opposite + \param blimit one byte past the end of data EMF+ manual 2.2.3.3, Microsoft name: ColorBalanceEffect Object */ -int U_PMF_IE_COLORBALANCE_get(const char *contents, int32_t *CyanRed, int32_t *MagentaGreen, int32_t *YellowBlue){ - if(!contents || !CyanRed || !MagentaGreen || !YellowBlue){ return(0); } +int U_PMF_IE_COLORBALANCE_get(const char *contents, int32_t *CyanRed, int32_t *MagentaGreen, int32_t *YellowBlue, const char *blimit){ + if(!contents || !CyanRed || !MagentaGreen || !YellowBlue || !blimit){ return(0); } + if(IS_MEM_UNSAFE(contents, sizeof(U_PMF_IE_COLORBALANCE), blimit))return(0); U_PMF_SERIAL_get(&contents, CyanRed, 4, 1, U_LE); U_PMF_SERIAL_get(&contents, MagentaGreen, 4, 1, U_LE); U_PMF_SERIAL_get(&contents, YellowBlue, 4, 1, U_LE); @@ -6634,11 +6914,13 @@ int U_PMF_IE_COLORBALANCE_get(const char *contents, int32_t *CyanRed, int32_t *M \param Adjust CurveAdjustment enumeration \param Channel CurveChannel enumeration \param Intensity adjustment to apply. "Adjust" determines what field this is and range values. + \param blimit one byte past the end of data EMF+ manual 2.2.3.4, Microsoft name: ColorCurveEffect Object */ -int U_PMF_IE_COLORCURVE_get(const char *contents, uint32_t *Adjust, uint32_t *Channel, int32_t *Intensity){ - if(!contents || !Adjust || !Channel || !Intensity){ return(0); } +int U_PMF_IE_COLORCURVE_get(const char *contents, uint32_t *Adjust, uint32_t *Channel, int32_t *Intensity, const char *blimit){ + if(!contents || !Adjust || !Channel || !Intensity || !blimit){ return(0); } + if(IS_MEM_UNSAFE(contents, sizeof(U_PMF_IE_COLORCURVE), blimit))return(0); U_PMF_SERIAL_get(&contents, Adjust, 4, 1, U_LE); U_PMF_SERIAL_get(&contents, Channel, 4, 1, U_LE); U_PMF_SERIAL_get(&contents, Intensity, 4, 1, U_LE); @@ -6653,12 +6935,14 @@ int U_PMF_IE_COLORCURVE_get(const char *contents, uint32_t *Adjust, uint32_t *Ch \param GLUT Green color lookup table \param RLUT Red color lookup table \param ALUT Alpha color lookup table + \param blimit one byte past the end of data EMF+ manual 2.2.3.5, Microsoft name: ColorLookupTableEffect Object */ int U_PMF_IE_COLORLOOKUPTABLE_get(const char *contents, - const uint8_t **BLUT, const uint8_t **GLUT, const uint8_t **RLUT, const uint8_t **ALUT){ - if(!contents || !BLUT || !GLUT || !RLUT || !ALUT){ return(0); } + const uint8_t **BLUT, const uint8_t **GLUT, const uint8_t **RLUT, const uint8_t **ALUT, const char *blimit){ + if(!contents || !BLUT || !GLUT || !RLUT || !ALUT || !blimit){ return(0); } + if(IS_MEM_UNSAFE(contents, sizeof(U_PMF_IE_COLORLOOKUPTABLE) + 4 * 256, blimit))return(0); U_PMF_PTRSAV_SHIFT((const char **)BLUT, &contents, 256); U_PMF_PTRSAV_SHIFT((const char **)GLUT, &contents, 256); U_PMF_PTRSAV_SHIFT((const char **)RLUT, &contents, 256); @@ -6671,11 +6955,14 @@ int U_PMF_IE_COLORLOOKUPTABLE_get(const char *contents, \return 1 on success, 0 on error \param contents Record from which to extract data \param Matrix 5 x 5 color transformation matrix, First 4 rows are [{4 multiplier values},0.0] for R,G,B,A, last Row is [{4 color translation valuess}, 1.0] + \param blimit one byte past the end of data EMF+ manual 2.2.3.6, Microsoft name: ColorMatrixEffect Object */ -int U_PMF_IE_COLORMATRIX_get(const char *contents, U_PMF_IE_COLORMATRIX *Matrix){ - if(!contents || !Matrix){ return(0); } +int U_PMF_IE_COLORMATRIX_get(const char *contents, U_PMF_IE_COLORMATRIX *Matrix, const char *blimit){ + if(!contents || !Matrix || !blimit){ return(0); } + /* Important! This only checks the constant part, the caller must check that returned data doesn't exceed blimit */ + if(IS_MEM_UNSAFE(contents, sizeof(U_PMF_IE_COLORMATRIX), blimit))return(0); U_PMF_SERIAL_get(&contents, Matrix, 4, 5*5, U_LE); return(1); } @@ -6687,11 +6974,13 @@ int U_PMF_IE_COLORMATRIX_get(const char *contents, U_PMF_IE_COLORMATRIX *Matrix) \param Hue -180 to 180, 0 is unchanged \param Saturation -100 to 100, 0 is unchanged \param Lightness -100 to 100, 0 is unchanged + \param blimit one byte past the end of data EMF+ manual 2.2.3.7, Microsoft name: HueSaturationLightnessEffect Object */ -int U_PMF_IE_HUESATURATIONLIGHTNESS_get(const char *contents, int32_t *Hue, int32_t *Saturation, int32_t *Lightness){ - if(!contents || !Hue || !Saturation || !Lightness){ return(0); } +int U_PMF_IE_HUESATURATIONLIGHTNESS_get(const char *contents, int32_t *Hue, int32_t *Saturation, int32_t *Lightness, const char *blimit){ + if(!contents || !Hue || !Saturation || !Lightness || !blimit){ return(0); } + if(IS_MEM_UNSAFE(contents, sizeof(U_PMF_IE_HUESATURATIONLIGHTNESS), blimit))return(0); U_PMF_SERIAL_get(&contents, Hue, 4, 1, U_LE); U_PMF_SERIAL_get(&contents, Saturation, 4, 1, U_LE); U_PMF_SERIAL_get(&contents, Lightness, 4, 1, U_LE); @@ -6705,11 +6994,13 @@ int U_PMF_IE_HUESATURATIONLIGHTNESS_get(const char *contents, int32_t *Hue, int3 \param Highlight 0 to 100, 100 is unchanged \param Midtone -100 to 100, 0 is unchanged \param Shadow 0 to 100, 0 is unchanged + \param blimit one byte past the end of data EMF+ manual 2.2.3.8, Microsoft name: LevelsEffect Object */ -int U_PMF_IE_LEVELS_get(const char *contents, int32_t *Highlight, int32_t *Midtone, int32_t *Shadow){ - if(!contents || !Highlight || !Midtone || !Shadow){ return(0); } +int U_PMF_IE_LEVELS_get(const char *contents, int32_t *Highlight, int32_t *Midtone, int32_t *Shadow, const char *blimit){ + if(!contents || !Highlight || !Midtone || !Shadow || !blimit){ return(0); } + if(IS_MEM_UNSAFE(contents, sizeof(U_PMF_IE_LEVELS), blimit))return(0); U_PMF_SERIAL_get(&contents, Highlight, 4, 1, U_LE); U_PMF_SERIAL_get(&contents, Midtone, 4, 1, U_LE); U_PMF_SERIAL_get(&contents, Shadow, 4, 1, U_LE); @@ -6722,12 +7013,15 @@ int U_PMF_IE_LEVELS_get(const char *contents, int32_t *Highlight, int32_t *Midto \param contents Record from which to extract data \param Elements Number of members in Rects \param Rects Caller must free. Pointer to memory holding an array of U_RECTL. + \param blimit one byte past the end of data EMF+ manual 2.2.3.9, Microsoft name: RedEyeCorrectionEffect Object */ -int U_PMF_IE_REDEYECORRECTION_get(const char *contents, int32_t *Elements, U_RECTL **Rects){ - if(!contents || !Elements || !Rects){ return(0); } +int U_PMF_IE_REDEYECORRECTION_get(const char *contents, int32_t *Elements, U_RECTL **Rects, const char *blimit){ + if(!contents || !Elements || !Rects || !blimit){ return(0); } + if(IS_MEM_UNSAFE(contents, sizeof(U_PMF_IE_REDEYECORRECTION), blimit))return(0); U_PMF_SERIAL_get(&contents, Elements, 4, 1, U_LE); + if(IS_MEM_UNSAFE(contents, *Elements * 4, blimit))return(0); *Rects = (U_RECTL *) malloc(*Elements * sizeof(U_RECTL)); if(!*Rects){ return(0); } U_PMF_SERIAL_get(&contents, *Rects, 4, *Elements * 4, U_LE); @@ -6740,11 +7034,13 @@ int U_PMF_IE_REDEYECORRECTION_get(const char *contents, int32_t *Elements, U_REC \param contents Record from which to extract data \param Radius Sharpening radius in pixels \param Sharpen 0 to 100, 0 is unchanged + \param blimit one byte past the end of data EMF+ manual 2.2.3.10, Microsoft name: SharpenEffect Object */ -int U_PMF_IE_SHARPEN_get(const char *contents, U_FLOAT *Radius, int32_t *Sharpen){ - if(!contents || !Radius || !Sharpen){ return(0); } +int U_PMF_IE_SHARPEN_get(const char *contents, U_FLOAT *Radius, int32_t *Sharpen, const char *blimit){ + if(!contents || !Radius || !Sharpen || !blimit){ return(0); } + if(IS_MEM_UNSAFE(contents, sizeof(U_PMF_IE_SHARPEN), blimit))return(0); U_PMF_SERIAL_get(&contents, Radius, 4, 1, U_LE); U_PMF_SERIAL_get(&contents, Sharpen, 4, 1, U_LE); return(1); @@ -6756,16 +7052,51 @@ int U_PMF_IE_SHARPEN_get(const char *contents, U_FLOAT *Radius, int32_t *Sharpen \param contents Record from which to extract data \param Hue -180 to 180, [positive==clockwise] rotation in degrees starting from blue \param Amount -100 [add black] to 100[add white], 0 is unchanged. Change in hue on specified axis + \param blimit one byte past the end of data EMF+ manual 2.2.3.11, Microsoft name: TintEffect Object */ -int U_PMF_IE_TINT_get(const char *contents, int32_t *Hue, int32_t *Amount){ - if(!contents || !Hue || !Amount){ return(0); } +int U_PMF_IE_TINT_get(const char *contents, int32_t *Hue, int32_t *Amount, const char *blimit){ + if(!contents || !Hue || !Amount || !blimit){ return(0); } + if(IS_MEM_UNSAFE(contents, sizeof(U_PMF_IE_TINT), blimit))return(0); U_PMF_SERIAL_get(&contents, Hue, 4, 1, U_LE); U_PMF_SERIAL_get(&contents, Amount, 4, 1, U_LE); return(1); } +/* + + end of U_PMF_*_get() functions + ===================================================================================== + start of U_PMR_*_get() functions + + These functions all assume that the size field in the common EMF+ header has already + been checked, so that the extent the record claims exists in the data read in for the file. + Consequently none of them takes a blimit parameter. They generate a new one from the + header size field and contents if needed. + +*/ + +int U_PMR_common_stack_get(const char *contents, U_PMF_CMN_HDR *Header, uint32_t *StackID){ + if(!contents || !StackID){ return(0); } + + U_PMF_CMN_HDR lclHeader; + U_PMF_CMN_HDR_get(&contents, &lclHeader); + if(lclHeader.Size < sizeof(U_PMF_RESTORE))return(0); + if(Header){ memcpy(Header,&lclHeader,sizeof(U_PMF_CMN_HDR)); } + + U_PMF_SERIAL_get(&contents, StackID, 4, 1, U_LE); + return(1); +} + +/* for records that have a type but no associated flag bits or data */ +int U_PMR_common_header_get(const char *contents, U_PMF_CMN_HDR *Header){ + /* memory access safe, only uses the common header */ + if(!contents){ return(0); } + U_PMF_CMN_HDR_get(&contents, Header); + return(1); +} + /** \brief Get data from a U_PMR_OFFSETCLIP record \return 1 on success, 0 on error @@ -6779,7 +7110,12 @@ int U_PMF_IE_TINT_get(const char *contents, int32_t *Hue, int32_t *Amount){ int U_PMR_OFFSETCLIP_get(const char *contents, U_PMF_CMN_HDR *Header, U_FLOAT *dX, U_FLOAT *dY){ if(!contents){ return(0); } - U_PMF_CMN_HDR_get(&contents, Header); + + U_PMF_CMN_HDR lclHeader; + U_PMF_CMN_HDR_get(&contents, &lclHeader); + if(lclHeader.Size < sizeof(U_PMF_OFFSETCLIP))return(0); + if(Header){ memcpy(Header,&lclHeader,sizeof(U_PMF_CMN_HDR)); } + U_PMF_SERIAL_get(&contents, dX, 4, 1, U_LE); U_PMF_SERIAL_get(&contents, dY, 4, 1, U_LE); return(1); @@ -6812,10 +7148,14 @@ int U_PMR_RESETCLIP_get(const char *contents, U_PMF_CMN_HDR *Header){ int U_PMR_SETCLIPPATH_get(const char *contents, U_PMF_CMN_HDR *Header, uint32_t *PathID, int *CMenum){ if(!contents || !PathID || !CMenum){ return(0); } - uint16_t Flags = U_PMF_HEADERFLAGS_get(contents); - *CMenum = (Flags >> U_FF_SHFT_CM4) & U_FF_MASK_CM4; - *PathID = (Flags >> U_FF_SHFT_OID8) & U_FF_MASK_OID8; - U_PMF_CMN_HDR_get(&contents, Header); + + U_PMF_CMN_HDR lclHeader; + U_PMF_CMN_HDR_get(&contents, &lclHeader); + if(lclHeader.Size < sizeof(U_PMF_SETCLIPPATH))return(0); + if(Header){ memcpy(Header,&lclHeader,sizeof(U_PMF_CMN_HDR)); } + + *CMenum = (lclHeader.Flags >> U_FF_SHFT_CM4) & U_FF_MASK_CM4; + *PathID = (lclHeader.Flags >> U_FF_SHFT_OID8) & U_FF_MASK_OID8; return(1); } @@ -6833,9 +7173,13 @@ int U_PMR_SETCLIPRECT_get(const char *contents, U_PMF_CMN_HDR *Header, int *CMenum, U_PMF_RECTF *Rect){ if(!contents || !CMenum || !Rect ){ return(0); } - uint16_t Flags = U_PMF_HEADERFLAGS_get(contents); - *CMenum = (Flags >> U_FF_SHFT_CM4) & U_FF_MASK_CM4; - U_PMF_CMN_HDR_get(&contents, Header); + + U_PMF_CMN_HDR lclHeader; + U_PMF_CMN_HDR_get(&contents, &lclHeader); + if(lclHeader.Size < sizeof(U_PMF_SETCLIPRECT))return(0); + if(Header){ memcpy(Header,&lclHeader,sizeof(U_PMF_CMN_HDR)); } + + *CMenum = (lclHeader.Flags >> U_FF_SHFT_CM4) & U_FF_MASK_CM4; U_PMF_SERIAL_get(&contents, Rect, 4, 4, U_LE); return(1); } @@ -6853,10 +7197,14 @@ int U_PMR_SETCLIPRECT_get(const char *contents, U_PMF_CMN_HDR *Header, int U_PMR_SETCLIPREGION_get(const char *contents, U_PMF_CMN_HDR *Header, uint32_t *PathID, int *CMenum){ if(!contents || !PathID || !CMenum){ return(0); } - uint16_t Flags = U_PMF_HEADERFLAGS_get(contents); - *CMenum = (Flags >> U_FF_SHFT_CM4) & U_FF_MASK_CM4; - *PathID = (Flags >> U_FF_SHFT_OID8) & U_FF_MASK_OID8; - U_PMF_CMN_HDR_get(&contents, Header); + + U_PMF_CMN_HDR lclHeader; + U_PMF_CMN_HDR_get(&contents, &lclHeader); + if(lclHeader.Size < sizeof(U_PMF_SETCLIPREGION))return(0); + if(Header){ memcpy(Header,&lclHeader,sizeof(U_PMF_CMN_HDR)); } + + *CMenum = (lclHeader.Flags >> U_FF_SHFT_CM4) & U_FF_MASK_CM4; + *PathID = (lclHeader.Flags >> U_FF_SHFT_OID8) & U_FF_MASK_OID8; return(1); } @@ -6868,11 +7216,18 @@ int U_PMR_SETCLIPREGION_get(const char *contents, U_PMF_CMN_HDR *Header, \param Data Private data, may be anything EMF+ manual 2.3.2.1, Microsoft name: EmfPlusComment Record, Index 0x03 + + Caller must check Data for possible memory access violations. */ int U_PMR_COMMENT_get(const char *contents, U_PMF_CMN_HDR *Header, const char **Data){ if(!contents || !Data){ return(0); } - U_PMF_CMN_HDR_get(&contents, Header); + + U_PMF_CMN_HDR lclHeader; + U_PMF_CMN_HDR_get(&contents, &lclHeader); + if(lclHeader.Size < sizeof(U_PMF_COMMENT))return(0); + if(Header){ memcpy(Header,&lclHeader,sizeof(U_PMF_CMN_HDR)); } + U_PMF_PTRSAV_SHIFT(Data, &contents, 0); return(1); } @@ -6922,9 +7277,13 @@ int U_PMR_HEADER_get(const char *contents, U_PMF_CMN_HDR *Header, U_PMF_GRAPHICSVERSION *Version, int *IsDual, int *IsVideo, uint32_t *LogicalDpiX, uint32_t *LogicalDpiY){ if(!contents || !Version || !IsDual || !IsVideo || !LogicalDpiX || !LogicalDpiY){ return(0); } uint32_t tmp; - uint16_t Flags = U_PMF_HEADERFLAGS_get(contents); - *IsDual = (Flags & U_PPF_DM ? 1 : 0 ); - U_PMF_CMN_HDR_get(&contents, Header); + + U_PMF_CMN_HDR lclHeader; + U_PMF_CMN_HDR_get(&contents, &lclHeader); + if(lclHeader.Size < sizeof(U_PMF_HEADER))return(0); + if(Header){ memcpy(Header,&lclHeader,sizeof(U_PMF_CMN_HDR)); } + + *IsDual = (lclHeader.Flags & U_PPF_DM ? 1 : 0 ); U_PMF_SERIAL_get(&contents, Version, 4, 1, U_LE); U_PMF_SERIAL_get(&contents, &tmp, 4, 1, U_LE); U_PMF_SERIAL_get(&contents, LogicalDpiX, 4, 1, U_LE); @@ -6945,7 +7304,12 @@ int U_PMR_HEADER_get(const char *contents, U_PMF_CMN_HDR *Header, int U_PMR_CLEAR_get(const char *contents, U_PMF_CMN_HDR *Header, U_PMF_ARGB *Color){ if(!contents || !Color){ return(0); } - U_PMF_CMN_HDR_get(&contents, Header); + + U_PMF_CMN_HDR lclHeader; + U_PMF_CMN_HDR_get(&contents, &lclHeader); + if(lclHeader.Size < sizeof(U_PMF_CLEAR))return(0); + if(Header){ memcpy(Header,&lclHeader,sizeof(U_PMF_CMN_HDR)); } + U_PMF_SERIAL_get(&contents, Color, 4, 1, U_LE); return(1); } @@ -6968,16 +7332,26 @@ int U_PMR_DRAWARC_get(const char *contents, U_PMF_CMN_HDR *Header, U_FLOAT *Start, U_FLOAT *Sweep, U_PMF_RECTF *Rect){ if(!contents || !PenID || !ctype || !Start || !Sweep || !Rect){ return(0); } - uint16_t Flags = U_PMF_HEADERFLAGS_get(contents); - *ctype = (Flags & U_PPF_C ? 1 : 0 ); - *PenID = (Flags >> U_FF_SHFT_OID8) & U_FF_MASK_OID8; - U_PMF_CMN_HDR_get(&contents, Header); + + const char *blimit = contents; + U_PMF_CMN_HDR lclHeader; + U_PMF_CMN_HDR_get(&contents, &lclHeader); + if(lclHeader.Size < sizeof(U_PMF_DRAWARC))return(0); + if(Header){ memcpy(Header,&lclHeader,sizeof(U_PMF_CMN_HDR)); } + blimit += lclHeader.Size; + + *ctype = (lclHeader.Flags & U_PPF_C ? 1 : 0 ); + *PenID = (lclHeader.Flags >> U_FF_SHFT_OID8) & U_FF_MASK_OID8; U_PMF_SERIAL_get(&contents, Start, 4, 1, U_LE); U_PMF_SERIAL_get(&contents, Sweep, 4, 1, U_LE); - U_PMF_SERIAL_get(&contents, Rect, 4, 4, U_LE); + U_PMF_RECTF *Rects = NULL; + if(!U_PMF_VARRECTS_get(&contents, lclHeader.Flags, 1, &Rects, blimit))return(0); + memcpy(Rect,Rects,sizeof(U_PMF_RECTF)); + free(Rects); return(1); } + /** \brief Get data from a U_PMR_DRAWBEZIERS record \return 1 on success, 0 on error @@ -6996,14 +7370,20 @@ int U_PMR_DRAWBEZIERS_get(const char *contents, U_PMF_CMN_HDR *Header, uint32_t *Elements, U_PMF_POINTF **Points){ if(!contents || !PenID || !ctype || !RelAbs || !Elements || !Points){ return(0); } - uint16_t Flags = U_PMF_HEADERFLAGS_get(contents); - *ctype = (Flags & U_PPF_C ? 1 : 0 ); - *RelAbs = (Flags & U_PPF_P ? 1 : 0 ); - *PenID = (Flags >> U_FF_SHFT_OID8) & U_FF_MASK_OID8; - U_PMF_CMN_HDR_get(&contents, Header); + + const char *blimit = contents; + U_PMF_CMN_HDR lclHeader; + U_PMF_CMN_HDR_get(&contents, &lclHeader); + if(lclHeader.Size < sizeof(U_PMF_DRAWBEZIERS))return(0); + if(Header){ memcpy(Header,&lclHeader,sizeof(U_PMF_CMN_HDR)); } + blimit += lclHeader.Size; + + *ctype = (lclHeader.Flags & U_PPF_C ? 1 : 0 ); + *RelAbs = (lclHeader.Flags & U_PPF_P ? 1 : 0 ); + *PenID = (lclHeader.Flags >> U_FF_SHFT_OID8) & U_FF_MASK_OID8; U_PMF_SERIAL_get(&contents, Elements, 4, 1, U_LE); - U_PMF_VARPOINTS_get(&contents, Flags, *Elements, Points); - return(1); + int status = U_PMF_VARPOINTS_get(contents, lclHeader.Flags, *Elements, Points, blimit ); + return(status); } /** @@ -7025,14 +7405,20 @@ int U_PMR_DRAWCLOSEDCURVE_get(const char *contents, U_PMF_CMN_HDR *Header, U_FLOAT *Tension, uint32_t *Elements, U_PMF_POINTF **Points){ if(!contents || !PenID || !ctype || !RelAbs || !Tension || !Elements || !Points){ return(0); } - uint16_t Flags = U_PMF_HEADERFLAGS_get(contents); - *ctype = (Flags & U_PPF_C ? 1 : 0 ); - *RelAbs = (Flags & U_PPF_P ? 1 : 0 ); - *PenID = (Flags >> U_FF_SHFT_OID8) & U_FF_MASK_OID8; - U_PMF_CMN_HDR_get(&contents, Header); + + const char *blimit = contents; + U_PMF_CMN_HDR lclHeader; + U_PMF_CMN_HDR_get(&contents, &lclHeader); + if(lclHeader.Size < sizeof(U_PMF_DRAWCLOSEDCURVE))return(0); + if(Header){ memcpy(Header,&lclHeader,sizeof(U_PMF_CMN_HDR)); } + blimit += lclHeader.Size; + + *ctype = (lclHeader.Flags & U_PPF_C ? 1 : 0 ); + *RelAbs = (lclHeader.Flags & U_PPF_P ? 1 : 0 ); + *PenID = (lclHeader.Flags >> U_FF_SHFT_OID8) & U_FF_MASK_OID8; U_PMF_SERIAL_get(&contents, Tension, 4, 1, U_LE); U_PMF_SERIAL_get(&contents, Elements, 4, 1, U_LE); - U_PMF_VARPOINTS_get(&contents, Flags, *Elements, Points); + U_PMF_VARPOINTS_get(contents, lclHeader.Flags, *Elements, Points, blimit); return(1); } @@ -7056,15 +7442,21 @@ int U_PMR_DRAWCURVE_get(const char *contents, U_PMF_CMN_HDR *Header, U_FLOAT *Tension, uint32_t *Offset, uint32_t *NSegs, uint32_t *Elements, U_PMF_POINTF **Points){ if(!contents || !PenID || !ctype || !Tension || !Offset || !NSegs || !Elements || !Points){ return(0); } - uint16_t Flags = U_PMF_HEADERFLAGS_get(contents); - *ctype = (Flags & U_PPF_C ? 1 : 0 ); - *PenID = (Flags >> U_FF_SHFT_OID8) & U_FF_MASK_OID8; - U_PMF_CMN_HDR_get(&contents, Header); + + const char *blimit = contents; + U_PMF_CMN_HDR lclHeader; + U_PMF_CMN_HDR_get(&contents, &lclHeader); + if(lclHeader.Size < sizeof(U_PMF_DRAWCURVE))return(0); + if(Header){ memcpy(Header,&lclHeader,sizeof(U_PMF_CMN_HDR)); } + blimit += lclHeader.Size; + + *ctype = (lclHeader.Flags & U_PPF_C ? 1 : 0 ); + *PenID = (lclHeader.Flags >> U_FF_SHFT_OID8) & U_FF_MASK_OID8; U_PMF_SERIAL_get(&contents, Tension, 4, 1, U_LE); U_PMF_SERIAL_get(&contents, Offset, 4, 1, U_LE); U_PMF_SERIAL_get(&contents, NSegs, 4, 1, U_LE); U_PMF_SERIAL_get(&contents, Elements, 4, 1, U_LE); - U_PMF_VARPOINTS_get(&contents, Flags, *Elements, Points); + U_PMF_VARPOINTS_get(contents, lclHeader.Flags, *Elements, Points, blimit); return(1); } @@ -7092,15 +7484,22 @@ int U_PMR_DRAWDRIVERSTRING_get(const char *contents, U_PMF_CMN_HDR *Header, uint16_t **Glyphs, U_PMF_POINTF **Points, U_PMF_TRANSFORMMATRIX **Matrix){ if(!contents || !FontID || !btype || !Tension || !BrushID || !DSOFlags || !HasMatrix || !Elements || !Glyphs || !Points || !Matrix){ return(0); } - uint16_t Flags = U_PMF_HEADERFLAGS_get(contents); - *btype = (Flags & U_PPF_B ? 1 : 0 ); - *FontID = (Flags >> U_FF_SHFT_OID8) & U_FF_MASK_OID8; - U_PMF_CMN_HDR_get(&contents, Header); + + const char *blimit = contents; + U_PMF_CMN_HDR lclHeader; + U_PMF_CMN_HDR_get(&contents, &lclHeader); + if(lclHeader.Size < sizeof(U_PMF_DRAWDRIVERSTRING))return(0); + if(Header){ memcpy(Header,&lclHeader,sizeof(U_PMF_CMN_HDR)); } + blimit += lclHeader.Size; + + *btype = (lclHeader.Flags & U_PPF_B ? 1 : 0 ); + *FontID = (lclHeader.Flags >> U_FF_SHFT_OID8) & U_FF_MASK_OID8; U_PMF_SERIAL_get(&contents, Tension, 4, 1, U_LE); U_PMF_SERIAL_get(&contents, BrushID, 4, 1, (*btype ? U_XE : U_LE)); /* color is not byte swapped, ID integer is */ U_PMF_SERIAL_get(&contents, DSOFlags, 4, 1, U_LE); U_PMF_SERIAL_get(&contents, HasMatrix, 4, 1, U_LE); U_PMF_SERIAL_get(&contents, Elements, 4, 1, U_LE); + if(IS_MEM_UNSAFE(contents, *Elements*2 + *Elements*2*4 + 24, blimit))return(0); if(!U_PMF_SERIAL_array_copy_get(&contents, (void **)Glyphs, 2, *Elements, U_LE, (*DSOFlags & U_DSO_CmapLookup))){ return(0); } if(!U_PMF_SERIAL_array_copy_get(&contents, (void **)Points, 4, *Elements *2, U_LE, (*DSOFlags & U_DSO_RealizedAdvance))){ return(0); } if(!U_PMF_SERIAL_array_copy_get(&contents, (void **)Matrix, 4, 6, U_LE, (*HasMatrix))){ return(0); } @@ -7122,10 +7521,14 @@ int U_PMR_DRAWELLIPSE_get(const char *contents, U_PMF_CMN_HDR *Header, uint32_t *PenID, int *ctype, U_PMF_RECTF *Rect){ if(!contents || !PenID || !ctype || !Rect){ return(0); } - uint16_t Flags = U_PMF_HEADERFLAGS_get(contents); - *ctype = (Flags & U_PPF_C ? 1 : 0 ); - *PenID = (Flags >> U_FF_SHFT_OID8) & U_FF_MASK_OID8; - U_PMF_CMN_HDR_get(&contents, Header); + + U_PMF_CMN_HDR lclHeader; + U_PMF_CMN_HDR_get(&contents, &lclHeader); + if(lclHeader.Size < sizeof(U_PMF_DRAWELLIPSE))return(0); + if(Header){ memcpy(Header,&lclHeader,sizeof(U_PMF_CMN_HDR)); } + + *ctype = (lclHeader.Flags & U_PPF_C ? 1 : 0 ); + *PenID = (lclHeader.Flags >> U_FF_SHFT_OID8) & U_FF_MASK_OID8; U_PMF_SERIAL_get(&contents, Rect, 4, 4, U_LE); return(1); } @@ -7149,10 +7552,14 @@ int U_PMR_DRAWIMAGE_get(const char *contents, U_PMF_CMN_HDR *Header, uint32_t *ImgAttrID, int32_t *SrcUnit, U_PMF_RECTF *SrcRect, U_PMF_RECTF *DstRect){ if(!contents || !ImgID || !ctype || !ImgAttrID || !SrcUnit || !SrcRect || !DstRect){ return(0); } - uint16_t Flags = U_PMF_HEADERFLAGS_get(contents); - *ctype = (Flags & U_PPF_C ? 1 : 0 ); - *ImgID = (Flags >> U_FF_SHFT_OID8) & U_FF_MASK_OID8; - U_PMF_CMN_HDR_get(&contents, Header); + + U_PMF_CMN_HDR lclHeader; + U_PMF_CMN_HDR_get(&contents, &lclHeader); + if(lclHeader.Size < sizeof(U_PMF_DRAWIMAGE))return(0); + if(Header){ memcpy(Header,&lclHeader,sizeof(U_PMF_CMN_HDR)); } + + *ctype = (lclHeader.Flags & U_PPF_C ? 1 : 0 ); + *ImgID = (lclHeader.Flags >> U_FF_SHFT_OID8) & U_FF_MASK_OID8; U_PMF_SERIAL_get(&contents, ImgAttrID, 4, 1, U_LE); U_PMF_SERIAL_get(&contents, SrcUnit, 4, 1, U_LE); U_PMF_SERIAL_get(&contents, SrcRect, 4, 4, U_LE); @@ -7182,17 +7589,23 @@ int U_PMR_DRAWIMAGEPOINTS_get(const char *contents, U_PMF_CMN_HDR *Header, uint32_t *ImgAttrID, int32_t *SrcUnit, U_PMF_RECTF *SrcRect, uint32_t *Elements, U_PMF_POINTF **Points){ if(!contents || !ImgID || !ctype || !etype || !RelAbs || !ImgAttrID || !SrcUnit || !Elements || !Points){ return(0); } - uint16_t Flags = U_PMF_HEADERFLAGS_get(contents); - *ctype = (Flags & U_PPF_C ? 1 : 0 ); - *etype = (Flags & U_PPF_E ? 1 : 0 ); - *RelAbs = (Flags & U_PPF_P ? 1 : 0 ); - *ImgID = (Flags >> U_FF_SHFT_OID8) & U_FF_MASK_OID8; - U_PMF_CMN_HDR_get(&contents, Header); + + const char *blimit = contents; + U_PMF_CMN_HDR lclHeader; + U_PMF_CMN_HDR_get(&contents, &lclHeader); + if(lclHeader.Size < sizeof(U_PMF_DRAWIMAGEPOINTS))return(0); + if(Header){ memcpy(Header,&lclHeader,sizeof(U_PMF_CMN_HDR)); } + blimit += lclHeader.Size; + + *ctype = (lclHeader.Flags & U_PPF_C ? 1 : 0 ); + *etype = (lclHeader.Flags & U_PPF_E ? 1 : 0 ); + *RelAbs = (lclHeader.Flags & U_PPF_P ? 1 : 0 ); + *ImgID = (lclHeader.Flags >> U_FF_SHFT_OID8) & U_FF_MASK_OID8; U_PMF_SERIAL_get(&contents, ImgAttrID, 4, 1, U_LE); U_PMF_SERIAL_get(&contents, SrcUnit, 4, 1, U_LE); U_PMF_SERIAL_get(&contents, SrcRect, 4, 4, U_LE); U_PMF_SERIAL_get(&contents, Elements, 4, 1, U_LE); - U_PMF_VARPOINTS_get(&contents, Flags, *Elements, Points); + U_PMF_VARPOINTS_get(contents, lclHeader.Flags, *Elements, Points, blimit); return(1); } @@ -7215,14 +7628,20 @@ int U_PMR_DRAWLINES_get(const char *contents, U_PMF_CMN_HDR *Header, uint32_t *Elements, U_PMF_POINTF **Points){ if(!contents || !PenID || !ctype || !dtype || !RelAbs || !Elements || !Points){ return(0); } - uint16_t Flags = U_PMF_HEADERFLAGS_get(contents); - *ctype = (Flags & U_PPF_C ? 1 : 0 ); - *dtype = (Flags & U_PPF_D ? 1 : 0 ); - *RelAbs = (Flags & U_PPF_P ? 1 : 0 ); - *PenID = (Flags >> U_FF_SHFT_OID8) & U_FF_MASK_OID8; - U_PMF_CMN_HDR_get(&contents, Header); + + const char *blimit = contents; + U_PMF_CMN_HDR lclHeader; + U_PMF_CMN_HDR_get(&contents, &lclHeader); + if(lclHeader.Size < sizeof(U_PMF_DRAWLINES))return(0); + if(Header){ memcpy(Header,&lclHeader,sizeof(U_PMF_CMN_HDR)); } + blimit += lclHeader.Size; + + *ctype = (lclHeader.Flags & U_PPF_C ? 1 : 0 ); + *dtype = (lclHeader.Flags & U_PPF_D ? 1 : 0 ); + *RelAbs = (lclHeader.Flags & U_PPF_P ? 1 : 0 ); + *PenID = (lclHeader.Flags >> U_FF_SHFT_OID8) & U_FF_MASK_OID8; U_PMF_SERIAL_get(&contents, Elements, 4, 1, U_LE); - U_PMF_VARPOINTS_get(&contents, Flags, *Elements, Points); + U_PMF_VARPOINTS_get(contents, lclHeader.Flags, *Elements, Points, blimit); return(1); } @@ -7239,9 +7658,13 @@ int U_PMR_DRAWLINES_get(const char *contents, U_PMF_CMN_HDR *Header, int U_PMR_DRAWPATH_get(const char *contents, U_PMF_CMN_HDR *Header, uint32_t *PathID, uint32_t *PenID){ if(!contents || !PathID || !PenID){ return(0); } - uint16_t Flags = U_PMF_HEADERFLAGS_get(contents); - *PathID = (Flags >> U_FF_SHFT_OID8) & U_FF_MASK_OID8; - U_PMF_CMN_HDR_get(&contents, Header); + + U_PMF_CMN_HDR lclHeader; + U_PMF_CMN_HDR_get(&contents, &lclHeader); + if(lclHeader.Size < sizeof(U_PMF_DRAWPATH))return(0); + if(Header){ memcpy(Header,&lclHeader,sizeof(U_PMF_CMN_HDR)); } + + *PathID = (lclHeader.Flags >> U_FF_SHFT_OID8) & U_FF_MASK_OID8; U_PMF_SERIAL_get(&contents, PenID, 4, 1, U_LE); return(1); } @@ -7264,13 +7687,22 @@ int U_PMR_DRAWPIE_get(const char *contents, U_PMF_CMN_HDR *Header, U_FLOAT *Start, U_FLOAT *Sweep, U_PMF_RECTF *Rect){ if(!contents || !PenID || !ctype || !Start || !Sweep || !Rect){ return(0); } - uint16_t Flags = U_PMF_HEADERFLAGS_get(contents); - *ctype = (Flags & U_PPF_C ? 1 : 0 ); - *PenID = (Flags >> U_FF_SHFT_OID8) & U_FF_MASK_OID8; - U_PMF_CMN_HDR_get(&contents, Header); + + const char *blimit = contents; + U_PMF_CMN_HDR lclHeader; + U_PMF_CMN_HDR_get(&contents, &lclHeader); + if(lclHeader.Size < sizeof(U_PMF_DRAWPIE))return(0); + if(Header){ memcpy(Header,&lclHeader,sizeof(U_PMF_CMN_HDR)); } + blimit += lclHeader.Size; + + *ctype = (lclHeader.Flags & U_PPF_C ? 1 : 0 ); + *PenID = (lclHeader.Flags >> U_FF_SHFT_OID8) & U_FF_MASK_OID8; U_PMF_SERIAL_get(&contents, Start, 4, 1, U_LE); U_PMF_SERIAL_get(&contents, Sweep, 4, 1, U_LE); - U_PMF_SERIAL_get(&contents, Rect, 4, 4, U_LE); + U_PMF_RECTF *Rects = NULL; + if(!U_PMF_VARRECTS_get(&contents, lclHeader.Flags, 1, &Rects, blimit))return(0); + memcpy(Rect,Rects,sizeof(U_PMF_RECTF)); + free(Rects); return(1); } @@ -7294,12 +7726,18 @@ int U_PMR_DRAWRECTS_get(const char *contents, U_PMF_CMN_HDR *Header, uint32_t *Elements, U_PMF_RECTF **Rects){ if(!contents || !PenID || !Elements || !Rects){ return(0); } - uint16_t Flags = U_PMF_HEADERFLAGS_get(contents); - *PenID = (Flags >> U_FF_SHFT_OID8) & U_FF_MASK_OID8; - *ctype = (Flags & U_PPF_C ? 1 : 0 ); - U_PMF_CMN_HDR_get(&contents, Header); + + const char *blimit = contents; + U_PMF_CMN_HDR lclHeader; + U_PMF_CMN_HDR_get(&contents, &lclHeader); + if(lclHeader.Size < sizeof(U_PMF_DRAWPIE))return(0); + if(Header){ memcpy(Header,&lclHeader,sizeof(U_PMF_CMN_HDR)); } + blimit += lclHeader.Size; + + *PenID = (lclHeader.Flags >> U_FF_SHFT_OID8) & U_FF_MASK_OID8; + *ctype = (lclHeader.Flags & U_PPF_C ? 1 : 0 ); U_PMF_SERIAL_get(&contents, Elements, 4, 1, U_LE); - U_PMF_VARRECTS_get(&contents, Flags, *Elements, Rects); + U_PMF_VARRECTS_get(&contents, lclHeader.Flags, *Elements, Rects, blimit); return(1); } @@ -7323,14 +7761,21 @@ int U_PMR_DRAWSTRING_get(const char *contents, U_PMF_CMN_HDR *Header, uint32_t *BrushID, uint32_t *FormatID, uint32_t *Elements, U_PMF_RECTF *Rect, uint16_t **String){ if(!contents || !FontID || !btype || !BrushID || !FormatID || !Elements || !String){ return(0); } - uint16_t Flags = U_PMF_HEADERFLAGS_get(contents); - *btype = (Flags & U_PPF_B ? 1 : 0 ); - *FontID = (Flags >> U_FF_SHFT_OID8) & U_FF_MASK_OID8; - U_PMF_CMN_HDR_get(&contents, Header); + + const char *blimit = contents; + U_PMF_CMN_HDR lclHeader; + U_PMF_CMN_HDR_get(&contents, &lclHeader); + if(lclHeader.Size < sizeof(U_PMF_DRAWPIE))return(0); + if(Header){ memcpy(Header,&lclHeader,sizeof(U_PMF_CMN_HDR)); } + blimit += lclHeader.Size; + + *btype = (lclHeader.Flags & U_PPF_B ? 1 : 0 ); + *FontID = (lclHeader.Flags >> U_FF_SHFT_OID8) & U_FF_MASK_OID8; U_PMF_SERIAL_get(&contents, BrushID, 4, 1, (*btype ? U_XE : U_LE)); /* color is not byte swapped, ID integer is */ U_PMF_SERIAL_get(&contents, FormatID, 4, 1, U_LE); U_PMF_SERIAL_get(&contents, Elements, 4, 1, U_LE); U_PMF_SERIAL_get(&contents, Rect, 4, 4, U_LE); + if(IS_MEM_UNSAFE(contents, *Elements * 2, blimit))return(0); if(!U_PMF_SERIAL_array_copy_get(&contents, (void **)String, 2, *Elements, U_XE, 1)){ return(0); } return(1); } @@ -7356,16 +7801,22 @@ int U_PMR_FILLCLOSEDCURVE_get(const char *contents, U_PMF_CMN_HDR *Header, uint32_t *BrushID, U_FLOAT *Tension, uint32_t *Elements, U_PMF_POINTF **Points){ if(!contents || !btype || !ctype || !ftype || !RelAbs || !BrushID || !Tension || !Elements || !Points){ return(0); } - uint16_t Flags = U_PMF_HEADERFLAGS_get(contents); - *btype = (Flags & U_PPF_B ? 1 : 0 ); - *ctype = (Flags & U_PPF_C ? 1 : 0 ); - *ftype = (Flags & U_PPF_F ? 1 : 0 ); - *RelAbs = (Flags & U_PPF_P ? 1 : 0 ); - U_PMF_CMN_HDR_get(&contents, Header); + + const char *blimit = contents; + U_PMF_CMN_HDR lclHeader; + U_PMF_CMN_HDR_get(&contents, &lclHeader); + if(lclHeader.Size < sizeof(U_PMF_DRAWLINES))return(0); + if(Header){ memcpy(Header,&lclHeader,sizeof(U_PMF_CMN_HDR)); } + blimit += lclHeader.Size; + + *btype = (lclHeader.Flags & U_PPF_B ? 1 : 0 ); + *ctype = (lclHeader.Flags & U_PPF_C ? 1 : 0 ); + *ftype = (lclHeader.Flags & U_PPF_F ? 1 : 0 ); + *RelAbs = (lclHeader.Flags & U_PPF_P ? 1 : 0 ); U_PMF_SERIAL_get(&contents, BrushID, 4, 1, (*btype ? U_XE : U_LE)); /* color is not byte swapped, ID integer is */ U_PMF_SERIAL_get(&contents, Tension, 4, 1, U_LE); U_PMF_SERIAL_get(&contents, Elements, 4, 1, U_LE); - U_PMF_VARPOINTS_get(&contents, Flags, *Elements, Points); + U_PMF_VARPOINTS_get(contents, lclHeader.Flags, *Elements, Points, blimit); return(1); } @@ -7386,10 +7837,14 @@ int U_PMR_FILLELLIPSE_get(const char *contents, U_PMF_CMN_HDR *Header, uint32_t *BrushID, U_PMF_RECTF *Rect){ if(!contents || !btype || !ctype || !BrushID || !Rect){ return(0); } - uint16_t Flags = U_PMF_HEADERFLAGS_get(contents); - *btype = (Flags & U_PPF_B ? 1 : 0 ); - *ctype = (Flags & U_PPF_C ? 1 : 0 ); - U_PMF_CMN_HDR_get(&contents, Header); + + U_PMF_CMN_HDR lclHeader; + U_PMF_CMN_HDR_get(&contents, &lclHeader); + if(lclHeader.Size < sizeof(U_PMF_FILLELLIPSE))return(0); + if(Header){ memcpy(Header,&lclHeader,sizeof(U_PMF_CMN_HDR)); } + + *btype = (lclHeader.Flags & U_PPF_B ? 1 : 0 ); + *ctype = (lclHeader.Flags & U_PPF_C ? 1 : 0 ); U_PMF_SERIAL_get(&contents, BrushID, 4, 1, (*btype ? U_XE : U_LE)); /* color is not byte swapped, ID integer is */ U_PMF_SERIAL_get(&contents, Rect, 4, 4, U_LE); return(1); @@ -7412,10 +7867,14 @@ int U_PMR_FILLPATH_get(const char *contents, U_PMF_CMN_HDR *Header, uint32_t *PathID, int *btype, uint32_t *BrushID){ if(!contents || !PathID || !btype || !BrushID){ return(0); } - uint16_t Flags = U_PMF_HEADERFLAGS_get(contents); - *btype = (Flags & U_PPF_B ? 1 : 0 ); - *PathID = (Flags >> U_FF_SHFT_OID8) & U_FF_MASK_OID8; - U_PMF_CMN_HDR_get(&contents, Header); + + U_PMF_CMN_HDR lclHeader; + U_PMF_CMN_HDR_get(&contents, &lclHeader); + if(lclHeader.Size < sizeof(U_PMF_FILLPATH))return(0); + if(Header){ memcpy(Header,&lclHeader,sizeof(U_PMF_CMN_HDR)); } + + *btype = (lclHeader.Flags & U_PPF_B ? 1 : 0 ); + *PathID = (lclHeader.Flags >> U_FF_SHFT_OID8) & U_FF_MASK_OID8; U_PMF_SERIAL_get(&contents, BrushID, 4, 1, (*btype ? U_XE : U_LE)); /* color is not byte swapped, ID integer is */ return(1); } @@ -7439,14 +7898,23 @@ int U_PMR_FILLPIE_get(const char *contents, U_PMF_CMN_HDR *Header, uint32_t *BrushID, U_FLOAT *Start, U_FLOAT *Sweep, U_PMF_RECTF *Rect){ if(!contents || !btype || !ctype || !BrushID || !Start || !Sweep || !Rect){ return(0); } - uint16_t Flags = U_PMF_HEADERFLAGS_get(contents); - *btype = (Flags & U_PPF_B ? 1 : 0 ); - *ctype = (Flags & U_PPF_C ? 1 : 0 ); - U_PMF_CMN_HDR_get(&contents, Header); + + const char *blimit = contents; + U_PMF_CMN_HDR lclHeader; + U_PMF_CMN_HDR_get(&contents, &lclHeader); + if(lclHeader.Size < sizeof(U_PMF_FILLPIE))return(0); + if(Header){ memcpy(Header,&lclHeader,sizeof(U_PMF_CMN_HDR)); } + blimit += lclHeader.Size; + + *btype = (lclHeader.Flags & U_PPF_B ? 1 : 0 ); + *ctype = (lclHeader.Flags & U_PPF_C ? 1 : 0 ); U_PMF_SERIAL_get(&contents, BrushID, 4, 1, (*btype ? U_XE : U_LE)); /* color is not byte swapped, ID integer is */ U_PMF_SERIAL_get(&contents, Start, 4, 1, U_LE); U_PMF_SERIAL_get(&contents, Sweep, 4, 1, U_LE); - U_PMF_SERIAL_get(&contents, Rect, 4, 4, U_LE); + U_PMF_RECTF *Rects = NULL; + if(!U_PMF_VARRECTS_get(&contents, lclHeader.Flags, 1, &Rects, blimit))return(0); + memcpy(Rect,Rects,sizeof(U_PMF_RECTF)); + free(Rects); return(1); } @@ -7469,14 +7937,20 @@ int U_PMR_FILLPOLYGON_get(const char *contents, U_PMF_CMN_HDR *Header, uint32_t *BrushID, uint32_t *Elements, U_PMF_POINTF **Points){ if(!contents || !btype || !ctype || !RelAbs || !BrushID || !Elements || !Points){ return(0); } - uint16_t Flags = U_PMF_HEADERFLAGS_get(contents); - *btype = (Flags & U_PPF_B ? 1 : 0 ); - *ctype = (Flags & U_PPF_C ? 1 : 0 ); - *RelAbs = (Flags & U_PPF_R ? 1 : 0 ); - U_PMF_CMN_HDR_get(&contents, Header); + + const char *blimit = contents; + U_PMF_CMN_HDR lclHeader; + U_PMF_CMN_HDR_get(&contents, &lclHeader); + if(lclHeader.Size < sizeof(U_PMF_DRAWLINES))return(0); + if(Header){ memcpy(Header,&lclHeader,sizeof(U_PMF_CMN_HDR)); } + blimit += lclHeader.Size; + + *btype = (lclHeader.Flags & U_PPF_B ? 1 : 0 ); + *ctype = (lclHeader.Flags & U_PPF_C ? 1 : 0 ); + *RelAbs = (lclHeader.Flags & U_PPF_R ? 1 : 0 ); U_PMF_SERIAL_get(&contents, BrushID, 4, 1, (*btype ? U_XE : U_LE)); /* color is not byte swapped, ID integer is */ U_PMF_SERIAL_get(&contents, Elements, 4, 1, U_LE); - U_PMF_VARPOINTS_get(&contents, Flags, *Elements, Points); + U_PMF_VARPOINTS_get(contents, lclHeader.Flags, *Elements, Points, blimit); return(1); } @@ -7505,13 +7979,19 @@ int U_PMR_FILLRECTS_get(const char *contents, U_PMF_CMN_HDR *Header, uint32_t *BrushID, uint32_t *Elements, U_PMF_RECTF **Rects){ if(!contents || !btype || !ctype || !BrushID || !Elements || !Rects){ return(0); } - uint16_t Flags = U_PMF_HEADERFLAGS_get(contents); - *btype = (Flags & U_PPF_B ? 1 : 0 ); - *ctype = (Flags & U_PPF_C ? 1 : 0 ); - U_PMF_CMN_HDR_get(&contents, Header); + + const char *blimit = contents; + U_PMF_CMN_HDR lclHeader; + U_PMF_CMN_HDR_get(&contents, &lclHeader); + if(lclHeader.Size < sizeof(U_PMF_FILLRECTS))return(0); + if(Header){ memcpy(Header,&lclHeader,sizeof(U_PMF_CMN_HDR)); } + blimit += lclHeader.Size; + + *btype = (lclHeader.Flags & U_PPF_B ? 1 : 0 ); + *ctype = (lclHeader.Flags & U_PPF_C ? 1 : 0 ); U_PMF_SERIAL_get(&contents, BrushID, 4, 1, (*btype ? U_XE : U_LE)); /* color is not byte swapped, ID integer is */ U_PMF_SERIAL_get(&contents, Elements, 4, 1, U_LE); - U_PMF_VARRECTS_get(&contents, Flags, *Elements, Rects); + U_PMF_VARRECTS_get(&contents, lclHeader.Flags, *Elements, Rects, blimit); /* correct btype, if necessary, for invalid EMF+ input */ if((*BrushID > 63) & !*btype)*btype=1; return(1); @@ -7534,11 +8014,15 @@ int U_PMR_FILLREGION_get(const char *contents, U_PMF_CMN_HDR *Header, uint32_t *RgnID, int *btype, int *ctype, uint32_t *BrushID){ if(!contents || !RgnID || !btype || !ctype || !BrushID){ return(0); } - uint16_t Flags = U_PMF_HEADERFLAGS_get(contents); - *btype = (Flags & U_PPF_B ? 1 : 0 ); - *ctype = (Flags & U_PPF_C ? 1 : 0 ); - *RgnID = (Flags >> U_FF_SHFT_OID8) & U_FF_MASK_OID8; - U_PMF_CMN_HDR_get(&contents, Header); + + U_PMF_CMN_HDR lclHeader; + U_PMF_CMN_HDR_get(&contents, &lclHeader); + if(lclHeader.Size < sizeof(U_PMF_FILLREGION))return(0); + if(Header){ memcpy(Header,&lclHeader,sizeof(U_PMF_CMN_HDR)); } + + *btype = (lclHeader.Flags & U_PPF_B ? 1 : 0 ); + *ctype = (lclHeader.Flags & U_PPF_C ? 1 : 0 ); + *RgnID = (lclHeader.Flags >> U_FF_SHFT_OID8) & U_FF_MASK_OID8; U_PMF_SERIAL_get(&contents, BrushID, 4, 1, (*btype ? U_XE : U_LE)); /* color is not byte swapped, ID integer is */ return(1); } @@ -7556,6 +8040,8 @@ int U_PMR_FILLREGION_get(const char *contents, U_PMF_CMN_HDR *Header, EMF+ manual 2.3.5.1, Microsoft name: EmfPlusObject Record, Index 0x13 + Caller must check Data for possible memory access violations. + OTHER NOTES: All objects are to be stored in the same table and retrieved by index. Documentation indicates that this table contains only 64 slots, although the index @@ -7585,11 +8071,15 @@ int U_PMR_OBJECT_get(const char *contents, U_PMF_CMN_HDR *Header, uint32_t *ObjID, int *otype, int *ntype, uint32_t *TSize, const char **Data){ if(!contents || !ObjID || !otype || !ntype || !Data){ return(0); } - uint16_t Flags = U_PMF_HEADERFLAGS_get(contents); - *ntype = (Flags & U_PPF_N ? 1 : 0 ); - *ObjID = (Flags >> U_FF_SHFT_OID8) & U_FF_MASK_OID8; - *otype = (Flags >> U_FF_SHFT_OT) & U_FF_MASK_OT; - U_PMF_CMN_HDR_get(&contents, Header); + + U_PMF_CMN_HDR lclHeader; + U_PMF_CMN_HDR_get(&contents, &lclHeader); + if(lclHeader.Size < sizeof(U_PMF_OBJECT))return(0); + if(Header){ memcpy(Header,&lclHeader,sizeof(U_PMF_CMN_HDR)); } + + *ntype = (lclHeader.Flags & U_PPF_N ? 1 : 0 ); + *ObjID = (lclHeader.Flags >> U_FF_SHFT_OID8) & U_FF_MASK_OID8; + *otype = (lclHeader.Flags >> U_FF_SHFT_OT) & U_FF_MASK_OT; if(*ntype){ U_PMF_SERIAL_get(&contents, TSize, 4, 1, U_LE); } else { *TSize = 0; } U_PMF_PTRSAV_SHIFT(Data, &contents, 0); @@ -7606,12 +8096,19 @@ int U_PMR_OBJECT_get(const char *contents, U_PMF_CMN_HDR *Header, \param Data "Serialized image effects parameter block". One of the ImageEffects objects. EMF+ manual 2.3.5.2, Microsoft name: EmfPlusSerializableObject Record, Index 0x38 + + Caller must check Data for possible memory access violations. */ int U_PMR_SERIALIZABLEOBJECT_get(const char *contents, U_PMF_CMN_HDR *Header, uint8_t *GUID, uint32_t *Size, const char **Data){ if(!contents || !GUID || !Size || !Data){ return(0); } - U_PMF_CMN_HDR_get(&contents, Header); + + U_PMF_CMN_HDR lclHeader; + U_PMF_CMN_HDR_get(&contents, &lclHeader); + if(lclHeader.Size < sizeof(U_PMF_SERIALIZABLEOBJECT))return(0); + if(Header){ memcpy(Header,&lclHeader,sizeof(U_PMF_CMN_HDR)); } + U_PMF_SERIAL_get(&contents, GUID, 1, 16, U_XE); U_PMF_SERIAL_get(&contents, Size, 4, 1, U_LE); U_PMF_PTRSAV_SHIFT(Data, &contents, 0); @@ -7631,10 +8128,14 @@ int U_PMR_SERIALIZABLEOBJECT_get(const char *contents, U_PMF_CMN_HDR *Header, int U_PMR_SETANTIALIASMODE_get(const char *contents, U_PMF_CMN_HDR *Header, int *SMenum, int *aatype){ if(!contents || !SMenum || !aatype){ return(0); } - uint16_t Flags = U_PMF_HEADERFLAGS_get(contents); - *aatype = (Flags & U_PPF_AA ? 1 : 0 ); - *SMenum = (Flags >> U_FF_SHFT_AA) & U_FF_MASK_AA; - U_PMF_CMN_HDR_get(&contents, Header); + + U_PMF_CMN_HDR lclHeader; + U_PMF_CMN_HDR_get(&contents, &lclHeader); + if(lclHeader.Size < sizeof(U_PMF_SETANTIALIASMODE))return(0); + if(Header){ memcpy(Header,&lclHeader,sizeof(U_PMF_CMN_HDR)); } + + *aatype = (lclHeader.Flags & U_PPF_AA ? 1 : 0 ); + *SMenum = (lclHeader.Flags >> U_FF_SHFT_AA) & U_FF_MASK_AA; return(1); } @@ -7649,6 +8150,7 @@ int U_PMR_SETANTIALIASMODE_get(const char *contents, U_PMF_CMN_HDR *Header, */ int U_PMR_SETCOMPOSITINGMODE_get(const char *contents, U_PMF_CMN_HDR *Header, int *CMenum){ + /* memory access safe, only uses the common header */ if(!contents || !CMenum){ return(0); } uint16_t Flags = U_PMF_HEADERFLAGS_get(contents); *CMenum = (Flags >> U_FF_SHFT_CM) & U_FF_MASK_CM; @@ -7667,6 +8169,7 @@ int U_PMR_SETCOMPOSITINGMODE_get(const char *contents, U_PMF_CMN_HDR *Header, */ int U_PMR_SETCOMPOSITINGQUALITY_get(const char *contents, U_PMF_CMN_HDR *Header, int *CQenum){ + /* memory access safe, only uses the common header */ if(!contents || !CQenum){ return(0); } uint16_t Flags = U_PMF_HEADERFLAGS_get(contents); *CQenum = (Flags >> U_FF_SHFT_CQ) & U_FF_MASK_CQ; @@ -7685,6 +8188,7 @@ int U_PMR_SETCOMPOSITINGQUALITY_get(const char *contents, U_PMF_CMN_HDR *Header, */ int U_PMR_SETINTERPOLATIONMODE_get(const char *contents, U_PMF_CMN_HDR *Header, int *IMenum){ + /* memory access safe, only uses the common header */ if(!contents || !IMenum){ return(0); } uint16_t Flags = U_PMF_HEADERFLAGS_get(contents); *IMenum = (Flags >> U_FF_SHFT_IM) & U_FF_MASK_IM; @@ -7703,6 +8207,7 @@ int U_PMR_SETINTERPOLATIONMODE_get(const char *contents, U_PMF_CMN_HDR *Header, */ int U_PMR_SETPIXELOFFSETMODE_get(const char *contents, U_PMF_CMN_HDR *Header, int *POMenum){ + /* memory access safe, only uses the common header */ if(!contents || !POMenum){ return(0); } uint16_t Flags = U_PMF_HEADERFLAGS_get(contents); *POMenum = (Flags >> U_FF_SHFT_PxOffM) & U_FF_MASK_PxOffM; @@ -7723,7 +8228,12 @@ int U_PMR_SETPIXELOFFSETMODE_get(const char *contents, U_PMF_CMN_HDR *Header, int U_PMR_SETRENDERINGORIGIN_get(const char *contents, U_PMF_CMN_HDR *Header, int32_t *X, int32_t *Y){ if(!contents || !X || !Y){ return(0); } - U_PMF_CMN_HDR_get(&contents, Header); + + U_PMF_CMN_HDR lclHeader; + if(!U_PMF_CMN_HDR_get(&contents, &lclHeader))return(0); + if(lclHeader.Size < sizeof(U_PMF_SETRENDERINGORIGIN))return(0); + if(Header){ memcpy(Header,&lclHeader,sizeof(U_PMF_CMN_HDR)); } + U_PMF_SERIAL_get(&contents, X, 4, 1, U_LE); U_PMF_SERIAL_get(&contents, Y, 4, 1, U_LE); return(1); @@ -7740,6 +8250,7 @@ int U_PMR_SETRENDERINGORIGIN_get(const char *contents, U_PMF_CMN_HDR *Header, */ int U_PMR_SETTEXTCONTRAST_get(const char *contents, U_PMF_CMN_HDR *Header, int *TGC){ + /* memory access safe, only uses the common header */ if(!contents || !TGC){ return(0); } uint16_t Flags = U_PMF_HEADERFLAGS_get(contents); *TGC = (Flags >> U_FF_SHFT_TGC) & U_FF_MASK_TGC; @@ -7758,6 +8269,7 @@ int U_PMR_SETTEXTCONTRAST_get(const char *contents, U_PMF_CMN_HDR *Header, */ int U_PMR_SETTEXTRENDERINGHINT_get(const char *contents, U_PMF_CMN_HDR *Header, int *TRHenum){ + /* memory access safe, only uses the common header */ if(!contents || !TRHenum){ return(0); } uint16_t Flags = U_PMF_HEADERFLAGS_get(contents); *TRHenum = (Flags >> U_FF_SHFT_TRH) & U_FF_MASK_TRH; @@ -7781,9 +8293,13 @@ int U_PMR_BEGINCONTAINER_get(const char *contents, U_PMF_CMN_HDR *Header, int *UTenum, U_PMF_RECTF *DstRect, U_PMF_RECTF *SrcRect, uint32_t *StackID){ if(!contents || !UTenum || !DstRect || !SrcRect || !StackID){ return(0); } - uint16_t Flags = U_PMF_HEADERFLAGS_get(contents); - *UTenum = (Flags >> U_FF_SHFT_UT) & U_FF_MASK_UT; - U_PMF_CMN_HDR_get(&contents, Header); + + U_PMF_CMN_HDR lclHeader; + U_PMF_CMN_HDR_get(&contents, &lclHeader); + if(lclHeader.Size < sizeof(U_PMF_SETCLIPREGION))return(0); + if(Header){ memcpy(Header,&lclHeader,sizeof(U_PMF_CMN_HDR)); } + + *UTenum = (lclHeader.Flags >> U_FF_SHFT_UT) & U_FF_MASK_UT; U_PMF_SERIAL_get(&contents, DstRect, 4, 4, U_LE); U_PMF_SERIAL_get(&contents, SrcRect, 4, 4, U_LE); U_PMF_SERIAL_get(&contents, StackID, 4, 1, U_LE); @@ -7800,10 +8316,7 @@ int U_PMR_BEGINCONTAINER_get(const char *contents, U_PMF_CMN_HDR *Header, EMF+ manual 2.3.7.2, Microsoft name: EmfPlusBeginContainerNoParams Record, Index 0x28 */ int U_PMR_BEGINCONTAINERNOPARAMS_get(const char *contents, U_PMF_CMN_HDR *Header, uint32_t *StackID){ - if(!contents || !StackID){ return(0); } - U_PMF_CMN_HDR_get(&contents, Header); - U_PMF_SERIAL_get(&contents, StackID, 4, 1, U_LE); - return(1); + return(U_PMR_common_stack_get(contents, Header, StackID)); } /** @@ -7815,12 +8328,8 @@ int U_PMR_BEGINCONTAINERNOPARAMS_get(const char *contents, U_PMF_CMN_HDR *Header EMF+ manual 2.3.7.3, Microsoft name: EmfPlusEndContainer Record, Index 0x29 */ -int U_PMR_ENDCONTAINER_get(const char *contents, U_PMF_CMN_HDR *Header, - uint32_t *StackID){ - if(!contents || !StackID){ return(0); } - U_PMF_CMN_HDR_get(&contents, Header); - U_PMF_SERIAL_get(&contents, StackID, 4, 1, U_LE); - return(1); +int U_PMR_ENDCONTAINER_get(const char *contents, U_PMF_CMN_HDR *Header, uint32_t *StackID){ + return(U_PMR_common_stack_get(contents, Header, StackID)); } /** @@ -7833,10 +8342,7 @@ int U_PMR_ENDCONTAINER_get(const char *contents, U_PMF_CMN_HDR *Header, EMF+ manual 2.3.7.4, Microsoft name: EmfPlusRestore Record, Index 0x26 */ int U_PMR_RESTORE_get(const char *contents, U_PMF_CMN_HDR *Header, uint32_t *StackID){ - if(!contents || !StackID){ return(0); } - U_PMF_CMN_HDR_get(&contents, Header); - U_PMF_SERIAL_get(&contents, StackID, 4, 1, U_LE); - return(1); + return(U_PMR_common_stack_get(contents, Header, StackID)); } /** @@ -7849,10 +8355,7 @@ int U_PMR_RESTORE_get(const char *contents, U_PMF_CMN_HDR *Header, uint32_t *Sta EMF+ manual 2.3.7.5, Microsoft name: EmfPlusSave Record, Index 0x25 */ int U_PMR_SAVE_get(const char *contents, U_PMF_CMN_HDR *Header, uint32_t *StackID){ - if(!contents || !StackID){ return(0); } - U_PMF_CMN_HDR_get(&contents, Header); - U_PMF_SERIAL_get(&contents, StackID, 4, 1, U_LE); - return(1); + return(U_PMR_common_stack_get(contents, Header, StackID)); } /** @@ -7870,11 +8373,17 @@ int U_PMR_SETTSCLIP_get(const char *contents, U_PMF_CMN_HDR *Header, int *ctype, uint32_t *Elements, U_PMF_RECTF **Rects){ if(!contents || !ctype || !Elements || !Rects){ return(0); } - uint16_t Flags = U_PMF_HEADERFLAGS_get(contents); - *ctype = (Flags & U_PPF_K ? 1 : 0 ); - *Elements = (Flags >> U_FF_SHFT_TSC) & U_FF_MASK_TSC; - U_PMF_CMN_HDR_get(&contents, Header); - U_PMF_VARRECTS_get(&contents, Flags, *Elements, Rects); + + const char *blimit = contents; + U_PMF_CMN_HDR lclHeader; + U_PMF_CMN_HDR_get(&contents, &lclHeader); + if(lclHeader.Size < sizeof(U_PMF_SETTSCLIP))return(0); + if(Header){ memcpy(Header,&lclHeader,sizeof(U_PMF_CMN_HDR)); } + blimit += lclHeader.Size; + + *ctype = (lclHeader.Flags & U_PPF_K ? 1 : 0 ); + *Elements = (lclHeader.Flags >> U_FF_SHFT_TSC) & U_FF_MASK_TSC; + U_PMF_VARRECTS_get(&contents, lclHeader.Flags, *Elements, Rects, blimit); return(1); } @@ -7898,6 +8407,8 @@ int U_PMR_SETTSCLIP_get(const char *contents, U_PMF_CMN_HDR *Header, \param Data Palette (optional) EMF+ manual 2.3.8.2, Microsoft name: EmfPlusSetTSGraphics Record, Index 0x39 + + Caller must check Data for possible memory access violations. */ int U_PMR_SETTSGRAPHICS_get(const char *contents, U_PMF_CMN_HDR *Header, int *vgatype, int *pptype, @@ -7909,10 +8420,14 @@ int U_PMR_SETTSGRAPHICS_get(const char *contents, U_PMF_CMN_HDR *Header, !AntiAliasMode || !TextRenderHint || !CompositingMode || !CompositingQuality || !RenderOriginX || !RenderOriginY || !TextContrast || !FilterType || !PixelOffset || !WorldToDevice || !Data){ return(0); } - uint16_t Flags = U_PMF_HEADERFLAGS_get(contents); - *vgatype = (Flags & U_PPF_VGA ? 1 : 0 ); - *pptype = (Flags & U_PPF_PP ? 1 : 0 ); - U_PMF_CMN_HDR_get(&contents, Header); + + U_PMF_CMN_HDR lclHeader; + U_PMF_CMN_HDR_get(&contents, &lclHeader); + if(lclHeader.Size < sizeof(U_PMF_SETTSGRAPHICS))return(0); + if(Header){ memcpy(Header,&lclHeader,sizeof(U_PMF_CMN_HDR)); } + + *vgatype = (lclHeader.Flags & U_PPF_VGA ? 1 : 0 ); + *pptype = (lclHeader.Flags & U_PPF_PP ? 1 : 0 ); U_PMF_SERIAL_get(&contents, AntiAliasMode, 1, 1, U_XE); U_PMF_SERIAL_get(&contents, TextRenderHint, 1, 1, U_XE); U_PMF_SERIAL_get(&contents, CompositingMode, 1, 1, U_XE); @@ -7940,9 +8455,13 @@ int U_PMR_MULTIPLYWORLDTRANSFORM_get(const char *contents, U_PMF_CMN_HDR *Header int *xmtype, U_PMF_TRANSFORMMATRIX *Matrix){ if(!contents || !xmtype || !Matrix){ return(0); } - uint16_t Flags = U_PMF_HEADERFLAGS_get(contents); - *xmtype = (Flags & U_PPF_XM ? 1 : 0 ); - U_PMF_CMN_HDR_get(&contents, Header); + + U_PMF_CMN_HDR lclHeader; + U_PMF_CMN_HDR_get(&contents, &lclHeader); + if(lclHeader.Size < sizeof(U_PMF_MULTIPLYWORLDTRANSFORM))return(0); + if(Header){ memcpy(Header,&lclHeader,sizeof(U_PMF_CMN_HDR)); } + + *xmtype = (lclHeader.Flags & U_PPF_XM ? 1 : 0 ); U_PMF_SERIAL_get(&contents, Matrix, 4, 6, U_LE); return(1); } @@ -7956,9 +8475,7 @@ int U_PMR_MULTIPLYWORLDTRANSFORM_get(const char *contents, U_PMF_CMN_HDR *Header EMF+ manual 2.3.9.2, Microsoft name: EmfPlusResetWorldTransform Record, Index 0x2B */ int U_PMR_RESETWORLDTRANSFORM_get(const char *contents, U_PMF_CMN_HDR *Header){ - if(!contents){ return(0); } - U_PMF_CMN_HDR_get(&contents, Header); - return(1); + return( U_PMR_common_header_get(contents,Header)); } /** @@ -7975,9 +8492,13 @@ int U_PMR_ROTATEWORLDTRANSFORM_get(const char *contents, U_PMF_CMN_HDR *Header, int *xmtype, U_FLOAT *Angle){ if(!contents || !xmtype || !Angle){ return(0); } - uint16_t Flags = U_PMF_HEADERFLAGS_get(contents); - *xmtype = (Flags & U_PPF_XM ? 1 : 0 ); - U_PMF_CMN_HDR_get(&contents, Header); + + U_PMF_CMN_HDR lclHeader; + U_PMF_CMN_HDR_get(&contents, &lclHeader); + if(lclHeader.Size < sizeof(U_PMF_ROTATEWORLDTRANSFORM))return(0); + if(Header){ memcpy(Header,&lclHeader,sizeof(U_PMF_CMN_HDR)); } + + *xmtype = (lclHeader.Flags & U_PPF_XM ? 1 : 0 ); U_PMF_SERIAL_get(&contents, Angle, 4, 1, U_LE); return(1); } @@ -7997,9 +8518,13 @@ int U_PMR_SCALEWORLDTRANSFORM_get(const char *contents, U_PMF_CMN_HDR *Header, int *xmtype, U_FLOAT *Sx, U_FLOAT *Sy){ if(!contents || !xmtype || !Sx || !Sy){ return(0); } - uint16_t Flags = U_PMF_HEADERFLAGS_get(contents); - *xmtype = (Flags & U_PPF_XM ? 1 : 0 ); - U_PMF_CMN_HDR_get(&contents, Header); + + U_PMF_CMN_HDR lclHeader; + U_PMF_CMN_HDR_get(&contents, &lclHeader); + if(lclHeader.Size < sizeof(U_PMF_SCALEWORLDTRANSFORM))return(0); + if(Header){ memcpy(Header,&lclHeader,sizeof(U_PMF_CMN_HDR)); } + + *xmtype = (lclHeader.Flags & U_PPF_XM ? 1 : 0 ); U_PMF_SERIAL_get(&contents, Sx, 4, 1, U_LE); U_PMF_SERIAL_get(&contents, Sy, 4, 1, U_LE); return(1); @@ -8019,9 +8544,13 @@ int U_PMR_SETPAGETRANSFORM_get(const char *contents, U_PMF_CMN_HDR *Header, int *PUenum, U_FLOAT *Scale){ if(!contents || !PUenum || !Scale){ return(0); } - uint16_t Flags = U_PMF_HEADERFLAGS_get(contents); - *PUenum = (Flags >> U_FF_SHFT_PU) & U_FF_MASK_PU; - U_PMF_CMN_HDR_get(&contents, Header); + + U_PMF_CMN_HDR lclHeader; + U_PMF_CMN_HDR_get(&contents, &lclHeader); + if(lclHeader.Size < sizeof(U_PMF_SETPAGETRANSFORM))return(0); + if(Header){ memcpy(Header,&lclHeader,sizeof(U_PMF_CMN_HDR)); } + + *PUenum = (lclHeader.Flags >> U_FF_SHFT_PU) & U_FF_MASK_PU; U_PMF_SERIAL_get(&contents, Scale, 4, 1, U_LE); return(1); } @@ -8038,7 +8567,12 @@ int U_PMR_SETPAGETRANSFORM_get(const char *contents, U_PMF_CMN_HDR *Header, int U_PMR_SETWORLDTRANSFORM_get(const char *contents, U_PMF_CMN_HDR *Header, U_PMF_TRANSFORMMATRIX *Matrix){ if(!contents || !Matrix){ return(0); } - U_PMF_CMN_HDR_get(&contents, Header); + + U_PMF_CMN_HDR lclHeader; + U_PMF_CMN_HDR_get(&contents, &lclHeader); + if(lclHeader.Size < sizeof(U_PMF_SETWORLDTRANSFORM))return(0); + if(Header){ memcpy(Header,&lclHeader,sizeof(U_PMF_CMN_HDR)); } + U_PMF_SERIAL_get(&contents, Matrix, 4, 6, U_LE); return(1); } @@ -8058,9 +8592,13 @@ int U_PMR_TRANSLATEWORLDTRANSFORM_get(const char *contents, U_PMF_CMN_HDR *Heade int *xmtype, U_FLOAT *Dx, U_FLOAT *Dy){ if(!contents || !xmtype || !Dx || !Dy){ return(0); } - uint16_t Flags = U_PMF_HEADERFLAGS_get(contents); - *xmtype = (Flags & U_PPF_XM ? 1 : 0 ); - U_PMF_CMN_HDR_get(&contents, Header); + + U_PMF_CMN_HDR lclHeader; + U_PMF_CMN_HDR_get(&contents, &lclHeader); + if(lclHeader.Size < sizeof(U_PMF_TRANSLATEWORLDTRANSFORM))return(0); + if(Header){ memcpy(Header,&lclHeader,sizeof(U_PMF_CMN_HDR)); } + + *xmtype = (lclHeader.Flags & U_PPF_XM ? 1 : 0 ); U_PMF_SERIAL_get(&contents, Dx, 4, 1, U_LE); U_PMF_SERIAL_get(&contents, Dy, 4, 1, U_LE); return(1); @@ -8079,9 +8617,7 @@ int U_PMR_TRANSLATEWORLDTRANSFORM_get(const char *contents, U_PMF_CMN_HDR *Heade the path by using the current pen, and fills its interior by using the current brush." */ int U_PMR_STROKEFILLPATH_get(const char *contents, U_PMF_CMN_HDR *Header){ - if(!contents){ return(0); } - U_PMF_CMN_HDR_get(&contents, Header); - return(1); + return( U_PMR_common_header_get(contents,Header)); } /** @@ -8093,9 +8629,7 @@ int U_PMR_STROKEFILLPATH_get(const char *contents, U_PMF_CMN_HDR *Header){ EMF+ manual mentioned in 2.1.1.1, reserved, not otherwise documented, Microsoft name: EmfPlusMultiFormatStart Record, Index 0x05 */ int U_PMR_MULTIFORMATSTART_get(const char *contents, U_PMF_CMN_HDR *Header){ - if(!contents){ return(0); } - U_PMF_CMN_HDR_get(&contents, Header); - return(1); + return( U_PMR_common_header_get(contents,Header)); } /** @@ -8107,9 +8641,7 @@ int U_PMR_MULTIFORMATSTART_get(const char *contents, U_PMF_CMN_HDR *Header){ EMF+ manual mentioned in 2.1.1.1, reserved, not otherwise documented, Microsoft name: EmfPlusMultiFormatSection Record, Index 0x06 */ int U_PMR_MULTIFORMATSECTION_get(const char *contents, U_PMF_CMN_HDR *Header){ - if(!contents){ return(0); } - U_PMF_CMN_HDR_get(&contents, Header); - return(1); + return( U_PMR_common_header_get(contents,Header)); } /** @@ -8121,9 +8653,7 @@ int U_PMR_MULTIFORMATSECTION_get(const char *contents, U_PMF_CMN_HDR *Header){ EMF+ manual mentioned in 2.1.1.1, reserved, not otherwise documented, Microsoft name: EmfPlusMultiFormatEnd Record, Index 0x06 */ int U_PMR_MULTIFORMATEND_get(const char *contents, U_PMF_CMN_HDR *Header){ - if(!contents){ return(0); } - U_PMF_CMN_HDR_get(&contents, Header); - return(1); + return( U_PMR_common_header_get(contents,Header)); } diff --git a/src/libuemf/upmf.h b/src/libuemf/upmf.h index 27ac94a89..dbda02ba7 100644 --- a/src/libuemf/upmf.h +++ b/src/libuemf/upmf.h @@ -27,11 +27,11 @@ /* File: upmf.h -Version: 0.0.2 -Date: 04-NOV-2013 +Version: 0.0.4 +Date: 17-MAR-2015 Author: David Mathog, Biology Division, Caltech email: mathog@caltech.edu -Copyright: 2013 David Mathog and California Institute of Technology (Caltech) +Copyright: 2015 David Mathog and California Institute of Technology (Caltech) */ #ifndef _UPMF_ @@ -1805,9 +1805,8 @@ typedef struct { /** @brief EMF+ manual 2.2.2.25, Microsoft name: EmfPlusLinearGradientBrushOptionalData Object For U_PMF_LINEARGRADIENTBRUSHDATA data field */ -typedef struct { - U_PMF_ROTMATRIX Matrix; //!< Rotation matrix, Manuals says that this should be Transformation matrix, but last two values are missing -/* variable part of object, not part of structure. +/* Entire object is variable and not part of a structure! U_PMF_LINEARGRADIENTBRUSHOPTIONALDATA + U_PMF_ROTMATRIX Matrix; //!< Rotation matrix, Manuals says that this should be Transformation matrix, but last two values are missing (various) pattern; //!< Presence and meaning depend on Flags field, see below Flag values @@ -1818,7 +1817,6 @@ typedef struct { 0 0 1 U_PMF_BLENDFACTORS 0 1 1 U_PMF_BLENDFACTORS, U_PMF_BLENDFACTORS */ -} U_PMF_LINEARGRADIENTBRUSHOPTIONALDATA; /** @brief EMF+ manual 2.2.2.26, Microsoft name: EmfPlusLinePath Object */ typedef struct { @@ -1888,7 +1886,10 @@ typedef struct { Bitfields in the FILE (LITTLE endian here, manual uses BIG endian) are: bits 4-7 PathPointType flags bits 0-3 PathPointType enumeration + @{ */ +typedef uint8_t U_PMF_PATHPOINTTYPE; //!< EMF+ manual 2.2.2.31, Microsoft name: EmfPlusPathPointType Object +/** @} */ /** \defgroup U_PMF_PPTYPERLE PMF Run Length Encoded Path Point Types @brief EMF+ manual 2.2.2.32, Microsoft name: EmfPlusPathPointTypeRLE Object @@ -2838,6 +2839,7 @@ void U_PMF_MEMCPY_DSTSHIFT(char **Dst, const void *Src, size_t Size); void U_PMF_REPCPY_DSTSHIFT(char **Dst, const void *Src, size_t Size, size_t Reps); void U_PMF_PTRSAV_SHIFT(const char **Dst, const char **Src, size_t Size); uint16_t U_PMF_HEADERFLAGS_get(const char *contents); +int U_PMF_RECORD_SIZE_get(const char *contents); int U_PMF_CMN_HDR_get(const char **contents, U_PMF_CMN_HDR *Header); int U_OID_To_OT(uint32_t OID); int U_OID_To_BT(uint32_t OID); @@ -3035,77 +3037,77 @@ U_PSEUDO_OBJ *U_PMR_STROKEFILLPATH_set(void); /* EMF+ prototypes (objects_get) */ -int U_PMF_BRUSH_get(const char *contents, uint32_t *Version, uint32_t *Type, const char **Data); -int U_PMF_CUSTOMLINECAP_get(const char *contents, uint32_t *Version, uint32_t *Type, const char **Data); -int U_PMF_FONT_get(const char *contents, uint32_t *Version, U_FLOAT *EmSize, uint32_t *SizeUnit, int32_t *FSFlags, uint32_t *Length, const char **Data); -int U_PMF_IMAGE_get(const char *contents, uint32_t *Version, uint32_t *Type, const char **Data); -int U_PMF_IMAGEATTRIBUTES_get(const char *contents, uint32_t *Version, uint32_t *WrapMode, uint32_t *ClampColor, uint32_t *ObjectClamp); -int U_PMF_PATH_get(const char *contents, uint32_t *Version, uint32_t *Count, uint16_t *Flags, const char **Points, const char **Types); -int U_PMF_PEN_get(const char *contents, uint32_t *Version, uint32_t *Type, const char **PenData, const char **Brush); -int U_PMF_REGION_get(const char *contents, uint32_t *Version, uint32_t *Count, const char **Nodes); -int U_PMF_STRINGFORMAT_get(const char *contents, U_PMF_STRINGFORMAT *Sfs, const char **Data); -int U_PMF_ARGB_get(const char *contents, uint8_t *Blue, uint8_t *Green, uint8_t *Red, uint8_t *Alpha); -int U_PMF_BITMAP_get(const char *contents, U_PMF_BITMAP *Bs, const char **Data); -int U_PMF_BITMAPDATA_get(const char *contents, U_PMF_PALETTE *Ps, const char **Colors, const char **Data); -int U_PMF_BLENDCOLORS_get(const char *contents, uint32_t *Elements, U_FLOAT **Positions, const char **Colors); -int U_PMF_BLENDFACTORS_get(const char *contents, uint32_t *Elements, U_FLOAT **Positions, U_FLOAT **Factors); -int U_PMF_BOUNDARYPATHDATA_get(const char *contents, int32_t *Size, const char **Data); -int U_PMF_BOUNDARYPOINTDATA_get(const char *contents, int32_t *Elements, U_PMF_POINTF **Points); -int U_PMF_CHARACTERRANGE_get(const char *contents, int32_t *First, int32_t *Length); -int U_PMF_COMPOUNDLINEDATA_get(const char *contents, int32_t *Elements, U_FLOAT **Widths); -int U_PMF_COMPRESSEDIMAGE_get(const char *contents, const char **Data); -int U_PMF_CUSTOMENDCAPDATA_get(const char *contents, int32_t *Size, const char **Data); -int U_PMF_CUSTOMLINECAPARROWDATA_get(const char *contents, U_PMF_CUSTOMLINECAPARROWDATA *Ccad); -int U_PMF_CUSTOMLINECAPDATA_get(const char *contents, U_PMF_CUSTOMLINECAPDATA *Clcd, const char **Data); -int U_PMF_CUSTOMLINECAPOPTIONALDATA_get(const char *contents, uint32_t Flags, const char **FillData, const char **LineData); -int U_PMF_CUSTOMSTARTCAPDATA_get(const char *contents, int32_t *Size, const char **Data); -int U_PMF_DASHEDLINEDATA_get(const char *contents, int32_t *Elements, U_FLOAT **Lengths); -int U_PMF_FILLPATHOBJ_get(const char *contents, int32_t *Size, const char **Data); -int U_PMF_FOCUSSCALEDATA_get(const char *contents, uint32_t *Count, U_FLOAT *ScaleX, U_FLOAT *ScaleY); -int U_PMF_GRAPHICSVERSION_get(const char *contents, int *Signature, int *GrfVersion); -int U_PMF_HATCHBRUSHDATA_get(const char *contents, uint32_t *Style, U_PMF_ARGB *Foreground, U_PMF_ARGB *Background); -int U_PMF_INTEGER7_get(const char **contents, U_FLOAT *Value); -int U_PMF_INTEGER15_get(const char **contents, U_FLOAT *Value); +int U_PMF_BRUSH_get(const char *contents, uint32_t *Version, uint32_t *Type, const char **Data, const char *blimit); +int U_PMF_CUSTOMLINECAP_get(const char *contents, uint32_t *Version, uint32_t *Type, const char **Data, const char *blimit); +int U_PMF_FONT_get(const char *contents, uint32_t *Version, U_FLOAT *EmSize, uint32_t *SizeUnit, int32_t *FSFlags, uint32_t *Length, const char **Data, const char *blimit); +int U_PMF_IMAGE_get(const char *contents, uint32_t *Version, uint32_t *Type, const char **Data, const char *blimit); +int U_PMF_IMAGEATTRIBUTES_get(const char *contents, uint32_t *Version, uint32_t *WrapMode, uint32_t *ClampColor, uint32_t *ObjectClamp, const char *blimit); +int U_PMF_PATH_get(const char *contents, uint32_t *Version, uint32_t *Count, uint16_t *Flags, const char **Points, const char **Types, const char *blimit); +int U_PMF_PEN_get(const char *contents, uint32_t *Version, uint32_t *Type, const char **PenData, const char **Brush, const char *blimit); +int U_PMF_REGION_get(const char *contents, uint32_t *Version, uint32_t *Count, const char **Nodes, const char *blimit); +int U_PMF_STRINGFORMAT_get(const char *contents, U_PMF_STRINGFORMAT *Sfs, const char **Data, const char *blimit); +int U_PMF_ARGB_get(const char *contents, uint8_t *Blue, uint8_t *Green, uint8_t *Red, uint8_t *Alpha, const char *blimit); +int U_PMF_BITMAP_get(const char *contents, U_PMF_BITMAP *Bs, const char **Data, const char *blimit); +int U_PMF_BITMAPDATA_get(const char *contents, U_PMF_PALETTE *Ps, const char **Colors, const char **Data, const char *blimit); +int U_PMF_BLENDCOLORS_get(const char *contents, uint32_t *Elements, U_FLOAT **Positions, const char **Colors, const char *blimit); +int U_PMF_BLENDFACTORS_get(const char *contents, uint32_t *Elements, U_FLOAT **Positions, U_FLOAT **Factors, const char *blimit); +int U_PMF_BOUNDARYPATHDATA_get(const char *contents, int32_t *Size, const char **Data, const char *blimit); +int U_PMF_BOUNDARYPOINTDATA_get(const char *contents, int32_t *Elements, U_PMF_POINTF **Points, const char *blimit); +int U_PMF_CHARACTERRANGE_get(const char *contents, int32_t *First, int32_t *Length, const char *blimit); +int U_PMF_COMPOUNDLINEDATA_get(const char *contents, int32_t *Elements, U_FLOAT **Widths, const char *blimit); +int U_PMF_COMPRESSEDIMAGE_get(const char *contents, const char **Data, const char *blimit); +int U_PMF_CUSTOMENDCAPDATA_get(const char *contents, int32_t *Size, const char **Data, const char *blimit); +int U_PMF_CUSTOMLINECAPARROWDATA_get(const char *contents, U_PMF_CUSTOMLINECAPARROWDATA *Ccad, const char *blimit); +int U_PMF_CUSTOMLINECAPDATA_get(const char *contents, U_PMF_CUSTOMLINECAPDATA *Clcd, const char **Data, const char *blimit); +int U_PMF_CUSTOMLINECAPOPTIONALDATA_get(const char *contents, uint32_t Flags, const char **FillData, const char **LineData, const char *blimit); +int U_PMF_CUSTOMSTARTCAPDATA_get(const char *contents, int32_t *Size, const char **Data, const char *blimit); +int U_PMF_DASHEDLINEDATA_get(const char *contents, int32_t *Elements, U_FLOAT **Lengths, const char *blimit); +int U_PMF_FILLPATHOBJ_get(const char *contents, int32_t *Size, const char **Data, const char *blimit); +int U_PMF_FOCUSSCALEDATA_get(const char *contents, uint32_t *Count, U_FLOAT *ScaleX, U_FLOAT *ScaleY, const char *blimit); +int U_PMF_GRAPHICSVERSION_get(const char *contents, int *Signature, int *GrfVersion, const char *blimit); +int U_PMF_HATCHBRUSHDATA_get(const char *contents, uint32_t *Style, U_PMF_ARGB *Foreground, U_PMF_ARGB *Background, const char *blimit); +int U_PMF_INTEGER7_get(const char **contents, U_FLOAT *Value, const char *blimit); +int U_PMF_INTEGER15_get(const char **contents, U_FLOAT *Value, const char *blimit); int U_PMF_LANGUAGEIDENTIFIER_get(U_PMF_LANGUAGEIDENTIFIER LId, int *SubLId, int *PriLId); -int U_PMF_LINEARGRADIENTBRUSHDATA_get(const char *contents, U_PMF_LINEARGRADIENTBRUSHDATA *Lgbd, const char **Data); -int U_PMF_LINEARGRADIENTBRUSHOPTIONALDATA_get(const char *contents, uint32_t Flags, U_PMF_TRANSFORMMATRIX *Tm, const char **Bc, const char **BfH, const char **BfV); -int U_PMF_LINEPATH_get(const char *contents, int32_t *Size, const char **Data); -int U_PMF_METAFILE_get(const char *contents, uint32_t *Type, uint32_t *Size, const char **Data); -int U_PMF_PALETTE_get(const char *contents, uint32_t *Flags, uint32_t *Elements, const char **Data); -int U_PMF_PATHGRADIENTBRUSHDATA_get(const char *contents, U_PMF_PATHGRADIENTBRUSHDATA *Pgbd, const char **Gradient, const char **Boundary, const char **Data); -int U_PMF_PATHGRADIENTBRUSHOPTIONALDATA_get(const char *contents, uint32_t Flags, U_PMF_TRANSFORMMATRIX *Matrix, const char **Pattern, const char **Data); -int U_PMF_PATHPOINTTYPE_get(const char *contents, int *Flags, int *Type); -int U_PMF_PATHPOINTTYPERLE_get(const char *contents, int *Bezier, int *RL, int *Ppt); -int U_PMF_PENDATA_get(const char *contents, uint32_t *Flags, uint32_t *Unit, U_FLOAT *Width, const char **Data); +int U_PMF_LINEARGRADIENTBRUSHDATA_get(const char *contents, U_PMF_LINEARGRADIENTBRUSHDATA *Lgbd, const char **Data, const char *blimit); +int U_PMF_LINEARGRADIENTBRUSHOPTIONALDATA_get(const char *contents, uint32_t Flags, U_PMF_TRANSFORMMATRIX *Tm, const char **Bc, const char **BfH, const char **BfV, const char *blimit); +int U_PMF_LINEPATH_get(const char *contents, int32_t *Size, const char **Data, const char *blimit); +int U_PMF_METAFILE_get(const char *contents, uint32_t *Type, uint32_t *Size, const char **Data, const char *blimit); +int U_PMF_PALETTE_get(const char *contents, uint32_t *Flags, uint32_t *Elements, const char **Data, const char *blimit); +int U_PMF_PATHGRADIENTBRUSHDATA_get(const char *contents, U_PMF_PATHGRADIENTBRUSHDATA *Pgbd, const char **Gradient, const char **Boundary, const char **Data, const char *blimit); +int U_PMF_PATHGRADIENTBRUSHOPTIONALDATA_get(const char *contents, uint32_t Flags, U_PMF_TRANSFORMMATRIX *Matrix, const char **Pattern, const char **Data, const char *blimit); +int U_PMF_PATHPOINTTYPE_get(const char *contents, int *Flags, int *Type, const char *blimit); +int U_PMF_PATHPOINTTYPERLE_get(const char *contents, int *Bezier, int *RL, int *Ppt, const char *blimit); +int U_PMF_PENDATA_get(const char *contents, uint32_t *Flags, uint32_t *Unit, U_FLOAT *Width, const char **Data, const char *blimit); int U_PMF_PENOPTIONALDATA_get(const char *contents, uint32_t Flags, U_PMF_TRANSFORMMATRIX *Matrix, int32_t *StartCap, int32_t *EndCap, uint32_t *Join, U_FLOAT *MiterLimit, int32_t *Style, int32_t *DLCap, U_FLOAT *DLOffset, - const char **DLData, int32_t *Alignment, const char **CmpndLineData, const char **CSCapData, const char **CECapData); -int U_PMF_POINT_get(const char **contents, U_FLOAT *X, U_FLOAT *Y); -int U_PMF_POINTF_get(const char **contents, U_FLOAT *X, U_FLOAT *Y); -int U_PMF_POINTR_get(const char **contents, U_FLOAT *X, U_FLOAT *Y); -int U_PMF_RECT_get(const char **contents, int16_t *X, int16_t *Y, int16_t *Width, int16_t *Height); -int U_PMF_RECTF_get(const char **contents, U_FLOAT *X, U_FLOAT *Y, U_FLOAT *Width, U_FLOAT *Height); -int U_PMF_REGIONNODE_get(const char *contents, uint32_t *Type, const char **Data); + const char **DLData, int32_t *Alignment, const char **CmpndLineData, const char **CSCapData, const char **CECapData, const char *blimit); +int U_PMF_POINT_get(const char **contents, U_FLOAT *X, U_FLOAT *Y, const char *blimit); +int U_PMF_POINTF_get(const char **contents, U_FLOAT *X, U_FLOAT *Y, const char *blimit); +int U_PMF_POINTR_get(const char **contents, U_FLOAT *X, U_FLOAT *Y, const char *blimit); +int U_PMF_RECT_get(const char **contents, int16_t *X, int16_t *Y, int16_t *Width, int16_t *Height, const char *blimit); +int U_PMF_RECTF_get(const char **contents, U_FLOAT *X, U_FLOAT *Y, U_FLOAT *Width, U_FLOAT *Height, const char *blimit); +int U_PMF_REGIONNODE_get(const char *contents, uint32_t *Type, const char **Data, const char *blimit); /* There is no U_PMF_REGIONNODECHILDNODES_get, see the note in upmf.c */ -int U_PMF_REGIONNODEPATH_get(const char *contents, int32_t *Size, const char **Data); -int U_PMF_SOLIDBRUSHDATA_get(const char *contents, U_PMF_ARGB *Color); +int U_PMF_REGIONNODEPATH_get(const char *contents, int32_t *Size, const char **Data, const char *blimit); +int U_PMF_SOLIDBRUSHDATA_get(const char *contents, U_PMF_ARGB *Color, const char *blimit); int U_PMF_STRINGFORMATDATA_get(const char *contents, uint32_t TabStopCount, uint32_t RangeCount, - const U_FLOAT **TabStops, const U_PMF_CHARACTERRANGE **CharRange); -int U_PMF_TEXTUREBRUSHDATA_get(const char *contents, uint32_t *Flags, int32_t *WrapMode, const char **Data); -int U_PMF_TEXTUREBRUSHOPTIONALDATA_get(const char *contents, int HasImage, U_PMF_TRANSFORMMATRIX *Matrix, const char **Image); -int U_PMF_TRANSFORMMATRIX_get(const char *contents, U_PMF_TRANSFORMMATRIX *Matrix); -int U_PMF_IE_BLUR_get(const char *contents, U_FLOAT *Radius, uint32_t *ExpandEdge); -int U_PMF_IE_BRIGHTNESSCONTRAST_get(const char *contents, int32_t *Brightness, int32_t *Contrast); -int U_PMF_IE_COLORBALANCE_get(const char *contents, int32_t *CyanRed, int32_t *MagentaGreen, int32_t *YellowBlue); -int U_PMF_IE_COLORCURVE_get(const char *contents, uint32_t *Adjust, uint32_t *Channel, int32_t *Intensity); + const U_FLOAT **TabStops, const U_PMF_CHARACTERRANGE **CharRange, const char *blimit); +int U_PMF_TEXTUREBRUSHDATA_get(const char *contents, uint32_t *Flags, int32_t *WrapMode, const char **Data, const char *blimit); +int U_PMF_TEXTUREBRUSHOPTIONALDATA_get(const char *contents, int HasImage, U_PMF_TRANSFORMMATRIX *Matrix, const char **Image, const char *blimit); +int U_PMF_TRANSFORMMATRIX_get(const char *contents, U_PMF_TRANSFORMMATRIX *Matrix, const char *blimit); +int U_PMF_IE_BLUR_get(const char *contents, U_FLOAT *Radius, uint32_t *ExpandEdge, const char *blimit); +int U_PMF_IE_BRIGHTNESSCONTRAST_get(const char *contents, int32_t *Brightness, int32_t *Contrast, const char *blimit); +int U_PMF_IE_COLORBALANCE_get(const char *contents, int32_t *CyanRed, int32_t *MagentaGreen, int32_t *YellowBlue, const char *blimit); +int U_PMF_IE_COLORCURVE_get(const char *contents, uint32_t *Adjust, uint32_t *Channel, int32_t *Intensity, const char *blimit); int U_PMF_IE_COLORLOOKUPTABLE_get(const char *contents, - const uint8_t **BLUT, const uint8_t **GLUT, const uint8_t **RLUT, const uint8_t **ALUT); -int U_PMF_IE_COLORMATRIX_get(const char *contents, U_PMF_IE_COLORMATRIX *Matrix); -int U_PMF_IE_HUESATURATIONLIGHTNESS_get(const char *contents, int32_t *Hue, int32_t *Saturation, int32_t *Lightness); -int U_PMF_IE_LEVELS_get(const char *contents, int32_t *Highlight, int32_t *Midtone, int32_t *Shadow); -int U_PMF_IE_REDEYECORRECTION_get(const char *contents, int32_t *Elements, U_RECTL **Rects); -int U_PMF_IE_SHARPEN_get(const char *contents, U_FLOAT *Radius, int32_t *Sharpen); -int U_PMF_IE_TINT_get(const char *contents, int32_t *Hue, int32_t *Amount); + const uint8_t **BLUT, const uint8_t **GLUT, const uint8_t **RLUT, const uint8_t **ALUT, const char *blimit); +int U_PMF_IE_COLORMATRIX_get(const char *contents, U_PMF_IE_COLORMATRIX *Matrix, const char *blimit); +int U_PMF_IE_HUESATURATIONLIGHTNESS_get(const char *contents, int32_t *Hue, int32_t *Saturation, int32_t *Lightness, const char *blimit); +int U_PMF_IE_LEVELS_get(const char *contents, int32_t *Highlight, int32_t *Midtone, int32_t *Shadow, const char *blimit); +int U_PMF_IE_REDEYECORRECTION_get(const char *contents, int32_t *Elements, U_RECTL **Rects, const char *blimit); +int U_PMF_IE_SHARPEN_get(const char *contents, U_FLOAT *Radius, int32_t *Sharpen, const char *blimit); +int U_PMF_IE_TINT_get(const char *contents, int32_t *Hue, int32_t *Amount, const char *blimit); /* EMF+ prototypes (records_get) */ diff --git a/src/libuemf/upmf_print.c b/src/libuemf/upmf_print.c index 13bbfade8..7d9598b0d 100644 --- a/src/libuemf/upmf_print.c +++ b/src/libuemf/upmf_print.c @@ -6,11 +6,11 @@ /* File: upmf_print.c -Version: 0.0.3 -Date: 24-MAR-2014 +Version: 0.0.5 +Date: 24-MAR-2015 Author: David Mathog, Biology Division, Caltech email: mathog@caltech.edu -Copyright: 2014 David Mathog and California Institute of Technology (Caltech) +Copyright: 2015 David Mathog and California Institute of Technology (Caltech) */ /* compiler options: @@ -30,6 +30,7 @@ extern "C" { #include #include "upmf_print.h" #include "uemf_print.h" +#include "uemf_safe.h" //! \cond @@ -49,7 +50,7 @@ int U_PMR_NODATAREC_print(const char *contents){ /* this function is not visible in the API. Common routine used by many functions that draw points. */ -void U_PMF_VARPOINTS_print(const char **contents, int Flags, uint32_t Elements){ +void U_PMF_VARPOINTS_print(const char **contents, int Flags, uint32_t Elements, const char *blimit){ unsigned int i; U_FLOAT Xpos, Ypos; @@ -58,9 +59,9 @@ void U_PMF_VARPOINTS_print(const char **contents, int Flags, uint32_t Elements){ else { printf(" + Points(Float):"); } for(Xpos = Ypos = i = 0; i1 are child nodes. + \param blimit one byte past the end of data EMF+ manual 2.2.2.40, Microsoft name: EmfPlusRegionNode Object */ -int U_PMF_REGIONNODE_print(const char *contents, int Level){ +int U_PMF_REGIONNODE_print(const char *contents, int Level, const char *blimit){ int len=4; /* Type will always be present */ uint32_t Type; const char *Data; - int status = U_PMF_REGIONNODE_get(contents, &Type, &Data); + int status = U_PMF_REGIONNODE_get(contents, &Type, &Data, blimit); if(status){ printf("\n + RegionNode(Level:%d) { Type:%X(",Level,Type); U_PMF_NODETYPE_print(Type); printf(")"); if(Type >= U_RNDT_And && Type <= U_RNDT_Complement){ - len += U_PMF_REGIONNODECHILDNODES_print(Data, Level+1); + len += U_PMF_REGIONNODECHILDNODES_print(Data, Level+1, blimit); } else if(Type == U_RNDT_Rect){ len += sizeof(U_PMF_RECTF); - (void) U_PMF_RECTF_print(&Data); + (void) U_PMF_RECTF_print(&Data, blimit); printf("\n"); } else if(Type == U_RNDT_Path){ - len += U_PMF_REGIONNODEPATH_print(Data); + len += U_PMF_REGIONNODEPATH_print(Data, blimit); } /* U_RNDT_Empty and U_RNDT_Infinite do not change the length */ else if(Type == U_RNDT_Empty ){ printf(" Empty" ); } @@ -1624,18 +1702,19 @@ int U_PMF_REGIONNODE_print(const char *contents, int Level){ \return size on success, 0 on error \param contents Record from which to print data \param Level Tree level. This routine is recursive and could go down many levels. 1 is the top, >1 are child nodes. + \param blimit one byte past the end of data EMF+ manual 2.2.2.41, Microsoft name: EmfPlusRegionNodeChildNodes Object */ -int U_PMF_REGIONNODECHILDNODES_print(const char *contents, int Level){ +int U_PMF_REGIONNODECHILDNODES_print(const char *contents, int Level, const char *blimit){ uint32_t size,rsize; printf(" RegionNodeChildNodes:\n"); printf(" + RNCN__Left(Level:%d) {", Level); - size = U_PMF_REGIONNODE_print(contents, Level); + size = U_PMF_REGIONNODE_print(contents, Level, blimit); printf(" + RNCN__Left(Level:%d) },\n", Level); if(size){ contents += size; printf(" + RNCN_Right(Level:%d) {", Level); - rsize = U_PMF_REGIONNODE_print(contents, Level); + rsize = U_PMF_REGIONNODE_print(contents, Level, blimit); size += rsize; printf(" + RNCN_Right(Level:%d) },\n",Level); } @@ -1646,15 +1725,16 @@ int U_PMF_REGIONNODECHILDNODES_print(const char *contents, int Level){ \brief Print data from a U_PMF_REGIONNODEPATH object \return Size of data on success, 0 on error \param contents Record from which to print data + \param blimit one byte past the end of data EMF+ manual 2.2.2.42, Microsoft name: EmfPlusRegionNodePath Object */ -int U_PMF_REGIONNODEPATH_print(const char *contents){ +int U_PMF_REGIONNODEPATH_print(const char *contents, const char * blimit){ int32_t Size; const char *Data; - int status = U_PMF_REGIONNODEPATH_get(contents, &Size, &Data); + int status = U_PMF_REGIONNODEPATH_get(contents, &Size, &Data, blimit); if(status){ printf(" RegionNodePath: \n"); - (void) U_PMF_PATH_print(Data); + (void) U_PMF_PATH_print(Data, blimit); status = Size + 4; /* data sizee + the 4 bytes encoding the size */ } return(status); @@ -1665,11 +1745,12 @@ int U_PMF_REGIONNODEPATH_print(const char *contents){ \brief Print data from a U_PMF_SOLIDBRUSHDATA object \return 1 on success, 0 on error \param contents Record from which to print data + \param blimit one byte past the end of data EMF+ manual 2.2.2.43, Microsoft name: EmfPlusSolidBrushData Object */ -int U_PMF_SOLIDBRUSHDATA_print(const char *contents){ +int U_PMF_SOLIDBRUSHDATA_print(const char *contents, const char *blimit){ U_PMF_ARGB Color; - int status = U_PMF_SOLIDBRUSHDATA_get(contents, &Color); + int status = U_PMF_SOLIDBRUSHDATA_get(contents, &Color, blimit); if(status){ printf(" SolidBrushData: "); (void) U_PMF_ARGB_print((char *) &Color); @@ -1683,12 +1764,13 @@ int U_PMF_SOLIDBRUSHDATA_print(const char *contents){ \param contents Record from which to print data \param TabStopCount Entries in TabStop array \param RangeCount Entries in CharRange array + \param blimit one byte past the end of data EMF+ manual 2.2.2.44, Microsoft name: EmfPlusStringFormatData Object */ -int U_PMF_STRINGFORMATDATA_print(const char *contents, uint32_t TabStopCount, uint32_t RangeCount){ +int U_PMF_STRINGFORMATDATA_print(const char *contents, uint32_t TabStopCount, uint32_t RangeCount, const char *blimit){ const U_FLOAT *TabStops; const U_PMF_CHARACTERRANGE *CharRange; - int status = U_PMF_STRINGFORMATDATA_get(contents, TabStopCount, RangeCount, &TabStops, &CharRange); + int status = U_PMF_STRINGFORMATDATA_get(contents, TabStopCount, RangeCount, &TabStops, &CharRange, blimit); if(status){ printf(" SFdata: TabStopCount:%u RangeCount:%u\n", TabStopCount, RangeCount); @@ -1708,13 +1790,14 @@ int U_PMF_STRINGFORMATDATA_print(const char *contents, uint32_t TabStopCount, ui \brief Print data from a U_PMF_TEXTUREBRUSHDATA object \return 1 on success, 0 on error \param contents Record from which to print data + \param blimit one byte past the end of data EMF+ manual 2.2.2.45, Microsoft name: EmfPlusTextureBrushData Object */ -int U_PMF_TEXTUREBRUSHDATA_print(const char *contents){ +int U_PMF_TEXTUREBRUSHDATA_print(const char *contents, const char *blimit){ uint32_t Flags; int32_t WrapMode; const char *Data; - int status = U_PMF_TEXTUREBRUSHDATA_get(contents, &Flags, &WrapMode, &Data); + int status = U_PMF_TEXTUREBRUSHDATA_get(contents, &Flags, &WrapMode, &Data, blimit); if(status){ printf(" + TBdata: Flags:%X WrapMode:%d", Flags, WrapMode); } @@ -1725,18 +1808,23 @@ int U_PMF_TEXTUREBRUSHDATA_print(const char *contents){ \brief Print data from a U_PMF_TEXTUREBRUSHOPTIONALDATA object \return 1 on success, 0 on error \param contents Record from which to print data + \param HasMatrix True if the record contains a matrix. \param HasImage True if the record contains an image. + \param blimit one byte past the end of data EMF+ manual 2.2.2.46, Microsoft name: EmfPlusTextureBrushOptionalData Object */ -int U_PMF_TEXTUREBRUSHOPTIONALDATA_print(const char *contents, int HasImage){ +int U_PMF_TEXTUREBRUSHOPTIONALDATA_print(const char *contents, int HasMatrix, int HasImage, const char *blimit){ U_PMF_TRANSFORMMATRIX Matrix; + U_PMF_TRANSFORMMATRIX *pMatrix; const char *Image; - int status = U_PMF_TEXTUREBRUSHOPTIONALDATA_get(contents, HasImage, &Matrix, &Image); + if(HasMatrix){ pMatrix = &Matrix; } + else { pMatrix = NULL; } + int status = U_PMF_TEXTUREBRUSHOPTIONALDATA_get(contents, HasImage, pMatrix, &Image, blimit); if(status){ printf(" + TBOptdata: Image:%c", (HasImage ? 'Y' : 'N')); (void) U_PMF_TRANSFORMMATRIX2_print(&Matrix); - (void) U_PMF_IMAGE_print(Image); + (void) U_PMF_IMAGE_print(Image, blimit); } return(status); } @@ -1745,11 +1833,12 @@ int U_PMF_TEXTUREBRUSHOPTIONALDATA_print(const char *contents, int HasImage){ \brief Print data from a U_PMF_TRANSFORMMATRIX object stored in file byte order. \return 1 on success, 0 on error \param contents Record from which to print data + \param blimit one byte past the end of data EMF+ manual 2.2.2.47, Microsoft name: EmfPlusTransformMatrix Object */ -int U_PMF_TRANSFORMMATRIX_print(const char *contents){ +int U_PMF_TRANSFORMMATRIX_print(const char *contents, const char *blimit){ U_PMF_TRANSFORMMATRIX Tm; - int status = U_PMF_TRANSFORMMATRIX_get(contents, &Tm); + int status = U_PMF_TRANSFORMMATRIX_get(contents, &Tm, blimit); if(status){ U_PMF_TRANSFORMMATRIX2_print(&Tm); } @@ -1782,12 +1871,13 @@ int U_PMF_ROTMATRIX2_print(U_PMF_ROTMATRIX *Rm){ \brief Print data from a U_PMF_IE_BLUR object \return 1 on success, 0 on error \param contents Record from which to print data + \param blimit one byte past the end of data EMF+ manual 2.2.3.1, Microsoft name: BlurEffect Object */ -int U_PMF_IE_BLUR_print(const char *contents){ +int U_PMF_IE_BLUR_print(const char *contents, const char *blimit){ U_FLOAT Radius; uint32_t ExpandEdge; - int status = U_PMF_IE_BLUR_get(contents, &Radius, &ExpandEdge); + int status = U_PMF_IE_BLUR_get(contents, &Radius, &ExpandEdge, blimit); if(status){ printf("BlurEffect Radius:%f ExpandEdge:%u\n", Radius, ExpandEdge); } @@ -1798,11 +1888,12 @@ int U_PMF_IE_BLUR_print(const char *contents){ \brief Print data from a U_PMF_IE_BRIGHTNESSCONTRAST object \return 1 on success, 0 on error \param contents Record from which to print data + \param blimit one byte past the end of data EMF+ manual 2.2.3.2, Microsoft name: BrightnessContrastEffect Object */ -int U_PMF_IE_BRIGHTNESSCONTRAST_print(const char *contents){ +int U_PMF_IE_BRIGHTNESSCONTRAST_print(const char *contents, const char *blimit){ int32_t Brightness, Contrast; - int status = U_PMF_IE_BRIGHTNESSCONTRAST_get(contents, &Brightness, &Contrast); + int status = U_PMF_IE_BRIGHTNESSCONTRAST_get(contents, &Brightness, &Contrast, blimit); if(status){ printf("BrightnessContrastEffect Brightness:%d Contrast:%d\n", Brightness, Contrast); } @@ -1813,11 +1904,12 @@ int U_PMF_IE_BRIGHTNESSCONTRAST_print(const char *contents){ \brief Print data from a U_PMF_IE_COLORBALANCE object \return 1 on success, 0 on error \param contents Record from which to print data + \param blimit one byte past the end of data EMF+ manual 2.2.3.3, Microsoft name: ColorBalanceEffect Object */ -int U_PMF_IE_COLORBALANCE_print(const char *contents){ +int U_PMF_IE_COLORBALANCE_print(const char *contents, const char *blimit){ int32_t CyanRed, MagentaGreen, YellowBlue; - int status = U_PMF_IE_COLORBALANCE_get(contents, &CyanRed, &MagentaGreen, &YellowBlue); + int status = U_PMF_IE_COLORBALANCE_get(contents, &CyanRed, &MagentaGreen, &YellowBlue, blimit); if(status){ printf("ColorBalanceEffect CyanRed:%d MagentaGreen:%d YellowBlue:%d\n", CyanRed, MagentaGreen, YellowBlue); } @@ -1828,12 +1920,13 @@ int U_PMF_IE_COLORBALANCE_print(const char *contents){ \brief Print data from a U_PMF_IE_COLORCURVE object \return 1 on success, 0 on error \param contents Record from which to print data + \param blimit one byte past the end of data EMF+ manual 2.2.3.4, Microsoft name: ColorCurveEffect Object */ -int U_PMF_IE_COLORCURVE_print(const char *contents){ +int U_PMF_IE_COLORCURVE_print(const char *contents, const char *blimit){ uint32_t Adjust, Channel; int32_t Intensity; - int status = U_PMF_IE_COLORCURVE_get(contents, &Adjust, &Channel, &Intensity); + int status = U_PMF_IE_COLORCURVE_get(contents, &Adjust, &Channel, &Intensity, blimit); if(status){ printf("ColorBalanceEffect Adjust:%u Channel:%u Intensity:%d\n", Adjust, Channel, Intensity); } @@ -1844,11 +1937,12 @@ int U_PMF_IE_COLORCURVE_print(const char *contents){ \brief Print data from a U_PMF_IE_COLORLOOKUPTABLE object \return 1 on success, 0 on error \param contents Record from which to print data + \param blimit one byte past the end of data EMF+ manual 2.2.3.5, Microsoft name: ColorLookupTableEffect Object */ -int U_PMF_IE_COLORLOOKUPTABLE_print(const char *contents){ +int U_PMF_IE_COLORLOOKUPTABLE_print(const char *contents, const char *blimit){ const uint8_t *BLUT, *GLUT, *RLUT, *ALUT; - int status = U_PMF_IE_COLORLOOKUPTABLE_get(contents, &BLUT, &GLUT, &RLUT, &ALUT); + int status = U_PMF_IE_COLORLOOKUPTABLE_get(contents, &BLUT, &GLUT, &RLUT, &ALUT, blimit); if(status){ printf("ColorLookupTableEffect \n"); U_PMF_UINT8_ARRAY_print(" BLUT:", BLUT, 256, "\n"); @@ -1863,12 +1957,13 @@ int U_PMF_IE_COLORLOOKUPTABLE_print(const char *contents){ \brief Print data from a U_PMF_IE_COLORMATRIX object \return 1 on success, 0 on error \param contents Record from which to print data + \param blimit one byte past the end of data EMF+ manual 2.2.3.6, Microsoft name: ColorMatrixEffect Object */ -int U_PMF_IE_COLORMATRIX_print(const char *contents){ +int U_PMF_IE_COLORMATRIX_print(const char *contents, const char *blimit){ U_PMF_IE_COLORMATRIX Matrix; int i,j; - int status = U_PMF_IE_COLORMATRIX_get(contents, &Matrix); + int status = U_PMF_IE_COLORMATRIX_get(contents, &Matrix, blimit); if(status){ printf("ColorMatrixEffect\n"); for(i=0;i<5;i++){ @@ -1885,11 +1980,12 @@ int U_PMF_IE_COLORMATRIX_print(const char *contents){ \brief Print data from a U_PMF_IE_HUESATURATIONLIGHTNESS object \return 1 on success, 0 on error \param contents Record from which to print data + \param blimit one byte past the end of data EMF+ manual 2.2.3.7, Microsoft name: HueSaturationLightnessEffect Object */ -int U_PMF_IE_HUESATURATIONLIGHTNESS_print(const char *contents){ +int U_PMF_IE_HUESATURATIONLIGHTNESS_print(const char *contents, const char *blimit){ int32_t Hue, Saturation, Lightness; - int status = U_PMF_IE_HUESATURATIONLIGHTNESS_get(contents, &Hue, &Saturation, &Lightness); + int status = U_PMF_IE_HUESATURATIONLIGHTNESS_get(contents, &Hue, &Saturation, &Lightness, blimit); if(status){ printf("HueSaturationLightnessEffect Hue:%d Saturation:%d Lightness:%d\n", Hue, Saturation, Lightness); } @@ -1900,11 +1996,12 @@ int U_PMF_IE_HUESATURATIONLIGHTNESS_print(const char *contents){ \brief Print data from a U_PMF_IE_LEVELS object \return 1 on success, 0 on error \param contents Record from which to print data + \param blimit one byte past the end of data EMF+ manual 2.2.3.8, Microsoft name: LevelsEffect Object */ -int U_PMF_IE_LEVELS_print(const char *contents){ +int U_PMF_IE_LEVELS_print(const char *contents, const char *blimit){ int32_t Highlight, Midtone, Shadow; - int status = U_PMF_IE_LEVELS_get(contents, &Highlight, &Midtone, &Shadow); + int status = U_PMF_IE_LEVELS_get(contents, &Highlight, &Midtone, &Shadow, blimit); if(status){ printf("LevelEffect Highlight:%d Midtone:%d Shadow:%d\n", Highlight, Midtone, Shadow); } @@ -1915,12 +2012,13 @@ int U_PMF_IE_LEVELS_print(const char *contents){ \brief Print data from a U_PMF_IE_REDEYECORRECTION object \return 1 on success, 0 on error \param contents Record from which to print data + \param blimit one byte past the end of data EMF+ manual 2.2.3.9, Microsoft name: RedEyeCorrectionEffect Object */ -int U_PMF_IE_REDEYECORRECTION_print(const char *contents){ +int U_PMF_IE_REDEYECORRECTION_print(const char *contents, const char *blimit){ int32_t Elements; U_RECTL *Rects; - int status = U_PMF_IE_REDEYECORRECTION_get(contents, &Elements, &Rects); + int status = U_PMF_IE_REDEYECORRECTION_get(contents, &Elements, &Rects, blimit); if(status){ printf("RedEyeCorrectionEffect Elements:%u", Elements); for(; Elements; Elements--, Rects++){ @@ -1935,13 +2033,14 @@ int U_PMF_IE_REDEYECORRECTION_print(const char *contents){ /** \brief Print data from a U_PMF_IE_SHARPEN object \return 1 on success, 0 on error + \param blimit one byte past the end of data \param contents Record from which to print data EMF+ manual 2.2.3.10, Microsoft name: SharpenEffect Object */ -int U_PMF_IE_SHARPEN_print(const char *contents){ +int U_PMF_IE_SHARPEN_print(const char *contents, const char *blimit){ U_FLOAT Radius; int32_t Sharpen; - int status = U_PMF_IE_SHARPEN_get(contents, &Radius, &Sharpen); + int status = U_PMF_IE_SHARPEN_get(contents, &Radius, &Sharpen, blimit); if(status){ printf("SharpenEffect Radius:%f Sharpen:%u\n", Radius, Sharpen); } @@ -1952,11 +2051,12 @@ int U_PMF_IE_SHARPEN_print(const char *contents){ \brief Print data from a U_PMF_IE_TINT object \return 1 on success, 0 on error \param contents Record from which to print data + \param blimit one byte past the end of data EMF+ manual 2.2.3.11, Microsoft name: TintEffect Object */ -int U_PMF_IE_TINT_print(const char *contents){ +int U_PMF_IE_TINT_print(const char *contents, const char *blimit){ int32_t Hue, Amount; - int status = U_PMF_IE_TINT_get(contents, &Hue, &Amount); + int status = U_PMF_IE_TINT_get(contents, &Hue, &Amount, blimit); if(status){ printf("TintEffect Hue:%d Amount:%d\n", Hue, Amount); } @@ -1981,6 +2081,9 @@ int U_PMR_OFFSETCLIP_print(const char *contents){ if(status){ printf(" + dx:%f dy:%f\n",dX,dY); } + else { + printf(" corrupt record\n"); + } return(status); } @@ -2007,6 +2110,9 @@ int U_PMR_SETCLIPPATH_print(const char *contents){ if(status){ printf(" + PathID:%u CMenum:%d\n",PathID,CMenum); } + else { + printf(" corrupt record\n"); + } return(status); } @@ -2027,6 +2133,9 @@ int U_PMR_SETCLIPRECT_print(const char *contents){ U_PMF_RECTF_S_print(&Rect); printf("\n"); } + else { + printf(" corrupt record\n"); + } return(status); } @@ -2045,6 +2154,9 @@ int U_PMR_SETCLIPREGION_print(const char *contents){ U_PMF_COMBINEMODEENUMERATION_print(CMenum); printf(")\n"); } + else { + printf(" corrupt record\n"); + } return(status); } @@ -2061,6 +2173,11 @@ int U_PMR_COMMENT_print(const char *contents){ unsigned int i=0; int status = U_PMR_COMMENT_get(contents, &Header, &Data); if(status){ + const char *blimit = contents + Header.Size; + if(IS_MEM_UNSAFE(Data, Header.DataSize, blimit)){ + printf(" corrupt record\n"); + return(0); + } /* try to print it, but only ASCII, bail on anything that is not ASCII */ printf(" + Data:"); for(i=0; i< Header.DataSize; i++,Data++){ @@ -2070,6 +2187,9 @@ int U_PMR_COMMENT_print(const char *contents){ } printf("\n"); } + else { + printf(" corrupt record\n"); + } return(status); } @@ -2107,9 +2227,12 @@ int U_PMR_HEADER_print(const char *contents){ if(status){ /* try to print it, but only ASCII, bail on anything that is not ASCII */ printf(" + "); - (void) U_PMF_GRAPHICSVERSION_print((char *) &Version); + (void) U_PMF_GRAPHICSVERSION_memsafe_print((char *)&Version);; printf(" IsDual:%c IsVideo:%d LogicalDpiX,y:{%u,%u}\n",(IsDual ? 'Y' : 'N'),IsVideo,LogicalDpiX, LogicalDpiY); } + else { + printf(" corrupt record\n"); + } return(status); } @@ -2127,6 +2250,9 @@ int U_PMR_CLEAR_print(const char *contents){ printf(" + Color:"); (void) U_PMF_ARGB_print((char *) &Color); } + else { + printf(" corrupt record\n"); + } return(status); } @@ -2147,6 +2273,9 @@ int U_PMR_DRAWARC_print(const char *contents){ (void) U_PMF_VARRECTF_S_print(&Rect, 1); printf("\n"); } + else { + printf(" corrupt record\n"); + } return(status); } @@ -2167,6 +2296,9 @@ int U_PMR_DRAWBEZIERS_print(const char *contents){ U_PMF_VARPOINTF_S_print(Points, Elements); free(Points); } + else { + printf(" corrupt record\n"); + } return(status); } @@ -2194,6 +2326,9 @@ int U_PMR_DRAWCLOSEDCURVE_print(const char *contents){ U_PMF_VARPOINTF_S_print(Points, Elements); free(Points); } + else { + printf(" corrupt record\n"); + } return(status); } @@ -2221,6 +2356,9 @@ int U_PMR_DRAWCURVE_print(const char *contents){ U_PMF_VARPOINTF_S_print(Points, Elements); free(Points); } + else { + printf(" corrupt record\n"); + } return(status); } @@ -2269,7 +2407,9 @@ int U_PMR_DRAWDRIVERSTRING_print(const char *contents){ free(Matrix); printf("\n"); } - + } + else { + printf(" corrupt record\n"); } return(status); } @@ -2290,6 +2430,9 @@ int U_PMR_DRAWELLIPSE_print(const char *contents){ (void) U_PMF_VARRECTF_S_print(&Rect, 1); printf("\n"); } + else { + printf(" corrupt record\n"); + } return(status); } @@ -2313,6 +2456,9 @@ int U_PMR_DRAWIMAGE_print(const char *contents){ (void) U_PMF_RECTF_S_print(&DstRect); printf("\n"); } + else { + printf(" corrupt record\n"); + } return(status); } @@ -2339,6 +2485,9 @@ int U_PMR_DRAWIMAGEPOINTS_print(const char *contents){ U_PMF_VARPOINTF_S_print(Points, Elements); free(Points); } + else { + printf(" corrupt record\n"); + } return(status); } @@ -2360,6 +2509,9 @@ int U_PMR_DRAWLINES_print(const char *contents){ U_PMF_VARPOINTF_S_print(Points, Elements); free(Points); } + else { + printf(" corrupt record\n"); + } return(status); } @@ -2375,6 +2527,9 @@ int U_PMR_DRAWPATH_print(const char *contents){ if(status){ printf(" + PathIdx:%d PenIdx:%d\n", PathIdx, PenIdx); } + else { + printf(" corrupt record\n"); + } return(status); } @@ -2395,6 +2550,9 @@ int U_PMR_DRAWPIE_print(const char *contents){ (void) U_PMF_VARRECTF_S_print(&Rect, 1); printf("\n"); } + else { + printf(" corrupt record\n"); + } return(status); } @@ -2402,10 +2560,9 @@ int U_PMR_DRAWPIE_print(const char *contents){ \brief Print data from a U_PMR_DRAWRECTS record \return size of record in bytes on success, 0 on error \param contents Record from which to print data - \param blimit One byte past the last record in memory. EMF+ manual 2.3.4.13, Microsoft name: EmfPlusDrawRects Record, Index 0x0B */ -int U_PMR_DRAWRECTS_print(const char *contents, const char *blimit){ +int U_PMR_DRAWRECTS_print(const char *contents){ uint32_t PenID; int ctype; uint32_t Elements; @@ -2413,11 +2570,13 @@ int U_PMR_DRAWRECTS_print(const char *contents, const char *blimit){ U_PMF_CMN_HDR hdr; int status = U_PMR_DRAWRECTS_get(contents, &hdr, &PenID, &ctype, &Elements, &Rects); if(status){ - if(contents + hdr.Size >= blimit)return(0); printf(" + PenID:%u ctype:%d Elements:%u Rect:", PenID,ctype,Elements); (void) U_PMF_VARRECTF_S_print(Rects, Elements); printf("\n"); } + else { + printf(" corrupt record\n"); + } if(Rects)free(Rects); return(status); } @@ -2452,6 +2611,9 @@ int U_PMR_DRAWSTRING_print(const char *contents){ printf(" String(as_UTF8):(none)\n"); } } + else { + printf(" corrupt record\n"); + } return(status); } @@ -2477,6 +2639,9 @@ int U_PMR_FILLCLOSEDCURVE_print(const char *contents){ U_PMF_VARPOINTF_S_print(Points, Elements); free(Points); } + else { + printf(" corrupt record\n"); + } return(status); } @@ -2498,6 +2663,9 @@ int U_PMR_FILLELLIPSE_print(const char *contents){ (void) U_PMF_VARRECTF_S_print(&Rect, 1); printf("\n"); } + else { + printf(" corrupt record\n"); + } return(status); } @@ -2516,6 +2684,9 @@ int U_PMR_FILLPATH_print(const char *contents){ (void) U_PMF_VARBRUSHID_print(btype, BrushID); printf("\n"); } + else { + printf(" corrupt record\n"); + } return(status); } @@ -2537,6 +2708,9 @@ int U_PMR_FILLPIE_print(const char *contents){ (void) U_PMF_VARRECTF_S_print(&Rect, 1); printf("\n"); } + else { + printf(" corrupt record\n"); + } return(status); } @@ -2558,6 +2732,9 @@ int U_PMR_FILLPOLYGON_print(const char *contents){ U_PMF_VARPOINTF_S_print(Points, Elements); free(Points); } + else { + printf(" corrupt record\n"); + } return(status); } @@ -2565,23 +2742,24 @@ int U_PMR_FILLPOLYGON_print(const char *contents){ \brief Print data from a U_PMR_FILLRECTS record \return size of record in bytes on success, 0 on error \param contents Record from which to print data - \param blimit One byte past the last record in memory. EMF+ manual 2.3.4.20, Microsoft name: EmfPlusFillRects Record, Index 0x0A */ -int U_PMR_FILLRECTS_print(const char *contents, const char *blimit){ +int U_PMR_FILLRECTS_print(const char *contents){ int btype, ctype; uint32_t BrushID, Elements; U_PMF_RECTF *Rects; U_PMF_CMN_HDR hdr; int status = U_PMR_FILLRECTS_get(contents, &hdr, &btype,&ctype, &BrushID, &Elements, &Rects); if(status){ - if(contents + hdr.Size >= blimit)return(0); printf(" + btype:%d ctype:%d Elements:%u",btype,ctype,Elements); (void) U_PMF_VARBRUSHID_print(btype, BrushID); (void) U_PMF_VARRECTF_S_print(Rects, Elements); free(Rects); printf("\n"); } + else { + printf(" corrupt record\n"); + } return(status); } @@ -2600,6 +2778,9 @@ int U_PMR_FILLREGION_print(const char *contents){ (void) U_PMF_VARBRUSHID_print(btype, BrushID); printf("\n"); } + else { + printf(" corrupt record\n"); + } return(status); } @@ -2611,6 +2792,10 @@ int U_PMR_FILLREGION_print(const char *contents){ \param ObjCont Structure that holds accumulated object. \param term Flag used when an abnormal termination of a series of continuation records is encountered. EMF+ manual 2.3.5.1, Microsoft name: EmfPlusObject Record, Index 0x13 + + This is the ONLY EMF+ record type which needs an explicit blimit passed in. Since it glues + together multiple records, and calls itself recursively, the initial caller cannot determine + that all of the sizes will be OK from the first record's header. */ int U_PMR_OBJECT_print(const char *contents, const char *blimit, U_OBJ_ACCUM *ObjCont, int term){ U_PMF_CMN_HDR Header; @@ -2641,8 +2826,11 @@ int U_PMR_OBJECT_print(const char *contents, const char *blimit, U_OBJ_ACCUM *Ob /* In a corrupt EMF+ file we might hit a new type of record before all the continuation records expected have been found. If that happens terminate whatever we have accumulated so far, and then go on to emit the new (unexpected) record. */ - if(contents + Header.Size >= blimit)return(0); - if(!status)return(status); + if(IS_MEM_UNSAFE(contents, Header.Size, blimit))return(0); + if(!status){ + printf(" corrupt record\n"); + return(status); + } if((ObjCont->used > 0) && (U_OA_append(ObjCont, NULL, 0, otype, ObjID) < 0)){ U_PMR_OBJECT_print(contents, blimit, ObjCont, 1); } @@ -2665,16 +2853,17 @@ int U_PMR_OBJECT_print(const char *contents, const char *blimit, U_OBJ_ACCUM *Ob ttype = otype; } if(status){ + blimit = ObjCont->accum + ObjCont->used; /* more restrictive blimit, just to end of object */ switch(ttype){ - case U_OT_Brush: (void) U_PMF_BRUSH_print(ObjCont->accum); break; - case U_OT_Pen: (void) U_PMF_PEN_print(ObjCont->accum); break; - case U_OT_Path: (void) U_PMF_PATH_print(ObjCont->accum); break; - case U_OT_Region: (void) U_PMF_REGION_print(ObjCont->accum); break; - case U_OT_Image: (void) U_PMF_IMAGE_print(ObjCont->accum); break; - case U_OT_Font: (void) U_PMF_FONT_print(ObjCont->accum); break; - case U_OT_StringFormat: (void) U_PMF_STRINGFORMAT_print(ObjCont->accum); break; - case U_OT_ImageAttributes: (void) U_PMF_IMAGEATTRIBUTES_print(ObjCont->accum); break; - case U_OT_CustomLineCap: (void) U_PMF_CUSTOMLINECAP_print(ObjCont->accum,""); break; + case U_OT_Brush: (void) U_PMF_BRUSH_print(ObjCont->accum, blimit); break; + case U_OT_Pen: (void) U_PMF_PEN_print(ObjCont->accum, blimit); break; + case U_OT_Path: (void) U_PMF_PATH_print(ObjCont->accum, blimit); break; + case U_OT_Region: (void) U_PMF_REGION_print(ObjCont->accum, blimit); break; + case U_OT_Image: (void) U_PMF_IMAGE_print(ObjCont->accum, blimit); break; + case U_OT_Font: (void) U_PMF_FONT_print(ObjCont->accum, blimit); break; + case U_OT_StringFormat: (void) U_PMF_STRINGFORMAT_print(ObjCont->accum, blimit); break; + case U_OT_ImageAttributes: (void) U_PMF_IMAGEATTRIBUTES_print(ObjCont->accum, blimit); break; + case U_OT_CustomLineCap: (void) U_PMF_CUSTOMLINECAP_print(ObjCont->accum,"", blimit); break; case U_OT_Invalid: default: printf("INVALID OBJECT TYPE!!!!\n"); @@ -2707,24 +2896,27 @@ int U_PMR_SERIALIZABLEOBJECT_print(const char *contents){ printf("\n + Effect:"); free(string); switch(iee){ - case U_IEE_Unknown: printf("(undefined)\n"); break; - case U_IEE_BlurEffectGuid: U_PMF_IE_BLUR_print(Data); break; - case U_IEE_BrightnessContrastEffectGuid: U_PMF_IE_BRIGHTNESSCONTRAST_print(Data); break; - case U_IEE_ColorBalanceEffectGuid: U_PMF_IE_COLORBALANCE_print(Data); break; - case U_IEE_ColorCurveEffectGuid: U_PMF_IE_COLORCURVE_print(Data); break; - case U_IEE_ColorLookupTableEffectGuid: U_PMF_IE_COLORLOOKUPTABLE_print(Data); break; - case U_IEE_ColorMatrixEffectGuid: U_PMF_IE_COLORMATRIX_print(Data); break; - case U_IEE_HueSaturationLightnessEffectGuid: U_PMF_IE_HUESATURATIONLIGHTNESS_print(Data); break; - case U_IEE_LevelsEffectGuid: U_PMF_IE_LEVELS_print(Data); break; - case U_IEE_RedEyeCorrectionEffectGuid: U_PMF_IE_REDEYECORRECTION_print(Data); break; - case U_IEE_SharpenEffectGuid: U_PMF_IE_SHARPEN_print(Data); break; - case U_IEE_TintEffectGuid: U_PMF_IE_TINT_print(Data); break; + case U_IEE_Unknown: printf("(undefined)\n"); break; + case U_IEE_BlurEffectGuid: U_PMF_IE_BLUR_print(Data, Data + sizeof(U_PMF_IE_BLUR)); break; + case U_IEE_BrightnessContrastEffectGuid: U_PMF_IE_BRIGHTNESSCONTRAST_print(Data, Data + sizeof(U_PMF_IE_BRIGHTNESSCONTRAST)); break; + case U_IEE_ColorBalanceEffectGuid: U_PMF_IE_COLORBALANCE_print(Data, Data + sizeof(U_PMF_IE_COLORBALANCE)); break; + case U_IEE_ColorCurveEffectGuid: U_PMF_IE_COLORCURVE_print(Data, Data + sizeof(U_PMF_IE_COLORCURVE)); break; + case U_IEE_ColorLookupTableEffectGuid: U_PMF_IE_COLORLOOKUPTABLE_print(Data, Data + sizeof(U_PMF_IE_COLORLOOKUPTABLE)); break; + case U_IEE_ColorMatrixEffectGuid: U_PMF_IE_COLORMATRIX_print(Data, Data + sizeof(U_PMF_IE_COLORMATRIX)); break; + case U_IEE_HueSaturationLightnessEffectGuid: U_PMF_IE_HUESATURATIONLIGHTNESS_print(Data, Data + sizeof(U_PMF_IE_HUESATURATIONLIGHTNESS)); break; + case U_IEE_LevelsEffectGuid: U_PMF_IE_LEVELS_print(Data, Data + sizeof(U_PMF_IE_LEVELS)); break; + case U_IEE_RedEyeCorrectionEffectGuid: U_PMF_IE_REDEYECORRECTION_print(Data, Data + sizeof(U_PMF_IE_REDEYECORRECTION)); break; + case U_IEE_SharpenEffectGuid: U_PMF_IE_SHARPEN_print(Data, Data + sizeof(U_PMF_IE_SHARPEN)); break; + case U_IEE_TintEffectGuid: U_PMF_IE_TINT_print(Data, Data + sizeof(U_PMF_IE_TINT)); break; } } else { printf(" + GUID:ERROR Size:%u\n",Size); } } + else { + printf(" corrupt record\n"); + } return(status); } @@ -2740,6 +2932,9 @@ int U_PMR_SETANTIALIASMODE_print(const char *contents){ if(status){ printf(" + SMenum:%d AntiAlias:%c\n",SMenum,(aatype ? 'Y' : 'N')); } + else { + printf(" corrupt record\n"); + } return(status); } @@ -2755,6 +2950,9 @@ int U_PMR_SETCOMPOSITINGMODE_print(const char *contents){ if(status){ printf(" + CMenum:%d\n",CMenum); } + else { + printf(" corrupt record\n"); + } return(status); } @@ -2770,6 +2968,9 @@ int U_PMR_SETCOMPOSITINGQUALITY_print(const char *contents){ if(status){ printf(" + CQenum:%d\n",CQenum); } + else { + printf(" corrupt record\n"); + } return(status); } @@ -2785,6 +2986,9 @@ int U_PMR_SETINTERPOLATIONMODE_print(const char *contents){ if(status){ printf(" + IMenum:%d\n",IMenum); } + else { + printf(" corrupt record\n"); + } return(status); } @@ -2800,6 +3004,9 @@ int U_PMR_SETPIXELOFFSETMODE_print(const char *contents){ if(status){ printf(" + POMenum:%d\n",POMenum); } + else { + printf(" corrupt record\n"); + } return(status); } @@ -2815,6 +3022,9 @@ int U_PMR_SETRENDERINGORIGIN_print(const char *contents){ if(status){ printf(" + X:%d Y:%d\n", X, Y); } + else { + printf(" corrupt record\n"); + } return(status); } @@ -2830,6 +3040,9 @@ int U_PMR_SETTEXTCONTRAST_print(const char *contents){ if(status){ printf(" + GC:%d\n", GC); } + else { + printf(" corrupt record\n"); + } return(status); } @@ -2845,6 +3058,9 @@ int U_PMR_SETTEXTRENDERINGHINT_print(const char *contents){ if(status){ printf(" + TRHenum:%d\n",TRHenum); } + else { + printf(" corrupt record\n"); + } return(status); } @@ -2865,6 +3081,9 @@ int U_PMR_BEGINCONTAINER_print(const char *contents){ printf(" SrcRect:"); (void) U_PMF_RECTF_S_print(&SrcRect); printf(" StackID:%u\n", StackID); } + else { + printf(" corrupt record\n"); + } return(status); } @@ -2880,6 +3099,9 @@ int U_PMR_BEGINCONTAINERNOPARAMS_print(const char *contents){ if(status){ printf(" + StackID:%u\n", StackID); } + else { + printf(" corrupt record\n"); + } return(status); } @@ -2895,6 +3117,9 @@ int U_PMR_ENDCONTAINER_print(const char *contents){ if(status){ printf(" + StackID:%u\n", StackID); } + else { + printf(" corrupt record\n"); + } return(status); } @@ -2910,6 +3135,9 @@ int U_PMR_RESTORE_print(const char *contents){ if(status){ printf(" + StackID:%u\n", StackID); } + else { + printf(" corrupt record\n"); + } return(status); } @@ -2925,6 +3153,9 @@ int U_PMR_SAVE_print(const char *contents){ if(status){ printf(" + StackID:%u\n", StackID); } + else { + printf(" corrupt record\n"); + } return(status); } @@ -2945,6 +3176,9 @@ int U_PMR_SETTSCLIP_print(const char *contents){ free(Rects); printf("\n"); } + else { + printf(" corrupt record\n"); + } return(status); } @@ -2967,6 +3201,7 @@ int U_PMR_SETTSGRAPHICS_print(const char *contents){ &RenderOriginX, &RenderOriginY, &TextContrast, &FilterType, &PixelOffset, &WorldToDevice, &Data); if(status){ + const char *blimit = contents + status; printf(" + vgatype:%d pptype:%u",vgatype,pptype); printf(" AntiAliasMode:%u TextRenderHint:%u CompositingMode:%u CompositingQuality:%u", AntiAliasMode, TextRenderHint, CompositingMode, CompositingQuality); @@ -2974,9 +3209,12 @@ int U_PMR_SETTSGRAPHICS_print(const char *contents){ printf(" TextContrast:%u",TextContrast); printf(" WorldToDevice:"); U_PMF_TRANSFORMMATRIX2_print(&WorldToDevice); - if(pptype){ (void) U_PMF_PALETTE_print(Data); } + if(pptype && !U_PMF_PALETTE_print(Data, blimit))return(0); printf("\n"); } + else { + printf(" corrupt record\n"); + } return(status); } @@ -2996,6 +3234,9 @@ int U_PMR_MULTIPLYWORLDTRANSFORM_print(const char *contents){ U_PMF_TRANSFORMMATRIX2_print(&Matrix); printf("\n"); } + else { + printf(" corrupt record\n"); + } return(status); } @@ -3022,6 +3263,9 @@ int U_PMR_ROTATEWORLDTRANSFORM_print(const char *contents){ if(status){ printf(" + xmtype:%d Multiply:%s Angle:%f\n",xmtype,(xmtype ? "Post" : "Pre"), Angle); } + else { + printf(" corrupt record\n"); + } return(status); } @@ -3038,6 +3282,9 @@ int U_PMR_SCALEWORLDTRANSFORM_print(const char *contents){ if(status){ printf(" + xmtype:%d Multiply:%s ScaleX:%f ScaleY:%f\n",xmtype,(xmtype ? "Post" : "Pre"), Sx, Sy); } + else { + printf(" corrupt record\n"); + } return(status); } @@ -3054,6 +3301,9 @@ int U_PMR_SETPAGETRANSFORM_print(const char *contents){ if(status){ printf(" + UTenum:%d Scale:%f\n",UTenum, Scale); } + else { + printf(" corrupt record\n"); + } return(status); } @@ -3071,6 +3321,9 @@ int U_PMR_SETWORLDTRANSFORM_print(const char *contents){ U_PMF_TRANSFORMMATRIX2_print(&Matrix); printf("\n"); } + else { + printf(" corrupt record\n"); + } return(status); } @@ -3087,6 +3340,9 @@ int U_PMR_TRANSLATEWORLDTRANSFORM_print(const char *contents){ if(status){ printf(" + xmtype:%d Multiply:%s TranslateX:%f TranlateY:%f\n",xmtype,(xmtype ? "Post" : "Pre"), Dx, Dy); } + else { + printf(" corrupt record\n"); + } return(status); } diff --git a/src/libuemf/upmf_print.h b/src/libuemf/upmf_print.h index 3ba6694eb..fe1c57d60 100644 --- a/src/libuemf/upmf_print.h +++ b/src/libuemf/upmf_print.h @@ -6,11 +6,11 @@ /* File: upmf_print.h -Version: 0.0.2 -Date: 17-OCT-2013 +Version: 0.0.4 +Date: 24-MAR-2015 Author: David Mathog, Biology Division, Caltech email: mathog@caltech.edu -Copyright: 2013 David Mathog and California Institute of Technology (Caltech) +Copyright: 2015 David Mathog and California Institute of Technology (Caltech) */ #ifndef _UPMF_PRINT_ @@ -33,77 +33,78 @@ int U_PMF_PX_FMT_ENUM_print(int pfe); int U_PMF_NODETYPE_print(int Type); /* prototypes for objects used in PMR records */ -int U_PMF_BRUSH_print(const char *contents); -int U_PMF_CUSTOMLINECAP_print(const char *contents, const char *Which); -int U_PMF_FONT_print(const char *contents); -int U_PMF_IMAGE_print(const char *contents); -int U_PMF_IMAGEATTRIBUTES_print(const char *contents); -int U_PMF_PATH_print(const char *contents); -int U_PMF_PEN_print(const char *contents); -int U_PMF_REGION_print(const char *contents); -int U_PMF_STRINGFORMAT_print(const char *contents); +int U_PMF_BRUSH_print(const char *contents, const char *blimit); +int U_PMF_CUSTOMLINECAP_print(const char *contents, const char *Which, const char *blimit); +int U_PMF_FONT_print(const char *contents, const char *blimit); +int U_PMF_IMAGE_print(const char *contents, const char *blimit); +int U_PMF_IMAGEATTRIBUTES_print(const char *contents, const char *blimit); +int U_PMF_PATH_print(const char *contents, const char *blimit); +int U_PMF_PEN_print(const char *contents, const char *blimit); +int U_PMF_REGION_print(const char *contents, const char *blimit); +int U_PMF_STRINGFORMAT_print(const char *contents, const char *blimit); int U_PMF_ARGB_print(const char *contents); -int U_PMF_BITMAP_print(const char *contents); -int U_PMF_BITMAPDATA_print(const char *contents); -int U_PMF_BLENDCOLORS_print(const char *contents); -int U_PMF_BLENDFACTORS_print(const char *contents, const char *type); -int U_PMF_BOUNDARYPATHDATA_print(const char *contents); -int U_PMF_BOUNDARYPOINTDATA_print(const char *contents); -int U_PMF_CHARACTERRANGE_print(const char *contents); -int U_PMF_COMPOUNDLINEDATA_print(const char *contents); -int U_PMF_COMPRESSEDIMAGE_print(const char *contents); -int U_PMF_CUSTOMENDCAPDATA_print(const char *contents); -int U_PMF_CUSTOMLINECAPARROWDATA_print(const char *contents); -int U_PMF_CUSTOMLINECAPDATA_print(const char *contents); -int U_PMF_CUSTOMLINECAPOPTIONALDATA_print(const char *contents, uint32_t Flags); -int U_PMF_CUSTOMSTARTCAPDATA_print(const char *contents); -int U_PMF_DASHEDLINEDATA_print(const char *contents); -int U_PMF_FILLPATHOBJ_print(const char *contents); -int U_PMF_FOCUSSCALEDATA_print(const char *contents); -int U_PMF_GRAPHICSVERSION_print(const char *contents); -int U_PMF_HATCHBRUSHDATA_print(const char *contents); +int U_PMF_BITMAP_print(const char *contents, const char *blimit); +int U_PMF_BITMAPDATA_print(const char *contents, const char *blimit); +int U_PMF_BLENDCOLORS_print(const char *contents, const char *blimit); +int U_PMF_BLENDFACTORS_print(const char *contents, const char *type, const char *blimit); +int U_PMF_BOUNDARYPATHDATA_print(const char *contents, const char *blimit); +int U_PMF_BOUNDARYPOINTDATA_print(const char *contents, const char *blimit); +int U_PMF_CHARACTERRANGE_print(const char *contents, const char *blimit); +int U_PMF_COMPOUNDLINEDATA_print(const char *contents, const char *blimit); +int U_PMF_COMPRESSEDIMAGE_print(const char *contents, const char *blimit); +int U_PMF_CUSTOMENDCAPDATA_print(const char *contents, const char *blimit); +int U_PMF_CUSTOMLINECAPARROWDATA_print(const char *contents, const char *blimit); +int U_PMF_CUSTOMLINECAPDATA_print(const char *contents, const char *blimit); +int U_PMF_CUSTOMLINECAPOPTIONALDATA_print(const char *contents, uint32_t Flags, const char *blimit); +int U_PMF_CUSTOMSTARTCAPDATA_print(const char *contents, const char *blimit); +int U_PMF_DASHEDLINEDATA_print(const char *contents, const char *blimit); +int U_PMF_FILLPATHOBJ_print(const char *contents, const char *blimit); +int U_PMF_FOCUSSCALEDATA_print(const char *contents, const char *blimit); +int U_PMF_GRAPHICSVERSION_memsafe_print(const char *contents); +int U_PMF_GRAPHICSVERSION_print(const char *contents, const char *blimit); +int U_PMF_HATCHBRUSHDATA_print(const char *contents, const char *blimit); int U_PMF_LANGUAGEIDENTIFIER_print(U_PMF_LANGUAGEIDENTIFIER LId); -int U_PMF_LINEARGRADIENTBRUSHDATA_print(const char *contents); -int U_PMF_LINEARGRADIENTBRUSHOPTIONALDATA_print(const char *contents, int BDFlag); -int U_PMF_LINEPATH_print(const char *contents); -int U_PMF_METAFILE_print(const char *contents); -int U_PMF_PALETTE_print(const char *contents); -int U_PMF_PATHGRADIENTBRUSHDATA_print(const char *contents); -int U_PMF_PATHGRADIENTBRUSHOPTIONALDATA_print(const char *contents, int BDFlag); -int U_PMF_PATHPOINTTYPE_print(const char *contents); -int U_PMF_PATHPOINTTYPERLE_print(const char *contents); -int U_PMF_PENDATA_print(const char *contents); -int U_PMF_PENOPTIONALDATA_print(const char *contents, int Flags); -int U_PMF_POINT_print(const char **contents); -int U_PMF_POINTF_print(const char **contents); -int U_PMF_POINTR_print(const char **contents, U_FLOAT *Xpos, U_FLOAT *Ypos); +int U_PMF_LINEARGRADIENTBRUSHDATA_print(const char *contents, const char *blimit); +int U_PMF_LINEARGRADIENTBRUSHOPTIONALDATA_print(const char *contents, int BDFlag, const char *blimit); +int U_PMF_LINEPATH_print(const char *contents, const char *blimit); +int U_PMF_METAFILE_print(const char *contents, const char *blimit); +int U_PMF_PALETTE_print(const char *contents, const char *blimit); +int U_PMF_PATHGRADIENTBRUSHDATA_print(const char *contents, const char *blimit); +int U_PMF_PATHGRADIENTBRUSHOPTIONALDATA_print(const char *contents, int BDFlag, const char *blimit); +int U_PMF_PATHPOINTTYPE_print(const char *contents, const char *blimit); +int U_PMF_PATHPOINTTYPERLE_print(const char *contents, const char *blimit); +int U_PMF_PENDATA_print(const char *contents, const char *blimit); +int U_PMF_PENOPTIONALDATA_print(const char *contents, int Flags, const char *blimit); +int U_PMF_POINT_print(const char **contents, const char *blimit); +int U_PMF_POINTF_print(const char **contents, const char *blimit); +int U_PMF_POINTR_print(const char **contents, U_FLOAT *Xpos, U_FLOAT *Ypos, const char *blimit); int U_PMF_POINT_S_print(U_PMF_POINT *Point); int U_PMF_POINTF_S_print(U_PMF_POINTF *Point); -int U_PMF_RECT_print(const char **contents); -int U_PMF_RECTF_print(const char **contents); +int U_PMF_RECT_print(const char **contents, const char *blimit); +int U_PMF_RECTF_print(const char **contents, const char *blimit); int U_PMF_RECT_S_print(U_PMF_RECT *Rect); int U_PMF_RECTF_S_print(U_PMF_RECTF *Rect); -int U_PMF_REGIONNODE_print(const char *contents, int Level); -int U_PMF_REGIONNODECHILDNODES_print(const char *contents, int Level); -int U_PMF_REGIONNODEPATH_print(const char *contents); -int U_PMF_SOLIDBRUSHDATA_print(const char *contents); -int U_PMF_STRINGFORMATDATA_print(const char *contents, uint32_t TabStopCount, uint32_t RangeCount); -int U_PMF_TEXTUREBRUSHDATA_print(const char *contents); -int U_PMF_TEXTUREBRUSHOPTIONALDATA_print(const char *contents, int HasImage); -int U_PMF_TRANSFORMMATRIX_print(const char *contents); +int U_PMF_REGIONNODE_print(const char *contents, int Level, const char *blimit); +int U_PMF_REGIONNODECHILDNODES_print(const char *contents, int Level, const char *blimit); +int U_PMF_REGIONNODEPATH_print(const char *contents, const char *blimit); +int U_PMF_SOLIDBRUSHDATA_print(const char *contents, const char *blimit); +int U_PMF_STRINGFORMATDATA_print(const char *contents, uint32_t TabStopCount, uint32_t RangeCount, const char *blimit); +int U_PMF_TEXTUREBRUSHDATA_print(const char *contents, const char *blimit); +int U_PMF_TEXTUREBRUSHOPTIONALDATA_print(const char *contents, int HasMatrix, int HasImage, const char *blimit); +int U_PMF_TRANSFORMMATRIX_print(const char *contents, const char *blimit); int U_PMF_TRANSFORMMATRIX2_print(U_PMF_TRANSFORMMATRIX *Matrix); int U_PMF_ROTMATRIX2_print(U_PMF_ROTMATRIX *Matrix); -int U_PMF_IE_BLUR_print(const char *contents); -int U_PMF_IE_BRIGHTNESSCONTRAST_print(const char *contents); -int U_PMF_IE_COLORBALANCE_print(const char *contents); -int U_PMF_IE_COLORCURVE_print(const char *contents); -int U_PMF_IE_COLORLOOKUPTABLE_print(const char *contents); -int U_PMF_IE_COLORMATRIX_print(const char *contents); -int U_PMF_IE_HUESATURATIONLIGHTNESS_print(const char *contents); -int U_PMF_IE_LEVELS_print(const char *contents); -int U_PMF_IE_REDEYECORRECTION_print(const char *contents); -int U_PMF_IE_SHARPEN_print(const char *contents); -int U_PMF_IE_TINT_print(const char *contents); +int U_PMF_IE_BLUR_print(const char *contents, const char *blimit); +int U_PMF_IE_BRIGHTNESSCONTRAST_print(const char *contents, const char *blimit); +int U_PMF_IE_COLORBALANCE_print(const char *contents, const char *blimit); +int U_PMF_IE_COLORCURVE_print(const char *contents, const char *blimit); +int U_PMF_IE_COLORLOOKUPTABLE_print(const char *contents, const char *blimit); +int U_PMF_IE_COLORMATRIX_print(const char *contents, const char *blimit); +int U_PMF_IE_HUESATURATIONLIGHTNESS_print(const char *contents, const char *blimit); +int U_PMF_IE_LEVELS_print(const char *contents, const char *blimit); +int U_PMF_IE_REDEYECORRECTION_print(const char *contents, const char *blimit); +int U_PMF_IE_SHARPEN_print(const char *contents, const char *blimit); +int U_PMF_IE_TINT_print(const char *contents, const char *blimit); /* prototypes for PMR records */ int U_PMR_OFFSETCLIP_print(const char *contents); @@ -127,14 +128,14 @@ int U_PMR_DRAWIMAGEPOINTS_print(const char *contents); int U_PMR_DRAWLINES_print(const char *contents); int U_PMR_DRAWPATH_print(const char *contents); int U_PMR_DRAWPIE_print(const char *contents); -int U_PMR_DRAWRECTS_print(const char *contents, const char *blimit); +int U_PMR_DRAWRECTS_print(const char *contents); int U_PMR_DRAWSTRING_print(const char *contents); int U_PMR_FILLCLOSEDCURVE_print(const char *contents); int U_PMR_FILLELLIPSE_print(const char *contents); int U_PMR_FILLPATH_print(const char *contents); int U_PMR_FILLPIE_print(const char *contents); int U_PMR_FILLPOLYGON_print(const char *contents); -int U_PMR_FILLRECTS_print(const char *contents, const char *blimit); +int U_PMR_FILLRECTS_print(const char *contents); int U_PMR_FILLREGION_print(const char *contents); int U_PMR_OBJECT_print(const char *contents, const char *blimit, U_OBJ_ACCUM *ObjCont, int term); int U_PMR_SERIALIZABLEOBJECT_print(const char *contents); diff --git a/src/libuemf/uwmf.c b/src/libuemf/uwmf.c index b378e587f..35d38f69a 100644 --- a/src/libuemf/uwmf.c +++ b/src/libuemf/uwmf.c @@ -19,8 +19,8 @@ /* File: uwmf.c -Version: 0.0.15 -Date: 11-APR-2014 +Version: 0.0.16 +Date: 25-MAR-2015 Author: David Mathog, Biology Division, Caltech email: mathog@caltech.edu Copyright: 2014 David Mathog and California Institute of Technology (Caltech) @@ -47,6 +47,7 @@ extern "C" { #endif #include "uwmf.h" #include "uwmf_endian.h" +#include "uemf_safe.h" /** \brief Look up the full numeric type of a WMR record by type. @@ -671,6 +672,51 @@ const char *U_wmr_escnames(int idx){ /* one prototype from uwmf_endian. Put it here because end user should never need to see it, so not in uemf.h or uwmf_endian.h */ void U_swap2(void *ul, unsigned int count); + +/** + \brief Check that the bitmap in the specified packed DIB is compatible with the record size + + \return 1 on success, 0 on failure + \param record EMF record that contains a DIB pixel array + \param blimit one byte past the end of the record. + + This method can only test DIBs that hold Microsoft's various bitmap types. PNG or JPG is just a bag + of bytes, and there is no possible way to derive from the known width and height how big it should be. + + This should not be called directly by end user code. +*/ +int packed_DIB_safe( + const char *record, + const char *blimit + ){ + int dibparams = U_BI_UNKNOWN; // type of image not yet determined + const char *px = NULL; // DIB pixels + const U_RGBQUAD *ct = NULL; // DIB color table + int bs; + int usedbytes; + + if(!bitmapinfo_safe(record, blimit))return(0); // this DIB has issues with colors fitting into the record + uint32_t width, height, colortype, numCt, invert; // these values will be set in get_DIB_params + // next call returns pointers and values, but allocates no memory + dibparams = wget_DIB_params(record, &px, (const U_RGBQUAD **) &ct, &numCt, &width, &height, &colortype, &invert); + // sanity checking + if(numCt && colortype >= U_BCBM_COLOR16)return(0); //color tables not used above 16 bit pixels + if(!numCt && colortype < U_BCBM_COLOR16)return(0); //color tables mandatory for < 16 bit + + if(dibparams ==U_BI_RGB){ + // this is the only DIB type where we can calculate how big it should be when stored in the WMF file + bs = colortype/8; + if(bs<1){ + usedbytes = (width*colortype + 7)/8; // width of line in fully and partially occupied bytes + } + else { + usedbytes = width*bs; + } + if(IS_MEM_UNSAFE(px, usedbytes, blimit))return(0); + } + return(1); +} + //! \endcond /** @@ -4439,9 +4485,7 @@ size_t U_WMRRECSAFE_get( memcpy(&Size16, contents + offsetof(U_METARECORD,Size16_4), 4); size = 2*Size16; /* Record is not self consistent - described size past the end of WMF in memory */ - if(size < U_SIZE_METARECORD || - contents + size - 1 >= blimit || - contents + size - 1 < contents)size=0; + if(size < U_SIZE_METARECORD || IS_MEM_UNSAFE(contents, size, blimit))size=0; return(size); } @@ -4826,20 +4870,21 @@ int wmfheader_get( ){ uint32_t Key; int size=0; - if(!Placeable || !Header || contents + 4 >= blimit)return(0); + if(!contents || !Placeable || !Header || !blimit)return(0); + if(IS_MEM_UNSAFE(contents, 4, blimit))return(0); memcpy(&Key, contents + offsetof(U_WMRPLACEABLE,Key), 4); if(Key == 0x9AC6CDD7){ size += U_SIZE_WMRPLACEABLE; - if(contents + size >= blimit)return(0); + if(IS_MEM_UNSAFE(contents, size, blimit))return(0); memcpy(Placeable, contents, U_SIZE_WMRPLACEABLE); contents += U_SIZE_WMRPLACEABLE; } else { memset(Placeable, 0, U_SIZE_WMRPLACEABLE); } - if(contents + size + U_SIZE_WMRHEADER >= blimit)return(0); + if(IS_MEM_UNSAFE(contents, size + U_SIZE_WMRHEADER, blimit))return(0); size += 2* (*(uint16_t *)(contents + offsetof(U_WMRHEADER,Size16w))); - if(contents + size >= blimit)return(0); + if(IS_MEM_UNSAFE(contents, size, blimit))return(0); memcpy(Header, contents, U_SIZE_WMRHEADER); return(size); } @@ -5512,7 +5557,11 @@ int U_WMRPOLYGON_get( uint16_t *Length, const char **Data ){ - return U_WMRCORE_2U16_N16_get(contents, (U_SIZE_WMRPOLYGON), NULL, Length, Data); + int size = U_WMRCORE_2U16_N16_get(contents, (U_SIZE_WMRPOLYGON), NULL, Length, Data); + if(size){ + if(IS_MEM_UNSAFE(*Data, (*Length)*sizeof(U_POINT16), contents+size))return(0); + } + return size; } /** @@ -5527,7 +5576,11 @@ int U_WMRPOLYLINE_get( uint16_t *Length, const char **Data ){ - return U_WMRCORE_2U16_N16_get(contents, (U_SIZE_WMRPOLYLINE), NULL, Length, Data); + int size = U_WMRCORE_2U16_N16_get(contents, (U_SIZE_WMRPOLYGON), NULL, Length, Data); + if(size){ + if(IS_MEM_UNSAFE(*Data, (*Length)*sizeof(U_POINT16), contents+size))return(0); + } + return size; } /** @@ -5550,7 +5603,11 @@ int U_WMRESCAPE_get( uint16_t *Length, const char **Data ){ - return U_WMRCORE_2U16_N16_get(contents, (U_SIZE_WMRESCAPE), Escape, Length, Data); + int size = U_WMRCORE_2U16_N16_get(contents, (U_SIZE_WMRESCAPE), Escape, Length, Data); + if(size){ + if(IS_MEM_UNSAFE(*Data, *Length, contents+size))return(0); + } + return size; } /** @@ -5787,6 +5844,7 @@ int U_WMRSETDIBTODEV_get( Dst->y = *(int16_t *)( contents + offsetof(U_WMRSETDIBTODEV, yDst )); Dst->x = *(int16_t *)( contents + offsetof(U_WMRSETDIBTODEV, xDst )); *dib = ( contents + offsetof(U_WMRSETDIBTODEV, dib )); + if(!packed_DIB_safe(*dib, *dib+size))return(0); return(size); } @@ -5948,6 +6006,7 @@ int U_WMRDIBBITBLT_get( Dst->y = *(int16_t *)( contents + offsetof(U_WMRDIBBITBLT_PX, yDst )); Dst->x = *(int16_t *)( contents + offsetof(U_WMRDIBBITBLT_PX, xDst )); *dib = ( contents + offsetof(U_WMRDIBBITBLT_PX, dib )); + if(!packed_DIB_safe(*dib, *dib+size))return(0); } return(size); } @@ -5999,6 +6058,7 @@ int U_WMRDIBSTRETCHBLT_get( cDst->y = *(int16_t *)( contents + offsetof(U_WMRDIBSTRETCHBLT_PX, hDst )); cDst->x = *(int16_t *)( contents + offsetof(U_WMRDIBSTRETCHBLT_PX, wDst )); *dib = ( contents + offsetof(U_WMRDIBSTRETCHBLT_PX, dib )); + if(!packed_DIB_safe(*dib, *dib+size))return(0); } return(size); } @@ -6040,11 +6100,13 @@ int U_WMRDIBCREATEPATTERNBRUSH_get( if(TmpBm16.Width <= 0 || TmpBm16.Height <= 0 || TmpBm16.Planes != 1 || TmpBm16.BitsPixel == 0){ *Bm16 = NULL; *dib = (contents + offsetof(U_WMRDIBCREATEPATTERNBRUSH, Src)); + if(!packed_DIB_safe(*dib, *dib+size))return(0); } } else { /* from DIB */ *Bm16 = NULL; *dib = (contents + offsetof(U_WMRDIBCREATEPATTERNBRUSH, Src)); + if(!packed_DIB_safe(*dib, *dib+size))return(0); } return(size); } @@ -6085,6 +6147,7 @@ int U_WMRSTRETCHDIB_get( Dst->y = *(int16_t *)( contents + offsetof(U_WMRSTRETCHDIB, yDst )); Dst->x = *(int16_t *)( contents + offsetof(U_WMRSTRETCHDIB, xDst )); *dib = ( contents + offsetof(U_WMRSTRETCHDIB, dib )); + if(!packed_DIB_safe(*dib, *dib+size))return(0); return(size); } @@ -6914,7 +6977,12 @@ int U_WMRCREATEFONTINDIRECT_get( const char *contents, const char **font ){ - return U_WMRCORE_2U16_N16_get(contents, (U_SIZE_WMRCREATEFONTINDIRECT), NULL, NULL, font); + int size = U_WMRCORE_2U16_N16_get(contents, (U_SIZE_WMRCREATEFONTINDIRECT), NULL, NULL, font); + if(size){ + if(IS_MEM_UNSAFE(*font, U_SIZE_FONT_CORE, contents+size))return(0); + if(contents + size - *font > U_SIZE_FONT_CORE + 32)return(0); // font name must fit in a 32 bit field + } + return size; } /** @@ -6927,6 +6995,7 @@ int U_WMRCREATEBRUSHINDIRECT_get( const char *contents, const char **brush ){ + // U_SIZE_WMRCREATEBRUSHINDIRECT is everything, no variable part, so the test below is sufficient return U_WMRCORE_2U16_N16_get(contents, (U_SIZE_WMRCREATEBRUSHINDIRECT), NULL, NULL, brush); } @@ -6947,16 +7016,19 @@ int U_WMRCREATEBITMAP_get(void){ \return length of the U_WMRCREATEREGION record in bytes, or 0 on error \param contents record to extract data from \param Region pointer to U_REGION structure in memory. Pointer may not be aligned properly for structure. + + Caller must check at the returned Region does not extend outside of the record! */ int U_WMRCREATEREGION_get( const char *contents, const char **Region ){ - return U_WMRCORE_2U16_N16_get(contents, (U_SIZE_WMRCREATEREGION), NULL, NULL, Region); + return U_WMRCORE_2U16_N16_get(contents, (U_SIZE_WMRCREATEREGION), NULL, NULL, Region); } + #ifdef __cplusplus } #endif diff --git a/src/libuemf/uwmf.h b/src/libuemf/uwmf.h index 54f7f36fe..2237d2221 100644 --- a/src/libuemf/uwmf.h +++ b/src/libuemf/uwmf.h @@ -36,8 +36,8 @@ /* File: uwmf.h -Version: 0.0.10 -Date: 24-MAR-2014 +Version: 0.0.11 +Date: 23-APR-2014 Author: David Mathog, Biology Division, Caltech email: mathog@caltech.edu Copyright: 2014 David Mathog and California Institute of Technology (Caltech) @@ -728,6 +728,7 @@ enum U_WMR_TYPES{ #define U_SIZE_WMRCREATEFONTINDIRECT 26 /**< X 28 */ #define U_SIZE_WMRCREATEBRUSHINDIRECT 14 /**< X 16 */ #define U_SIZE_WMRCREATEREGION 26 /**< X 28 */ +#define U_SIZE_WMRCREATEREGION_CORE 24 /**< X 28 Like U_SIZE_WMRCREATEREGION minus the variable part */ /** @} */ diff --git a/src/libuemf/uwmf_print.c b/src/libuemf/uwmf_print.c index 0e089a5cd..dd460b2b0 100644 --- a/src/libuemf/uwmf_print.c +++ b/src/libuemf/uwmf_print.c @@ -319,7 +319,7 @@ void scan_print( \param dh void pointer to DIB header A DIB header in an WMF may be either a BitmapCoreHeader or BitmapInfoHeader. */ -void dibheader_print(const void *dh){ +void dibheader_print(const char *dh, const char *blimit){ uint32_t Size; memcpy(&Size, dh, 4); /* may not be aligned */ if(Size == 0xC ){ @@ -330,7 +330,7 @@ void dibheader_print(const void *dh){ } else { printf(" (BitmapInfoHeader) "); - bitmapinfo_print(dh); /* may not be aligned, called routine must handle it */ + bitmapinfo_print(dh, blimit); /* may not be aligned, called routine must handle it */ } } @@ -922,7 +922,7 @@ void U_WMRSETDIBTODEV_print(const char *contents){ printf(" Src X,Y:{%d,%d}\n", Src.x, Src.y ); printf(" W,H:%d,%d\n", cwh.x, cwh.y ); printf(" Dst X,Y:{%d,%d}\n", Dst.x, Dst.y ); - printf(" DIB:"); dibheader_print(dib); printf("\n"); + printf(" DIB:"); dibheader_print(dib, dib+size); printf("\n"); } } @@ -993,7 +993,7 @@ void U_WMRDIBBITBLT_print(const char *contents){ printf(" Src X,Y:{%d,%d}\n", Src.x, Src.x ); printf(" W,H:%d,%d\n", cwh.x, cwh.y ); printf(" Dst X,Y:{%d,%d}\n", Dst.x, Dst.y ); - if(dib){ printf(" DIB:"); dibheader_print(dib); printf("\n"); } + if(dib){ printf(" DIB:"); dibheader_print(dib, dib+size); printf("\n"); } else { printf(" DIB: none\n"); } } } @@ -1009,7 +1009,7 @@ void U_WMRDIBSTRETCHBLT_print(const char *contents){ printf(" Src X,Y:{%d,%d}\n", Src.x, Src.x ); printf(" Dst W,H:%d,%d\n", cDst.x, cDst.y ); printf(" Dst X,Y:{%d,%d}\n", Dst.x, Dst.y ); - if(dib){ printf(" DIB:"); dibheader_print(dib); printf("\n"); } + if(dib){ printf(" DIB:"); dibheader_print(dib, dib+size); printf("\n"); } else { printf(" DIB: none\n"); } } } @@ -1028,7 +1028,7 @@ void U_WMRDIBCREATEPATTERNBRUSH_print(const char *contents){ printf(" Src:Bitmap16:"); bitmap16_print(Bm16); printf("\n"); } else { /* from DIB */ - printf(" Src:DIB:"); dibheader_print(dib); printf("\n"); + printf(" Src:DIB:"); dibheader_print(dib, dib+size); printf("\n"); } } } @@ -1046,7 +1046,7 @@ void U_WMRSTRETCHDIB_print(const char *contents){ printf(" Src X,Y:{%d,%d}\n", Src.x, Src.x ); printf(" Dst W,H:%d,%d\n", cDst.x, cDst.y ); printf(" Dst X,Y:{%d,%d}\n", Dst.x, Dst.y ); - if(dib){ printf(" DIB:"); dibheader_print(dib); printf("\n"); } + if(dib){ printf(" DIB:"); dibheader_print(dib, dib+size); printf("\n"); } else { printf(" DIB: none\n"); } } } diff --git a/src/libuemf/uwmf_print.h b/src/libuemf/uwmf_print.h index 8daee0feb..54dfe9c9c 100644 --- a/src/libuemf/uwmf_print.h +++ b/src/libuemf/uwmf_print.h @@ -37,7 +37,7 @@ void bitmapcoreheader_print(U_BITMAPCOREHEADER ch); void logbrushw_print(U_WLOGBRUSH lb); void polypolygon_print(uint16_t nPolys, const uint16_t *aPolyCounts, const char *Points); void scan_print(U_SCAN sc); -void dibheader_print(const void *dh); +void dibheader_print(const char *dh, const char *blimit); /* prototypes for WMF records */ int wmfheader_print(const char *contents, const char *blimit); -- cgit v1.2.3 From 9b9f0427b04c7e84f7c0baad54ce3005ad08ac65 Mon Sep 17 00:00:00 2001 From: mathog <> Date: Mon, 27 Apr 2015 12:30:27 -0700 Subject: add two files omitted in patch at revision 14062 (bzr r14063) --- src/libuemf/uemf_safe.c | 1202 +++++++++++++++++++++++++++++++++++++++++++++++ src/libuemf/uemf_safe.h | 32 ++ 2 files changed, 1234 insertions(+) create mode 100644 src/libuemf/uemf_safe.c create mode 100644 src/libuemf/uemf_safe.h (limited to 'src') diff --git a/src/libuemf/uemf_safe.c b/src/libuemf/uemf_safe.c new file mode 100644 index 000000000..36284d60e --- /dev/null +++ b/src/libuemf/uemf_safe.c @@ -0,0 +1,1202 @@ +/** + @file uemf_safe.c + + @brief Functions for checking EMF records for memory issues. + + EMF records come in a variety of sizes, and some types have variable sizes. + These functions check the record types and report if there are any issues + that could cause a memory access problem. All counts and offsets are examined + and the data structure checked so that no referenced byte is outside of the + declared size of the record. + + Many variables are initialized to zero even though they will always be set because + some versions of gcc give spurious "may be used uninitialized" warnings otherwise. +*/ + +/* +File: uemf_safe.c +Version: 0.0.4 +Date: 23-APR-2015 +Author: David Mathog, Biology Division, Caltech +email: mathog@caltech.edu +Copyright: 2015 David Mathog and California Institute of Technology (Caltech) +*/ + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include +#include +#include /* for offsetof() macro */ +#include "uemf.h" +#include "uemf_endian.h" // for u_emf_record_sizeok + +// hide almost everuything in here from Doxygen +//! \cond + +/** + \brief Test a U_EXTLOGPEN object. + \param elp PU_EXTLOGPEN object + \param blimit one byte past the end of the record +*/ +int extlogpen_safe( + PU_EXTLOGPEN elp, + const char *blimit + ){ + int count=elp->elpNumEntries; + if(IS_MEM_UNSAFE(&(elp->elpStyleEntry), count*4, blimit))return(0); + return(1); +} + +/** + \brief Test a U_EMRTEXT record + \param pemt Pointer to a U_EMRTEXT record + \param record Pointer to the start of the record which contains this U_EMRTEXT + \param blimit one byte past the end of the record. +*/ +int emrtext_safe( + PU_EMRTEXT pemt, + const char *record, + const char *blimit + ){ + int off; + uint32_t count = pemt->nChars; + uint32_t fOptions = pemt->fOptions; + uint32_t offDx = 0; + off = sizeof(U_EMRTEXT); + if(!(fOptions & U_ETO_NO_RECT)){ + if(IS_MEM_UNSAFE(pemt, sizeof(U_RECTL), blimit))return(0); + off+=sizeof(U_RECTL); + } + offDx = *(uint32_t *)((char *)pemt +off); + if(IS_MEM_UNSAFE(pemt, off + 4, blimit))return(0); + if(IS_MEM_UNSAFE(record, offDx + count*4, blimit))return(0); + return(1); +} + +/** + \return 1 on success, 0 on failure + \brief Test a U_RGNDATA object. + \param rd pointer to a U_RGNDATA object. + \param cbRgnData size of the U_RGNDATA object. +*/ +int rgndata_safe( + PU_RGNDATA rd, + int cbRgnData + ){ + int count = rd->rdh.nCount; + if(4*count + (int)sizeof(U_RGNDATAHEADER) > cbRgnData)return(0); + return(1); +} + + +/** + \return 1 on success, 0 on failure + \brief Test a U_BITMAPINFO object. + \param Bmi pointer to a U_BITMAPINFO object. + \param blimit one byte past the end of the record. +*/ +int bitmapinfo_safe( + const char *Bmi, + const char *blimit + ){ + int ClrUsed; + if(IS_MEM_UNSAFE(Bmi, offsetof(U_BITMAPINFO,bmiHeader) + sizeof(U_BITMAPINFOHEADER), blimit))return(0); + ClrUsed = get_real_color_count(Bmi + offsetof(U_BITMAPINFO,bmiHeader)); + if(ClrUsed && IS_MEM_UNSAFE(Bmi, offsetof(U_BITMAPINFO,bmiColors) + ClrUsed*sizeof(U_RGBQUAD), blimit))return(0); + return(1); +} + +/** + \brief Check that the bitmap in the specified DIB is compatible with the record size + + \return 1 on success, 0 on failure + \param record EMF record that contains a DIB pixel array + \param iUsage DIBcolors Enumeration + \param offBmi offset from the start of the record to the start of the bitmapinfo structure + \param cbBmi declared space for the bitmapinfo structure in the record + \param offBits offset from the start of the record to the start of the bitmap + \param cbBits declared space for the bitmap in the record (amount used may be less than this) + \param blimit one byte past the end of the record. + + This method can only test DIBs that hold Microsoft's various bitmap types. PNG or JPG is just a bag + of bytes, and there is no possible way to derive from the known width and height how big it should be. +*/ +int DIB_safe( + const char *record, + uint32_t iUsage, + uint32_t offBmi, + uint32_t cbBmi, + uint32_t offBits, + uint32_t cbBits, + const char *blimit + ){ + int dibparams = U_BI_UNKNOWN; // type of image not yet determined + const char *px = NULL; // DIB pixels + const U_RGBQUAD *ct = NULL; // DIB color table + int bs; + int usedbytes; + + if(!cbBmi)return(1); // No DIB in a record where it is optional + if(IS_MEM_UNSAFE(record, offBmi + cbBmi, blimit))return(0); + if(!bitmapinfo_safe(record + offBmi, blimit))return(0); // checks the number of colors + if(cbBits && IS_MEM_UNSAFE(record, offBits + cbBits, blimit))return(0); + if(iUsage == U_DIB_RGB_COLORS){ + uint32_t width, height, colortype, numCt, invert; // these values will be set in get_DIB_params + // next call returns pointers and values, but allocates no memory + dibparams = get_DIB_params(record, offBits, offBmi, &px, (const U_RGBQUAD **) &ct, + &numCt, &width, &height, &colortype, &invert); + + // sanity checking + if(numCt && colortype >= U_BCBM_COLOR16)return(0); //color tables not used above 16 bit pixels + if(!numCt && colortype < U_BCBM_COLOR16)return(0); //color tables mandatory for < 16 bit + + if(dibparams ==U_BI_RGB){ + // this is the only DIB type where we can calculate how big it should be when stored in the EMF file + bs = colortype/8; + if(bs<1){ + usedbytes = (width*colortype + 7)/8; // width of line in fully and partially occupied bytes + } + else { + usedbytes = width*bs; + } + if(IS_MEM_UNSAFE(record+offBits, usedbytes, blimit))return(0); + } + } + return(1); +} + + +/* ********************************************************************************************** +These functions contain shared code used by various U_EMR*_safe functions. These should NEVER be called +by end user code and to further that end prototypes are NOT provided and they are hidden from Doxygen. + + + These all have this form: + + void core1_safe(const char *record){ + + but some do not actually use torev. + + + +*********************************************************************************************** */ + +// all core*_safe call this, U_EMRSETMARGN_safe and some others all it directly +// numbered as core5 to be consistent with uemf.c, but must appear before the others as there is no prototype +// sizeof(U_ENHMETARECORD) bytes in the record +int core5_safe(const char *record, int minSize){ + PU_EMR pEmr = (PU_EMR)(record); + if((int) pEmr->nSize < minSize)return(0); + return(1); +} + +// Functions with the same form starting with U_EMRPOLYBEZIER_safe +int core1_safe(const char *record){ + if(!core5_safe(record, U_SIZE_EMRPOLYLINETO))return(0); + PU_EMRPOLYLINETO pEmr = (PU_EMRPOLYLINETO) (record); + int count=pEmr->cptl; + const char *blimit = record + pEmr->emr.nSize; + if(IS_MEM_UNSAFE(pEmr->aptl, count*sizeof(U_POINTL), blimit))return(0); + return(1); +} + +// Functions with the same form starting with U_EMRPOLYPOLYLINE_safe +int core2_safe(const char *record){ + if(!core5_safe(record, U_SIZE_EMRPOLYPOLYLINE))return(0); + PU_EMRPOLYPOLYLINE pEmr = (PU_EMRPOLYPOLYLINE) (record); + int count = pEmr->cptl; + int nPolys = pEmr->nPolys; + const char * blimit = record + pEmr->emr.nSize; + if(IS_MEM_UNSAFE(pEmr->aPolyCounts, nPolys*4, blimit))return(0); + record += sizeof(U_EMRPOLYPOLYLINE) - 4 + sizeof(uint32_t)* nPolys; + if(IS_MEM_UNSAFE(record, count*sizeof(U_POINTL), blimit))return(0); + return(1); +} + + +// Functions with the same form starting with U_EMRSETMAPMODE_safe +int core3_safe(const char *record){ + if(!core5_safe(record, U_SIZE_EMRSETMAPMODE))return(0); + return(1); +} + +// Functions taking a single U_RECT or U_RECTL, starting with U_EMRELLIPSE_safe, also U_EMRFILLPATH_safe, +int core4_safe(const char *record){ + if(!core5_safe(record, U_SIZE_EMRELLIPSE))return(0); + return(1); +} + +// Functions with the same form starting with U_EMRPOLYBEZIER16_safe +int core6_safe(const char *record){ + if(!core5_safe(record, U_SIZE_EMRPOLYBEZIER16))return(0); + PU_EMRPOLYBEZIER16 pEmr = (PU_EMRPOLYBEZIER16) (record); + int count=pEmr->cpts; + const char *blimit = record + pEmr->emr.nSize; + if(IS_MEM_UNSAFE(pEmr->apts, count*sizeof(U_POINT16), blimit))return(0); + return(1); +} + + +// Records with the same form starting with U_EMRSETWINDOWEXTEX_safe, that is, all with two uint32_t values after the emr +int core7_safe(const char *record){ + if(!core5_safe(record, U_SIZE_EMRSETWINDOWEXTEX))return(0); + return(1); +} + +// For U_EMREXTTEXTOUTA and U_EMREXTTEXTOUTW, type=0 for the first one +int core8_safe(const char *record){ + if(!core5_safe(record, U_SIZE_EMREXTTEXTOUTA))return(0); + PU_EMREXTTEXTOUTA pEmr = (PU_EMREXTTEXTOUTA) (record); + const char *blimit = record + pEmr->emr.nSize; + if(!emrtext_safe(&(pEmr->emrtext),record,blimit))return(0); + return(1); +} + +// Functions that take a rect and a pair of points, starting with U_EMRARC_safe +int core9_safe(const char *record){ + if(!core5_safe(record, U_SIZE_EMRARC))return(0); + return(1); +} + +// Functions with the same form starting with U_EMRPOLYPOLYLINE16_safe +int core10_safe(const char *record){ + if(!core5_safe(record, U_SIZE_EMRPOLYPOLYLINE16))return(0); + PU_EMRPOLYPOLYLINE16 pEmr = (PU_EMRPOLYPOLYLINE16) (record); + int count = pEmr->cpts; + int nPolys = pEmr->nPolys; + const char *blimit = record + pEmr->emr.nSize; + if(IS_MEM_UNSAFE(pEmr->aPolyCounts, nPolys*4, blimit))return(0); + record += sizeof(U_EMRPOLYPOLYLINE16) - 4 + sizeof(uint32_t)* nPolys; + if(IS_MEM_UNSAFE(record, count*sizeof(U_POINT16), blimit))return(0); + return(1); +} + +// Functions with the same form starting with U_EMRINVERTRGN_safe and U_EMRPAINTRGN_safe, +int core11_safe(const char *record){ + if(!core5_safe(record, U_SIZE_EMRINVERTRGN))return(0); + PU_EMRINVERTRGN pEmr = (PU_EMRINVERTRGN)(record); + int cbRgnData = pEmr->cbRgnData; + const char *blimit = record + pEmr->emr.nSize; + if(IS_MEM_UNSAFE(pEmr->RgnData, cbRgnData, blimit))return(0); + return(rgndata_safe(pEmr->RgnData, cbRgnData)); +} + + +// common code for U_EMRCREATEMONOBRUSH_safe and U_EMRCREATEDIBPATTERNBRUSHPT_safe, +int core12_safe(const char *record){ + if(!core5_safe(record, U_SIZE_EMRCREATEMONOBRUSH))return(0); + PU_EMRCREATEMONOBRUSH pEmr = (PU_EMRCREATEMONOBRUSH) (record); + const char *blimit = record + pEmr->emr.nSize; + U_OFFBMI offBmi = pEmr->offBmi; + U_CBBMI cbBmi = pEmr->cbBmi; + U_OFFBITS offBits = pEmr->offBits; + U_CBBITS cbBits = pEmr->cbBits; + uint32_t iUsage = pEmr->iUsage; + return(DIB_safe(record, iUsage, offBmi, cbBmi, offBits, cbBits, blimit)); +} + +// common code for U_EMRALPHABLEND_safe and U_EMRTRANSPARENTBLT_safe, +int core13_safe(const char *record){ + if(!core5_safe(record, U_SIZE_EMRALPHABLEND))return(0); + PU_EMRALPHABLEND pEmr = (PU_EMRALPHABLEND) (record); + const char *blimit = record + pEmr->emr.nSize; + U_OFFBMISRC offBmiSrc = pEmr->offBmiSrc; + U_CBBMISRC cbBmiSrc = pEmr->cbBmiSrc; + U_OFFBITSSRC offBitsSrc = pEmr->offBitsSrc; + U_CBBITS cbBitsSrc = pEmr->cbBitsSrc; + uint32_t iUsageSrc = pEmr->iUsageSrc; + return(DIB_safe(record, iUsageSrc, offBmiSrc, cbBmiSrc, offBitsSrc, cbBitsSrc, blimit)); +} + +/* ********************************************************************************************** +These are the core EMR_safe functions, each converts a particular type of record. +All operate in place on the chunk of memory holding that record. +Some of these have offsets or counts which, if corrupt or evil would result in access outside + the record. These cases return a status value of 0 if that happens, 1 on success. Other + records which do not have these issues do not return a status value. +They are listed in order by the corresponding U_EMR_* index number. +*********************************************************************************************** */ + +/** + All of the record level (hidden) functions have this form: + \brief Convert a pointer to a U_EMR_whatever record which has not been implemented. + \param record pointer to a buffer holding the EMR record + \param torev 1 for native to reversed, 0 for reversed to native +*/ +int U_EMRNOTIMPLEMENTED_safe(const char *record){ + fprintf(stderr,"EMF WARNING: could not safety check record because that type has not been implemented!\n"); + return(core5_safe(record, sizeof(U_EMR))); +} + +// U_EMRHEADER 1 +int U_EMRHEADER_safe(const char *record){ + // use _MIN form so that it accepts very old EMF files + return(core5_safe(record, U_SIZE_EMRHEADER_MIN)); +} + +// U_EMRPOLYBEZIER 2 +int U_EMRPOLYBEZIER_safe(const char *record){ + return(core1_safe(record)); +} + +// U_EMRPOLYGON 3 +int U_EMRPOLYGON_safe(const char *record){ + return(core1_safe(record)); +} + +// U_EMRPOLYLINE 4 +int U_EMRPOLYLINE_safe(const char *record){ + return(core1_safe(record)); +} + +// U_EMRPOLYBEZIERTO 5 +int U_EMRPOLYBEZIERTO_safe(const char *record){ + return(core1_safe(record)); +} + +// U_EMRPOLYLINETO 6 +int U_EMRPOLYLINETO_safe(const char *record){ + return(core1_safe(record)); +} + +// U_EMRPOLYPOLYLINE 7 +int U_EMRPOLYPOLYLINE_safe(const char *record){ + return(core2_safe(record)); +} + +// U_EMRPOLYPOLYGON 8 +int U_EMRPOLYPOLYGON_safe(const char *record){ + return(core2_safe(record)); +} + +// U_EMRSETWINDOWEXTEX 9 +int U_EMRSETWINDOWEXTEX_safe(const char *record){ + return(core7_safe(record)); +} + +// U_EMRSETWINDOWORGEX 10 +int U_EMRSETWINDOWORGEX_safe(const char *record){ + return(core7_safe(record)); +} + +// U_EMRSETVIEWPORTEXTEX 11 +int U_EMRSETVIEWPORTEXTEX_safe(const char *record){ + return(core7_safe(record)); +} + +// U_EMRSETVIEWPORTORGEX 12 +int U_EMRSETVIEWPORTORGEX_safe(const char *record){ + return(core7_safe(record)); +} + +// U_EMRSETBRUSHORGEX 13 +int U_EMRSETBRUSHORGEX_safe(const char *record){ + return(core7_safe(record)); +} + +// U_EMREOF 14 +int U_EMREOF_safe(const char *record){ + if(!core5_safe(record, U_SIZE_EMREOF))return(0); + PU_EMREOF pEmr = (PU_EMREOF)(record); + const char *blimit = record + pEmr->emr.nSize; + int cbPalEntries=pEmr->cbPalEntries; + if(cbPalEntries){ + if(IS_MEM_UNSAFE(record, pEmr->offPalEntries + 2*2, blimit))return(0);// 2 16 bit values in U_LOGPALLETE + } + int off = sizeof(U_EMREOF) + 4 * cbPalEntries; + if(IS_MEM_UNSAFE(record, off + 4, blimit))return(0); + return(1); +} + + +// U_EMRSETPIXELV 15 +int U_EMRSETPIXELV_safe(const char *record){ + return(core5_safe(record, U_SIZE_EMRSETPIXELV)); + +} + + +// U_EMRSETMAPPERFLAGS 16 +int U_EMRSETMAPPERFLAGS_safe(const char *record){ + return(core5_safe(record, U_SIZE_EMRSETMAPPERFLAGS)); +} + + +// U_EMRSETMAPMODE 17 +int U_EMRSETMAPMODE_safe(const char *record){ + return(core3_safe(record)); +} + +// U_EMRSETBKMODE 18 +int U_EMRSETBKMODE_safe(const char *record){ + return(core3_safe(record)); +} + +// U_EMRSETPOLYFILLMODE 19 +int U_EMRSETPOLYFILLMODE_safe(const char *record){ + return(core3_safe(record)); +} + +// U_EMRSETROP2 20 +int U_EMRSETROP2_safe(const char *record){ + return(core3_safe(record)); +} + +// U_EMRSETSTRETCHBLTMODE 21 +int U_EMRSETSTRETCHBLTMODE_safe(const char *record){ + return(core3_safe(record)); +} + +// U_EMRSETTEXTALIGN 22 +int U_EMRSETTEXTALIGN_safe(const char *record){ + return(core3_safe(record)); +} + +// U_EMRSETCOLORADJUSTMENT 23 +int U_EMRSETCOLORADJUSTMENT_safe(const char *record){ + return(core5_safe(record, U_SIZE_EMRSETCOLORADJUSTMENT)); +} + +// U_EMRSETTEXTCOLOR 24 +int U_EMRSETTEXTCOLOR_safe(const char *record){ + return(core5_safe(record, U_SIZE_EMRSETTEXTCOLOR)); +} + +// U_EMRSETBKCOLOR 25 +int U_EMRSETBKCOLOR_safe(const char *record){ + return(core5_safe(record, U_SIZE_EMRSETBKCOLOR)); +} + +// U_EMROFFSETCLIPRGN 26 +int U_EMROFFSETCLIPRGN_safe(const char *record){ + return(core7_safe(record)); +} + +// U_EMRMOVETOEX 27 +int U_EMRMOVETOEX_safe(const char *record){ + return(core7_safe(record)); +} + +// U_EMRSETMETARGN 28 +int U_EMRSETMETARGN_safe(const char *record){ + return(core5_safe(record, U_SIZE_EMRSETMETARGN)); +} + +// U_EMREXCLUDECLIPRECT 29 +int U_EMREXCLUDECLIPRECT_safe(const char *record){ + return(core4_safe(record)); +} + +// U_EMRINTERSECTCLIPRECT 30 +int U_EMRINTERSECTCLIPRECT_safe(const char *record){ + return(core4_safe(record)); +} + +// U_EMRSCALEVIEWPORTEXTEX 31 +int U_EMRSCALEVIEWPORTEXTEX_safe(const char *record){ + return(core4_safe(record)); +} + +// U_EMRSCALEWINDOWEXTEX 32 +int U_EMRSCALEWINDOWEXTEX_safe(const char *record){ + return(core4_safe(record)); +} + +// U_EMRSAVEDC 33 +int U_EMRSAVEDC_safe(const char *record){ + return(core5_safe(record, U_SIZE_EMRSAVEDC)); +} + +// U_EMRRESTOREDC 34 +int U_EMRRESTOREDC_safe(const char *record){ + return(core3_safe(record)); +} + +// U_EMRSETWORLDTRANSFORM 35 +int U_EMRSETWORLDTRANSFORM_safe(const char *record){ + return(core5_safe(record, U_SIZE_EMRSETWORLDTRANSFORM)); +} + +// U_EMRMODIFYWORLDTRANSFORM 36 +int U_EMRMODIFYWORLDTRANSFORM_safe(const char *record){ + return(core5_safe(record, U_SIZE_EMRMODIFYWORLDTRANSFORM)); +} + +// U_EMRSELECTOBJECT 37 +int U_EMRSELECTOBJECT_safe(const char *record){ + return(core5_safe(record, U_SIZE_EMRSELECTOBJECT)); +} + +// U_EMRCREATEPEN 38 +int U_EMRCREATEPEN_safe(const char *record){ + return(core5_safe(record, U_SIZE_EMRCREATEPEN)); +} + +// U_EMRCREATEBRUSHINDIRECT 39 +int U_EMRCREATEBRUSHINDIRECT_safe(const char *record){ + return(core5_safe(record, U_SIZE_EMRCREATEBRUSHINDIRECT)); +} + +// U_EMRDELETEOBJECT 40 +int U_EMRDELETEOBJECT_safe(const char *record){ + return(core5_safe(record, U_SIZE_EMRDELETEOBJECT)); + +} + +// U_EMRANGLEARC 41 +int U_EMRANGLEARC_safe(const char *record){ + return(core5_safe(record, U_SIZE_EMRANGLEARC)); +} + +// U_EMRELLIPSE 42 +int U_EMRELLIPSE_safe(const char *record){ + return(core4_safe(record)); +} + +// U_EMRRECTANGLE 43 +int U_EMRRECTANGLE_safe(const char *record){ + return(core4_safe(record)); +} + +// U_EMRROUNDRECT 44 +int U_EMRROUNDRECT_safe(const char *record){ + return(core5_safe(record, U_SIZE_EMRROUNDRECT)); +} + +// U_EMRARC 45 +int U_EMRARC_safe(const char *record){ + return(core9_safe(record)); +} + +// U_EMRCHORD 46 +int U_EMRCHORD_safe(const char *record){ + return(core9_safe(record)); +} + +// U_EMRPIE 47 +int U_EMRPIE_safe(const char *record){ + return(core9_safe(record)); +} + +// U_EMRSELECTPALETTE 48 +int U_EMRSELECTPALETTE_safe(const char *record){ + return(core3_safe(record)); +} + +// U_EMRCREATEPALETTE 49 +int U_EMRCREATEPALETTE_safe(const char *record){ + return(core5_safe(record, U_SIZE_EMRCREATEPALETTE)); +} + +// U_EMRSETPALETTEENTRIES 50 +int U_EMRSETPALETTEENTRIES_safe(const char *record){ + return(core5_safe(record, U_SIZE_EMRSETPALETTEENTRIES)); +} + +// U_EMRRESIZEPALETTE 51 +int U_EMRRESIZEPALETTE_safe(const char *record){ + return(core7_safe(record)); +} + +// U_EMRREALIZEPALETTE 52 +int U_EMRREALIZEPALETTE_safe(const char *record){ + return(core5_safe(record, U_SIZE_EMRREALIZEPALETTE)); +} + +// U_EMREXTFLOODFILL 53 +int U_EMREXTFLOODFILL_safe(const char *record){ + return(core5_safe(record, U_SIZE_EMREXTFLOODFILL)); +} + +// U_EMRLINETO 54 +int U_EMRLINETO_safe(const char *record){ + return(core7_safe(record)); +} + +// U_EMRARCTO 55 +int U_EMRARCTO_safe(const char *record){ + return(core9_safe(record)); +} + +// U_EMRPOLYDRAW 56 +int U_EMRPOLYDRAW_safe(const char *record){ + if(!core5_safe(record, U_SIZE_EMRPOLYDRAW))return(0); + PU_EMRPOLYDRAW pEmr = (PU_EMRPOLYDRAW)(record); + int count = pEmr->cptl; + const char *blimit = record + pEmr->emr.nSize; + if(IS_MEM_UNSAFE(pEmr->aptl, count*sizeof(U_POINTL), blimit))return(0); + return(1); +} + +// U_EMRSETARCDIRECTION 57 +int U_EMRSETARCDIRECTION_safe(const char *record){ + return(core3_safe(record)); +} + +// U_EMRSETMITERLIMIT 58 +int U_EMRSETMITERLIMIT_safe(const char *record){ + return(core3_safe(record)); +} + + +// U_EMRBEGINPATH 59 +int U_EMRBEGINPATH_safe(const char *record){ + return(core5_safe(record, U_SIZE_EMRBEGINPATH)); +} + +// U_EMRENDPATH 60 +int U_EMRENDPATH_safe(const char *record){ + return(core5_safe(record, U_SIZE_EMRENDPATH)); +} + +// U_EMRCLOSEFIGURE 61 +int U_EMRCLOSEFIGURE_safe(const char *record){ + return(core5_safe(record, U_SIZE_EMRCLOSEFIGURE)); +} + +// U_EMRFILLPATH 62 +int U_EMRFILLPATH_safe(const char *record){ + return(core4_safe(record)); +} + +// U_EMRSTROKEANDFILLPATH 63 +int U_EMRSTROKEANDFILLPATH_safe(const char *record){ + return(core4_safe(record)); +} + +// U_EMRSTROKEPATH 64 +int U_EMRSTROKEPATH_safe(const char *record){ + return(core4_safe(record)); +} + +// U_EMRFLATTENPATH 65 +int U_EMRFLATTENPATH_safe(const char *record){ + return(core5_safe(record, U_SIZE_EMRFLATTENPATH)); +} + +// U_EMRWIDENPATH 66 +int U_EMRWIDENPATH_safe(const char *record){ + return(core5_safe(record, U_SIZE_EMRWIDENPATH)); +} + +// U_EMRSELECTCLIPPATH 67 +int U_EMRSELECTCLIPPATH_safe(const char *record){ + return(core3_safe(record)); +} + +// U_EMRABORTPATH 68 +int U_EMRABORTPATH_safe(const char *record){ + return(core5_safe(record, U_SIZE_EMRABORTPATH)); +} + +// U_EMRUNDEF69 69 +#define U_EMRUNDEF69_safe(A) U_EMRNOTIMPLEMENTED_safe(A) //!< Not implemented. + +// U_EMRCOMMENT 70 Comment (any binary data, interpretation is program specific) +int U_EMRCOMMENT_safe(const char *record){ + if(!core5_safe(record, U_SIZE_EMRCOMMENT))return(0); + PU_EMRCOMMENT pEmr = (PU_EMRCOMMENT)(record); + int cbData = pEmr->cbData; + const char *blimit =record + pEmr->emr.nSize; + if(IS_MEM_UNSAFE(record, cbData + sizeof(U_SIZE_EMRCOMMENT), blimit))return(0); + return(1); +} + +// U_EMRFILLRGN 71 +int U_EMRFILLRGN_safe(const char *record){ + if(!core5_safe(record, U_SIZE_EMRFILLRGN))return(0); + PU_EMRFILLRGN pEmr = (PU_EMRFILLRGN)(record); + int cbRgnData = pEmr->cbRgnData; + const char *blimit = record + pEmr->emr.nSize; + if(IS_MEM_UNSAFE(pEmr->RgnData, cbRgnData, blimit))return(0); + return(rgndata_safe(pEmr->RgnData, cbRgnData)); +} + +// U_EMRFRAMERGN 72 +int U_EMRFRAMERGN_safe(const char *record){ + if(!core5_safe(record, U_SIZE_EMRFRAMERGN))return(0); + PU_EMRFRAMERGN pEmr = (PU_EMRFRAMERGN)(record); + int cbRgnData = pEmr->cbRgnData; + const char *blimit = record + pEmr->emr.nSize; + if(IS_MEM_UNSAFE(pEmr->RgnData, cbRgnData, blimit))return(0); + return(rgndata_safe(pEmr->RgnData, cbRgnData)); +} + +// U_EMRINVERTRGN 73 +int U_EMRINVERTRGN_safe(const char *record){ + return(core11_safe(record)); +} + +// U_EMRPAINTRGN 74 +int U_EMRPAINTRGN_safe(const char *record){ + return(core11_safe(record)); +} + +// U_EMREXTSELECTCLIPRGN 75 +int U_EMREXTSELECTCLIPRGN_safe(const char *record){ + if(!core5_safe(record, U_SIZE_EMREXTSELECTCLIPRGN))return(0); + PU_EMREXTSELECTCLIPRGN pEmr = (PU_EMREXTSELECTCLIPRGN)(record); + int cbRgnData = pEmr->cbRgnData; + const char *blimit = record + pEmr->emr.nSize; + if(IS_MEM_UNSAFE(pEmr->RgnData, cbRgnData, blimit))return(0); + return(rgndata_safe(pEmr->RgnData, cbRgnData)); +} + +// U_EMRBITBLT 76 +int U_EMRBITBLT_safe(const char *record){ + if(!core5_safe(record, U_SIZE_EMRBITBLT))return(0); + PU_EMRBITBLT pEmr = (PU_EMRBITBLT) (record); + const char *blimit = record + pEmr->emr.nSize; + U_OFFBMISRC offBmiSrc = pEmr->offBmiSrc; + U_CBBMISRC cbBmiSrc = pEmr->cbBmiSrc; + U_OFFBITSSRC offBitsSrc = pEmr->offBitsSrc; + U_CBBITS cbBitsSrc = pEmr->cbBitsSrc; + uint32_t iUsageSrc = pEmr->iUsageSrc; + return(DIB_safe(record, iUsageSrc, offBmiSrc, cbBmiSrc, offBitsSrc, cbBitsSrc, blimit)); +} + +// U_EMRSTRETCHBLT 77 +int U_EMRSTRETCHBLT_safe(const char *record){ + if(!core5_safe(record, U_SIZE_EMRSTRETCHBLT))return(0); + PU_EMRBITBLT pEmr = (PU_EMRBITBLT) (record); + const char *blimit = record + pEmr->emr.nSize; + U_OFFBMISRC offBmiSrc = pEmr->offBmiSrc; + U_CBBMISRC cbBmiSrc = pEmr->cbBmiSrc; + U_OFFBITSSRC offBitsSrc = pEmr->offBitsSrc; + U_CBBITS cbBitsSrc = pEmr->cbBitsSrc; + uint32_t iUsageSrc = pEmr->iUsageSrc; + return(DIB_safe(record, iUsageSrc, offBmiSrc, cbBmiSrc, offBitsSrc, cbBitsSrc, blimit)); +} + +// U_EMRMASKBLT 78 +int U_EMRMASKBLT_safe(const char *record){ + if(!core5_safe(record, U_SIZE_EMRMASKBLT))return(0); + PU_EMRMASKBLT pEmr = (PU_EMRMASKBLT) (record); + const char *blimit = record + pEmr->emr.nSize; + U_OFFBMISRC offBmiSrc = pEmr->offBmiSrc; + U_CBBMISRC cbBmiSrc = pEmr->cbBmiSrc; + U_OFFBMIMSK offBmiMask = pEmr->offBmiMask; + U_CBBMIMSK cbBmiMask = pEmr->cbBmiMask; + U_OFFBITSSRC offBitsSrc = pEmr->offBitsSrc; + U_CBBITSSRC cbBitsSrc = pEmr->cbBitsSrc; + U_OFFBITSMSK offBitsMask = pEmr->offBitsMask; + U_CBBITSMSK cbBitsMask = pEmr->cbBitsMask; + uint32_t iUsageSrc = pEmr->iUsageSrc; + uint32_t iUsageMask = pEmr->iUsageMask; + if(!DIB_safe(record, iUsageSrc, offBmiSrc, cbBmiSrc, offBitsSrc, cbBitsSrc, blimit))return(0); + return(DIB_safe(record, iUsageMask, offBmiMask, cbBmiMask, offBitsMask, cbBitsMask, blimit)); +} + +// U_EMRPLGBLT 79 +int U_EMRPLGBLT_safe(const char *record){ + if(!core5_safe(record, U_SIZE_EMRPLGBLT))return(0); + PU_EMRPLGBLT pEmr = (PU_EMRPLGBLT) (record); + const char *blimit = record + pEmr->emr.nSize; + U_OFFBMISRC offBmiSrc = pEmr->offBmiSrc; + U_CBBMISRC cbBmiSrc = pEmr->cbBmiSrc; + U_OFFBMIMSK offBmiMask = pEmr->offBmiMask; + U_CBBMIMSK cbBmiMask = pEmr->cbBmiMask; + U_OFFBITSSRC offBitsSrc = pEmr->offBitsSrc; + U_CBBITSSRC cbBitsSrc = pEmr->cbBitsSrc; + U_OFFBITSMSK offBitsMask = pEmr->offBitsMask; + U_CBBITSMSK cbBitsMask = pEmr->cbBitsMask; + uint32_t iUsageSrc = pEmr->iUsageSrc; + uint32_t iUsageMask = pEmr->iUsageMask; + if(!DIB_safe(record, iUsageSrc, offBmiSrc, cbBmiSrc, offBitsSrc, cbBitsSrc, blimit))return(0); + return(DIB_safe(record, iUsageMask, offBmiMask, cbBmiMask, offBitsMask, cbBitsMask, blimit)); +} + +// U_EMRSETDIBITSTODEVICE 80 +int U_EMRSETDIBITSTODEVICE_safe(const char *record){ + if(!core5_safe(record, U_SIZE_EMRSETDIBITSTODEVICE))return(0); + PU_EMRSETDIBITSTODEVICE pEmr = (PU_EMRSETDIBITSTODEVICE) (record); + const char *blimit = record + pEmr->emr.nSize; + U_OFFBMISRC offBmiSrc = pEmr->offBmiSrc; + U_CBBMISRC cbBmiSrc = pEmr->cbBmiSrc; + U_OFFBITSSRC offBitsSrc = pEmr->offBitsSrc; + U_CBBITSSRC cbBitsSrc = pEmr->cbBitsSrc; + uint32_t iUsageSrc = pEmr->iUsageSrc; + return(DIB_safe(record, iUsageSrc, offBmiSrc, cbBmiSrc, offBitsSrc, cbBitsSrc, blimit)); +} + +// U_EMRSTRETCHDIBITS 81 +int U_EMRSTRETCHDIBITS_safe(const char *record){ + if(!core5_safe(record, U_SIZE_EMRSTRETCHDIBITS))return(0); + PU_EMRSTRETCHDIBITS pEmr = (PU_EMRSTRETCHDIBITS) (record); + const char *blimit = record + pEmr->emr.nSize; + U_OFFBMISRC offBmiSrc = pEmr->offBmiSrc; + U_CBBMISRC cbBmiSrc = pEmr->cbBmiSrc; + U_OFFBITSSRC offBitsSrc = pEmr->offBitsSrc; + U_CBBITSSRC cbBitsSrc = pEmr->cbBitsSrc; + uint32_t iUsageSrc = pEmr->iUsageSrc; + return(DIB_safe(record, iUsageSrc, offBmiSrc, cbBmiSrc, offBitsSrc, cbBitsSrc, blimit)); +} + +// U_EMREXTCREATEFONTINDIRECTW 82 +int U_EMREXTCREATEFONTINDIRECTW_safe(const char *record){ + /* Panose or logfont, LogFontExDv is not supported. Test smallest to largest */ + if(core5_safe(record, U_SIZE_EMREXTCREATEFONTINDIRECTW_LOGFONT))return(1); + return(core5_safe(record, U_SIZE_EMREXTCREATEFONTINDIRECTW_LOGFONT_PANOSE)); +} + +// U_EMREXTTEXTOUTA 83 +int U_EMREXTTEXTOUTA_safe(const char *record){ + return(core8_safe(record)); +} + +// U_EMREXTTEXTOUTW 84 +int U_EMREXTTEXTOUTW_safe(const char *record){ + return(core8_safe(record)); +} + +// U_EMRPOLYBEZIER16 85 +/** + \brief Convert a pointer to a U_EMR_POLYBEZIER16 record. + \param record pointer to a buffer holding the EMR record +*/ +int U_EMRPOLYBEZIER16_safe(const char *record){ + return(core6_safe(record)); +} + +// U_EMRPOLYGON16 86 +int U_EMRPOLYGON16_safe(const char *record){ + return(core6_safe(record)); +} + +// U_EMRPOLYLINE16 87 +int U_EMRPOLYLINE16_safe(const char *record){ + return(core6_safe(record)); +} + +// U_EMRPOLYBEZIERTO16 88 +int U_EMRPOLYBEZIERTO16_safe(const char *record){ + return(core6_safe(record)); +} + +// U_EMRPOLYLINETO16 89 +/** + \brief Convert a pointer to a U_EMR_POLYLINETO16 record. + \param record pointer to a buffer holding the EMR record +*/ +int U_EMRPOLYLINETO16_safe(const char *record){ + return(core6_safe(record)); +} + +// U_EMRPOLYPOLYLINE16 90 +int U_EMRPOLYPOLYLINE16_safe(const char *record){ + return(core10_safe(record)); +} + +// U_EMRPOLYPOLYGON16 91 +int U_EMRPOLYPOLYGON16_safe(const char *record){ + return(core10_safe(record)); +} + + +// U_EMRPOLYDRAW16 92 +int U_EMRPOLYDRAW16_safe(const char *record){ + if(!core5_safe(record, U_SIZE_EMRPOLYDRAW16))return(0); + PU_EMRPOLYDRAW16 pEmr = (PU_EMRPOLYDRAW16)(record); + int count = pEmr->cpts; + const char *blimit = record + pEmr->emr.nSize; + if(IS_MEM_UNSAFE(pEmr->apts, count*sizeof(U_POINT16), blimit))return(0); + return(1); +} + +// U_EMRCREATEMONOBRUSH 93 +int U_EMRCREATEMONOBRUSH_safe(const char *record){ + return(core12_safe(record)); +} + +// U_EMRCREATEDIBPATTERNBRUSHPT_safe 94 +int U_EMRCREATEDIBPATTERNBRUSHPT_safe(const char *record){ + return(core12_safe(record)); +} + + +// U_EMREXTCREATEPEN 95 +int U_EMREXTCREATEPEN_safe(const char *record){ + if(!core5_safe(record, U_SIZE_EMREXTCREATEPEN))return(0); + PU_EMREXTCREATEPEN pEmr = (PU_EMREXTCREATEPEN)(record); + const char *blimit = record + pEmr->emr.nSize; + U_OFFBMI offBmi = pEmr->offBmi; + U_CBBMI cbBmi = pEmr->cbBmi; + U_OFFBITS offBits = pEmr->offBits; + U_CBBITS cbBits = pEmr->cbBits; + if(!DIB_safe(record, U_DIB_RGB_COLORS, offBmi, cbBmi, offBits, cbBits, blimit))return(0); + return(extlogpen_safe((PU_EXTLOGPEN) &(pEmr->elp), blimit)); +} + +// U_EMRPOLYTEXTOUTA 96 NOT IMPLEMENTED, denigrated after Windows NT +#define U_EMRPOLYTEXTOUTA_safe(A) U_EMRNOTIMPLEMENTED_safe(A) //!< Not implemented. +// U_EMRPOLYTEXTOUTW 97 NOT IMPLEMENTED, denigrated after Windows NT +#define U_EMRPOLYTEXTOUTW_safe(A) U_EMRNOTIMPLEMENTED_safe(A) //!< Not implemented. + +// U_EMRSETICMMODE 98 +int U_EMRSETICMMODE_safe(const char *record){ + return(core3_safe(record)); +} + +// U_EMRCREATECOLORSPACE 99 +int U_EMRCREATECOLORSPACE_safe(const char *record){ + return(core5_safe(record, U_SIZE_EMRCREATECOLORSPACE)); +} + +// U_EMRSETCOLORSPACE 100 +int U_EMRSETCOLORSPACE_safe(const char *record){ + return(core3_safe(record)); +} + +// U_EMRDELETECOLORSPACE 101 +int U_EMRDELETECOLORSPACE_safe(const char *record){ + return(core3_safe(record)); +} + +// U_EMRGLSRECORD 102 Not implemented +#define U_EMRGLSRECORD_safe(A) U_EMRNOTIMPLEMENTED_safe(A) //!< Not implemented. +// U_EMRGLSBOUNDEDRECORD 103 Not implemented +#define U_EMRGLSBOUNDEDRECORD_safe(A) U_EMRNOTIMPLEMENTED_safe(A) //!< Not implemented. + +// U_EMRPIXELFORMAT 104 +int U_EMRPIXELFORMAT_safe(const char *record){ + return(core5_safe(record, U_SIZE_EMRPIXELFORMAT)); +} + +// U_EMRDRAWESCAPE 105 Not implemented +#define U_EMRDRAWESCAPE_safe(A) U_EMRNOTIMPLEMENTED_safe(A) //!< Not implemented. +// U_EMREXTESCAPE 106 Not implemented +#define U_EMREXTESCAPE_safe(A) U_EMRNOTIMPLEMENTED_safe(A) //!< Not implemented. +// U_EMRUNDEF107 107 Not implemented +#define U_EMRUNDEF107_safe(A) U_EMRNOTIMPLEMENTED_safe(A) //!< Not implemented. + +// U_EMRSMALLTEXTOUT 108 +int U_EMRSMALLTEXTOUT_safe(const char *record){ + if(!core5_safe(record, U_SIZE_EMRSMALLTEXTOUT))return(0); + PU_EMRSMALLTEXTOUT pEmr = (PU_EMRSMALLTEXTOUT)(record); + int roff=sizeof(U_EMRSMALLTEXTOUT); // offset to the start of the variable fields + int fuOptions = pEmr->fuOptions; + int cChars = pEmr->cChars; + const char *blimit = record + pEmr->emr.nSize; + if(!(fuOptions & U_ETO_NO_RECT)){ + if(IS_MEM_UNSAFE(record, roff + sizeof(U_RECTL), blimit))return(0); + } + if(IS_MEM_UNSAFE(record, roff + sizeof(U_RECTL) + cChars, blimit))return(0); + return(1); +} + +// U_EMRFORCEUFIMAPPING 109 Not implemented +#define U_EMRFORCEUFIMAPPING_safe(A) U_EMRNOTIMPLEMENTED_safe(A) //!< Not implemented. +// U_EMRNAMEDESCAPE 110 Not implemented +#define U_EMRNAMEDESCAPE_safe(A) U_EMRNOTIMPLEMENTED_safe(A) //!< Not implemented. +// U_EMRCOLORCORRECTPALETTE 111 Not implemented +#define U_EMRCOLORCORRECTPALETTE_safe(A) U_EMRNOTIMPLEMENTED_safe(A) //!< Not implemented. +// U_EMRSETICMPROFILEA 112 Not implemented +#define U_EMRSETICMPROFILEA_safe(A) U_EMRNOTIMPLEMENTED_safe(A) //!< Not implemented. +// U_EMRSETICMPROFILEW 113 Not implemented +#define U_EMRSETICMPROFILEW_safe(A) U_EMRNOTIMPLEMENTED_safe(A) //!< Not implemented. + +// U_EMRALPHABLEND 114 +int U_EMRALPHABLEND_safe(const char *record){ + return(core13_safe(record)); +} + +// U_EMRSETLAYOUT 115 +int U_EMRSETLAYOUT_safe(const char *record){ + return(core3_safe(record)); +} + +// U_EMRTRANSPARENTBLT 116 +int U_EMRTRANSPARENTBLT_safe(const char *record){ + return(core13_safe(record)); +} + + +// U_EMRUNDEF117 117 Not implemented +#define U_EMRUNDEF117_safe(A) U_EMRNOTIMPLEMENTED_safe(A) //!< Not implemented. +// U_EMRGRADIENTFILL 118 +int U_EMRGRADIENTFILL_safe(const char *record){ + if(!core5_safe(record, U_SIZE_EMRGRADIENTFILL))return(0); + PU_EMRGRADIENTFILL pEmr = (PU_EMRGRADIENTFILL)(record); + int nTriVert = pEmr->nTriVert; + int nGradObj = pEmr->nGradObj; + int ulMode = pEmr->ulMode; + const char *blimit = record + pEmr->emr.nSize; + if(IS_MEM_UNSAFE(record, nTriVert*sizeof(U_TRIVERTEX), blimit))return(0); + record += nTriVert * sizeof(U_TRIVERTEX); + if(nGradObj){ + if( ulMode == U_GRADIENT_FILL_TRIANGLE){ + if(IS_MEM_UNSAFE(record, nGradObj*sizeof(U_GRADIENT3), blimit))return(0); + } + else if(ulMode == U_GRADIENT_FILL_RECT_H || ulMode == U_GRADIENT_FILL_RECT_V){ + if(IS_MEM_UNSAFE(record, nGradObj*sizeof(U_GRADIENT4), blimit))return(0); + } + } + return(1); +} + +// U_EMRSETLINKEDUFIS 119 Not implemented +#define U_EMRSETLINKEDUFIS_safe(A) U_EMRNOTIMPLEMENTED_safe(A) //!< Not implemented. +// U_EMRSETTEXTJUSTIFICATION120 Not implemented (denigrated) +#define U_EMRSETTEXTJUSTIFICATION_safe(A) U_EMRNOTIMPLEMENTED_safe(A) //!< Not implemented. +// U_EMRCOLORMATCHTOTARGETW 121 Not implemented +#define U_EMRCOLORMATCHTOTARGETW_safe(A) U_EMRNOTIMPLEMENTED_safe(A) //!< Not implemented. + +// U_EMRCREATECOLORSPACEW 122 +int U_EMRCREATECOLORSPACEW_safe(const char *record){ + return(core5_safe(record, U_SIZE_EMRCREATECOLORSPACEW)); +} + +//! \endcond + +/** + \brief Test an EMF record in memory from Big Endian to Little Endian. + \return 0 on failure, 1 on success + \param record pointer to the EMF record in memory + + Normally this would be called immediately after reading a record from a file + and having called U_emf_record_sizeok(). + It is NOT safe to call this routine without first calling U_emf_record_sizeok)()! + If the file has been converted from one endian to another calling this routine is + not necessary, because those routines also perform these checks. +*/ +int U_emf_record_safe(const char *record){ + int rstatus=1; + + if(!record)return(0); // programming error + + switch (U_EMRTYPE(record)) + { + case U_EMR_HEADER: rstatus=U_EMRHEADER_safe(record); break; + case U_EMR_POLYBEZIER: rstatus=U_EMRPOLYBEZIER_safe(record); break; + case U_EMR_POLYGON: rstatus=U_EMRPOLYGON_safe(record); break; + case U_EMR_POLYLINE: rstatus=U_EMRPOLYLINE_safe(record); break; + case U_EMR_POLYBEZIERTO: rstatus=U_EMRPOLYBEZIERTO_safe(record); break; + case U_EMR_POLYLINETO: rstatus=U_EMRPOLYLINETO_safe(record); break; + case U_EMR_POLYPOLYLINE: rstatus=U_EMRPOLYPOLYLINE_safe(record); break; + case U_EMR_POLYPOLYGON: rstatus=U_EMRPOLYPOLYGON_safe(record); break; + case U_EMR_SETWINDOWEXTEX: rstatus=U_EMRSETWINDOWEXTEX_safe(record); break; + case U_EMR_SETWINDOWORGEX: rstatus=U_EMRSETWINDOWORGEX_safe(record); break; + case U_EMR_SETVIEWPORTEXTEX: rstatus=U_EMRSETVIEWPORTEXTEX_safe(record); break; + case U_EMR_SETVIEWPORTORGEX: rstatus=U_EMRSETVIEWPORTORGEX_safe(record); break; + case U_EMR_SETBRUSHORGEX: rstatus=U_EMRSETBRUSHORGEX_safe(record); break; + case U_EMR_EOF: rstatus=U_EMREOF_safe(record); break; + case U_EMR_SETPIXELV: rstatus=U_EMRSETPIXELV_safe(record); break; + case U_EMR_SETMAPPERFLAGS: rstatus=U_EMRSETMAPPERFLAGS_safe(record); break; + case U_EMR_SETMAPMODE: rstatus=U_EMRSETMAPMODE_safe(record); break; + case U_EMR_SETBKMODE: rstatus=U_EMRSETBKMODE_safe(record); break; + case U_EMR_SETPOLYFILLMODE: rstatus=U_EMRSETPOLYFILLMODE_safe(record); break; + case U_EMR_SETROP2: rstatus=U_EMRSETROP2_safe(record); break; + case U_EMR_SETSTRETCHBLTMODE: rstatus=U_EMRSETSTRETCHBLTMODE_safe(record); break; + case U_EMR_SETTEXTALIGN: rstatus=U_EMRSETTEXTALIGN_safe(record); break; + case U_EMR_SETCOLORADJUSTMENT: rstatus=U_EMRSETCOLORADJUSTMENT_safe(record); break; + case U_EMR_SETTEXTCOLOR: rstatus=U_EMRSETTEXTCOLOR_safe(record); break; + case U_EMR_SETBKCOLOR: rstatus=U_EMRSETBKCOLOR_safe(record); break; + case U_EMR_OFFSETCLIPRGN: rstatus=U_EMROFFSETCLIPRGN_safe(record); break; + case U_EMR_MOVETOEX: rstatus=U_EMRMOVETOEX_safe(record); break; + case U_EMR_SETMETARGN: rstatus=U_EMRSETMETARGN_safe(record); break; + case U_EMR_EXCLUDECLIPRECT: rstatus=U_EMREXCLUDECLIPRECT_safe(record); break; + case U_EMR_INTERSECTCLIPRECT: rstatus=U_EMRINTERSECTCLIPRECT_safe(record); break; + case U_EMR_SCALEVIEWPORTEXTEX: rstatus=U_EMRSCALEVIEWPORTEXTEX_safe(record); break; + case U_EMR_SCALEWINDOWEXTEX: rstatus=U_EMRSCALEWINDOWEXTEX_safe(record); break; + case U_EMR_SAVEDC: rstatus=U_EMRSAVEDC_safe(record); break; + case U_EMR_RESTOREDC: rstatus=U_EMRRESTOREDC_safe(record); break; + case U_EMR_SETWORLDTRANSFORM: rstatus=U_EMRSETWORLDTRANSFORM_safe(record); break; + case U_EMR_MODIFYWORLDTRANSFORM: rstatus=U_EMRMODIFYWORLDTRANSFORM_safe(record); break; + case U_EMR_SELECTOBJECT: rstatus=U_EMRSELECTOBJECT_safe(record); break; + case U_EMR_CREATEPEN: rstatus=U_EMRCREATEPEN_safe(record); break; + case U_EMR_CREATEBRUSHINDIRECT: rstatus=U_EMRCREATEBRUSHINDIRECT_safe(record); break; + case U_EMR_DELETEOBJECT: rstatus=U_EMRDELETEOBJECT_safe(record); break; + case U_EMR_ANGLEARC: rstatus=U_EMRANGLEARC_safe(record); break; + case U_EMR_ELLIPSE: rstatus=U_EMRELLIPSE_safe(record); break; + case U_EMR_RECTANGLE: rstatus=U_EMRRECTANGLE_safe(record); break; + case U_EMR_ROUNDRECT: rstatus=U_EMRROUNDRECT_safe(record); break; + case U_EMR_ARC: rstatus=U_EMRARC_safe(record); break; + case U_EMR_CHORD: rstatus=U_EMRCHORD_safe(record); break; + case U_EMR_PIE: rstatus=U_EMRPIE_safe(record); break; + case U_EMR_SELECTPALETTE: rstatus=U_EMRSELECTPALETTE_safe(record); break; + case U_EMR_CREATEPALETTE: rstatus=U_EMRCREATEPALETTE_safe(record); break; + case U_EMR_SETPALETTEENTRIES: rstatus=U_EMRSETPALETTEENTRIES_safe(record); break; + case U_EMR_RESIZEPALETTE: rstatus=U_EMRRESIZEPALETTE_safe(record); break; + case U_EMR_REALIZEPALETTE: rstatus=U_EMRREALIZEPALETTE_safe(record); break; + case U_EMR_EXTFLOODFILL: rstatus=U_EMREXTFLOODFILL_safe(record); break; + case U_EMR_LINETO: rstatus=U_EMRLINETO_safe(record); break; + case U_EMR_ARCTO: rstatus=U_EMRARCTO_safe(record); break; + case U_EMR_POLYDRAW: rstatus=U_EMRPOLYDRAW_safe(record); break; + case U_EMR_SETARCDIRECTION: rstatus=U_EMRSETARCDIRECTION_safe(record); break; + case U_EMR_SETMITERLIMIT: rstatus=U_EMRSETMITERLIMIT_safe(record); break; + case U_EMR_BEGINPATH: rstatus=U_EMRBEGINPATH_safe(record); break; + case U_EMR_ENDPATH: rstatus=U_EMRENDPATH_safe(record); break; + case U_EMR_CLOSEFIGURE: rstatus=U_EMRCLOSEFIGURE_safe(record); break; + case U_EMR_FILLPATH: rstatus=U_EMRFILLPATH_safe(record); break; + case U_EMR_STROKEANDFILLPATH: rstatus=U_EMRSTROKEANDFILLPATH_safe(record); break; + case U_EMR_STROKEPATH: rstatus=U_EMRSTROKEPATH_safe(record); break; + case U_EMR_FLATTENPATH: rstatus=U_EMRFLATTENPATH_safe(record); break; + case U_EMR_WIDENPATH: rstatus=U_EMRWIDENPATH_safe(record); break; + case U_EMR_SELECTCLIPPATH: rstatus=U_EMRSELECTCLIPPATH_safe(record); break; + case U_EMR_ABORTPATH: rstatus=U_EMRABORTPATH_safe(record); break; + case U_EMR_UNDEF69: rstatus=U_EMRUNDEF69_safe(record); break; + case U_EMR_COMMENT: rstatus=U_EMRCOMMENT_safe(record); break; + case U_EMR_FILLRGN: rstatus=U_EMRFILLRGN_safe(record); break; + case U_EMR_FRAMERGN: rstatus=U_EMRFRAMERGN_safe(record); break; + case U_EMR_INVERTRGN: rstatus=U_EMRINVERTRGN_safe(record); break; + case U_EMR_PAINTRGN: rstatus=U_EMRPAINTRGN_safe(record); break; + case U_EMR_EXTSELECTCLIPRGN: rstatus=U_EMREXTSELECTCLIPRGN_safe(record); break; + case U_EMR_BITBLT: rstatus=U_EMRBITBLT_safe(record); break; + case U_EMR_STRETCHBLT: rstatus=U_EMRSTRETCHBLT_safe(record); break; + case U_EMR_MASKBLT: rstatus=U_EMRMASKBLT_safe(record); break; + case U_EMR_PLGBLT: rstatus=U_EMRPLGBLT_safe(record); break; + case U_EMR_SETDIBITSTODEVICE: rstatus=U_EMRSETDIBITSTODEVICE_safe(record); break; + case U_EMR_STRETCHDIBITS: rstatus=U_EMRSTRETCHDIBITS_safe(record); break; + case U_EMR_EXTCREATEFONTINDIRECTW: rstatus=U_EMREXTCREATEFONTINDIRECTW_safe(record); break; + case U_EMR_EXTTEXTOUTA: rstatus=U_EMREXTTEXTOUTA_safe(record); break; + case U_EMR_EXTTEXTOUTW: rstatus=U_EMREXTTEXTOUTW_safe(record); break; + case U_EMR_POLYBEZIER16: rstatus=U_EMRPOLYBEZIER16_safe(record); break; + case U_EMR_POLYGON16: rstatus=U_EMRPOLYGON16_safe(record); break; + case U_EMR_POLYLINE16: rstatus=U_EMRPOLYLINE16_safe(record); break; + case U_EMR_POLYBEZIERTO16: rstatus=U_EMRPOLYBEZIERTO16_safe(record); break; + case U_EMR_POLYLINETO16: rstatus=U_EMRPOLYLINETO16_safe(record); break; + case U_EMR_POLYPOLYLINE16: rstatus=U_EMRPOLYPOLYLINE16_safe(record); break; + case U_EMR_POLYPOLYGON16: rstatus=U_EMRPOLYPOLYGON16_safe(record); break; + case U_EMR_POLYDRAW16: rstatus=U_EMRPOLYDRAW16_safe(record); break; + case U_EMR_CREATEMONOBRUSH: rstatus=U_EMRCREATEMONOBRUSH_safe(record); break; + case U_EMR_CREATEDIBPATTERNBRUSHPT: rstatus=U_EMRCREATEDIBPATTERNBRUSHPT_safe(record); break; + case U_EMR_EXTCREATEPEN: rstatus=U_EMREXTCREATEPEN_safe(record); break; + case U_EMR_POLYTEXTOUTA: rstatus=U_EMRPOLYTEXTOUTA_safe(record); break; + case U_EMR_POLYTEXTOUTW: rstatus=U_EMRPOLYTEXTOUTW_safe(record); break; + case U_EMR_SETICMMODE: rstatus=U_EMRSETICMMODE_safe(record); break; + case U_EMR_CREATECOLORSPACE: rstatus=U_EMRCREATECOLORSPACE_safe(record); break; + case U_EMR_SETCOLORSPACE: rstatus=U_EMRSETCOLORSPACE_safe(record); break; + case U_EMR_DELETECOLORSPACE: rstatus=U_EMRDELETECOLORSPACE_safe(record); break; + case U_EMR_GLSRECORD: rstatus=U_EMRGLSRECORD_safe(record); break; + case U_EMR_GLSBOUNDEDRECORD: rstatus=U_EMRGLSBOUNDEDRECORD_safe(record); break; + case U_EMR_PIXELFORMAT: rstatus=U_EMRPIXELFORMAT_safe(record); break; + case U_EMR_DRAWESCAPE: rstatus=U_EMRDRAWESCAPE_safe(record); break; + case U_EMR_EXTESCAPE: rstatus=U_EMREXTESCAPE_safe(record); break; + case U_EMR_UNDEF107: rstatus=U_EMRUNDEF107_safe(record); break; + case U_EMR_SMALLTEXTOUT: rstatus=U_EMRSMALLTEXTOUT_safe(record); break; + case U_EMR_FORCEUFIMAPPING: rstatus=U_EMRFORCEUFIMAPPING_safe(record); break; + case U_EMR_NAMEDESCAPE: rstatus=U_EMRNAMEDESCAPE_safe(record); break; + case U_EMR_COLORCORRECTPALETTE: rstatus=U_EMRCOLORCORRECTPALETTE_safe(record); break; + case U_EMR_SETICMPROFILEA: rstatus=U_EMRSETICMPROFILEA_safe(record); break; + case U_EMR_SETICMPROFILEW: rstatus=U_EMRSETICMPROFILEW_safe(record); break; + case U_EMR_ALPHABLEND: rstatus=U_EMRALPHABLEND_safe(record); break; + case U_EMR_SETLAYOUT: rstatus=U_EMRSETLAYOUT_safe(record); break; + case U_EMR_TRANSPARENTBLT: rstatus=U_EMRTRANSPARENTBLT_safe(record); break; + case U_EMR_UNDEF117: rstatus=U_EMRUNDEF117_safe(record); break; + case U_EMR_GRADIENTFILL: rstatus=U_EMRGRADIENTFILL_safe(record); break; + case U_EMR_SETLINKEDUFIS: rstatus=U_EMRSETLINKEDUFIS_safe(record); break; + case U_EMR_SETTEXTJUSTIFICATION: rstatus=U_EMRSETTEXTJUSTIFICATION_safe(record); break; + case U_EMR_COLORMATCHTOTARGETW: rstatus=U_EMRCOLORMATCHTOTARGETW_safe(record); break; + case U_EMR_CREATECOLORSPACEW: rstatus=U_EMRCREATECOLORSPACEW_safe(record); break; + default: rstatus=U_EMRNOTIMPLEMENTED_safe(record); break; + } //end of switch + return(rstatus); +} + + +#ifdef __cplusplus +} +#endif diff --git a/src/libuemf/uemf_safe.h b/src/libuemf/uemf_safe.h new file mode 100644 index 000000000..0c9e3cc69 --- /dev/null +++ b/src/libuemf/uemf_safe.h @@ -0,0 +1,32 @@ +/** + @file uemf_safe.h + + @brief Defintions and prototype for function for converting EMF records between Big Endian and Little Endian byte orders. +*/ + +/* +File: uemf_endian.h +Version: 0.0.2 +Date: 26-MAR-2015 +Author: David Mathog, Biology Division, Caltech +email: mathog@caltech.edu +Copyright: 2015 David Mathog and California Institute of Technology (Caltech) +*/ + +#ifndef _UEMF_SAFE_ +#define _UEMF_SAFE_ + +#ifdef __cplusplus +extern "C" { +#endif + +// prototypes +int U_emf_record_safe(const char *record); +int bitmapinfo_safe(const char *Bmi, const char *blimit); +//! \endcond + +#ifdef __cplusplus +} +#endif + +#endif /* _UEMF_SAFE_ */ -- cgit v1.2.3 From 4bd4a89e23064b6782728d7965b12443978dcd29 Mon Sep 17 00:00:00 2001 From: Marc Jeanmougin Date: Tue, 28 Apr 2015 00:56:20 +0200 Subject: removed a few "using Inkscape::Util::GSListConstIterator" (bzr r13922.1.16) --- src/extension/implementation/implementation.cpp | 1 - src/extension/internal/bitmap/imagemagick.cpp | 2 -- src/extension/internal/bluredge.cpp | 1 - src/extension/internal/grid.cpp | 2 -- src/removeoverlap.cpp | 1 - src/ui/dialog/align-and-distribute.cpp | 5 ----- src/ui/dialog/transformation.cpp | 1 - 7 files changed, 13 deletions(-) (limited to 'src') diff --git a/src/extension/implementation/implementation.cpp b/src/extension/implementation/implementation.cpp index 717ca3310..b0ff3e91c 100644 --- a/src/extension/implementation/implementation.cpp +++ b/src/extension/implementation/implementation.cpp @@ -47,7 +47,6 @@ Gtk::Widget *Implementation::prefs_effect(Inkscape::Extension::Effect *module, I SPDocument * current_document = view->doc(); - using Inkscape::Util::GSListConstIterator; std::vector selected = ((SPDesktop *)view)->getSelection()->itemList(); Inkscape::XML::Node const* first_select = NULL; if (!selected.empty()) { diff --git a/src/extension/internal/bitmap/imagemagick.cpp b/src/extension/internal/bitmap/imagemagick.cpp index 3a29b3dc0..5e4c930bc 100644 --- a/src/extension/internal/bitmap/imagemagick.cpp +++ b/src/extension/internal/bitmap/imagemagick.cpp @@ -240,8 +240,6 @@ ImageMagick::prefs_effect(Inkscape::Extension::Effect *module, Inkscape::UI::Vie { SPDocument * current_document = view->doc(); - using Inkscape::Util::GSListConstIterator; - std::vector selected = ((SPDesktop *)view)->getSelection()->itemList(); Inkscape::XML::Node * first_select = NULL; if (!selected.empty()) { diff --git a/src/extension/internal/bluredge.cpp b/src/extension/internal/bluredge.cpp index b80e5ddbb..9f19f8b3b 100644 --- a/src/extension/internal/bluredge.cpp +++ b/src/extension/internal/bluredge.cpp @@ -63,7 +63,6 @@ BlurEdge::effect (Inkscape::Extension::Effect *module, Inkscape::UI::View::View Inkscape::Preferences *prefs = Inkscape::Preferences::get(); double old_offset = prefs->getDouble("/options/defaultoffsetwidth/value", 1.0, "px"); - using Inkscape::Util::GSListConstIterator; // TODO need to properly refcount the items, at least std::vector items(selection->itemList()); selection->clear(); diff --git a/src/extension/internal/grid.cpp b/src/extension/internal/grid.cpp index 60d606a02..932d9a0d0 100644 --- a/src/extension/internal/grid.cpp +++ b/src/extension/internal/grid.cpp @@ -190,8 +190,6 @@ Grid::prefs_effect(Inkscape::Extension::Effect *module, Inkscape::UI::View::View { SPDocument * current_document = view->doc(); - using Inkscape::Util::GSListConstIterator; - std::vector selected = ((SPDesktop *)view)->getSelection()->itemList(); Inkscape::XML::Node * first_select = NULL; if (!selected.empty()) { diff --git a/src/removeoverlap.cpp b/src/removeoverlap.cpp index 01ce2c47e..9ea75de0d 100644 --- a/src/removeoverlap.cpp +++ b/src/removeoverlap.cpp @@ -39,7 +39,6 @@ namespace { * horizontally and yGap vertically */ void removeoverlap(std::vector const &items, double const xGap, double const yGap) { - using Inkscape::Util::GSListConstIterator; std::vector selected(items); std::vector records; std::vector rs; diff --git a/src/ui/dialog/align-and-distribute.cpp b/src/ui/dialog/align-and-distribute.cpp index 1ee72dcbc..882427912 100644 --- a/src/ui/dialog/align-and-distribute.cpp +++ b/src/ui/dialog/align-and-distribute.cpp @@ -97,7 +97,6 @@ void ActionAlign::do_action(SPDesktop *desktop, int index) Inkscape::Preferences *prefs = Inkscape::Preferences::get(); bool sel_as_group = prefs->getBool("/dialogs/align/sel-as-groups"); - using Inkscape::Util::GSListConstIterator; std::vector selected(selection->itemList()); if (selected.empty()) return; @@ -250,7 +249,6 @@ private : Inkscape::Selection *selection = desktop->getSelection(); if (!selection) return; - using Inkscape::Util::GSListConstIterator; std::vector selected(selection->itemList()); if (selected.empty()) return; @@ -548,7 +546,6 @@ private : Inkscape::Selection *selection = desktop->getSelection(); if (!selection) return; - using Inkscape::Util::GSListConstIterator; std::vector selected(selection->itemList()); if (selected.empty()) return; @@ -646,7 +643,6 @@ private : Inkscape::Selection *selection = desktop->getSelection(); if (!selection) return; - using Inkscape::Util::GSListConstIterator; std::vector selected(selection->itemList()); if (selected.empty()) return; @@ -745,7 +741,6 @@ private : Inkscape::Selection *selection = desktop->getSelection(); if (!selection) return; - using Inkscape::Util::GSListConstIterator; std::vector selected(selection->itemList()); if (selected.empty()) return; diff --git a/src/ui/dialog/transformation.cpp b/src/ui/dialog/transformation.cpp index 459e6e937..5bd3cb309 100644 --- a/src/ui/dialog/transformation.cpp +++ b/src/ui/dialog/transformation.cpp @@ -740,7 +740,6 @@ void Transformation::applyPageMove(Inkscape::Selection *selection) if (_check_move_relative.get_active()) { // shift each object relatively to the previous one - using Inkscape::Util::GSListConstIterator; std::vector selected(selection->itemList()); if (selected.empty()) return; -- cgit v1.2.3 From 643c75ddbbbea2f018050faa1e7e38c71482418a Mon Sep 17 00:00:00 2001 From: Marc Jeanmougin Date: Tue, 28 Apr 2015 01:20:57 +0200 Subject: removed a few useless SP_OBJECT() casts (bzr r13922.1.17) --- src/selection-chemistry.cpp | 28 ++++++++++++++-------------- src/selection.cpp | 4 ++-- src/splivarot.cpp | 4 ++-- src/ui/dialog/object-attributes.cpp | 2 +- src/ui/dialog/transformation.cpp | 2 +- src/ui/tools/gradient-tool.cpp | 2 +- src/widgets/stroke-style.cpp | 4 ++-- 7 files changed, 23 insertions(+), 23 deletions(-) (limited to 'src') diff --git a/src/selection-chemistry.cpp b/src/selection-chemistry.cpp index c1d4f58e4..7255e80cb 100644 --- a/src/selection-chemistry.cpp +++ b/src/selection-chemistry.cpp @@ -889,14 +889,14 @@ sp_item_list_common_parent_group(std::vector const items) if (items.empty()) { return NULL; } - SPObject *parent = SP_OBJECT(items[0])->parent; + SPObject *parent = items[0]->parent; // Strictly speaking this CAN happen, if user selects from Inkscape::XML editor if (!dynamic_cast(parent)) { return NULL; } for (std::vector::const_iterator item=items.begin();item!=items.end();item++) { if((*item)==items[0])continue; - if (SP_OBJECT(*item)->parent != parent) { + if ((*item)->parent != parent) { return NULL; } } @@ -2896,7 +2896,7 @@ void sp_selection_to_marker(SPDesktop *desktop, bool apply) //items = g_slist_sort(items, (GCompareFunc) sp_object_compare_position); // Why needed? // bottommost object, after sorting - SPObject *parent = SP_OBJECT(items[0])->parent; + SPObject *parent = items[0]->parent; Geom::Affine parent_transform; { @@ -2911,7 +2911,7 @@ void sp_selection_to_marker(SPDesktop *desktop, bool apply) // Create a list of duplicates, to be pasted inside marker element. std::vector repr_copies; for (std::vector::const_reverse_iterator i=items.rbegin();i!=items.rend();i++){ - Inkscape::XML::Node *dup = SP_OBJECT(*i)->getRepr()->duplicate(xml_doc); + Inkscape::XML::Node *dup = (*i)->getRepr()->duplicate(xml_doc); repr_copies.push_back(dup); } @@ -3248,7 +3248,7 @@ sp_selection_tile(SPDesktop *desktop, bool apply) sort(items.begin(),items.end(),sp_object_compare_position); // bottommost object, after sorting - SPObject *parent = SP_OBJECT(items[0])->parent; + SPObject *parent = items[0]->parent; Geom::Affine parent_transform; @@ -3262,12 +3262,12 @@ sp_selection_tile(SPDesktop *desktop, bool apply) } // remember the position of the first item - gint pos = SP_OBJECT(items[0])->getRepr()->position(); + gint pos = items[0]->getRepr()->position(); // create a list of duplicates std::vector repr_copies; for (std::vector::const_iterator i=items.begin();i!=items.end();i++){ - Inkscape::XML::Node *dup = SP_OBJECT(*i)->getRepr()->duplicate(xml_doc); + Inkscape::XML::Node *dup = (*i)->getRepr()->duplicate(xml_doc); repr_copies.push_back(dup); } @@ -3520,7 +3520,7 @@ void sp_selection_create_bitmap_copy(SPDesktop *desktop) // Create the filename. gchar *const basename = g_strdup_printf("%s-%s-%u.png", document->getName(), - SP_OBJECT(items[0])->getRepr()->attribute("id"), + items[0]->getRepr()->attribute("id"), current); // Imagemagick is known not to handle spaces in filenames, so we replace anything but letters, // digits, and a few other chars, with "_" @@ -3540,8 +3540,8 @@ void sp_selection_create_bitmap_copy(SPDesktop *desktop) //g_print("%s\n", filepath); // Remember parent and z-order of the topmost one - gint pos = SP_OBJECT(items.back())->getRepr()->position(); - SPObject *parent_object = SP_OBJECT(items.back())->parent; + gint pos = items.back()->getRepr()->position(); + SPObject *parent_object = items.back()->parent; Inkscape::XML::Node *parent = parent_object->getRepr(); // Calculate resolution @@ -3857,7 +3857,7 @@ void sp_selection_set_mask(SPDesktop *desktop, bool apply_clip_path, bool apply_ apply_to_items = g_slist_prepend(apply_to_items, desktop->currentLayer()); for (std::vector::const_iterator i=items.begin();i!=items.end();i++) { - Inkscape::XML::Node *dup = SP_OBJECT(*i)->getRepr()->duplicate(xml_doc); + Inkscape::XML::Node *dup = (*i)->getRepr()->duplicate(xml_doc); mask_items = g_slist_prepend(mask_items, dup); SPObject *item = *i; @@ -3870,7 +3870,7 @@ void sp_selection_set_mask(SPDesktop *desktop, bool apply_clip_path, bool apply_ } } else if (!topmost) { // topmost item is used as a mask, which is applied to other items in a selection - Inkscape::XML::Node *dup = SP_OBJECT(items[0])->getRepr()->duplicate(xml_doc); + Inkscape::XML::Node *dup = items[0]->getRepr()->duplicate(xml_doc); mask_items = g_slist_prepend(mask_items, dup); if (remove_original) { @@ -4049,7 +4049,7 @@ void sp_selection_unset_mask(SPDesktop *desktop, bool apply_clip_path) { } } - SP_OBJECT(*i)->getRepr()->setAttribute(attributeName, "none"); + (*i)->getRepr()->setAttribute(attributeName, "none"); SPGroup *group = dynamic_cast(*i); if (ungroup_masked && group) { @@ -4070,7 +4070,7 @@ void sp_selection_unset_mask(SPDesktop *desktop, bool apply_clip_path) { GSList *items_to_move = NULL; for ( SPObject *child = obj->firstChild() ; child; child = child->getNext() ) { // Collect all clipped paths and masks within a single group - Inkscape::XML::Node *copy = SP_OBJECT(child)->getRepr()->duplicate(xml_doc); + Inkscape::XML::Node *copy = child->getRepr()->duplicate(xml_doc); if(copy->attribute("inkscape:original-d") && copy->attribute("inkscape:path-effect")) { copy->setAttribute("d", copy->attribute("inkscape:original-d")); diff --git a/src/selection.cpp b/src/selection.cpp index d9266b599..b2fb6447e 100644 --- a/src/selection.cpp +++ b/src/selection.cpp @@ -517,7 +517,7 @@ uint Selection::numberOfLayers() { std::vector const items = const_cast(this)->itemList(); std::set layers; for ( std::vector::const_iterator iter=items.begin();iter!=items.end();iter++ ) { - SPObject *layer = _layers->layerForObject(SP_OBJECT(*iter)); + SPObject *layer = _layers->layerForObject(*iter); layers.insert(layer); } return layers.size(); @@ -527,7 +527,7 @@ guint Selection::numberOfParents() { std::vector const items = const_cast(this)->itemList(); std::set parents; for ( std::vector::const_iterator iter=items.begin();iter!=items.end();iter++ ) { - SPObject *parent = SP_OBJECT(*iter)->parent; + SPObject *parent = (*iter)->parent; parents.insert(parent); } return parents.size(); diff --git a/src/splivarot.cpp b/src/splivarot.cpp index a04dedda9..f61a30462 100644 --- a/src/splivarot.cpp +++ b/src/splivarot.cpp @@ -354,8 +354,8 @@ sp_selected_path_boolop(Inkscape::Selection *selection, SPDesktop *desktop, bool if (bop == bool_op_diff || bop == bool_op_cut || bop == bool_op_slice) { // check in the tree to find which element of the selection list is topmost (for 2-operand commands only) - Inkscape::XML::Node *a = SP_OBJECT(il.front())->getRepr(); - Inkscape::XML::Node *b = SP_OBJECT(il.back())->getRepr(); + Inkscape::XML::Node *a = il.front()->getRepr(); + Inkscape::XML::Node *b = il.back()->getRepr(); if (a == NULL || b == NULL) { boolop_display_error_message(desktop, _("Unable to determine the z-order of the objects selected for difference, XOR, division, or path cut.")); diff --git a/src/ui/dialog/object-attributes.cpp b/src/ui/dialog/object-attributes.cpp index f43a15225..1bc570f43 100644 --- a/src/ui/dialog/object-attributes.cpp +++ b/src/ui/dialog/object-attributes.cpp @@ -127,7 +127,7 @@ void ObjectAttributes::widget_setup (void) blocked = true; // CPPIFY - SPObject *obj = SP_OBJECT(item); //to get the selected item + SPObject *obj = item; //to get the selected item // GObjectClass *klass = G_OBJECT_GET_CLASS(obj); //to deduce the object's type // GType type = G_TYPE_FROM_CLASS(klass); const SPAttrDesc *desc; diff --git a/src/ui/dialog/transformation.cpp b/src/ui/dialog/transformation.cpp index 5bd3cb309..f571828ce 100644 --- a/src/ui/dialog/transformation.cpp +++ b/src/ui/dialog/transformation.cpp @@ -1005,7 +1005,7 @@ void Transformation::applyPageTransform(Inkscape::Selection *selection) for(std::vector::const_iterator i=tmp.begin();i!=tmp.end();i++){ SPItem *item = *i; item->set_item_transform(displayed); - SP_OBJECT(item)->updateRepr(); + item->updateRepr(); } } else { sp_selection_apply_affine(selection, displayed); // post-multiply each object's transform diff --git a/src/ui/tools/gradient-tool.cpp b/src/ui/tools/gradient-tool.cpp index bf38b5ca5..526671515 100644 --- a/src/ui/tools/gradient-tool.cpp +++ b/src/ui/tools/gradient-tool.cpp @@ -913,7 +913,7 @@ static void sp_gradient_drag(GradientTool &rc, Geom::Point const pt, guint /*sta for (std::vector::const_iterator i = itemlist.begin();i!=itemlist.end();i++) { //FIXME: see above - sp_repr_css_change_recursive(SP_OBJECT(*i)->getRepr(), css, "style"); + sp_repr_css_change_recursive((*i)->getRepr(), css, "style"); sp_item_set_gradient(*i, vector, (SPGradientType) type, fill_or_stroke); diff --git a/src/widgets/stroke-style.cpp b/src/widgets/stroke-style.cpp index 481fa0609..482ca7af4 100644 --- a/src/widgets/stroke-style.cpp +++ b/src/widgets/stroke-style.cpp @@ -902,7 +902,7 @@ StrokeStyle::updateLine() return; std::vector const objects = sel->itemList(); - SPObject * const object = SP_OBJECT(objects[0]); + SPObject * const object = objects[0]; SPStyle * const style = object->style; /* Markers */ @@ -1002,7 +1002,7 @@ StrokeStyle::scaleLine() /* Set dash */ setScaledDash(css, ndash, dash, offset, width); - sp_desktop_apply_css_recursive (SP_OBJECT(*i), css, true); + sp_desktop_apply_css_recursive ((*i), css, true); } g_free(dash); -- cgit v1.2.3 From ba4dbfb351180e0fc4ad57be6e3534fa2ab5cf8c Mon Sep 17 00:00:00 2001 From: Alex Valavanis Date: Tue, 28 Apr 2015 00:38:31 +0100 Subject: Fix unnecessary inclusion of glibmm/threads.h. This can be resolved by ensuring that glibmm headers always preceed glib.h headers. Same applies with gtkmm/gtk+ etc (bzr r14064) --- src/display/canvas-axonomgrid.cpp | 4 ---- src/display/canvas-grid.cpp | 4 ---- src/extension/execution-env.cpp | 4 ---- src/extension/extension.cpp | 4 ---- src/extension/internal/bitmap/imagemagick.cpp | 4 ---- src/extension/internal/cdr-input.h | 4 ---- src/extension/internal/grid.cpp | 4 ---- src/extension/internal/pdfinput/pdf-input.h | 4 ---- src/extension/internal/vsd-input.h | 4 ---- src/extension/param/bool.cpp | 4 ---- src/extension/param/color.cpp | 4 ---- src/extension/param/description.cpp | 4 ---- src/extension/param/enum.cpp | 4 ---- src/extension/param/float.cpp | 4 ---- src/extension/param/int.cpp | 4 ---- src/extension/param/notebook.cpp | 4 ---- src/extension/param/radiobutton.cpp | 4 ---- src/extension/param/string.cpp | 4 ---- src/extension/prefdialog.h | 9 --------- src/inkscape.cpp | 4 ---- src/libdepixelize/kopftracer2011.cpp | 7 +------ src/live_effects/lpe-fillet-chamfer.h | 8 -------- src/live_effects/lpe-lattice2.cpp | 2 ++ src/live_effects/lpe-lattice2.h | 6 +++++- src/live_effects/parameter/originalpath.cpp | 4 ---- src/live_effects/parameter/originalpatharray.cpp | 4 ---- src/ui/dialog-events.cpp | 4 ---- src/ui/dialog/aboutbox.h | 8 -------- src/ui/dialog/calligraphic-profile-rename.h | 4 ---- src/ui/dialog/color-item.cpp | 4 ---- src/ui/dialog/debug.cpp | 4 ---- src/ui/dialog/export.cpp | 4 ---- src/ui/dialog/filedialogimpl-gtkmm.h | 8 -------- src/ui/dialog/filedialogimpl-win32.h | 5 ----- src/ui/dialog/floating-behavior.cpp | 4 ---- src/ui/dialog/font-substitution.cpp | 4 ---- src/ui/dialog/guides.h | 4 ---- src/ui/dialog/icon-preview.cpp | 4 ---- src/ui/dialog/layer-properties.h | 4 ---- src/ui/dialog/layers.h | 4 ---- src/ui/dialog/livepatheffect-add.h | 8 -------- src/ui/dialog/lpe-fillet-chamfer-properties.cpp | 4 ---- src/ui/dialog/lpe-powerstroke-properties.cpp | 4 ---- src/ui/dialog/messages.h | 8 -------- src/ui/dialog/objects.h | 4 ---- src/ui/dialog/ocaldialogs.h | 4 ---- src/ui/dialog/spellcheck.h | 4 ---- src/ui/dialog/symbols.cpp | 4 ---- src/ui/dialog/text-edit.h | 4 ---- src/ui/dialog/tile.h | 4 ---- src/ui/dialog/transformation.cpp | 4 ---- src/ui/previewholder.h | 4 ---- src/ui/tools/tool-base.cpp | 4 ---- src/ui/widget/addtoicon.cpp | 4 ---- src/ui/widget/button.h | 8 -------- src/ui/widget/clipmaskicon.cpp | 4 ---- src/ui/widget/color-picker.h | 8 -------- src/ui/widget/color-preview.h | 4 ---- src/ui/widget/dock-item.h | 4 ---- src/ui/widget/dock.h | 8 -------- src/ui/widget/entity-entry.cpp | 4 ---- src/ui/widget/filter-effect-chooser.h | 8 -------- src/ui/widget/frame.h | 8 -------- src/ui/widget/imageicon.h | 8 -------- src/ui/widget/imagetoggler.h | 4 ---- src/ui/widget/insertordericon.h | 3 ++- src/ui/widget/labelled.h | 8 -------- src/ui/widget/layertypeicon.cpp | 4 ---- src/ui/widget/licensor.h | 8 -------- src/ui/widget/notebook-page.h | 4 ---- src/ui/widget/object-composite-settings.h | 8 -------- src/ui/widget/panel.cpp | 4 ---- src/ui/widget/panel.h | 4 ---- src/ui/widget/preferences-widget.cpp | 4 ---- src/ui/widget/preferences-widget.h | 4 ---- src/ui/widget/rotateable.cpp | 4 ---- src/ui/widget/selected-style.h | 4 ---- src/ui/widget/spin-scale.h | 4 ---- src/ui/widget/spin-slider.h | 4 ---- src/ui/widget/spinbutton.h | 8 -------- src/ui/widget/style-swatch.h | 4 ---- src/ui/widget/tolerance-slider.cpp | 4 ---- src/ui/widget/unit-menu.h | 8 -------- src/verbs.cpp | 7 +++---- src/widgets/dash-selector.h | 4 ---- src/widgets/desktop-widget.h | 8 -------- src/widgets/fill-style.cpp | 4 ---- src/widgets/icon.cpp | 4 ---- src/widgets/paint-selector.cpp | 4 ---- src/widgets/shrink-wrap-button.cpp | 4 ---- src/widgets/sp-attribute-widget.h | 4 ---- src/widgets/spw-utilities.cpp | 4 ---- src/widgets/stroke-marker-selector.h | 8 -------- src/widgets/swatch-selector.h | 8 -------- src/widgets/toolbox.cpp | 4 ---- 95 files changed, 13 insertions(+), 454 deletions(-) (limited to 'src') diff --git a/src/display/canvas-axonomgrid.cpp b/src/display/canvas-axonomgrid.cpp index a2df86823..1794ccbab 100644 --- a/src/display/canvas-axonomgrid.cpp +++ b/src/display/canvas-axonomgrid.cpp @@ -17,10 +17,6 @@ # include "config.h" #endif -#if GLIBMM_DISABLE_DEPRECATED && HAVE_GLIBMM_THREADS_H -#include -#endif - #include #include diff --git a/src/display/canvas-grid.cpp b/src/display/canvas-grid.cpp index 9b9f64529..4eda9b194 100644 --- a/src/display/canvas-grid.cpp +++ b/src/display/canvas-grid.cpp @@ -17,10 +17,6 @@ # include "config.h" #endif -#if GLIBMM_DISABLE_DEPRECATED && HAVE_GLIBMM_THREADS_H -#include -#endif - #include #include diff --git a/src/extension/execution-env.cpp b/src/extension/execution-env.cpp index 13b8d60c4..e7cd43d9d 100644 --- a/src/extension/execution-env.cpp +++ b/src/extension/execution-env.cpp @@ -14,10 +14,6 @@ # include #endif -#if GLIBMM_DISABLE_DEPRECATED && HAVE_GLIBMM_THREADS_H -#include -#endif - #include "gtkmm/messagedialog.h" #include "execution-env.h" diff --git a/src/extension/extension.cpp b/src/extension/extension.cpp index 3d0f49a20..6f7539360 100644 --- a/src/extension/extension.cpp +++ b/src/extension/extension.cpp @@ -19,10 +19,6 @@ # include "config.h" #endif -#if GLIBMM_DISABLE_DEPRECATED && HAVE_GLIBMM_THREADS_H -#include -#endif - #include #include #include diff --git a/src/extension/internal/bitmap/imagemagick.cpp b/src/extension/internal/bitmap/imagemagick.cpp index 76f35415e..7c91bf1ef 100644 --- a/src/extension/internal/bitmap/imagemagick.cpp +++ b/src/extension/internal/bitmap/imagemagick.cpp @@ -12,10 +12,6 @@ # include "config.h" #endif -#if GLIBMM_DISABLE_DEPRECATED && HAVE_GLIBMM_THREADS_H -#include -#endif - #include #include diff --git a/src/extension/internal/cdr-input.h b/src/extension/internal/cdr-input.h index 3de6c1ed0..10af41d5a 100644 --- a/src/extension/internal/cdr-input.h +++ b/src/extension/internal/cdr-input.h @@ -19,10 +19,6 @@ #ifdef WITH_LIBCDR -#if GLIBMM_DISABLE_DEPRECATED && HAVE_GLIBMM_THREADS_H -#include -#endif - #include #include "../implementation/implementation.h" diff --git a/src/extension/internal/grid.cpp b/src/extension/internal/grid.cpp index 270edfe44..61f2f70e2 100644 --- a/src/extension/internal/grid.cpp +++ b/src/extension/internal/grid.cpp @@ -15,10 +15,6 @@ # include #endif -#if GLIBMM_DISABLE_DEPRECATED && HAVE_GLIBMM_THREADS_H -#include -#endif - #include #include #include diff --git a/src/extension/internal/pdfinput/pdf-input.h b/src/extension/internal/pdfinput/pdf-input.h index d57c3e993..866db5d82 100644 --- a/src/extension/internal/pdfinput/pdf-input.h +++ b/src/extension/internal/pdfinput/pdf-input.h @@ -16,10 +16,6 @@ #ifdef HAVE_POPPLER -#if GLIBMM_DISABLE_DEPRECATED && HAVE_GLIBMM_THREADS_H -#include -#endif - #include #include "../../implementation/implementation.h" diff --git a/src/extension/internal/vsd-input.h b/src/extension/internal/vsd-input.h index 3414e0ec9..acc52debf 100644 --- a/src/extension/internal/vsd-input.h +++ b/src/extension/internal/vsd-input.h @@ -19,10 +19,6 @@ #ifdef WITH_LIBVISIO -#if GLIBMM_DISABLE_DEPRECATED && HAVE_GLIBMM_THREADS_H -#include -#endif - #include #include "../implementation/implementation.h" diff --git a/src/extension/param/bool.cpp b/src/extension/param/bool.cpp index 548dec4fa..de9b1c586 100644 --- a/src/extension/param/bool.cpp +++ b/src/extension/param/bool.cpp @@ -10,10 +10,6 @@ # include "config.h" #endif -#if GLIBMM_DISABLE_DEPRECATED && HAVE_GLIBMM_THREADS_H -#include -#endif - #include #include #include diff --git a/src/extension/param/color.cpp b/src/extension/param/color.cpp index 5bd70359f..b774bac83 100644 --- a/src/extension/param/color.cpp +++ b/src/extension/param/color.cpp @@ -14,10 +14,6 @@ #include #include -#if GLIBMM_DISABLE_DEPRECATED && HAVE_GLIBMM_THREADS_H -#include -#endif - #include #include #include diff --git a/src/extension/param/description.cpp b/src/extension/param/description.cpp index 95ed04afc..326e75e4a 100644 --- a/src/extension/param/description.cpp +++ b/src/extension/param/description.cpp @@ -13,10 +13,6 @@ # include "config.h" #endif -#if GLIBMM_DISABLE_DEPRECATED && HAVE_GLIBMM_THREADS_H -#include -#endif - #include #include #include diff --git a/src/extension/param/enum.cpp b/src/extension/param/enum.cpp index 74b2a75ad..8bc0fbda7 100644 --- a/src/extension/param/enum.cpp +++ b/src/extension/param/enum.cpp @@ -18,10 +18,6 @@ # include "config.h" #endif -#if GLIBMM_DISABLE_DEPRECATED && HAVE_GLIBMM_THREADS_H -#include -#endif - #include #include #include diff --git a/src/extension/param/float.cpp b/src/extension/param/float.cpp index 464938f03..81508f6c0 100644 --- a/src/extension/param/float.cpp +++ b/src/extension/param/float.cpp @@ -10,10 +10,6 @@ # include "config.h" #endif -#if GLIBMM_DISABLE_DEPRECATED && HAVE_GLIBMM_THREADS_H -#include -#endif - #include #include #include diff --git a/src/extension/param/int.cpp b/src/extension/param/int.cpp index 819c75693..c286018fd 100644 --- a/src/extension/param/int.cpp +++ b/src/extension/param/int.cpp @@ -10,10 +10,6 @@ # include "config.h" #endif -#if GLIBMM_DISABLE_DEPRECATED && HAVE_GLIBMM_THREADS_H -#include -#endif - #include #include #include diff --git a/src/extension/param/notebook.cpp b/src/extension/param/notebook.cpp index 9ec31ca6b..20c8e8481 100644 --- a/src/extension/param/notebook.cpp +++ b/src/extension/param/notebook.cpp @@ -16,10 +16,6 @@ # include "config.h" #endif -#if GLIBMM_DISABLE_DEPRECATED && HAVE_GLIBMM_THREADS_H -#include -#endif - #include #include #include diff --git a/src/extension/param/radiobutton.cpp b/src/extension/param/radiobutton.cpp index 740acf1d1..8181c6f51 100644 --- a/src/extension/param/radiobutton.cpp +++ b/src/extension/param/radiobutton.cpp @@ -18,10 +18,6 @@ # include "config.h" #endif -#if GLIBMM_DISABLE_DEPRECATED && HAVE_GLIBMM_THREADS_H -#include -#endif - #include #include #include diff --git a/src/extension/param/string.cpp b/src/extension/param/string.cpp index d6e438db5..4e525ff73 100644 --- a/src/extension/param/string.cpp +++ b/src/extension/param/string.cpp @@ -10,10 +10,6 @@ # include "config.h" #endif -#if GLIBMM_DISABLE_DEPRECATED && HAVE_GLIBMM_THREADS_H -#include -#endif - #include #include #include diff --git a/src/extension/prefdialog.h b/src/extension/prefdialog.h index 905d35744..4714c2c3f 100644 --- a/src/extension/prefdialog.h +++ b/src/extension/prefdialog.h @@ -10,19 +10,10 @@ #ifndef INKSCAPE_EXTENSION_DIALOG_H__ #define INKSCAPE_EXTENSION_DIALOG_H__ -#ifdef HAVE_CONFIG_H -# include -#endif - -#if GLIBMM_DISABLE_DEPRECATED && HAVE_GLIBMM_THREADS_H -#include -#endif - #include #include #include - namespace Gtk { class CheckButton; } diff --git a/src/inkscape.cpp b/src/inkscape.cpp index 6a0e0f35a..888a64430 100644 --- a/src/inkscape.cpp +++ b/src/inkscape.cpp @@ -22,10 +22,6 @@ #include -#if GLIBMM_DISABLE_DEPRECATED && HAVE_GLIBMM_THREADS_H -#include -#endif - #include #include "debug/simple-event.h" #include "debug/event-tracker.h" diff --git a/src/libdepixelize/kopftracer2011.cpp b/src/libdepixelize/kopftracer2011.cpp index 1e769b0c9..96784b14f 100644 --- a/src/libdepixelize/kopftracer2011.cpp +++ b/src/libdepixelize/kopftracer2011.cpp @@ -28,11 +28,6 @@ #include -// Build fix under Inkscape build tree -#if GLIBMM_DISABLE_DEPRECATED && HAVE_GLIBMM_THREADS_H -#include -#endif - #include #include "kopftracer2011.h" #include "priv/colorspace.h" @@ -667,4 +662,4 @@ inline bool Heuristics::islands(PixelGraph::const_iterator a, fill-column:99 End: */ -// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 : +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 : diff --git a/src/live_effects/lpe-fillet-chamfer.h b/src/live_effects/lpe-fillet-chamfer.h index 0d6a1ff17..fb06e804c 100644 --- a/src/live_effects/lpe-fillet-chamfer.h +++ b/src/live_effects/lpe-fillet-chamfer.h @@ -15,14 +15,6 @@ * Released under GNU GPL, read the file 'COPYING' for more information */ -#if HAVE_CONFIG_H -# include "config.h" -#endif - -#if defined(GLIBMM_DISABLE_DEPRECATED) && defined(HAVE_GLIBMM_THREADS_H) -# include -#endif - #include "live_effects/parameter/enum.h" #include "live_effects/parameter/bool.h" #include "live_effects/parameter/unit.h" diff --git a/src/live_effects/lpe-lattice2.cpp b/src/live_effects/lpe-lattice2.cpp index abd6e7786..02bda3af5 100644 --- a/src/live_effects/lpe-lattice2.cpp +++ b/src/live_effects/lpe-lattice2.cpp @@ -18,6 +18,8 @@ #include "live_effects/lpe-lattice2.h" +#include + #include "sp-shape.h" #include "sp-item.h" #include "sp-path.h" diff --git a/src/live_effects/lpe-lattice2.h b/src/live_effects/lpe-lattice2.h index ff2e75641..b32903c9e 100644 --- a/src/live_effects/lpe-lattice2.h +++ b/src/live_effects/lpe-lattice2.h @@ -18,12 +18,16 @@ * * Released under GNU GPL, read the file 'COPYING' for more information */ -#include #include "live_effects/parameter/enum.h" +#include #include "live_effects/effect.h" #include "live_effects/parameter/point.h" #include "live_effects/lpegroupbbox.h" +namespace Gtk { +class Expander; +} + namespace Inkscape { namespace LivePathEffect { diff --git a/src/live_effects/parameter/originalpath.cpp b/src/live_effects/parameter/originalpath.cpp index 0884c4c9c..2741461be 100644 --- a/src/live_effects/parameter/originalpath.cpp +++ b/src/live_effects/parameter/originalpath.cpp @@ -8,10 +8,6 @@ # include "config.h" #endif -#if GLIBMM_DISABLE_DEPRECATED && HAVE_GLIBMM_THREADS_H -#include -#endif - #include #include "live_effects/parameter/originalpath.h" diff --git a/src/live_effects/parameter/originalpatharray.cpp b/src/live_effects/parameter/originalpatharray.cpp index 7706dbdf8..78e061e66 100644 --- a/src/live_effects/parameter/originalpatharray.cpp +++ b/src/live_effects/parameter/originalpatharray.cpp @@ -8,10 +8,6 @@ # include "config.h" #endif -#if GLIBMM_DISABLE_DEPRECATED && HAVE_GLIBMM_THREADS_H -#include -#endif - #include "live_effects/parameter/originalpatharray.h" #include diff --git a/src/ui/dialog-events.cpp b/src/ui/dialog-events.cpp index 5bc8088a1..8856631c0 100644 --- a/src/ui/dialog-events.cpp +++ b/src/ui/dialog-events.cpp @@ -15,10 +15,6 @@ # include "config.h" #endif -#if GLIBMM_DISABLE_DEPRECATED && HAVE_GLIBMM_THREADS_H -#include -#endif - #include #include #include diff --git a/src/ui/dialog/aboutbox.h b/src/ui/dialog/aboutbox.h index 015e344a1..f3234b88d 100644 --- a/src/ui/dialog/aboutbox.h +++ b/src/ui/dialog/aboutbox.h @@ -15,14 +15,6 @@ #ifndef INKSCAPE_UI_DIALOG_ABOUTBOX_H #define INKSCAPE_UI_DIALOG_ABOUTBOX_H -#ifdef HAVE_CONFIG_H -# include -#endif - -#if GLIBMM_DISABLE_DEPRECATED && HAVE_GLIBMM_THREADS_H -#include -#endif - #include namespace Inkscape { diff --git a/src/ui/dialog/calligraphic-profile-rename.h b/src/ui/dialog/calligraphic-profile-rename.h index fa13db196..4ef71900b 100644 --- a/src/ui/dialog/calligraphic-profile-rename.h +++ b/src/ui/dialog/calligraphic-profile-rename.h @@ -15,10 +15,6 @@ # include "config.h" #endif -#if GLIBMM_DISABLE_DEPRECATED && HAVE_GLIBMM_THREADS_H -# include -#endif - #include #include #include diff --git a/src/ui/dialog/color-item.cpp b/src/ui/dialog/color-item.cpp index a49a47d5c..6603d5c69 100644 --- a/src/ui/dialog/color-item.cpp +++ b/src/ui/dialog/color-item.cpp @@ -17,10 +17,6 @@ #include -#if GLIBMM_DISABLE_DEPRECATED && HAVE_GLIBMM_THREADS_H -#include -#endif - #include #include #include diff --git a/src/ui/dialog/debug.cpp b/src/ui/dialog/debug.cpp index 9e2287f80..d127261c0 100644 --- a/src/ui/dialog/debug.cpp +++ b/src/ui/dialog/debug.cpp @@ -13,10 +13,6 @@ # include #endif -#if GLIBMM_DISABLE_DEPRECATED && HAVE_GLIBMM_THREADS_H -#include -#endif - #include #include #include diff --git a/src/ui/dialog/export.cpp b/src/ui/dialog/export.cpp index 6d90c792e..9ac5c24fe 100644 --- a/src/ui/dialog/export.cpp +++ b/src/ui/dialog/export.cpp @@ -20,10 +20,6 @@ // This has to be included prior to anything that includes setjmp.h, it croaks otherwise #include -#if GLIBMM_DISABLE_DEPRECATED && HAVE_GLIBMM_THREADS_H -#include -#endif - #include #include #include diff --git a/src/ui/dialog/filedialogimpl-gtkmm.h b/src/ui/dialog/filedialogimpl-gtkmm.h index 6687915d7..7501b5e14 100644 --- a/src/ui/dialog/filedialogimpl-gtkmm.h +++ b/src/ui/dialog/filedialogimpl-gtkmm.h @@ -17,14 +17,6 @@ #ifndef __FILE_DIALOGIMPL_H__ #define __FILE_DIALOGIMPL_H__ -#ifdef HAVE_CONFIG_H -# include -#endif - -#if GLIBMM_DISABLE_DEPRECATED && HAVE_GLIBMM_THREADS_H -#include -#endif - //Gtk includes #include #include diff --git a/src/ui/dialog/filedialogimpl-win32.h b/src/ui/dialog/filedialogimpl-win32.h index 8c3b6bad6..b254c3ef6 100644 --- a/src/ui/dialog/filedialogimpl-win32.h +++ b/src/ui/dialog/filedialogimpl-win32.h @@ -16,11 +16,6 @@ #include #ifdef WIN32 -#if WITH_GLIBMM_2_32 -#if GLIBMM_DISABLE_DEPRECATED && HAVE_GLIBMM_THREADS_H -# include -#endif -#endif #include "filedialogimpl-gtkmm.h" diff --git a/src/ui/dialog/floating-behavior.cpp b/src/ui/dialog/floating-behavior.cpp index 11db14801..740acd989 100644 --- a/src/ui/dialog/floating-behavior.cpp +++ b/src/ui/dialog/floating-behavior.cpp @@ -14,10 +14,6 @@ # include "config.h" #endif -#if GLIBMM_DISABLE_DEPRECATED && HAVE_GLIBMM_THREADS_H -#include -#endif - #include #include #include diff --git a/src/ui/dialog/font-substitution.cpp b/src/ui/dialog/font-substitution.cpp index ae03bdf0e..2ef61978f 100644 --- a/src/ui/dialog/font-substitution.cpp +++ b/src/ui/dialog/font-substitution.cpp @@ -10,10 +10,6 @@ # include #endif -#if GLIBMM_DISABLE_DEPRECATED && HAVE_GLIBMM_THREADS_H -#include -#endif - #include #include #include diff --git a/src/ui/dialog/guides.h b/src/ui/dialog/guides.h index 22bf5097a..4ff7b4fde 100644 --- a/src/ui/dialog/guides.h +++ b/src/ui/dialog/guides.h @@ -15,10 +15,6 @@ # include #endif -#if GLIBMM_DISABLE_DEPRECATED && HAVE_GLIBMM_THREADS_H -#include -#endif - #include #if WITH_GTKMM_3_0 diff --git a/src/ui/dialog/icon-preview.cpp b/src/ui/dialog/icon-preview.cpp index b908a90cb..069b61cb7 100644 --- a/src/ui/dialog/icon-preview.cpp +++ b/src/ui/dialog/icon-preview.cpp @@ -17,10 +17,6 @@ # include #endif -#if GLIBMM_DISABLE_DEPRECATED && HAVE_GLIBMM_THREADS_H -#include -#endif - #include #include diff --git a/src/ui/dialog/layer-properties.h b/src/ui/dialog/layer-properties.h index d114c6ba5..c75a7f190 100644 --- a/src/ui/dialog/layer-properties.h +++ b/src/ui/dialog/layer-properties.h @@ -16,10 +16,6 @@ # include #endif -#if GLIBMM_DISABLE_DEPRECATED && HAVE_GLIBMM_THREADS_H -#include -#endif - #include #include #include diff --git a/src/ui/dialog/layers.h b/src/ui/dialog/layers.h index ae0ac6040..9cd2c3b92 100644 --- a/src/ui/dialog/layers.h +++ b/src/ui/dialog/layers.h @@ -16,10 +16,6 @@ # include #endif -#if GLIBMM_DISABLE_DEPRECATED && HAVE_GLIBMM_THREADS_H -#include -#endif - #include #include #include diff --git a/src/ui/dialog/livepatheffect-add.h b/src/ui/dialog/livepatheffect-add.h index 99ead878c..c686e8365 100644 --- a/src/ui/dialog/livepatheffect-add.h +++ b/src/ui/dialog/livepatheffect-add.h @@ -11,14 +11,6 @@ #ifndef INKSCAPE_DIALOG_LIVEPATHEFFECT_ADD_H #define INKSCAPE_DIALOG_LIVEPATHEFFECT_ADD_H -#ifdef HAVE_CONFIG_H -# include -#endif - -#if GLIBMM_DISABLE_DEPRECATED && HAVE_GLIBMM_THREADS_H -#include -#endif - #include #include #include diff --git a/src/ui/dialog/lpe-fillet-chamfer-properties.cpp b/src/ui/dialog/lpe-fillet-chamfer-properties.cpp index 7e5c17133..f63b19e86 100644 --- a/src/ui/dialog/lpe-fillet-chamfer-properties.cpp +++ b/src/ui/dialog/lpe-fillet-chamfer-properties.cpp @@ -8,10 +8,6 @@ #include #endif -#if GLIBMM_DISABLE_DEPRECATED &&HAVE_GLIBMM_THREADS_H -#include -#endif - #include #include "lpe-fillet-chamfer-properties.h" #include diff --git a/src/ui/dialog/lpe-powerstroke-properties.cpp b/src/ui/dialog/lpe-powerstroke-properties.cpp index a9e57970d..0cf3e9706 100644 --- a/src/ui/dialog/lpe-powerstroke-properties.cpp +++ b/src/ui/dialog/lpe-powerstroke-properties.cpp @@ -17,10 +17,6 @@ # include #endif -#if GLIBMM_DISABLE_DEPRECATED && HAVE_GLIBMM_THREADS_H -#include -#endif - #include "lpe-powerstroke-properties.h" #include #include diff --git a/src/ui/dialog/messages.h b/src/ui/dialog/messages.h index 54ca84f47..6ed246ece 100644 --- a/src/ui/dialog/messages.h +++ b/src/ui/dialog/messages.h @@ -16,14 +16,6 @@ #ifndef INKSCAPE_UI_DIALOG_MESSAGES_H #define INKSCAPE_UI_DIALOG_MESSAGES_H -#ifdef HAVE_CONFIG_H -# include -#endif - -#if GLIBMM_DISABLE_DEPRECATED && HAVE_GLIBMM_THREADS_H -#include -#endif - #include #include #include diff --git a/src/ui/dialog/objects.h b/src/ui/dialog/objects.h index 74c2382ac..1842fea11 100644 --- a/src/ui/dialog/objects.h +++ b/src/ui/dialog/objects.h @@ -16,10 +16,6 @@ # include #endif -#if GLIBMM_DISABLE_DEPRECATED && HAVE_GLIBMM_THREADS_H -# include -#endif - #include #include #include diff --git a/src/ui/dialog/ocaldialogs.h b/src/ui/dialog/ocaldialogs.h index bd028c145..6ceceb9ef 100644 --- a/src/ui/dialog/ocaldialogs.h +++ b/src/ui/dialog/ocaldialogs.h @@ -17,10 +17,6 @@ # include #endif -#if GLIBMM_DISABLE_DEPRECATED && HAVE_GLIBMM_THREADS_H -#include -#endif - //Gtk includes #include #include diff --git a/src/ui/dialog/spellcheck.h b/src/ui/dialog/spellcheck.h index 27b89e34e..e98a9d80e 100644 --- a/src/ui/dialog/spellcheck.h +++ b/src/ui/dialog/spellcheck.h @@ -16,10 +16,6 @@ # include #endif -#if GLIBMM_DISABLE_DEPRECATED && HAVE_GLIBMM_THREADS_H -#include -#endif - #include #include #include diff --git a/src/ui/dialog/symbols.cpp b/src/ui/dialog/symbols.cpp index eeb4d6cbe..06c17611f 100644 --- a/src/ui/dialog/symbols.cpp +++ b/src/ui/dialog/symbols.cpp @@ -18,10 +18,6 @@ #include #include -#if GLIBMM_DISABLE_DEPRECATED && HAVE_GLIBMM_THREADS_H -#include -#endif - #include #include diff --git a/src/ui/dialog/text-edit.h b/src/ui/dialog/text-edit.h index 8683d80a3..117ad2e28 100644 --- a/src/ui/dialog/text-edit.h +++ b/src/ui/dialog/text-edit.h @@ -22,10 +22,6 @@ # include #endif -#if GLIBMM_DISABLE_DEPRECATED && HAVE_GLIBMM_THREADS_H -#include -#endif - #include #include #include diff --git a/src/ui/dialog/tile.h b/src/ui/dialog/tile.h index 2f75a8922..de1d3028b 100644 --- a/src/ui/dialog/tile.h +++ b/src/ui/dialog/tile.h @@ -20,10 +20,6 @@ # include #endif -#if GLIBMM_DISABLE_DEPRECATED && HAVE_GLIBMM_THREADS_H -#include -#endif - #include #include #include diff --git a/src/ui/dialog/transformation.cpp b/src/ui/dialog/transformation.cpp index 233d99750..e7ee9529f 100644 --- a/src/ui/dialog/transformation.cpp +++ b/src/ui/dialog/transformation.cpp @@ -15,10 +15,6 @@ # include #endif -#if GLIBMM_DISABLE_DEPRECATED && HAVE_GLIBMM_THREADS_H -#include -#endif - #include #include #include <2geom/transforms.h> diff --git a/src/ui/previewholder.h b/src/ui/previewholder.h index f9f923be4..f6d1985cc 100644 --- a/src/ui/previewholder.h +++ b/src/ui/previewholder.h @@ -16,10 +16,6 @@ # include "config.h" #endif -#if GLIBMM_DISABLE_DEPRECATED && HAVE_GLIBMM_THREADS_H -#include -#endif - #include #include diff --git a/src/ui/tools/tool-base.cpp b/src/ui/tools/tool-base.cpp index a07f2fb86..2eb6d24d9 100644 --- a/src/ui/tools/tool-base.cpp +++ b/src/ui/tools/tool-base.cpp @@ -20,10 +20,6 @@ #include "widgets/desktop-widget.h" -#if GLIBMM_DISABLE_DEPRECATED && HAVE_GLIBMM_THREADS_H -#include -#endif - #include "shortcuts.h" #include "file.h" #include "ui/tools/tool-base.h" diff --git a/src/ui/widget/addtoicon.cpp b/src/ui/widget/addtoicon.cpp index f15d7abf7..823e24a00 100644 --- a/src/ui/widget/addtoicon.cpp +++ b/src/ui/widget/addtoicon.cpp @@ -12,10 +12,6 @@ # include #endif -#if GLIBMM_DISABLE_DEPRECATED && HAVE_GLIBMM_THREADS_H -# include -#endif - #include "ui/widget/addtoicon.h" #include diff --git a/src/ui/widget/button.h b/src/ui/widget/button.h index 471b7d8a2..d3c9afa02 100644 --- a/src/ui/widget/button.h +++ b/src/ui/widget/button.h @@ -10,14 +10,6 @@ #ifndef INKSCAPE_UI_WIDGET_BUTTON_H #define INKSCAPE_UI_WIDGET_BUTTON_H -#ifdef HAVE_CONFIG_H -# include -#endif - -#if GLIBMM_DISABLE_DEPRECATED && HAVE_GLIBMM_THREADS_H -#include -#endif - #include #include diff --git a/src/ui/widget/clipmaskicon.cpp b/src/ui/widget/clipmaskicon.cpp index 943b1bebc..421f1df1e 100644 --- a/src/ui/widget/clipmaskicon.cpp +++ b/src/ui/widget/clipmaskicon.cpp @@ -11,10 +11,6 @@ # include #endif -#if GLIBMM_DISABLE_DEPRECATED && HAVE_GLIBMM_THREADS_H -# include -#endif - #include "ui/widget/clipmaskicon.h" #include diff --git a/src/ui/widget/color-picker.h b/src/ui/widget/color-picker.h index b4da5dbf2..99904b081 100644 --- a/src/ui/widget/color-picker.h +++ b/src/ui/widget/color-picker.h @@ -13,16 +13,8 @@ #ifndef __COLOR_PICKER_H__ #define __COLOR_PICKER_H__ -#ifdef HAVE_CONFIG_H -# include -#endif - #include -#if GLIBMM_DISABLE_DEPRECATED && HAVE_GLIBMM_THREADS_H -#include -#endif - #include #include #include diff --git a/src/ui/widget/color-preview.h b/src/ui/widget/color-preview.h index 959b5e09b..caddfb9a2 100644 --- a/src/ui/widget/color-preview.h +++ b/src/ui/widget/color-preview.h @@ -15,10 +15,6 @@ # include #endif -#if GLIBMM_DISABLE_DEPRECATED && HAVE_GLIBMM_THREADS_H -#include -#endif - #include namespace Inkscape { diff --git a/src/ui/widget/dock-item.h b/src/ui/widget/dock-item.h index cc0c13eea..25a69d94c 100644 --- a/src/ui/widget/dock-item.h +++ b/src/ui/widget/dock-item.h @@ -15,10 +15,6 @@ # include #endif -#if GLIBMM_DISABLE_DEPRECATED && HAVE_GLIBMM_THREADS_H -#include -#endif - #include #include #include diff --git a/src/ui/widget/dock.h b/src/ui/widget/dock.h index 33e60b836..74b072d22 100644 --- a/src/ui/widget/dock.h +++ b/src/ui/widget/dock.h @@ -12,14 +12,6 @@ #ifndef INKSCAPE_UI_WIDGET_DOCK_H #define INKSCAPE_UI_WIDGET_DOCK_H -#ifdef HAVE_CONFIG_H -# include -#endif - -#if GLIBMM_DISABLE_DEPRECATED && HAVE_GLIBMM_THREADS_H -#include -#endif - #include #include #include "ui/widget/dock-item.h" diff --git a/src/ui/widget/entity-entry.cpp b/src/ui/widget/entity-entry.cpp index c7d5efe29..69173fa25 100644 --- a/src/ui/widget/entity-entry.cpp +++ b/src/ui/widget/entity-entry.cpp @@ -17,10 +17,6 @@ # include #endif -#if GLIBMM_DISABLE_DEPRECATED && HAVE_GLIBMM_THREADS_H -#include -#endif - #include #include diff --git a/src/ui/widget/filter-effect-chooser.h b/src/ui/widget/filter-effect-chooser.h index 6092c61a5..0bcf97433 100644 --- a/src/ui/widget/filter-effect-chooser.h +++ b/src/ui/widget/filter-effect-chooser.h @@ -12,14 +12,6 @@ * Released under GNU GPL, read the file 'COPYING' for more information */ -#ifdef HAVE_CONFIG_H -# include -#endif - -#if GLIBMM_DISABLE_DEPRECATED && HAVE_GLIBMM_THREADS_H -#include -#endif - #include #include diff --git a/src/ui/widget/frame.h b/src/ui/widget/frame.h index 55638ad40..a04666651 100644 --- a/src/ui/widget/frame.h +++ b/src/ui/widget/frame.h @@ -10,14 +10,6 @@ #ifndef INKSCAPE_UI_WIDGET_FRAME_H #define INKSCAPE_UI_WIDGET_FRAME_H -#ifdef HAVE_CONFIG_H -# include -#endif - -#if GLIBMM_DISABLE_DEPRECATED && HAVE_GLIBMM_THREADS_H -#include -#endif - #include #include #include diff --git a/src/ui/widget/imageicon.h b/src/ui/widget/imageicon.h index 8faf13cb1..2ea8b8533 100644 --- a/src/ui/widget/imageicon.h +++ b/src/ui/widget/imageicon.h @@ -12,14 +12,6 @@ * Released under GNU GPL, read the file 'COPYING' for more information */ -#ifdef HAVE_CONFIG_H -# include -#endif - -#if GLIBMM_DISABLE_DEPRECATED && HAVE_GLIBMM_THREADS_H -#include -#endif - #include #include diff --git a/src/ui/widget/imagetoggler.h b/src/ui/widget/imagetoggler.h index df6eb7ded..7b02fa4dc 100644 --- a/src/ui/widget/imagetoggler.h +++ b/src/ui/widget/imagetoggler.h @@ -14,10 +14,6 @@ #include "config.h" #endif -#if GLIBMM_DISABLE_DEPRECATED && HAVE_GLIBMM_THREADS_H -#include -#endif - #include #include #include diff --git a/src/ui/widget/insertordericon.h b/src/ui/widget/insertordericon.h index fb3412d3f..bf8ac4fa7 100644 --- a/src/ui/widget/insertordericon.h +++ b/src/ui/widget/insertordericon.h @@ -13,10 +13,11 @@ # include "config.h" #endif -#include #include #include +#include + namespace Inkscape { namespace UI { namespace Widget { diff --git a/src/ui/widget/labelled.h b/src/ui/widget/labelled.h index 5334454bc..88eb3ce19 100644 --- a/src/ui/widget/labelled.h +++ b/src/ui/widget/labelled.h @@ -11,14 +11,6 @@ #ifndef INKSCAPE_UI_WIDGET_LABELLED_H #define INKSCAPE_UI_WIDGET_LABELLED_H -#ifdef HAVE_CONFIG_H -# include -#endif - -#if GLIBMM_DISABLE_DEPRECATED && HAVE_GLIBMM_THREADS_H -#include -#endif - #include namespace Gtk { diff --git a/src/ui/widget/layertypeicon.cpp b/src/ui/widget/layertypeicon.cpp index 3d6182bf8..672c607e5 100644 --- a/src/ui/widget/layertypeicon.cpp +++ b/src/ui/widget/layertypeicon.cpp @@ -11,10 +11,6 @@ # include #endif -#if GLIBMM_DISABLE_DEPRECATED && HAVE_GLIBMM_THREADS_H -# include -#endif - #include "ui/widget/layertypeicon.h" #include diff --git a/src/ui/widget/licensor.h b/src/ui/widget/licensor.h index c75c5fe9e..b96162589 100644 --- a/src/ui/widget/licensor.h +++ b/src/ui/widget/licensor.h @@ -10,14 +10,6 @@ #ifndef INKSCAPE_UI_WIDGET_LICENSOR_H #define INKSCAPE_UI_WIDGET_LICENSOR_H -#ifdef HAVE_CONFIG_H -# include -#endif - -#if GLIBMM_DISABLE_DEPRECATED && HAVE_GLIBMM_THREADS_H -#include -#endif - #include class SPDocument; diff --git a/src/ui/widget/notebook-page.h b/src/ui/widget/notebook-page.h index 4f7915423..c11de1b5b 100644 --- a/src/ui/widget/notebook-page.h +++ b/src/ui/widget/notebook-page.h @@ -14,10 +14,6 @@ # include #endif -#if GLIBMM_DISABLE_DEPRECATED && HAVE_GLIBMM_THREADS_H -#include -#endif - #include namespace Gtk { diff --git a/src/ui/widget/object-composite-settings.h b/src/ui/widget/object-composite-settings.h index 5a723a2fd..ae16564e1 100644 --- a/src/ui/widget/object-composite-settings.h +++ b/src/ui/widget/object-composite-settings.h @@ -11,14 +11,6 @@ * Released under GNU GPL, read the file 'COPYING' for more information */ -#ifdef HAVE_CONFIG_H -# include -#endif - -#if GLIBMM_DISABLE_DEPRECATED && HAVE_GLIBMM_THREADS_H -#include -#endif - #include #include #include diff --git a/src/ui/widget/panel.cpp b/src/ui/widget/panel.cpp index 0cff25d88..8a1e98a63 100644 --- a/src/ui/widget/panel.cpp +++ b/src/ui/widget/panel.cpp @@ -15,10 +15,6 @@ # include #endif -#if GLIBMM_DISABLE_DEPRECATED && HAVE_GLIBMM_THREADS_H -#include -#endif - #include // for Gtk::RESPONSE_* #include #include diff --git a/src/ui/widget/panel.h b/src/ui/widget/panel.h index 5680cac30..a90060e17 100644 --- a/src/ui/widget/panel.h +++ b/src/ui/widget/panel.h @@ -17,10 +17,6 @@ # include #endif -#if GLIBMM_DISABLE_DEPRECATED && HAVE_GLIBMM_THREADS_H -#include -#endif - #include #include #include diff --git a/src/ui/widget/preferences-widget.cpp b/src/ui/widget/preferences-widget.cpp index 98028ed78..72597e4d9 100644 --- a/src/ui/widget/preferences-widget.cpp +++ b/src/ui/widget/preferences-widget.cpp @@ -14,10 +14,6 @@ # include #endif -#if GLIBMM_DISABLE_DEPRECATED && HAVE_GLIBMM_THREADS_H -#include -#endif - #include #include #include diff --git a/src/ui/widget/preferences-widget.h b/src/ui/widget/preferences-widget.h index 5d9816e74..8b75b8368 100644 --- a/src/ui/widget/preferences-widget.h +++ b/src/ui/widget/preferences-widget.h @@ -22,10 +22,6 @@ #include #include -#if GLIBMM_DISABLE_DEPRECATED && HAVE_GLIBMM_THREADS_H -#include -#endif - #include #include "ui/widget/spinbutton.h" #include diff --git a/src/ui/widget/rotateable.cpp b/src/ui/widget/rotateable.cpp index 2d7597d7c..5e938dee6 100644 --- a/src/ui/widget/rotateable.cpp +++ b/src/ui/widget/rotateable.cpp @@ -11,10 +11,6 @@ # include "config.h" #endif -#if GLIBMM_DISABLE_DEPRECATED && HAVE_GLIBMM_THREADS_H -#include -#endif - #include #include #include diff --git a/src/ui/widget/selected-style.h b/src/ui/widget/selected-style.h index 0b6a14762..804a6fef6 100644 --- a/src/ui/widget/selected-style.h +++ b/src/ui/widget/selected-style.h @@ -15,10 +15,6 @@ # include "config.h" #endif -#if GLIBMM_DISABLE_DEPRECATED && HAVE_GLIBMM_THREADS_H -#include -#endif - #include #if WITH_GTKMM_3_0 diff --git a/src/ui/widget/spin-scale.h b/src/ui/widget/spin-scale.h index d0447e4a6..50e4fc953 100644 --- a/src/ui/widget/spin-scale.h +++ b/src/ui/widget/spin-scale.h @@ -13,10 +13,6 @@ # include #endif -#if GLIBMM_DISABLE_DEPRECATED && HAVE_GLIBMM_THREADS_H -#include -#endif - #include #include #include diff --git a/src/ui/widget/spin-slider.h b/src/ui/widget/spin-slider.h index 74982ea58..a5999f14f 100644 --- a/src/ui/widget/spin-slider.h +++ b/src/ui/widget/spin-slider.h @@ -14,10 +14,6 @@ # include #endif -#if GLIBMM_DISABLE_DEPRECATED && HAVE_GLIBMM_THREADS_H -#include -#endif - #include #include #include diff --git a/src/ui/widget/spinbutton.h b/src/ui/widget/spinbutton.h index cbe33e8ea..30ffc7d77 100644 --- a/src/ui/widget/spinbutton.h +++ b/src/ui/widget/spinbutton.h @@ -10,14 +10,6 @@ #ifndef INKSCAPE_UI_WIDGET_SPINBUTTON_H #define INKSCAPE_UI_WIDGET_SPINBUTTON_H -#ifdef HAVE_CONFIG_H -# include -#endif - -#if GLIBMM_DISABLE_DEPRECATED && HAVE_GLIBMM_THREADS_H -#include -#endif - #include namespace Inkscape { diff --git a/src/ui/widget/style-swatch.h b/src/ui/widget/style-swatch.h index 582d2ebb3..0016e0256 100644 --- a/src/ui/widget/style-swatch.h +++ b/src/ui/widget/style-swatch.h @@ -17,10 +17,6 @@ # include "config.h" #endif -#if GLIBMM_DISABLE_DEPRECATED && HAVE_GLIBMM_THREADS_H -#include -#endif - #include #include #include diff --git a/src/ui/widget/tolerance-slider.cpp b/src/ui/widget/tolerance-slider.cpp index ff525c679..ced811c57 100644 --- a/src/ui/widget/tolerance-slider.cpp +++ b/src/ui/widget/tolerance-slider.cpp @@ -12,10 +12,6 @@ # include #endif -#if GLIBMM_DISABLE_DEPRECATED && HAVE_GLIBMM_THREADS_H -#include -#endif - #include #include #include diff --git a/src/ui/widget/unit-menu.h b/src/ui/widget/unit-menu.h index 2fd25a6a9..f414660f7 100644 --- a/src/ui/widget/unit-menu.h +++ b/src/ui/widget/unit-menu.h @@ -10,14 +10,6 @@ #ifndef INKSCAPE_UI_WIDGET_UNIT_H #define INKSCAPE_UI_WIDGET_UNIT_H -#ifdef HAVE_CONFIG_H -# include -#endif - -#if GLIBMM_DISABLE_DEPRECATED && HAVE_GLIBMM_THREADS_H -#include -#endif - #include #include "util/units.h" diff --git a/src/verbs.cpp b/src/verbs.cpp index 5febeeb7c..ea2c06dcf 100644 --- a/src/verbs.cpp +++ b/src/verbs.cpp @@ -32,10 +32,9 @@ #include #include -#if GLIBMM_DISABLE_DEPRECATED && HAVE_GLIBMM_THREADS_H -#include -#endif - +// Note that gtkmm headers must be included before gtk+ C headers +// in all files. The same applies for glibmm/glib etc. +// If this is not done, then errors will be generate relating to Glib::Threads being undefined #include #include #include diff --git a/src/widgets/dash-selector.h b/src/widgets/dash-selector.h index 5b9ebfa2b..ec5a1cbd5 100644 --- a/src/widgets/dash-selector.h +++ b/src/widgets/dash-selector.h @@ -14,10 +14,6 @@ # include #endif -#if GLIBMM_DISABLE_DEPRECATED && HAVE_GLIBMM_THREADS_H -#include -#endif - #include #include #include diff --git a/src/widgets/desktop-widget.h b/src/widgets/desktop-widget.h index a77d56fc3..489217d9a 100644 --- a/src/widgets/desktop-widget.h +++ b/src/widgets/desktop-widget.h @@ -12,14 +12,6 @@ * ? -2004 */ -#ifdef HAVE_CONFIG_H -# include -#endif - -#if GLIBMM_DISABLE_DEPRECATED && HAVE_GLIBMM_THREADS_H -#include -#endif - #include #include "message.h" #include "ui/view/view-widget.h" diff --git a/src/widgets/fill-style.cpp b/src/widgets/fill-style.cpp index d60a92b8b..b92b0a474 100644 --- a/src/widgets/fill-style.cpp +++ b/src/widgets/fill-style.cpp @@ -22,10 +22,6 @@ # include "config.h" #endif -#if GLIBMM_DISABLE_DEPRECATED && HAVE_GLIBMM_THREADS_H -#include -#endif - #include #include diff --git a/src/widgets/icon.cpp b/src/widgets/icon.cpp index afc4fcfb0..542d16797 100644 --- a/src/widgets/icon.cpp +++ b/src/widgets/icon.cpp @@ -16,10 +16,6 @@ # include "config.h" #endif -#if GLIBMM_DISABLE_DEPRECATED && HAVE_GLIBMM_THREADS_H -#include -#endif - #include #include #include diff --git a/src/widgets/paint-selector.cpp b/src/widgets/paint-selector.cpp index 948c80db3..740ce2b0e 100644 --- a/src/widgets/paint-selector.cpp +++ b/src/widgets/paint-selector.cpp @@ -24,10 +24,6 @@ #include #include -#if GLIBMM_DISABLE_DEPRECATED && HAVE_GLIBMM_THREADS_H -#include -#endif - #include "widgets/swatch-selector.h" #include "sp-pattern.h" #include diff --git a/src/widgets/shrink-wrap-button.cpp b/src/widgets/shrink-wrap-button.cpp index 3558780ed..941a0466c 100644 --- a/src/widgets/shrink-wrap-button.cpp +++ b/src/widgets/shrink-wrap-button.cpp @@ -13,10 +13,6 @@ #include "config.h" #endif -#if GLIBMM_DISABLE_DEPRECATED && HAVE_GLIBMM_THREADS_H -#include -#endif - #include #include diff --git a/src/widgets/sp-attribute-widget.h b/src/widgets/sp-attribute-widget.h index 4bd6c6959..d9b972201 100644 --- a/src/widgets/sp-attribute-widget.h +++ b/src/widgets/sp-attribute-widget.h @@ -19,10 +19,6 @@ # include "config.h" #endif -#if GLIBMM_DISABLE_DEPRECATED && HAVE_GLIBMM_THREADS_H -#include -#endif - #include #include #include diff --git a/src/widgets/spw-utilities.cpp b/src/widgets/spw-utilities.cpp index f87889bb1..7030753a5 100644 --- a/src/widgets/spw-utilities.cpp +++ b/src/widgets/spw-utilities.cpp @@ -17,10 +17,6 @@ #include #include -#if GLIBMM_DISABLE_DEPRECATED && HAVE_GLIBMM_THREADS_H -#include -#endif - #include #include diff --git a/src/widgets/stroke-marker-selector.h b/src/widgets/stroke-marker-selector.h index 27ac76d6f..a7ee788b8 100644 --- a/src/widgets/stroke-marker-selector.h +++ b/src/widgets/stroke-marker-selector.h @@ -10,14 +10,6 @@ * Released under GNU GPL, read the file 'COPYING' for more information */ -#ifdef HAVE_CONFIG_H -# include -#endif - -#if GLIBMM_DISABLE_DEPRECATED && HAVE_GLIBMM_THREADS_H -#include -#endif - #include #include #include diff --git a/src/widgets/swatch-selector.h b/src/widgets/swatch-selector.h index c8c9983a6..4b7aa483f 100644 --- a/src/widgets/swatch-selector.h +++ b/src/widgets/swatch-selector.h @@ -1,14 +1,6 @@ #ifndef SEEN_SP_SWATCH_SELECTOR_H #define SEEN_SP_SWATCH_SELECTOR_H -#ifdef HAVE_CONFIG_H -# include -#endif - -#if GLIBMM_DISABLE_DEPRECATED && HAVE_GLIBMM_THREADS_H -#include -#endif - #include class SPDocument; diff --git a/src/widgets/toolbox.cpp b/src/widgets/toolbox.cpp index 5d52db6f2..d56b91f5e 100644 --- a/src/widgets/toolbox.cpp +++ b/src/widgets/toolbox.cpp @@ -29,10 +29,6 @@ # include "config.h" #endif -#if GLIBMM_DISABLE_DEPRECATED && HAVE_GLIBMM_THREADS_H -#include -#endif - #include #include #include -- cgit v1.2.3 From c883d7627a479c8c5b6a9f77b9841fa5631572ad Mon Sep 17 00:00:00 2001 From: Krzysztof Kosi??ski Date: Mon, 27 Apr 2015 19:39:29 -0400 Subject: 2Geom sync - initial commit (bzr r14059.2.1) --- src/2geom/2geom.h | 6 +- src/2geom/CMakeLists.txt | 9 +- src/2geom/Makefile_insert | 25 +- src/2geom/affine.cpp | 30 +- src/2geom/affine.h | 6 +- src/2geom/angle.h | 4 +- src/2geom/basic-intersection.cpp | 177 +- src/2geom/basic-intersection.h | 94 +- src/2geom/bezier-clipping.cpp | 345 +- src/2geom/bezier-curve.cpp | 125 +- src/2geom/bezier-curve.h | 108 +- src/2geom/bezier-to-sbasis.h | 10 +- src/2geom/bezier-utils.cpp | 6 +- src/2geom/bezier.cpp | 324 ++ src/2geom/bezier.h | 505 +-- src/2geom/cairo-path-sink.cpp | 123 + src/2geom/cairo-path-sink.h | 87 + src/2geom/circle.cpp | 63 +- src/2geom/circle.h | 105 +- src/2geom/circulator.h | 9 +- src/2geom/concepts.h | 37 +- src/2geom/conic_section_clipper.h | 11 +- src/2geom/conic_section_clipper_cr.h | 11 +- src/2geom/conic_section_clipper_impl.cpp | 17 +- src/2geom/conic_section_clipper_impl.h | 22 +- src/2geom/conicsec.cpp | 81 +- src/2geom/conicsec.h | 22 +- src/2geom/conjugate_gradient.cpp | 143 - src/2geom/conjugate_gradient.h | 64 - src/2geom/convex-cover.cpp | 712 ---- src/2geom/convex-cover.h | 204 -- src/2geom/convex-hull.cpp | 746 ++++ src/2geom/convex-hull.h | 346 ++ src/2geom/coord.cpp | 3688 ++++++++++++++++++++ src/2geom/coord.h | 79 +- src/2geom/crossing.cpp | 2 +- src/2geom/crossing.h | 27 +- src/2geom/curve.cpp | 157 +- src/2geom/curve.h | 120 +- src/2geom/curves.h | 10 +- src/2geom/d2-sbasis.cpp | 4 +- src/2geom/d2-sbasis.h | 10 +- src/2geom/d2.h | 51 +- src/2geom/ellipse.cpp | 231 +- src/2geom/ellipse.h | 149 +- src/2geom/elliptical-arc.cpp | 76 +- src/2geom/elliptical-arc.h | 31 +- src/2geom/exception.h | 4 +- src/2geom/forward.h | 16 +- src/2geom/generic-interval.h | 29 +- src/2geom/generic-rect.h | 36 +- src/2geom/geom.cpp | 13 +- src/2geom/geom.h | 42 - src/2geom/hvlinesegment.h | 283 -- src/2geom/int-point.h | 47 +- src/2geom/intersection-graph.cpp | 296 ++ src/2geom/intersection-graph.h | 106 + src/2geom/intersection.h | 117 + src/2geom/interval.h | 39 +- src/2geom/line.cpp | 375 +- src/2geom/line.h | 368 +- src/2geom/linear.h | 66 +- src/2geom/nearest-point.cpp | 287 -- src/2geom/nearest-point.h | 133 - src/2geom/nearest-time.cpp | 322 ++ src/2geom/nearest-time.h | 141 + src/2geom/numeric/fitting-model.h | 4 +- src/2geom/numeric/matrix.h | 20 +- src/2geom/numeric/symmetric-matrix-fs-operation.h | 7 +- src/2geom/numeric/symmetric-matrix-fs-trace.h | 8 +- src/2geom/numeric/symmetric-matrix-fs.h | 5 +- src/2geom/numeric/vector.h | 13 +- src/2geom/ord.h | 9 +- src/2geom/path-intersection.cpp | 107 +- src/2geom/path-intersection.h | 18 +- src/2geom/path-sink.cpp | 73 +- src/2geom/path-sink.h | 98 +- src/2geom/path.cpp | 1236 ++++--- src/2geom/path.h | 1409 ++++---- src/2geom/pathvector.cpp | 214 +- src/2geom/pathvector.h | 318 +- src/2geom/piecewise.h | 13 +- src/2geom/point.cpp | 6 +- src/2geom/point.h | 170 +- src/2geom/quadtree.cpp | 4 - src/2geom/quadtree.h | 6 + src/2geom/ray.h | 4 +- src/2geom/rect.cpp | 11 + src/2geom/rect.h | 8 + src/2geom/recursive-bezier-intersection.cpp | 5 +- src/2geom/region.cpp | 45 - src/2geom/region.h | 130 - src/2geom/sbasis-2d.cpp | 2 +- src/2geom/sbasis-2d.h | 8 +- src/2geom/sbasis-curve.h | 25 +- src/2geom/sbasis-geometric.h | 44 +- src/2geom/sbasis-math.h | 11 +- src/2geom/sbasis-poly.h | 23 +- src/2geom/sbasis-roots.cpp | 52 +- src/2geom/sbasis-to-bezier.cpp | 42 +- src/2geom/sbasis-to-bezier.h | 14 +- src/2geom/sbasis.cpp | 10 +- src/2geom/sbasis.h | 115 +- src/2geom/shape.cpp | 689 ---- src/2geom/shape.h | 148 - src/2geom/solve-bezier-one-d.cpp | 30 +- src/2geom/solve-bezier-parametric.cpp | 51 +- src/2geom/solve-bezier.cpp | 57 +- src/2geom/solver.h | 11 +- src/2geom/svg-elliptical-arc.cpp | 2 +- src/2geom/svg-elliptical-arc.h | 26 +- src/2geom/svg-path-parser.cpp | 2206 ++++++------ src/2geom/svg-path-parser.h | 137 +- src/2geom/svg-path-writer.cpp | 296 ++ src/2geom/svg-path-writer.h | 122 + src/2geom/sweep.cpp | 8 +- src/2geom/sweep.h | 4 +- src/2geom/toposweep.cpp | 16 +- src/2geom/toposweep.h | 18 +- src/2geom/transforms.h | 3 + src/2geom/utils.h | 18 +- src/2geom/viewbox.cpp | 133 + src/2geom/viewbox.h | 102 + src/conn-avoid-ref.cpp | 4 +- src/desktop-events.cpp | 4 +- src/display/cairo-utils.cpp | 8 +- src/display/curve-test.h | 4 +- src/display/curve.cpp | 2 +- src/display/curve.h | 2 +- src/display/drawing-image.cpp | 2 +- src/extension/implementation/implementation.h | 9 +- src/extension/internal/emf-print.cpp | 20 +- src/extension/internal/javafx-out.cpp | 9 +- src/extension/internal/latex-pstricks.cpp | 5 +- src/extension/internal/metafile-print.cpp | 8 +- src/extension/internal/odf.cpp | 5 +- src/extension/internal/pov-out.cpp | 5 +- src/extension/internal/wmf-print.cpp | 19 +- src/gradient-chemistry.cpp | 6 +- src/gradient-drag.cpp | 22 +- src/helper/geom-curves.h | 10 +- src/helper/geom-pathstroke.cpp | 17 +- src/helper/geom.cpp | 13 +- src/libdepixelize/priv/splines-kopf2011.h | 2 +- src/live_effects/Makefile_insert | 2 - src/live_effects/effect.cpp | 94 +- src/live_effects/effect.h | 8 +- src/live_effects/lpe-angle_bisector.cpp | 10 +- src/live_effects/lpe-angle_bisector.h | 2 +- src/live_effects/lpe-attach-path.cpp | 16 +- src/live_effects/lpe-boolops.cpp | 79 - src/live_effects/lpe-boolops.h | 53 - src/live_effects/lpe-bounding-box.cpp | 2 +- src/live_effects/lpe-bspline.cpp | 12 +- src/live_effects/lpe-circle_3pts.cpp | 8 +- src/live_effects/lpe-circle_3pts.h | 2 +- src/live_effects/lpe-circle_with_radius.cpp | 6 +- src/live_effects/lpe-circle_with_radius.h | 2 +- src/live_effects/lpe-clone-original.cpp | 2 +- src/live_effects/lpe-constructgrid.cpp | 6 +- src/live_effects/lpe-constructgrid.h | 2 +- src/live_effects/lpe-curvestitch.cpp | 10 +- src/live_effects/lpe-curvestitch.h | 2 +- src/live_effects/lpe-ellipse_5pts.cpp | 8 +- src/live_effects/lpe-ellipse_5pts.h | 2 +- src/live_effects/lpe-fill-between-many.cpp | 4 +- src/live_effects/lpe-fill-between-strokes.cpp | 26 +- src/live_effects/lpe-fillet-chamfer.cpp | 20 +- src/live_effects/lpe-fillet-chamfer.h | 8 +- src/live_effects/lpe-gears.cpp | 6 +- src/live_effects/lpe-gears.h | 2 +- src/live_effects/lpe-interpolate.cpp | 2 +- src/live_effects/lpe-interpolate.h | 2 +- src/live_effects/lpe-interpolate_points.h | 2 +- src/live_effects/lpe-jointype.cpp | 2 +- src/live_effects/lpe-jointype.h | 2 +- src/live_effects/lpe-knot.cpp | 18 +- src/live_effects/lpe-knot.h | 10 +- src/live_effects/lpe-lattice2.cpp | 4 +- src/live_effects/lpe-line_segment.cpp | 16 +- src/live_effects/lpe-line_segment.h | 2 +- src/live_effects/lpe-mirror_symmetry.cpp | 10 +- src/live_effects/lpe-mirror_symmetry.h | 2 +- src/live_effects/lpe-offset.cpp | 2 +- src/live_effects/lpe-parallel.cpp | 2 +- src/live_effects/lpe-perp_bisector.cpp | 4 +- src/live_effects/lpe-perspective-envelope.cpp | 4 +- src/live_effects/lpe-powerstroke.cpp | 28 +- src/live_effects/lpe-powerstroke.h | 4 +- src/live_effects/lpe-rough-hatches.cpp | 3 +- src/live_effects/lpe-roughen.cpp | 4 +- src/live_effects/lpe-ruler.cpp | 2 +- src/live_effects/lpe-show_handles.cpp | 19 +- src/live_effects/lpe-show_handles.h | 2 +- src/live_effects/lpe-simplify.cpp | 15 +- src/live_effects/lpe-skeleton.cpp | 6 +- src/live_effects/lpe-skeleton.h | 4 +- src/live_effects/lpe-spiro.cpp | 3 +- src/live_effects/lpe-tangent_to_curve.cpp | 8 +- src/live_effects/lpe-taperstroke.cpp | 11 +- src/live_effects/lpe-test-doEffect-stack.cpp | 6 +- src/live_effects/lpe-test-doEffect-stack.h | 2 +- src/live_effects/lpe-vonkoch.cpp | 22 +- src/live_effects/lpe-vonkoch.h | 2 +- .../parameter/filletchamferpointarray.cpp | 26 +- .../parameter/filletchamferpointarray.h | 6 +- src/live_effects/parameter/originalpatharray.h | 2 +- src/live_effects/parameter/path.cpp | 6 +- src/live_effects/parameter/path.h | 6 +- .../parameter/powerstrokepointarray.cpp | 4 +- src/object-snapper.cpp | 6 +- src/sp-conn-end.cpp | 2 +- src/sp-path.cpp | 3 +- src/sp-polygon.cpp | 3 +- src/splivarot.cpp | 11 +- src/svg/svg-path.cpp | 15 +- src/ui/tool/node.cpp | 11 +- src/ui/tool/node.h | 4 + src/ui/tool/path-manipulator.cpp | 29 +- src/ui/tools/gradient-tool.cpp | 2 +- src/ui/tools/mesh-tool.cpp | 2 +- src/ui/tools/pen-tool.cpp | 19 +- 222 files changed, 13268 insertions(+), 7980 deletions(-) create mode 100644 src/2geom/bezier.cpp create mode 100644 src/2geom/cairo-path-sink.cpp create mode 100644 src/2geom/cairo-path-sink.h delete mode 100644 src/2geom/conjugate_gradient.cpp delete mode 100644 src/2geom/conjugate_gradient.h delete mode 100644 src/2geom/convex-cover.cpp delete mode 100644 src/2geom/convex-cover.h create mode 100644 src/2geom/convex-hull.cpp create mode 100644 src/2geom/convex-hull.h create mode 100644 src/2geom/coord.cpp delete mode 100644 src/2geom/hvlinesegment.h create mode 100644 src/2geom/intersection-graph.cpp create mode 100644 src/2geom/intersection-graph.h create mode 100644 src/2geom/intersection.h delete mode 100644 src/2geom/nearest-point.cpp delete mode 100644 src/2geom/nearest-point.h create mode 100644 src/2geom/nearest-time.cpp create mode 100644 src/2geom/nearest-time.h delete mode 100644 src/2geom/region.cpp delete mode 100644 src/2geom/region.h delete mode 100644 src/2geom/shape.cpp delete mode 100644 src/2geom/shape.h create mode 100644 src/2geom/svg-path-writer.cpp create mode 100644 src/2geom/svg-path-writer.h create mode 100644 src/2geom/viewbox.cpp create mode 100644 src/2geom/viewbox.h delete mode 100644 src/live_effects/lpe-boolops.cpp delete mode 100644 src/live_effects/lpe-boolops.h (limited to 'src') diff --git a/src/2geom/2geom.h b/src/2geom/2geom.h index 000f3423d..813e243b3 100644 --- a/src/2geom/2geom.h +++ b/src/2geom/2geom.h @@ -31,8 +31,8 @@ * the specific language governing rights and limitations. */ -#ifndef SEEN_LIB2GEOM_2GEOM_H -#define SEEN_LIB2GEOM_2GEOM_H +#ifndef LIB2GEOM_SEEN_2GEOM_H +#define LIB2GEOM_SEEN_2GEOM_H #include <2geom/forward.h> @@ -62,7 +62,7 @@ #include <2geom/math-utils.h> #include <2geom/utils.h> -#endif // SEEN_LIB2GEOM_HEADER_H +#endif // LIB2GEOM_SEEN_2GEOM_H /* Local Variables: mode:c++ diff --git a/src/2geom/CMakeLists.txt b/src/2geom/CMakeLists.txt index eeaecaa39..119c7aa71 100644 --- a/src/2geom/CMakeLists.txt +++ b/src/2geom/CMakeLists.txt @@ -2,23 +2,27 @@ set(2geom_SRC affine.cpp basic-intersection.cpp + bezier.cpp bezier-clipping.cpp bezier-curve.cpp bezier-utils.cpp + cairo-path-sink.cpp circle-circle.cpp circle.cpp # conic_section_clipper_impl.cpp # conicsec.cpp conjugate_gradient.cpp - convex-cover.cpp + convex-hull.cpp + coord.cpp crossing.cpp curve.cpp d2-sbasis.cpp ellipse.cpp elliptical-arc.cpp geom.cpp + intersection-graph.cpp line.cpp - nearest-point.cpp + nearest-time.cpp numeric/matrix.cpp path-intersection.cpp path-sink.cpp @@ -48,6 +52,7 @@ set(2geom_SRC toposweep.cpp transforms.cpp utils.cpp + viewbox.cpp # ------- diff --git a/src/2geom/Makefile_insert b/src/2geom/Makefile_insert index e77f413cb..86e64333d 100644 --- a/src/2geom/Makefile_insert +++ b/src/2geom/Makefile_insert @@ -15,10 +15,13 @@ 2geom/bezier-clipping.cpp \ 2geom/bezier-curve.cpp \ 2geom/bezier-curve.h \ + 2geom/bezier.cpp \ 2geom/bezier.h \ 2geom/bezier-to-sbasis.h \ 2geom/bezier-utils.cpp \ 2geom/bezier-utils.h \ + 2geom/cairo-path-sink.cpp \ + 2geom/cairo-path-sink.h \ 2geom/choose.h \ 2geom/circle-circle.cpp \ 2geom/circle.cpp \ @@ -32,10 +35,9 @@ 2geom/conic_section_clipper.h \ 2geom/conic_section_clipper_impl.cpp \ 2geom/conic_section_clipper_impl.h \ - 2geom/conjugate_gradient.cpp \ - 2geom/conjugate_gradient.h \ - 2geom/convex-cover.cpp \ - 2geom/convex-cover.h \ + 2geom/convex-hull.cpp \ + 2geom/convex-hull.h \ + 2geom/coord.cpp \ 2geom/coord.h \ 2geom/crossing.cpp \ 2geom/crossing.h \ @@ -56,6 +58,9 @@ 2geom/geom.cpp \ 2geom/geom.h \ 2geom/hvlinesegment.h \ + 2geom/intersection.h \ + 2geom/intersection-graph.cpp \ + 2geom/intersection-graph.h \ 2geom/interval.h \ 2geom/int-interval.h \ 2geom/int-point.h \ @@ -64,8 +69,8 @@ 2geom/line.cpp \ 2geom/line.h \ 2geom/math-utils.h \ - 2geom/nearest-point.cpp \ - 2geom/nearest-point.h \ + 2geom/nearest-time.cpp \ + 2geom/nearest-time.h \ 2geom/ord.h \ 2geom/path.cpp \ 2geom/path.h \ @@ -88,8 +93,6 @@ 2geom/rect.cpp \ 2geom/rect.h \ 2geom/recursive-bezier-intersection.cpp \ - 2geom/region.cpp \ - 2geom/region.h \ 2geom/sbasis-2d.cpp \ 2geom/sbasis-2d.h \ 2geom/sbasis.cpp \ @@ -104,8 +107,6 @@ 2geom/sbasis-roots.cpp \ 2geom/sbasis-to-bezier.cpp \ 2geom/sbasis-to-bezier.h \ - 2geom/shape.cpp \ - 2geom/shape.h \ 2geom/solve-bezier.cpp \ 2geom/solve-bezier-one-d.cpp \ 2geom/solve-bezier-parametric.cpp \ @@ -114,6 +115,8 @@ 2geom/svg-elliptical-arc.h \ 2geom/svg-path-parser.cpp \ 2geom/svg-path-parser.h \ + 2geom/svg-path-writer.cpp \ + 2geom/svg-path-writer.h \ 2geom/sweep.cpp \ 2geom/sweep.h \ 2geom/toposweep.cpp \ @@ -122,6 +125,8 @@ 2geom/transforms.h \ 2geom/utils.cpp \ 2geom/utils.h \ + 2geom/viewbox.cpp \ + 2geom/viewbox.h \ 2geom/numeric/fitting-model.h \ 2geom/numeric/fitting-tool.h \ 2geom/numeric/linear_system.h \ diff --git a/src/2geom/affine.cpp b/src/2geom/affine.cpp index 738d0fc48..e9ca5748e 100644 --- a/src/2geom/affine.cpp +++ b/src/2geom/affine.cpp @@ -222,6 +222,29 @@ bool Affine::isNonzeroRotation(Coord eps) const { are_near(_c[0]*_c[0] + _c[1]*_c[1], 1.0, eps); } +/** @brief Check whether this matrix represents a non-zero rotation about any point. + * @param eps Numerical tolerance + * @return True iff the matrix is of the form + * \f$\left[\begin{array}{ccc} + a & b & 0 \\ + -b & a & 0 \\ + c & d & 1 \end{array}\right]\f$, \f$a^2 + b^2 = 1\f$ and \f$a \neq 1\f$. */ +bool Affine::isNonzeroNonpureRotation(Coord eps) const { + return !are_near(_c[0], 1.0, eps) && + are_near(_c[0], _c[3], eps) && are_near(_c[1], -_c[2], eps) && + are_near(_c[0]*_c[0] + _c[1]*_c[1], 1.0, eps); +} + +/** @brief For a (possibly non-pure) non-zero-rotation matrix, calculate the rotation center. + * @pre The matrix must be a non-zero-rotation matrix to prevent division by zero, see isNonzeroNonpureRotation(). + * @return The rotation center x, the solution to the equation + * \f$A x = x\f$. */ +Point Affine::rotationCenter() const { + Coord x = (_c[2]*_c[5]+_c[4]-_c[4]*_c[3]) / (1-_c[3]-_c[0]+_c[0]*_c[3]-_c[2]*_c[1]); + Coord y = (_c[1]*x + _c[5]) / (1 - _c[3]); + return Point(x,y); +}; + /** @brief Check whether this matrix represents pure horizontal shearing. * @param eps Numerical tolerance * @return True iff the matrix is of the form @@ -342,8 +365,7 @@ bool Affine::preservesDistances(Coord eps) const /** @brief Check whether this transformation flips objects. * A transformation flips objects if it has a negative scaling component. */ bool Affine::flips() const { - // TODO shouldn't this be det() < 0? - return cross(xAxis(), yAxis()) > 0; + return det() < 0; } /** @brief Check whether this matrix is singular. @@ -356,7 +378,7 @@ bool Affine::isSingular(Coord eps) const { } /** @brief Compute the inverse matrix. - * Inverse is a matrix (denoted \f$A^{-1}) such that \f$AA^{-1} = A^{-1}A = I\f$. + * Inverse is a matrix (denoted \f$A^{-1}\f$) such that \f$AA^{-1} = A^{-1}A = I\f$. * Singular matrices have no inverse (for example a matrix that has two of its columns equal). * For such matrices, the identity matrix will be returned instead. * @param eps Numerical tolerance @@ -369,7 +391,7 @@ Affine Affine::inverse() const { fabs(_c[2]) + fabs(_c[3])); // a random matrix norm (either l1 or linfty if(mx > 0) { Geom::Coord const determ = det(); - if (!rel_error_bound(determ, mx*mx)) { + if (!rel_error_bound(std::sqrt(fabs(determ)), mx)) { Geom::Coord const ideterm = 1.0 / (determ); d._c[0] = _c[3] * ideterm; diff --git a/src/2geom/affine.h b/src/2geom/affine.h index af7b39360..470d5fc40 100644 --- a/src/2geom/affine.h +++ b/src/2geom/affine.h @@ -11,8 +11,8 @@ * This code is in public domain. */ -#ifndef SEEN_LIB2GEOM_AFFINE_H -#define SEEN_LIB2GEOM_AFFINE_H +#ifndef LIB2GEOM_SEEN_AFFINE_H +#define LIB2GEOM_SEEN_AFFINE_H #include #include <2geom/forward.h> @@ -150,6 +150,8 @@ public: bool isNonzeroScale(Coord eps = EPSILON) const; bool isNonzeroUniformScale(Coord eps = EPSILON) const; bool isNonzeroRotation(Coord eps = EPSILON) const; + bool isNonzeroNonpureRotation(Coord eps = EPSILON) const; + Point rotationCenter() const; bool isNonzeroHShear(Coord eps = EPSILON) const; bool isNonzeroVShear(Coord eps = EPSILON) const; diff --git a/src/2geom/angle.h b/src/2geom/angle.h index 1faf63c3f..77ecd5eb4 100644 --- a/src/2geom/angle.h +++ b/src/2geom/angle.h @@ -69,8 +69,8 @@ class Angle public: Angle() : _angle(0) {} //added default constructor because of cython Angle(Coord v) : _angle(v) { _normalize(); } // this can be called implicitly - explicit Angle(Point p) : _angle(atan2(p)) { _normalize(); } - Angle(Point a, Point b) : _angle(angle_between(a, b)) { _normalize(); } + explicit Angle(Point const &p) : _angle(atan2(p)) { _normalize(); } + Angle(Point const &a, Point const &b) : _angle(angle_between(a, b)) { _normalize(); } operator Coord() const { return radians(); } Angle &operator+=(Angle const &o) { _angle += o._angle; diff --git a/src/2geom/basic-intersection.cpp b/src/2geom/basic-intersection.cpp index 379ec597c..54374e282 100644 --- a/src/2geom/basic-intersection.cpp +++ b/src/2geom/basic-intersection.cpp @@ -1,3 +1,38 @@ +/** @file + * @brief Basic intersection routines + *//* + * Authors: + * Nathan Hurst + * Marco Cecchetti + * Jean-François Barraud + * + * Copyright 2008-2009 Authors + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + */ + #include <2geom/basic-intersection.h> #include <2geom/sbasis-to-bezier.h> #include <2geom/exception.h> @@ -33,24 +68,35 @@ namespace Geom { //#else namespace detail{ namespace bezier_clipping { -void portion (std::vector & B, Interval const& I); +void portion(std::vector &B, Interval const &I); +void derivative(std::vector &D, std::vector const &B); }; }; +void find_intersections(std::vector > &xs, + D2 const & A, + D2 const & B, + double precision) +{ + find_intersections_bezier_clipping(xs, bezier_points(A), bezier_points(B), precision); +} + void find_intersections(std::vector > &xs, D2 const & A, - D2 const & B) { + D2 const & B, + double precision) +{ vector BezA, BezB; sbasis_to_bezier(BezA, A); sbasis_to_bezier(BezB, B); - - xs.clear(); - find_intersections_bezier_clipping(xs, BezA, BezB); + find_intersections_bezier_clipping(xs, BezA, BezB, precision); } + void find_intersections(std::vector< std::pair > & xs, - std::vector const& A, - std::vector const& B, - double precision){ + std::vector const& A, + std::vector const& B, + double precision) +{ find_intersections_bezier_clipping(xs, A, B, precision); } @@ -61,6 +107,7 @@ void find_intersections(std::vector< std::pair > & xs, * Temporary storage is minimized by using part of the storage for the result * to hold an intermediate value until it is no longer needed. */ +// TODO replace with Bezier method void split(vector const &p, double t, vector &left, vector &right) { const unsigned sz = p.size(); @@ -88,44 +135,48 @@ void split(vector const &p, double t, } -void -find_self_intersections(std::vector > &xs, - D2 const & A) { - vector dr = roots(derivative(A[X])); + +void find_self_intersections(std::vector > &xs, + D2 const &A, + double precision) +{ + std::vector dr = derivative(A[X]).roots(); { - vector dyr = roots(derivative(A[Y])); + std::vector dyr = derivative(A[Y]).roots(); dr.insert(dr.begin(), dyr.begin(), dyr.end()); } dr.push_back(0); dr.push_back(1); // We want to be sure that we have no empty segments - sort(dr.begin(), dr.end()); - vector::iterator new_end = unique(dr.begin(), dr.end()); + std::sort(dr.begin(), dr.end()); + std::vector::iterator new_end = std::unique(dr.begin(), dr.end()); dr.resize( new_end - dr.begin() ); - vector > pieces; - { - vector in, l, r; - sbasis_to_bezier(in, A); + std::vector< D2 > pieces; + for (unsigned i = 0; i < dr.size() - 1; ++i) { + pieces.push_back(portion(A, dr[i], dr[i+1])); + } + /*{ + vector l, r, in = A; for(unsigned i = 0; i < dr.size()-1; i++) { split(in, (dr[i+1]-dr[i]) / (1 - dr[i]), l, r); pieces.push_back(l); in = r; } - } + }*/ for(unsigned i = 0; i < dr.size()-1; i++) { for(unsigned j = i+1; j < dr.size()-1; j++) { std::vector > section; - find_intersections( section, pieces[i], pieces[j]); + find_intersections(section, pieces[i], pieces[j], precision); for(unsigned k = 0; k < section.size(); k++) { double l = section[k].first; double r = section[k].second; // XXX: This condition will prune out false positives, but it might create some false negatives. Todo: Confirm it is correct. if(j == i+1) //if((l == 1) && (r == 0)) - if( ( l > 1-1e-4 ) && (r < 1e-4) )//FIXME: what precision should be used here??? + if( ( l > precision ) && (r < precision) )//FIXME: what precision should be used here??? continue; xs.push_back(std::make_pair((1-l)*dr[i] + l*dr[i+1], (1-r)*dr[j] + r*dr[j+1])); @@ -138,6 +189,46 @@ find_self_intersections(std::vector > &xs, //unique(xs.begin(), xs.end()); } +void find_self_intersections(std::vector > &xs, + D2 const &A, + double precision) +{ + D2 in; + sbasis_to_bezier(in, A); + find_self_intersections(xs, in, precision); +} + + +void subdivide(D2 const &a, + D2 const &b, + std::vector< std::pair > const &xs, + std::vector< D2 > &av, + std::vector< D2 > &bv) +{ + if (xs.empty()) { + av.push_back(a); + bv.push_back(b); + return; + } + + std::pair prev = std::make_pair(0., 0.); + for (unsigned i = 0; i < xs.size(); ++i) { + av.push_back(portion(a, prev.first, xs[i].first)); + bv.push_back(portion(b, prev.second, xs[i].second)); + av.back()[X].at0() = bv.back()[X].at0() = lerp(0.5, av.back()[X].at0(), bv.back()[X].at0()); + av.back()[X].at1() = bv.back()[X].at1() = lerp(0.5, av.back()[X].at1(), bv.back()[X].at1()); + av.back()[Y].at0() = bv.back()[Y].at0() = lerp(0.5, av.back()[Y].at0(), bv.back()[Y].at0()); + av.back()[Y].at1() = bv.back()[Y].at1() = lerp(0.5, av.back()[Y].at1(), bv.back()[Y].at1()); + prev = xs[i]; + } + av.push_back(portion(a, prev.first, 1)); + bv.push_back(portion(b, prev.second, 1)); + av.back()[X].at0() = bv.back()[X].at0() = lerp(0.5, av.back()[X].at0(), bv.back()[X].at0()); + av.back()[X].at1() = bv.back()[X].at1() = lerp(0.5, av.back()[X].at1(), bv.back()[X].at1()); + av.back()[Y].at0() = bv.back()[Y].at0() = lerp(0.5, av.back()[Y].at0(), bv.back()[Y].at0()); + av.back()[Y].at1() = bv.back()[Y].at1() = lerp(0.5, av.back()[Y].at1(), bv.back()[Y].at1()); +} + #ifdef HAVE_GSL #include @@ -304,38 +395,6 @@ void polish_intersections(std::vector > &xs, B, xs[i].second); } - - /** - * Compute the Hausdorf distance from A to B only. - */ - - -#if 0 -/** Compute the value of a bezier - Todo: find a good palce for this. - */ -// suggested by Sederberg. -Point OldBezier::operator()(double t) const { - int n = p.size()-1; - double u, bc, tn, tmp; - int i; - Point r; - for(int dim = 0; dim < 2; dim++) { - u = 1.0 - t; - bc = 1; - tn = 1; - tmp = p[0][dim]*u; - for(i=1; i& A, D2 const& B, double h_dist = 0, h_a_t = 0, h_b_t = 0; double dist = 0; Point Ax = A.at0(); - double t = Geom::nearest_point(Ax, B); + double t = Geom::nearest_time(Ax, B); dist = Geom::distance(Ax, B(t)); if (dist > h_dist) { h_a_t = 0; @@ -358,7 +417,7 @@ double hausdorfl(D2& A, D2 const& B, h_dist = dist; } Ax = A.at1(); - t = Geom::nearest_point(Ax, B); + t = Geom::nearest_time(Ax, B); dist = Geom::distance(Ax, B(t)); if (dist > h_dist) { h_a_t = 1; @@ -370,7 +429,7 @@ double hausdorfl(D2& A, D2 const& B, Point At = A(xs[i].first); Point Bu = B(xs[i].second); double distAtBu = Geom::distance(At, Bu); - t = Geom::nearest_point(At, B); + t = Geom::nearest_time(At, B); dist = Geom::distance(At, B(t)); //FIXME: we might miss it due to floating point precision... if (dist >= distAtBu-.1 && distAtBu > h_dist) { @@ -396,7 +455,7 @@ double hausdorf(D2& A, D2 const& B, double dist = 0; Point Bx = B.at0(); - double t = Geom::nearest_point(Bx, A); + double t = Geom::nearest_time(Bx, A); dist = Geom::distance(Bx, A(t)); if (dist > h_dist) { if(a_t) *a_t = t; @@ -404,7 +463,7 @@ double hausdorf(D2& A, D2 const& B, h_dist = dist; } Bx = B.at1(); - t = Geom::nearest_point(Bx, A); + t = Geom::nearest_time(Bx, A); dist = Geom::distance(Bx, A(t)); if (dist > h_dist) { if(a_t) *a_t = t; diff --git a/src/2geom/basic-intersection.h b/src/2geom/basic-intersection.h index 5a813ae99..0b0bf8930 100644 --- a/src/2geom/basic-intersection.h +++ b/src/2geom/basic-intersection.h @@ -1,11 +1,12 @@ -/** - * \file - * \brief Basic intersection routines - * +/** @file + * @brief Basic intersection routines + *//* * Authors: - * ? + * Nathan Hurst + * Marco Cecchetti + * Jean-François Barraud * - * Copyright ?-? authors + * Copyright 2008-2009 Authors * * This library is free software; you can redistribute it and/or * modify it either under the terms of the GNU Lesser General Public @@ -32,10 +33,11 @@ * */ -#ifndef SEEN_GEOM_BASICINTERSECTION_H -#define SEEN_GEOM_BASICINTERSECTION_H +#ifndef LIB2GEOM_SEEN_BASIC_INTERSECTION_H +#define LIB2GEOM_SEEN_BASIC_INTERSECTION_H #include <2geom/point.h> +#include <2geom/bezier.h> #include <2geom/sbasis.h> #include <2geom/d2.h> @@ -47,41 +49,29 @@ namespace Geom { -//why not allowing precision to be set here? -void find_intersections(std::vector >& xs, - D2 const & A, - D2 const & B); +void find_intersections(std::vector > &xs, + D2 const &A, + D2 const &B, + double precision = EPSILON); + +void find_intersections(std::vector > &xs, + D2 const &A, + D2 const &B, + double precision = EPSILON); + +void find_intersections(std::vector< std::pair > &xs, + std::vector const &A, + std::vector const &B, + double precision = EPSILON); + +void find_self_intersections(std::vector > &xs, + D2 const &A, + double precision = EPSILON); + +void find_self_intersections(std::vector > &xs, + D2 const &A, + double precision = EPSILON); -void find_intersections(std::vector< std::pair > & xs, - std::vector const& A, - std::vector const& B, - double precision = 1e-5); - -//why not allowing precision to be set here? -void find_self_intersections(std::vector >& xs, - D2 const & A); - - -//--not implemented -//void find_self_intersections(std::vector >& xs, -// std::vector const & A); - - -//TODO: this should be moved to .cpp, shouldn't it? -// #ifdef USE_RECURSIVE_INTERSECTOR -// /* -// * find_intersection -// * -// * input: A, B - set of control points of two Bezier curve -// * input: precision - required precision of computation -// * output: xs - set of pairs of parameter values -// * at which crossing happens -// */ -// void find_intersections_bezier_recursive (std::vector< std::pair > & xs, -// std::vector const& A, -// std::vector const& B, -// double precision = 1e-5); -// #else /* * find_intersection * @@ -96,10 +86,14 @@ void find_self_intersections(std::vector >& xs, void find_intersections_bezier_clipping (std::vector< std::pair > & xs, std::vector const& A, std::vector const& B, - double precision = 1e-5); + double precision = EPSILON); //#endif - +void subdivide(D2 const &a, + D2 const &b, + std::vector< std::pair > const &xs, + std::vector< D2 > &av, + std::vector< D2 > &bv); /* * find_collinear_normal @@ -115,7 +109,7 @@ void find_intersections_bezier_clipping (std::vector< std::pair void find_collinear_normal (std::vector< std::pair >& xs, std::vector const& A, std::vector const& B, - double precision = 1e-5); + double precision = EPSILON); void polish_intersections(std::vector > &xs, D2 const &A, @@ -125,19 +119,19 @@ void polish_intersections(std::vector > &xs, /** * Compute the Hausdorf distance from A to B only. */ -double hausdorfl(D2& A, D2 const& B, +double hausdorfl(D2& A, D2 const &B, double m_precision, - double *a_t=0, double* b_t=0); + double *a_t=NULL, double *b_t=NULL); /** * Compute the symmetric Hausdorf distance. */ -double hausdorf(D2& A, D2 const& B, +double hausdorf(D2 &A, D2 const &B, double m_precision, - double *a_t=0, double* b_t=0); + double *a_t=NULL, double *b_t=NULL); } -#endif // !SEEN_GEOM_BASICINTERSECTION_H +#endif // !LIB2GEOM_SEEN_BASIC_INTERSECTION_H /* Local Variables: diff --git a/src/2geom/bezier-clipping.cpp b/src/2geom/bezier-clipping.cpp index 9a055204f..be8dd5a5f 100644 --- a/src/2geom/bezier-clipping.cpp +++ b/src/2geom/bezier-clipping.cpp @@ -39,8 +39,9 @@ #include <2geom/point.h> #include <2geom/interval.h> #include <2geom/bezier.h> -//#include <2geom/convex-cover.h> #include <2geom/numeric/matrix.h> +#include <2geom/convex-hull.h> +#include <2geom/line.h> #include #include @@ -48,7 +49,7 @@ #include //#include - +using std::swap; #define VERBOSE 0 @@ -63,7 +64,6 @@ namespace detail { namespace bezier_clipping { // for debugging // -inline void print(std::vector const& cp, const char* msg = "") { std::cerr << msg << std::endl; @@ -72,7 +72,6 @@ void print(std::vector const& cp, const char* msg = "") } template< class charT > -inline std::basic_ostream & operator<< (std::basic_ostream & os, const Interval & I) { @@ -80,7 +79,6 @@ operator<< (std::basic_ostream & os, const Interval & I) return os; } -inline double angle (std::vector const& A) { size_t n = A.size() -1; @@ -88,7 +86,6 @@ double angle (std::vector const& A) return (180 * a / M_PI); } -inline size_t get_precision(Interval const& I) { double d = I.extent(); @@ -103,7 +100,6 @@ size_t get_precision(Interval const& I) return n; } -inline void range_assertion(int k, int m, int n, const char* msg) { if ( k < m || k > n) @@ -117,93 +113,12 @@ void range_assertion(int k, int m, int n, const char* msg) } -//////////////////////////////////////////////////////////////////////////////// -// convex hull - -/* - * return true in case the oriented polyline p0, p1, p2 is a right turn - */ -inline -bool is_a_right_turn (Point const& p0, Point const& p1, Point const& p2) -{ - if (p1 == p2) return false; - Point q1 = p1 - p0; - Point q2 = p2 - p0; - if (q1 == -q2) return false; - return (cross (q1, q2) < 0); -} - -/* - * return true if p < q wrt the lexicographyc order induced by the coordinates - */ -struct lex_less -{ - bool operator() (Point const& p, Point const& q) - { - return ((p[X] < q[X]) || (p[X] == q[X] && p[Y] < q[Y])); - } -}; - -/* - * return true if p > q wrt the lexicographyc order induced by the coordinates - */ -struct lex_greater -{ - bool operator() (Point const& p, Point const& q) - { - return ((p[X] > q[X]) || (p[X] == q[X] && p[Y] > q[Y])); - } -}; - -/* - * Compute the convex hull of a set of points. - * The implementation is based on the Andrew's scan algorithm - * note: in the Bezier clipping for collinear normals it seems - * to be more stable wrt the Graham's scan algorithm and in general - * a bit quikier - */ -void convex_hull (std::vector & P) -{ - size_t n = P.size(); - if (n < 2) return; - std::sort(P.begin(), P.end(), lex_less()); - if (n < 4) return; - // upper hull - size_t u = 2; - for (size_t i = 2; i < n; ++i) - { - while (u > 1 && !is_a_right_turn(P[u-2], P[u-1], P[i])) - { - --u; - } - std::swap(P[u], P[i]); - ++u; - } - std::sort(P.begin() + u, P.end(), lex_greater()); - std::rotate(P.begin(), P.begin() + 1, P.end()); - // lower hull - size_t l = u; - size_t k = u - 1; - for (size_t i = l; i < n; ++i) - { - while (l > k && !is_a_right_turn(P[l-2], P[l-1], P[i])) - { - --l; - } - std::swap(P[l], P[i]); - ++l; - } - P.resize(l); -} - - //////////////////////////////////////////////////////////////////////////////// // numerical routines /* * Compute the binomial coefficient (n, k) */ -inline double binomial(unsigned int n, unsigned int k) { return choose(n, k); @@ -212,7 +127,6 @@ double binomial(unsigned int n, unsigned int k) /* * Compute the determinant of the 2x2 matrix with column the point P1, P2 */ -inline double det(Point const& P1, Point const& P2) { return P1[X]*P2[Y] - P1[Y]*P2[X]; @@ -222,7 +136,6 @@ double det(Point const& P1, Point const& P2) * Solve the linear system [P1,P2] * P = Q * in case there isn't exactly one solution the routine returns false */ -inline bool solve(Point & P, Point const& P1, Point const& P2, Point const& Q) { double d = det(P1, P2); @@ -239,27 +152,11 @@ bool solve(Point & P, Point const& P1, Point const& P2, Point const& Q) /* * Map the sub-interval I in [0,1] into the interval J and assign it to J */ -inline void map_to(Interval & J, Interval const& I) { - double length = J.extent(); - J[1] = I.max() * length + J[0]; - J[0] = I.min() * length + J[0]; + J.setEnds(J.valueAt(I.min()), J.valueAt(I.max())); } -/* - * The interval [1,0] is used to represent the empty interval, this routine - * is just an helper function for creating such an interval - */ -inline -Interval make_empty_interval() -{ - Interval I(0); - I[0] = 1; - return I; -} - - //////////////////////////////////////////////////////////////////////////////// // bezier curve routines @@ -267,8 +164,8 @@ Interval make_empty_interval() * Return true if all the Bezier curve control points are near, * false otherwise */ -inline -bool is_constant(std::vector const& A, double precision = EPSILON) +// Bezier.isConstant(precision) +bool is_constant(std::vector const& A, double precision) { for (unsigned int i = 1; i < A.size(); ++i) { @@ -281,7 +178,7 @@ bool is_constant(std::vector const& A, double precision = EPSILON) /* * Compute the hodograph of the bezier curve B and return it in D */ -inline +// derivative(Bezier) void derivative(std::vector & D, std::vector const& B) { D.clear(); @@ -304,7 +201,7 @@ void derivative(std::vector & D, std::vector const& B) * Compute the hodograph of the Bezier curve B rotated of 90 degree * and return it in D; we have N(t) orthogonal to B(t) for any t */ -inline +// rot90(derivative(Bezier)) void normal(std::vector & N, std::vector const& B) { derivative(N,B); @@ -317,7 +214,7 @@ void normal(std::vector & N, std::vector const& B) /* * Compute the portion of the Bezier curve "B" wrt the interval [0,t] */ -inline +// portion(Bezier, 0, t) void left_portion(Coord t, std::vector & B) { size_t n = B.size(); @@ -333,7 +230,7 @@ void left_portion(Coord t, std::vector & B) /* * Compute the portion of the Bezier curve "B" wrt the interval [t,1] */ -inline +// portion(Bezier, t, 1) void right_portion(Coord t, std::vector & B) { size_t n = B.size(); @@ -349,7 +246,7 @@ void right_portion(Coord t, std::vector & B) /* * Compute the portion of the Bezier curve "B" wrt the interval "I" */ -inline +// portion(Bezier, I) void portion (std::vector & B , Interval const& I) { if (I.min() == 0) @@ -371,9 +268,9 @@ void portion (std::vector & B , Interval const& I) struct intersection_point_tag; struct collinear_normal_tag; template -void clip(Interval & dom, - std::vector const& A, - std::vector const& B); +OptInterval clip(std::vector const& A, + std::vector const& B, + double precision); template void iterate(std::vector& domsA, std::vector& domsB, @@ -392,14 +289,14 @@ void iterate(std::vector& domsA, * the line is returned in the output parameter "l" in the form of a 3 element * vector : l[0] * x + l[1] * y + l[2] == 0; the line is normalized. */ -inline +// Line(c[i], c[j]) void orientation_line (std::vector & l, std::vector const& c, size_t i, size_t j) { l[0] = c[j][Y] - c[i][Y]; l[1] = c[i][X] - c[j][X]; - l[2] = cross(c[i], c[j]); + l[2] = cross(c[j], c[i]); double length = std::sqrt(l[0] * l[0] + l[1] * l[1]); assert (length != 0); l[0] /= length; @@ -411,22 +308,20 @@ void orientation_line (std::vector & l, * Pick up an orientation line for the Bezier curve "c" and return it in * the output parameter "l" */ -inline -void pick_orientation_line (std::vector & l, - std::vector const& c) +Line pick_orientation_line (std::vector const &c, double precision) { size_t i = c.size(); - while (--i > 0 && are_near(c[0], c[i])) + while (--i > 0 && are_near(c[0], c[i], precision)) {} - if (i == 0) - { - // this should never happen because when a new curve portion is created - // we check that it is not constant; - // however this requires that the precision used in the is_constant - // routine has to be the same used here in the are_near test - assert(i != 0); - } - orientation_line(l, c, 0, i); + + // this should never happen because when a new curve portion is created + // we check that it is not constant; + // however this requires that the precision used in the is_constant + // routine has to be the same used here in the are_near test + assert(i != 0); + + Line line(c[0], c[i]); + return line; //std::cerr << "i = " << i << std::endl; } @@ -436,29 +331,25 @@ void pick_orientation_line (std::vector & l, * the line is returned in the output parameter "l" in the form of a 3 element * vector : l[0] * x + l[1] * y + l[2] == 0; the line is normalized. */ -inline -void orthogonal_orientation_line (std::vector & l, - std::vector const& c, - Point const& p) +Line orthogonal_orientation_line (std::vector const &c, + Point const &p, + double precision) { - if (is_constant(c)) - { - // this should never happen - assert(!is_constant(c)); - } - std::vector ol(2); - ol[0] = p; - ol[1] = (c.back() - c.front()).cw() + p; - orientation_line(l, ol, 0, 1); + // this should never happen + assert(!is_constant(c, precision)); + + Line line(p, (c.back() - c.front()).cw() + p); + return line; } /* * Compute the signed distance of the point "P" from the normalized line l */ -inline -double distance (Point const& P, std::vector const& l) +double signed_distance(Point const &p, Line const &l) { - return l[X] * P[X] + l[Y] * P[Y] + l[2]; + Coord a, b, c; + l.coefficients(a, b, c); + return a * p[X] + b * p[Y] + c; } /* @@ -466,26 +357,20 @@ double distance (Point const& P, std::vector const& l) * curve "c" from the normalized orientation line "l". * This bounds are returned through the output Interval parameter"bound". */ -inline -void fat_line_bounds (Interval& bound, - std::vector const& c, - std::vector const& l) +Interval fat_line_bounds (std::vector const &c, + Line const &l) { - bound[0] = 0; - bound[1] = 0; - for (size_t i = 0; i < c.size(); ++i) - { - const double d = distance(c[i], l); - if (bound[0] > d) bound[0] = d; - if (bound[1] < d) bound[1] = d; + Interval bound(0, 0); + for (size_t i = 0; i < c.size(); ++i) { + bound.expandTo(signed_distance(c[i], l)); } + return bound; } /* * return the x component of the intersection point between the line * passing through points p1, p2 and the line Y = "y" */ -inline double intersect (Point const& p1, Point const& p2, double y) { // we are sure that p2[Y] != p1[Y] because this routine is called @@ -500,23 +385,22 @@ double intersect (Point const& p1, Point const& p2, double y) * line "l" and the interval range "bound", the new parameter interval for * the clipped curve is returned through the output parameter "dom" */ -void clip_interval (Interval& dom, - std::vector const& B, - std::vector const& l, - Interval const& bound) +OptInterval clip_interval (std::vector const& B, + Line const &l, + Interval const &bound) { double n = B.size() - 1; // number of sub-intervals std::vector D; // distance curve control points D.reserve (B.size()); for (size_t i = 0; i < B.size(); ++i) { - const double d = distance (B[i], l); + const double d = signed_distance(B[i], l); D.push_back (Point(i/n, d)); } //print(D); - convex_hull(D); - std::vector & p = D; + ConvexHull p; + p.swap(D); //print(p); bool plower, phigher; @@ -589,8 +473,11 @@ void clip_interval (Interval& dom, // << " : tmin = " << tmin << ", tmax = " << tmax << std::endl; } - dom[0] = tmin; - dom[1] = tmax; + if (tmin == 1 && tmax == 0) { + return OptInterval(); + } else { + return Interval(tmin, tmax); + } } /* @@ -599,24 +486,20 @@ void clip_interval (Interval& dom, * is returned through the output parameter "dom" */ template <> -inline -void clip (Interval & dom, - std::vector const& A, - std::vector const& B) +OptInterval clip (std::vector const& A, + std::vector const& B, + double precision) { - std::vector bl(3); - Interval bound; - if (is_constant(A)) - { + Line bl; + if (is_constant(A, precision)) { Point M = middle_point(A.front(), A.back()); - orthogonal_orientation_line(bl, B, M); + bl = orthogonal_orientation_line(B, M, precision); + } else { + bl = pick_orientation_line(A, precision); } - else - { - pick_orientation_line(bl, A); - } - fat_line_bounds(bound, A, bl); - clip_interval(dom, B, bl, bound); + bl.normalize(); + Interval bound = fat_line_bounds(A, bl); + return clip_interval(B, bl, bound); } @@ -627,7 +510,6 @@ void clip (Interval & dom, * Compute a closed focus for the Bezier curve B and return it in F * A focus is any curve through which all lines perpendicular to B(t) pass. */ -inline void make_focus (std::vector & F, std::vector const& B) { assert (B.size() > 2); @@ -743,9 +625,8 @@ void distance_control_points (std::vector & D, * Clip the Bezier curve "B" wrt the focus "F"; the new parameter interval for * the clipped curve is returned through the output parameter "dom" */ -void clip_interval (Interval& dom, - std::vector const& B, - std::vector const& F) +OptInterval clip_interval (std::vector const& B, + std::vector const& F) { std::vector D; // distance curve control points distance_control_points(D, B, F); @@ -753,8 +634,8 @@ void clip_interval (Interval& dom, // ConvexHull chD(D); // std::vector& p = chD.boundary; // convex hull vertices - convex_hull(D); - std::vector & p = D; + ConvexHull p; + p.swap(D); //print(p, "CH(D)"); bool plower, clower; @@ -803,8 +684,11 @@ void clip_interval (Interval& dom, // std::cerr << "0 : lower " << p[0] // << " : tmin = " << tmin << ", tmax = " << tmax << std::endl; } - dom[0] = tmin; - dom[1] = tmax; + if (tmin == 1 && tmax == 0) { + return OptInterval(); + } else { + return Interval(tmin, tmax); + } } /* @@ -813,14 +697,13 @@ void clip_interval (Interval& dom, * for the clipped curve is returned through the output parameter "dom" */ template <> -inline -void clip (Interval & dom, - std::vector const& A, - std::vector const& B) +OptInterval clip (std::vector const& A, + std::vector const& B, + double /*precision*/) { std::vector F; make_focus(F, A); - clip_interval(dom, B, F); + return clip_interval(B, F); } @@ -828,9 +711,9 @@ void clip (Interval & dom, const double MAX_PRECISION = 1e-8; const double MIN_CLIPPED_SIZE_THRESHOLD = 0.8; const Interval UNIT_INTERVAL(0,1); -const Interval EMPTY_INTERVAL = make_empty_interval(); +const OptInterval EMPTY_INTERVAL; const Interval H1_INTERVAL(0, 0.5); -const Interval H2_INTERVAL(0.5 + MAX_PRECISION, 1.0); +const Interval H2_INTERVAL(nextafter(0.5, 1.0), 1.0); /* * iterate @@ -884,9 +767,9 @@ void iterate (std::vector& domsA, Interval* dom1 = &dompA; Interval* dom2 = &dompB; - Interval dom; + OptInterval dom; - if ( is_constant(A) && is_constant(B) ){ + if ( is_constant(A, precision) && is_constant(B, precision) ){ Point M1 = middle_point(C1->front(), C1->back()); Point M2 = middle_point(C2->front(), C2->back()); if (are_near(M1,M2)){ @@ -903,10 +786,9 @@ void iterate (std::vector& domsA, #if VERBOSE std::cerr << "iter: " << iter << std::endl; #endif - clip(dom, *C1, *C2); + dom = clip(*C1, *C2, precision); - // [1,0] is utilized to represent an empty interval - if (dom == EMPTY_INTERVAL) + if (dom.isEmpty()) { #if VERBOSE std::cerr << "dom: empty" << std::endl; @@ -917,15 +799,12 @@ void iterate (std::vector& domsA, std::cerr << "dom : " << dom << std::endl; #endif // all other cases where dom[0] > dom[1] are invalid - if (dom.min() > dom.max()) - { - assert(dom.min() < dom.max()); - } + assert(dom->min() <= dom->max()); - map_to(*dom2, dom); + map_to(*dom2, *dom); - portion(*C2, dom); - if (is_constant(*C2) && is_constant(*C1)) + portion(*C2, *dom); + if (is_constant(*C2, precision) && is_constant(*C1, precision)) { Point M1 = middle_point(C1->front(), C1->back()); Point M2 = middle_point(C2->front(), C2->back()); @@ -945,10 +824,10 @@ void iterate (std::vector& domsA, // if we have clipped less than 20% than we need to subdive the curve // with the largest domain into two sub-curves - if ( dom.extent() > MIN_CLIPPED_SIZE_THRESHOLD) + if (dom->extent() > MIN_CLIPPED_SIZE_THRESHOLD) { #if VERBOSE - std::cerr << "clipped less than 20% : " << dom.extent() << std::endl; + std::cerr << "clipped less than 20% : " << dom->extent() << std::endl; std::cerr << "angle(pA) : " << angle(pA) << std::endl; std::cerr << "angle(pB) : " << angle(pB) << std::endl; #endif @@ -983,8 +862,8 @@ void iterate (std::vector& domsA, return; } - std::swap(C1, C2); - std::swap(dom1, dom2); + swap(C1, C2); + swap(dom1, dom2); #if VERBOSE std::cerr << "dom(pA) : " << dompA << std::endl; std::cerr << "dom(pB) : " << dompB << std::endl; @@ -1047,7 +926,7 @@ void iterate (std::vector& domsA, Interval* dom1 = &dompA; Interval* dom2 = &dompB; - Interval dom; + OptInterval dom; size_t iter = 0; while (++iter < 100 @@ -1056,11 +935,9 @@ void iterate (std::vector& domsA, #if VERBOSE std::cerr << "iter: " << iter << std::endl; #endif - clip(dom, *C1, *C2); + dom = clip(*C1, *C2, precision); - // [1,0] is utilized to represent an empty interval - if (dom == EMPTY_INTERVAL) - { + if (dom.isEmpty()) { #if VERBOSE std::cerr << "dom: empty" << std::endl; #endif @@ -1069,13 +946,9 @@ void iterate (std::vector& domsA, #if VERBOSE std::cerr << "dom : " << dom << std::endl; #endif - // all other cases where dom[0] > dom[1] are invalid - if (dom.min() > dom.max()) - { - assert(dom.min() < dom.max()); - } + assert(dom->min() <= dom->max()); - map_to(*dom2, dom); + map_to(*dom2, *dom); // it's better to stop before losing computational precision if (iter > 1 && (dom2->extent() <= MAX_PRECISION)) @@ -1086,8 +959,8 @@ void iterate (std::vector& domsA, break; } - portion(*C2, dom); - if (iter > 1 && is_constant(*C2)) + portion(*C2, *dom); + if (iter > 1 && is_constant(*C2, precision)) { #if VERBOSE std::cerr << "new curve portion pC1 is constant" << std::endl; @@ -1098,10 +971,10 @@ void iterate (std::vector& domsA, // if we have clipped less than 20% than we need to subdive the curve // with the largest domain into two sub-curves - if ( dom.extent() > MIN_CLIPPED_SIZE_THRESHOLD) + if ( dom->extent() > MIN_CLIPPED_SIZE_THRESHOLD) { #if VERBOSE - std::cerr << "clipped less than 20% : " << dom.extent() << std::endl; + std::cerr << "clipped less than 20% : " << dom->extent() << std::endl; std::cerr << "angle(pA) : " << angle(pA) << std::endl; std::cerr << "angle(pB) : " << angle(pB) << std::endl; #endif @@ -1115,7 +988,7 @@ void iterate (std::vector& domsA, } pC1 = pC2 = pA; portion(pC1, H1_INTERVAL); - if (false && is_constant(pC1)) + if (false && is_constant(pC1, precision)) { #if VERBOSE std::cerr << "new curve portion pC1 is constant" << std::endl; @@ -1123,7 +996,7 @@ void iterate (std::vector& domsA, break; } portion(pC2, H2_INTERVAL); - if (is_constant(pC2)) + if (is_constant(pC2, precision)) { #if VERBOSE std::cerr << "new curve portion pC2 is constant" << std::endl; @@ -1146,7 +1019,7 @@ void iterate (std::vector& domsA, } pC1 = pC2 = pB; portion(pC1, H1_INTERVAL); - if (is_constant(pC1)) + if (is_constant(pC1, precision)) { #if VERBOSE std::cerr << "new curve portion pC1 is constant" << std::endl; @@ -1154,7 +1027,7 @@ void iterate (std::vector& domsA, break; } portion(pC2, H2_INTERVAL); - if (is_constant(pC2)) + if (is_constant(pC2, precision)) { #if VERBOSE std::cerr << "new curve portion pC2 is constant" << std::endl; @@ -1172,8 +1045,8 @@ void iterate (std::vector& domsA, return; } - std::swap(C1, C2); - std::swap(dom1, dom2); + swap(C1, C2); + swap(dom1, dom2); #if VERBOSE std::cerr << "dom(pA) : " << dompA << std::endl; std::cerr << "dom(pB) : " << dompB << std::endl; diff --git a/src/2geom/bezier-curve.cpp b/src/2geom/bezier-curve.cpp index 6dfb0f0b3..b81041f29 100644 --- a/src/2geom/bezier-curve.cpp +++ b/src/2geom/bezier-curve.cpp @@ -32,6 +32,9 @@ */ #include <2geom/bezier-curve.h> +#include <2geom/path-sink.h> +#include <2geom/basic-intersection.h> +#include <2geom/nearest-time.h> namespace Geom { @@ -97,7 +100,7 @@ namespace Geom * @class BezierCurveN * @brief Bezier curve with compile-time specified order. * - * @tparam degree unsigned value indicating the order of the bezier curve + * @tparam degree unsigned value indicating the order of the Bezier curve * * @relates BezierCurve * @ingroup Curves @@ -105,12 +108,10 @@ namespace Geom BezierCurve::BezierCurve(std::vector const &pts) + : inner(pts) { - inner = D2(Bezier::Order(pts.size() - 1), Bezier::Order(pts.size() - 1)); - for (unsigned d = 0; d < 2; ++d) { - for (unsigned i = 0; i < pts.size(); i++) { - inner[d][i] = pts[i][d]; - } + if (pts.size() < 2) { + THROW_RANGEERROR("Bezier curve must have at least 2 control points"); } } @@ -124,16 +125,87 @@ Coord BezierCurve::length(Coord tolerance) const return distance(initialPoint(), finalPoint()); case 2: { - std::vector pts = points(); + std::vector pts = controlPoints(); return bezier_length(pts[0], pts[1], pts[2], tolerance); } case 3: { - std::vector pts = points(); + std::vector pts = controlPoints(); return bezier_length(pts[0], pts[1], pts[2], pts[3], tolerance); } default: - return bezier_length(points(), tolerance); + return bezier_length(controlPoints(), tolerance); + } +} + +std::vector +BezierCurve::intersect(Curve const &other, Coord eps) const +{ + std::vector result; + + // optimization for the common case of no intersections + if (!boundsFast().intersects(other.boundsFast())) return result; + + BezierCurve const *bez = dynamic_cast(&other); + if (bez) { + std::vector > xs; + find_intersections(xs, inner, bez->inner, eps); + for (unsigned i = 0; i < xs.size(); ++i) { + CurveIntersection x(*this, other, xs[i].first, xs[i].second); + result.push_back(x); + } + } else { + THROW_NOTIMPLEMENTED(); + } + + return result; +} + +bool BezierCurve::operator==(Curve const &c) const +{ + if (this == &c) return true; + + BezierCurve const *other = dynamic_cast(&c); + if (!other) return false; + if (size() != other->size()) return false; + + for (unsigned i = 0; i < size(); ++i) { + if (controlPoint(i) != other->controlPoint(i)) return false; + } + return true; +} + +Coord BezierCurve::nearestTime(Point const &p, Coord from, Coord to) const +{ + return nearest_time(p, inner, from, to); +} + +void BezierCurve::feed(PathSink &sink, bool moveto_initial) const +{ + if (size() > 4) { + Curve::feed(sink, moveto_initial); + return; + } + + Point ip = controlPoint(0); + if (moveto_initial) { + sink.moveTo(ip); + } + switch (size()) { + case 2: + sink.lineTo(controlPoint(1)); + break; + case 3: + sink.quadTo(controlPoint(1), controlPoint(2)); + break; + case 4: + sink.curveTo(controlPoint(1), controlPoint(2), controlPoint(3)); + break; + default: + // TODO: add a path sink method that accepts a vector of control points + // and converts to cubic spline by default + assert(false); + break; } } @@ -164,9 +236,11 @@ Curve *BezierCurveN<1>::derivative() const { } template<> -Coord BezierCurveN<1>::nearestPoint(Point const& p, Coord from, Coord to) const +Coord BezierCurveN<1>::nearestTime(Point const& p, Coord from, Coord to) const { - if ( from > to ) std::swap(from, to); + using std::swap; + + if ( from > to ) swap(from, to); Point ip = pointAt(from); Point fp = pointAt(to); Point v = fp - ip; @@ -178,6 +252,33 @@ Coord BezierCurveN<1>::nearestPoint(Point const& p, Coord from, Coord to) const else return from + t*(to-from); } +template <> +void BezierCurveN<1>::feed(PathSink &sink, bool moveto_initial) const +{ + if (moveto_initial) { + sink.moveTo(controlPoint(0)); + } + sink.lineTo(controlPoint(1)); +} + +template <> +void BezierCurveN<2>::feed(PathSink &sink, bool moveto_initial) const +{ + if (moveto_initial) { + sink.moveTo(controlPoint(0)); + } + sink.quadTo(controlPoint(1), controlPoint(2)); +} + +template <> +void BezierCurveN<3>::feed(PathSink &sink, bool moveto_initial) const +{ + if (moveto_initial) { + sink.moveTo(controlPoint(0)); + } + sink.curveTo(controlPoint(1), controlPoint(2), controlPoint(3)); +} + static Coord bezier_length_internal(std::vector &v1, Coord tolerance) { @@ -186,7 +287,7 @@ static Coord bezier_length_internal(std::vector &v1, Coord tolerance) * but shorter than the length of the polyline formed by its control * points. When the difference between the two values is smaller than the * error tolerance, we can be sure that the true value is no further than - * 2*tolerance from their arithmetic mean. When it's larger, we recursively + * 0.5 * tolerance from their arithmetic mean. When it's larger, we recursively * subdivide the Bezier curve into two parts and add their lengths. */ Coord lower = distance(v1.front(), v1.back()); diff --git a/src/2geom/bezier-curve.h b/src/2geom/bezier-curve.h index d379526fa..9b08466f8 100644 --- a/src/2geom/bezier-curve.h +++ b/src/2geom/bezier-curve.h @@ -33,8 +33,8 @@ * the specific language governing rights and limitations. */ -#ifndef SEEN_LIB2GEOM_BEZIER_CURVE_H -#define SEEN_LIB2GEOM_BEZIER_CURVE_H +#ifndef LIB2GEOM_SEEN_BEZIER_CURVE_H +#define LIB2GEOM_SEEN_BEZIER_CURVE_H #include <2geom/curve.h> #include <2geom/sbasis-curve.h> // for non-native winding method @@ -48,25 +48,34 @@ class BezierCurve : public Curve { protected: D2 inner; BezierCurve() {} - BezierCurve(D2 const &b) : inner(b) {} BezierCurve(Bezier const &x, Bezier const &y) : inner(x, y) {} BezierCurve(std::vector const &pts); public: + explicit BezierCurve(D2 const &b) : inner(b) {} + /// @name Access and modify control points /// @{ /** @brief Get the order of the Bezier curve. * A Bezier curve has order() + 1 control points. */ unsigned order() const { return inner[X].order(); } + /** @brief Get the number of control points. */ + unsigned size() const { return inner[X].order() + 1; } + /** @brief Access control points of the curve. + * @param ix The (zero-based) index of the control point. Note that the caller is responsible for checking that this value is <= order(). + * @return The control point. No-reference return, use setPoint() to modify control points. */ + Point controlPoint(unsigned ix) const { return Point(inner[X][ix], inner[Y][ix]); } + Point operator[](unsigned ix) const { return Point(inner[X][ix], inner[Y][ix]); } /** @brief Get the control points. * @return Vector with order() + 1 control points. */ - std::vector points() const { return bezier_points(inner); } + std::vector controlPoints() const { return bezier_points(inner); } + /** @brief Modify a control point. * @param ix The zero-based index of the point to modify. Note that the caller is responsible for checking that this value is <= order(). * @param v The new value of the point */ - void setPoint(unsigned ix, Point v) { - inner[X].setPoint(ix, v[X]); - inner[Y].setPoint(ix, v[Y]); + void setPoint(unsigned ix, Point const &v) { + inner[X][ix] = v[X]; + inner[Y][ix] = v[Y]; } /** @brief Set new control points. * @param ps Vector which must contain order() + 1 points. @@ -80,23 +89,21 @@ public: setPoint(i, ps[i]); } } - /** @brief Access control points of the curve. - * @param ix The (zero-based) index of the control point. Note that the caller is responsible for checking that this value is <= order(). - * @return The control point. No-reference return, use setPoint() to modify control points. */ - Point const operator[](unsigned ix) const { return Point(inner[X][ix], inner[Y][ix]); } /// @} /// @name Construct a Bezier curve with runtime-determined order. /// @{ - /** @brief Construct a curve from a vector of control points. */ + /** @brief Construct a curve from a vector of control points. + * This will construct the appropriate specialization of BezierCurve (i.e. LineSegment, + * QuadraticBezier or Cubic Bezier) if the number of control points in the passed vector + * does not exceed 4. */ static BezierCurve *create(std::vector const &pts); /// @} // implementation of virtual methods goes here -#ifndef DOXYGEN_SHOULD_SKIP_THIS virtual Point initialPoint() const { return inner.at0(); } virtual Point finalPoint() const { return inner.at1(); } - virtual bool isDegenerate() const { return inner.isConstant(); } + virtual bool isDegenerate() const { return inner.isConstant(0); } virtual void setInitial(Point const &v) { setPoint(0, v); } virtual void setFinal(Point const &v) { setPoint(order(), v); } virtual Rect boundsFast() const { return *bounds_fast(inner); } @@ -120,19 +127,11 @@ public: return new BezierCurve(Geom::reverse(inner)); } - virtual Curve *transformed(Affine const &m) const { - BezierCurve *ret = new BezierCurve(); - std::vector ps = points(); - for (unsigned i = 0; i <= order(); i++) { - ps[i] = ps[i] * m; + virtual void transform(Affine const &m) { + for (unsigned i = 0; i < size(); ++i) { + setPoint(i, controlPoint(i) * m); } - ret->setPoints(ps); - return ret; } - virtual Curve &operator*=(Translate const &m) { - inner += m.vector(); - return *this; - }; virtual Curve *derivative() const { return new BezierCurve(Geom::derivative(inner[X]), Geom::derivative(inner[Y])); @@ -143,26 +142,32 @@ public: virtual std::vector roots(Coord v, Dim2 d) const { return (inner[d] - v).roots(); } + virtual Coord nearestTime(Point const &p, Coord from = 0, Coord to = 1) const; virtual Coord length(Coord tolerance) const; + virtual std::vector intersect(Curve const &other, Coord eps = EPSILON) const; virtual Point pointAt(Coord t) const { return inner.valueAt(t); } - virtual std::vector pointAndDerivatives(Coord t, unsigned n) const { return inner.valueAndDerivatives(t, n); } + virtual std::vector pointAndDerivatives(Coord t, unsigned n) const { + return inner.valueAndDerivatives(t, n); + } virtual Coord valueAt(Coord t, Dim2 d) const { return inner[d].valueAt(t); } virtual D2 toSBasis() const {return inner.toSBasis(); } -#endif + virtual bool operator==(Curve const &c) const; + virtual void feed(PathSink &sink, bool) const; }; template -class BezierCurveN : public BezierCurve { +class BezierCurveN + : public BezierCurve +{ + template + static void assert_degree(BezierCurveN const *) {} public: - template - static void assert_degree(BezierCurveN const *) {} - /// @name Construct Bezier curves /// @{ /** @brief Construct a Bezier curve of the specified order with all points zero. */ BezierCurveN() { - inner = D2 (Bezier::Order(degree), Bezier::Order(degree)); + inner = D2(Bezier(Bezier::Order(degree)), Bezier(Bezier::Order(degree))); } /** @brief Construct from 2D Bezier polynomial. */ @@ -224,7 +229,6 @@ public: BezierCurveN(sx.second, sy.second)); } -#ifndef DOXYGEN_SHOULD_SKIP_THIS virtual Curve *duplicate() const { return new BezierCurveN(*this); } @@ -242,30 +246,15 @@ public: return new BezierCurveN(Geom::reverse(inner)); } } - virtual Curve *transformed(Affine const &m) const { - if (degree == 1) { - return new BezierCurveN<1>(initialPoint() * m, finalPoint() * m); - } else { - BezierCurveN *ret = new BezierCurveN(); - std::vector ps = points(); - for (unsigned i = 0; i <= degree; i++) { - ps[i] = ps[i] * m; - } - ret->setPoints(ps); - return ret; - } - } - virtual Curve &operator*=(Translate const &m) { - inner += m.vector(); - return *this; - } virtual Curve *derivative() const; - - // the method below is defined so that LineSegment can specialize it - virtual Coord nearestPoint(Point const& p, Coord from = 0, Coord to = 1) const { - return Curve::nearestPoint(p, from, to); + + virtual Coord nearestTime(Point const &p, Coord from = 0, Coord to = 1) const { + return BezierCurve::nearestTime(p, from, to); + } + virtual void feed(PathSink &sink, bool moveto_initial) const { + // call super. this is implemented only to allow specializations + BezierCurve::feed(sink, moveto_initial); } -#endif }; // BezierCurveN<0> is meaningless; specialize it out @@ -291,9 +280,12 @@ Curve *BezierCurveN::derivative() const { return new BezierCurveN(Geom::derivative(inner[X]), Geom::derivative(inner[Y])); } -// optimized specializations for LineSegment +// optimized specializations template <> Curve *BezierCurveN<1>::derivative() const; -template <> Coord BezierCurveN<1>::nearestPoint(Point const &, Coord, Coord) const; +template <> Coord BezierCurveN<1>::nearestTime(Point const &, Coord, Coord) const; +template <> void BezierCurveN<1>::feed(PathSink &sink, bool moveto_initial) const; +template <> void BezierCurveN<2>::feed(PathSink &sink, bool moveto_initial) const; +template <> void BezierCurveN<3>::feed(PathSink &sink, bool moveto_initial) const; inline Point middle_point(LineSegment const& _segment) { return ( _segment.initialPoint() + _segment.finalPoint() ) / 2; @@ -309,7 +301,7 @@ Coord bezier_length(Point p0, Point p1, Point p2, Point p3, Coord tolerance = 0. } // end namespace Geom -#endif // _2GEOM_BEZIER_CURVE_H_ +#endif // LIB2GEOM_SEEN_BEZIER_CURVE_H /* Local Variables: diff --git a/src/2geom/bezier-to-sbasis.h b/src/2geom/bezier-to-sbasis.h index 8cd4bf444..73c55d9b2 100644 --- a/src/2geom/bezier-to-sbasis.h +++ b/src/2geom/bezier-to-sbasis.h @@ -29,8 +29,8 @@ * */ -#ifndef _BEZIER_TO_SBASIS -#define _BEZIER_TO_SBASIS +#ifndef LIB2GEOM_SEEN_BEZIER_TO_SBASIS_H +#define LIB2GEOM_SEEN_BEZIER_TO_SBASIS_H #include <2geom/coord.h> #include <2geom/point.h> @@ -79,13 +79,9 @@ D2 handles_to_sbasis(T const& handles, unsigned order) return sbc; } - } // end namespace Geom - - - -#endif +#endif // LIB2GEOM_SEEN_BEZIER_TO_SBASIS_H /* Local Variables: mode:c++ diff --git a/src/2geom/bezier-utils.cpp b/src/2geom/bezier-utils.cpp index ec17f6869..816bcdeb4 100644 --- a/src/2geom/bezier-utils.cpp +++ b/src/2geom/bezier-utils.cpp @@ -666,9 +666,9 @@ Point bezier_pt(unsigned const degree, Point const V[], double const t) { /** Pascal's triangle. */ - static int const pascal[4][4] = {{1}, - {1, 1}, - {1, 2, 1}, + static int const pascal[4][4] = {{1, 0, 0, 0}, + {1, 1, 0, 0}, + {1, 2, 1, 0}, {1, 3, 3, 1}}; assert( degree < 4); double const s = 1.0 - t; diff --git a/src/2geom/bezier.cpp b/src/2geom/bezier.cpp new file mode 100644 index 000000000..45496b75c --- /dev/null +++ b/src/2geom/bezier.cpp @@ -0,0 +1,324 @@ +/** + * @file + * @brief Bernstein-Bezier polynomial + *//* + * Authors: + * MenTaLguY + * Michael Sloan + * Nathan Hurst + * Krzysztof Kosiński + * + * Copyright 2007-2015 Authors + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + */ + +#include <2geom/bezier.h> +#include <2geom/solver.h> +#include <2geom/concepts.h> + +namespace Geom { + +std::vector Bezier::valueAndDerivatives(Coord t, unsigned n_derivs) const { + /* This is inelegant, as it uses several extra stores. I think there might be a way to + * evaluate roughly in situ. */ + + // initialize return vector with zeroes, such that we only need to replace the non-zero derivs + std::vector val_n_der(n_derivs + 1, Coord(0.0)); + + // initialize temp storage variables + std::valarray d_(order()+1); + for(unsigned i = 0; i < size(); i++) { + d_[i] = c_[i]; + } + + unsigned nn = n_derivs + 1; + if(n_derivs > order()) { + nn = order()+1; // only calculate the non zero derivs + } + for(unsigned di = 0; di < nn; di++) { + //val_n_der[di] = (casteljau_subdivision(t, &d_[0], NULL, NULL, order() - di)); + val_n_der[di] = bernstein_value_at(t, &d_[0], order() - di); + for(unsigned i = 0; i < order() - di; i++) { + d_[i] = (order()-di)*(d_[i+1] - d_[i]); + } + } + + return val_n_der; +} + +void Bezier::subdivide(Coord t, Bezier *left, Bezier *right) const +{ + if (left) { + left->c_.resize(size()); + if (right) { + right->c_.resize(size()); + casteljau_subdivision(t, &const_cast&>(c_)[0], + &left->c_[0], &right->c_[0], order()); + } else { + casteljau_subdivision(t, &const_cast&>(c_)[0], + &left->c_[0], NULL, order()); + } + } else if (right) { + right->c_.resize(size()); + casteljau_subdivision(t, &const_cast&>(c_)[0], + NULL, &right->c_[0], order()); + } +} + +std::pair Bezier::subdivide(Coord t) const +{ + std::pair ret; + subdivide(t, &ret.first, &ret.second); + return ret; +} + +std::vector Bezier::roots() const +{ + std::vector solutions; + find_bezier_roots(solutions, 0, 1); + std::sort(solutions.begin(), solutions.end()); + return solutions; +} + +std::vector Bezier::roots(Interval const &ivl) const +{ + std::vector solutions; + find_bernstein_roots(&const_cast&>(c_)[0], order(), solutions, 0, ivl.min(), ivl.max()); + std::sort(solutions.begin(), solutions.end()); + return solutions; +} + +Bezier Bezier::forward_difference(unsigned k) const +{ + Bezier fd(Order(order()-k)); + unsigned n = fd.size(); + + for(unsigned i = 0; i < n; i++) { + fd[i] = 0; + for(unsigned j = i; j < n; j++) { + fd[i] += (((j)&1)?-c_[j]:c_[j])*choose(n, j-i); + } + } + return fd; +} + +Bezier Bezier::elevate_degree() const +{ + Bezier ed(Order(order()+1)); + unsigned n = size(); + ed[0] = c_[0]; + ed[n] = c_[n-1]; + for(unsigned i = 1; i < n; i++) { + ed[i] = (i*c_[i-1] + (n - i)*c_[i])/(n); + } + return ed; +} + +Bezier Bezier::reduce_degree() const +{ + if(order() == 0) return *this; + Bezier ed(Order(order()-1)); + unsigned n = size(); + ed[0] = c_[0]; + ed[n-1] = c_[n]; // ensure exact endpoints + unsigned middle = n/2; + for(unsigned i = 1; i < middle; i++) { + ed[i] = (n*c_[i] - i*ed[i-1])/(n-i); + } + for(unsigned i = n-1; i >= middle; i--) { + ed[i] = (n*c_[i] - i*ed[n-i])/(i); + } + return ed; +} + +Bezier Bezier::elevate_to_degree(unsigned newDegree) const +{ + Bezier ed = *this; + for(unsigned i = degree(); i < newDegree; i++) { + ed = ed.elevate_degree(); + } + return ed; +} + +Bezier Bezier::deflate() const +{ + if(order() == 0) return *this; + unsigned n = order(); + Bezier b(Order(n-1)); + for(unsigned i = 0; i < n; i++) { + b[i] = (n*c_[i+1])/(i+1); + } + return b; +} + +SBasis Bezier::toSBasis() const +{ + SBasis sb; + bezier_to_sbasis(sb, (*this)); + return sb; + //return bezier_to_sbasis(&c_[0], order()); +} + +Bezier &Bezier::operator+=(Bezier const &other) +{ + if (c_.size() > other.size()) { + c_ += other.elevate_to_degree(degree()).c_; + } else if (c_.size() < other.size()) { + *this = elevate_to_degree(other.degree()); + c_ += other.c_; + } else { + c_ += other.c_; + } + return *this; +} + +Bezier &Bezier::operator-=(Bezier const &other) +{ + if (c_.size() > other.size()) { + c_ -= other.elevate_to_degree(degree()).c_; + } else if (c_.size() < other.size()) { + *this = elevate_to_degree(other.degree()); + c_ -= other.c_; + } else { + c_ -= other.c_; + } + return *this; +} + + + +Bezier multiply(Bezier const &f, Bezier const &g) +{ + unsigned m = f.order(); + unsigned n = g.order(); + Bezier h(Bezier::Order(m+n)); + // h_k = sum_(i+j=k) (m i)f_i (n j)g_j / (m+n k) + + for(unsigned i = 0; i <= m; i++) { + const double fi = choose(m,i)*f[i]; + for(unsigned j = 0; j <= n; j++) { + h[i+j] += fi * choose(n,j)*g[j]; + } + } + for(unsigned k = 0; k <= m+n; k++) { + h[k] /= choose(m+n, k); + } + return h; +} + +Bezier portion(Bezier const &a, double from, double to) +{ + Bezier ret(a); + + bool reverse_result = false; + if (from > to) { + std::swap(from, to); + reverse_result = true; + } + + do { + if (from == 0) { + if (to == 1) { + break; + } + casteljau_subdivision(to, &ret.c_[0], &ret.c_[0], NULL, ret.order()); + break; + } + casteljau_subdivision(from, &ret.c_[0], NULL, &ret.c_[0], ret.order()); + if (to == 1) break; + casteljau_subdivision((to - from) / (1 - from), &ret.c_[0], &ret.c_[0], NULL, ret.order()); + // to protect against numerical inaccuracy in the above expression, we manually set + // the last coefficient to a value evaluated directly from the original polynomial + ret.c_[ret.order()] = a.valueAt(to); + } while(0); + + if (reverse_result) { + std::reverse(&ret.c_[0], &ret.c_[0] + ret.c_.size()); + } + return ret; +} + +Bezier derivative(Bezier const &a) +{ + //if(a.order() == 1) return Bezier(0.0); + if(a.order() == 1) return Bezier(a.c_[1]-a.c_[0]); + Bezier der(Bezier::Order(a.order()-1)); + + for(unsigned i = 0; i < a.order(); i++) { + der.c_[i] = a.order()*(a.c_[i+1] - a.c_[i]); + } + return der; +} + +Bezier integral(Bezier const &a) +{ + Bezier inte(Bezier::Order(a.order()+1)); + + inte[0] = 0; + for(unsigned i = 0; i < inte.order(); i++) { + inte[i+1] = inte[i] + a[i]/(inte.order()); + } + return inte; +} + +OptInterval bounds_fast(Bezier const &b) +{ + OptInterval ret = Interval::from_array(&const_cast(b).c_[0], b.size()); + return ret; +} + +OptInterval bounds_exact(Bezier const &b) +{ + OptInterval ret(b.at0(), b.at1()); + std::vector r = derivative(b).roots(); + for (unsigned i = 0; i < r.size(); ++i) { + ret->expandTo(b.valueAt(r[i])); + } + return ret; +} + +OptInterval bounds_local(Bezier const &b, OptInterval const &i) +{ + //return bounds_local(b.toSBasis(), i); + if (i) { + return bounds_fast(portion(b, i->min(), i->max())); + } else { + return OptInterval(); + } +} + +} // end namespace Geom + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 : diff --git a/src/2geom/bezier.h b/src/2geom/bezier.h index 51d5211d9..be7df1a6b 100644 --- a/src/2geom/bezier.h +++ b/src/2geom/bezier.h @@ -1,13 +1,14 @@ /** * @file - * @brief Bezier polynomial + * @brief Bernstein-Bezier polynomial *//* * Authors: * MenTaLguY * Michael Sloan * Nathan Hurst + * Krzysztof Kosiński * - * Copyright 2007 Authors + * Copyright 2007-2015 Authors * * This library is free software; you can redistribute it and/or * modify it either under the terms of the GNU Lesser General Public @@ -37,70 +38,23 @@ #ifndef LIB2GEOM_SEEN_BEZIER_H #define LIB2GEOM_SEEN_BEZIER_H +#include #include #include -#include <2geom/coord.h> #include <2geom/choose.h> -#include -#include <2geom/math-utils.h> +#include <2geom/coord.h> #include <2geom/d2.h> -#include <2geom/solver.h> +#include <2geom/math-utils.h> namespace Geom { -inline Coord subdivideArr(Coord t, Coord const *v, Coord *left, Coord *right, unsigned order) { -/* - * Bernstein : - * Evaluate a Bernstein function at a particular parameter value - * Fill in control points for resulting sub-curves. - * - */ - - unsigned N = order+1; - std::valarray row(N); - for (unsigned i = 0; i < N; i++) - row[i] = v[i]; - - // Triangle computation - const double omt = (1-t); - if(left) - left[0] = row[0]; - if(right) - right[order] = row[order]; - for (unsigned i = 1; i < N; i++) { - for (unsigned j = 0; j < N - i; j++) { - row[j] = omt*row[j] + t*row[j+1]; - } - if(left) - left[i] = row[0]; - if(right) - right[order-i] = row[order-i]; - } - return (row[0]); -/* - Coord vtemp[order+1][order+1]; - - // Copy control points - std::copy(v, v+order+1, vtemp[0]); - - // Triangle computation - for (unsigned i = 1; i <= order; i++) { - for (unsigned j = 0; j <= order - i; j++) { - vtemp[i][j] = lerp(t, vtemp[i-1][j], vtemp[i-1][j+1]); - } - } - if(left != NULL) - for (unsigned j = 0; j <= order; j++) - left[j] = vtemp[j][0]; - if(right != NULL) - for (unsigned j = 0; j <= order; j++) - right[j] = vtemp[order-j][j]; - - return (vtemp[order][0]);*/ -} - +/** @brief Compute the value of a Bernstein-Bezier polynomial. + * This method uses a Horner-like fast evaluation scheme. + * @param t Time value + * @param c_ Pointer to coefficients + * @param n Degree of the polynomial (number of coefficients minus one) */ template -inline T bernsteinValueAt(double t, T const *c_, unsigned n) { +inline T bernstein_value_at(double t, T const *c_, unsigned n) { double u = 1.0 - t; double bc = 1; double tn = 1; @@ -113,16 +67,71 @@ inline T bernsteinValueAt(double t, T const *c_, unsigned n) { return (tmp + tn*t*c_[n]); } -class Bezier { +/** @brief Perform Casteljau subdivision of a Bezier polynomial. + * Given an array of coefficients and a time value, computes two new Bernstein-Bezier basis + * polynomials corresponding to the \f$[0, t]\f$ and \f$[t, 1]\f$ intervals of the original one. + * @param t Time value + * @param v Array of input coordinates + * @param left Output polynomial corresponding to \f$[0, t]\f$ + * @param right Output polynomial corresponding to \f$[t, 1]\f$ + * @param order Order of the input polynomial, equal to one less the number of coefficients + * @return Value of the polynomial at @a t */ +template +inline T casteljau_subdivision(double t, T const *v, T *left, T *right, unsigned order) { + // The Horner-like scheme gives very slightly different results, but we need + // the result of subdivision to match exactly with Bezier's valueAt function. + T val = bernstein_value_at(t, v, order); + + if (!left && !right) { + return val; + } + + if (!right) { + if (left != v) { + std::copy(v, v + order + 1, left); + } + for (std::size_t i = order; i > 0; --i) { + for (std::size_t j = i; j <= order; ++j) { + left[j] = lerp(t, left[j-1], left[j]); + } + } + left[order] = val; + return left[order]; + } + + if (right != v) { + std::copy(v, v + order + 1, right); + } + for (std::size_t i = 1; i <= order; ++i) { + if (left) { + left[i-1] = right[0]; + } + for (std::size_t j = i; j > 0; --j) { + right[j-1] = lerp(t, right[j-1], right[j]); + } + } + right[0] = val; + if (left) { + left[order] = right[0]; + } + return right[0]; +} + +/** + * @brief Polynomial in Bernstein-Bezier basis + * @ingroup Fragments + */ +class Bezier + : boost::arithmetic< Bezier, double + , boost::additive< Bezier + > > +{ private: std::valarray c_; friend Bezier portion(const Bezier & a, Coord from, Coord to); - friend OptInterval bounds_fast(Bezier const & b); - friend Bezier derivative(const Bezier & a); - friend class Bernstein; void @@ -130,13 +139,14 @@ private: double l, double r) const; protected: - Bezier(Coord const c[], unsigned ord) : c_(c, ord+1){ - //std::copy(c, c+order()+1, &c_[0]); - } + Bezier(Coord const c[], unsigned ord) + : c_(c, ord+1) + {} public: - unsigned int order() const { return c_.size()-1;} - unsigned int size() const { return c_.size();} + unsigned order() const { return c_.size()-1;} + unsigned degree() const { return order(); } + unsigned size() const { return c_.size();} Bezier() {} Bezier(const Bezier& b) :c_(b.c_) {} @@ -160,262 +170,145 @@ public: assert(ord.order == order()); } + /// @name Construct Bezier polynomials from their control points + /// @{ explicit Bezier(Coord c0) : c_(0., 1) { c_[0] = c0; } - - //Construct an order-1 bezier (linear Bézier) Bezier(Coord c0, Coord c1) : c_(0., 2) { c_[0] = c0; c_[1] = c1; } - - //Construct an order-2 bezier (quadratic Bézier) Bezier(Coord c0, Coord c1, Coord c2) : c_(0., 3) { c_[0] = c0; c_[1] = c1; c_[2] = c2; } - - //Construct an order-3 bezier (cubic Bézier) Bezier(Coord c0, Coord c1, Coord c2, Coord c3) : c_(0., 4) { c_[0] = c0; c_[1] = c1; c_[2] = c2; c_[3] = c3; } + Bezier(Coord c0, Coord c1, Coord c2, Coord c3, Coord c4) : c_(0., 5) { + c_[0] = c0; c_[1] = c1; c_[2] = c2; c_[3] = c3; c_[4] = c4; + } + Bezier(Coord c0, Coord c1, Coord c2, Coord c3, Coord c4, + Coord c5) : c_(0., 6) { + c_[0] = c0; c_[1] = c1; c_[2] = c2; c_[3] = c3; c_[4] = c4; + c_[5] = c5; + } + Bezier(Coord c0, Coord c1, Coord c2, Coord c3, Coord c4, + Coord c5, Coord c6) : c_(0., 7) { + c_[0] = c0; c_[1] = c1; c_[2] = c2; c_[3] = c3; c_[4] = c4; + c_[5] = c5; c_[6] = c6; + } + Bezier(Coord c0, Coord c1, Coord c2, Coord c3, Coord c4, + Coord c5, Coord c6, Coord c7) : c_(0., 8) { + c_[0] = c0; c_[1] = c1; c_[2] = c2; c_[3] = c3; c_[4] = c4; + c_[5] = c5; c_[6] = c6; c_[7] = c7; + } + Bezier(Coord c0, Coord c1, Coord c2, Coord c3, Coord c4, + Coord c5, Coord c6, Coord c7, Coord c8) : c_(0., 9) { + c_[0] = c0; c_[1] = c1; c_[2] = c2; c_[3] = c3; c_[4] = c4; + c_[5] = c5; c_[6] = c6; c_[7] = c7; c_[8] = c8; + } + Bezier(Coord c0, Coord c1, Coord c2, Coord c3, Coord c4, + Coord c5, Coord c6, Coord c7, Coord c8, Coord c9) : c_(0., 10) { + c_[0] = c0; c_[1] = c1; c_[2] = c2; c_[3] = c3; c_[4] = c4; + c_[5] = c5; c_[6] = c6; c_[7] = c7; c_[8] = c8; c_[9] = c9; + } - void resize (unsigned int n, Coord v = 0) - { - c_.resize (n, v); + template + Bezier(Iter first, Iter last) { + c_.resize(std::distance(first, last)); + for (std::size_t i = 0; first != last; ++first, ++i) { + c_[i] = *first; + } } + Bezier(std::vector const &vec) + : c_(&vec[0], vec.size()) + {} + /// @} - void clear() - { + void resize (unsigned int n, Coord v = 0) { + c_.resize (n, v); + } + void clear() { c_.resize(0); } - inline unsigned degree() const { return order(); } - //IMPL: FragmentConcept typedef Coord output_type; - inline bool isZero(double eps=EPSILON) const { + bool isZero(double eps=EPSILON) const { for(unsigned i = 0; i <= order(); i++) { if( ! are_near(c_[i], 0., eps) ) return false; } return true; } - inline bool isConstant(double eps=EPSILON) const { + bool isConstant(double eps=EPSILON) const { for(unsigned i = 1; i <= order(); i++) { if( ! are_near(c_[i], c_[0], eps) ) return false; } return true; } - inline bool isFinite() const { + bool isFinite() const { for(unsigned i = 0; i <= order(); i++) { if(!IS_FINITE(c_[i])) return false; } return true; } - inline Coord at0() const { return c_[0]; } - inline Coord at1() const { return c_[order()]; } - - inline Coord valueAt(double t) const { - int n = order(); - double u, bc, tn, tmp; - int i; - u = 1.0 - t; - bc = 1; - tn = 1; - tmp = c_[0]*u; - for(i=1; i&>(c_)[ix]; } - //inline Coord const &operator[](unsigned ix) const { return c_[ix]; } - inline void setPoint(unsigned ix, double val) { c_[ix] = val; } - - /** - * The size of the returned vector equals n_derivs+1. - */ - std::vector valueAndDerivatives(Coord t, unsigned n_derivs) const { - /* This is inelegant, as it uses several extra stores. I think there might be a way to - * evaluate roughly in situ. */ - - // initialize return vector with zeroes, such that we only need to replace the non-zero derivs - std::vector val_n_der(n_derivs + 1, Coord(0.0)); - - // initialize temp storage variables - std::valarray d_(order()+1); - for(unsigned i = 0; i < size(); i++) { - d_[i] = c_[i]; - } + Coord &operator[](unsigned ix) { return c_[ix]; } + Coord const &operator[](unsigned ix) const { return const_cast&>(c_)[ix]; } - unsigned nn = n_derivs + 1; - if(n_derivs > order()) { - nn = order()+1; // only calculate the non zero derivs - } - for(unsigned di = 0; di < nn; di++) { - //val_n_der[di] = (subdivideArr(t, &d_[0], NULL, NULL, order() - di)); - val_n_der[di] = bernsteinValueAt(t, &d_[0], order() - di); - for(unsigned i = 0; i < order() - di; i++) { - d_[i] = (order()-di)*(d_[i+1] - d_[i]); - } - } + void setCoeff(unsigned ix, double val) { c_[ix] = val; } - return val_n_der; - } + // The size of the returned vector equals n_derivs+1. + std::vector valueAndDerivatives(Coord t, unsigned n_derivs) const; - std::pair subdivide(Coord t) const { - Bezier a(Bezier::Order(*this)), b(Bezier::Order(*this)); - subdivideArr(t, &const_cast&>(c_)[0], &a.c_[0], &b.c_[0], order()); - return std::pair(a, b); - } + void subdivide(Coord t, Bezier *left, Bezier *right) const; + std::pair subdivide(Coord t) const; - std::vector roots() const { - std::vector solutions; - find_bezier_roots(solutions, 0, 1); - return solutions; - } - std::vector roots(Interval const ivl) const { - std::vector solutions; - find_bernstein_roots(&const_cast&>(c_)[0], order(), solutions, 0, ivl.min(), ivl.max()); - return solutions; - } + std::vector roots() const; + std::vector roots(Interval const &ivl) const; - Bezier forward_difference(unsigned k) { - Bezier fd(Order(order()-k)); - unsigned n = fd.size(); - - for(unsigned i = 0; i < n; i++) { - fd[i] = 0; - for(unsigned j = i; j < n; j++) { - fd[i] += (((j)&1)?-c_[j]:c_[j])*choose(n, j-i); - } - } - return fd; - } - - Bezier elevate_degree() const { - Bezier ed(Order(order()+1)); - unsigned n = size(); - ed[0] = c_[0]; - ed[n] = c_[n-1]; - for(unsigned i = 1; i < n; i++) { - ed[i] = (i*c_[i-1] + (n - i)*c_[i])/(n); - } - return ed; - } - - Bezier reduce_degree() const { - if(order() == 0) return *this; - Bezier ed(Order(order()-1)); - unsigned n = size(); - ed[0] = c_[0]; - ed[n-1] = c_[n]; // ensure exact endpoints - unsigned middle = n/2; - for(unsigned i = 1; i < middle; i++) { - ed[i] = (n*c_[i] - i*ed[i-1])/(n-i); - } - for(unsigned i = n-1; i >= middle; i--) { - ed[i] = (n*c_[i] - i*ed[n-i])/(i); - } - return ed; - } + Bezier forward_difference(unsigned k) const; + Bezier elevate_degree() const; + Bezier reduce_degree() const; + Bezier elevate_to_degree(unsigned newDegree) const; + Bezier deflate() const; - Bezier elevate_to_degree(unsigned newDegree) const { - Bezier ed = *this; - for(unsigned i = degree(); i < newDegree; i++) { - ed = ed.elevate_degree(); - } - return ed; + // basic arithmetic operators + Bezier &operator+=(double v) { + c_ += v; + return *this; } - - Bezier deflate() { - if(order() == 0) return *this; - unsigned n = order(); - Bezier b(Order(n-1)); - for(unsigned i = 0; i < n; i++) { - b[i] = (n*c_[i+1])/(i+1); - } - return b; + Bezier &operator-=(double v) { + c_ -= v; + return *this; } -}; - - -void bezier_to_sbasis (SBasis & sb, Bezier const& bz); - -inline -Bezier multiply(Bezier const& f, Bezier const& g) { - unsigned m = f.order(); - unsigned n = g.order(); - Bezier h(Bezier::Order(m+n)); - // h_k = sum_(i+j=k) (m i)f_i (n j)g_j / (m+n k) - - for(unsigned i = 0; i <= m; i++) { - const double fi = choose(m,i)*f[i]; - for(unsigned j = 0; j <= n; j++) { - h[i+j] += fi * choose(n,j)*g[j]; - } + Bezier &operator*=(double v) { + c_ *= v; + return *this; } - for(unsigned k = 0; k <= m+n; k++) { - h[k] /= choose(m+n, k); + Bezier &operator/=(double v) { + c_ /= v; + return *this; } - return h; -} - -inline -SBasis Bezier::toSBasis() const { - SBasis sb; - bezier_to_sbasis(sb, (*this)); - return sb; - //return bezier_to_sbasis(&c_[0], order()); -} - -//TODO: implement others -inline Bezier operator+(const Bezier & a, double v) { - Bezier result = Bezier(Bezier::Order(a)); - for(unsigned i = 0; i <= a.order(); i++) - result[i] = a[i] + v; - return result; -} - -inline Bezier operator-(const Bezier & a, double v) { - Bezier result = Bezier(Bezier::Order(a)); - for(unsigned i = 0; i <= a.order(); i++) - result[i] = a[i] - v; - return result; -} - -inline Bezier& operator+=(Bezier & a, double v) { - for(unsigned i = 0; i <= a.order(); ++i) - a[i] = a[i] + v; - return a; -} + Bezier &operator+=(Bezier const &other); + Bezier &operator-=(Bezier const &other); +}; -inline Bezier& operator-=(Bezier & a, double v) { - for(unsigned i = 0; i <= a.order(); ++i) - a[i] = a[i] - v; - return a; -} -inline Bezier operator*(const Bezier & a, double v) { - Bezier result = Bezier(Bezier::Order(a)); - for(unsigned i = 0; i <= a.order(); i++) - result[i] = a[i] * v; - return result; -} +void bezier_to_sbasis (SBasis &sb, Bezier const &bz); -inline Bezier operator/(const Bezier & a, double v) { - Bezier result = Bezier(Bezier::Order(a)); - for(unsigned i = 0; i <= a.order(); i++) - result[i] = a[i] / v; - return result; -} +Bezier multiply(Bezier const &f, Bezier const &g); inline Bezier reverse(const Bezier & a) { Bezier result = Bezier(Bezier::Order(a)); @@ -424,20 +317,7 @@ inline Bezier reverse(const Bezier & a) { return result; } -inline Bezier portion(const Bezier & a, double from, double to) { - //TODO: implement better? - std::valarray res(a.order() + 1); - if(from == 0) { - if(to == 1) { return Bezier(a); } - subdivideArr(to, &const_cast(a).c_[0], &res[0], NULL, a.order()); - return Bezier(&res[0], a.order()); - } - subdivideArr(from, &const_cast(a).c_[0], NULL, &res[0], a.order()); - if(to == 1) return Bezier(&res[0], a.order()); - std::valarray res2(a.order()+1); - subdivideArr((to - from)/(1 - from), &res[0], &res2[0], NULL, a.order()); - return Bezier(&res2[0], a.order()); -} +Bezier portion(const Bezier & a, double from, double to); // XXX Todo: how to handle differing orders inline std::vector bezier_points(const D2 & a) { @@ -450,52 +330,19 @@ inline std::vector bezier_points(const D2 & a) { return result; } -inline Bezier derivative(const Bezier & a) { - //if(a.order() == 1) return Bezier(0.0); - if(a.order() == 1) return Bezier(a.c_[1]-a.c_[0]); - Bezier der(Bezier::Order(a.order()-1)); - - for(unsigned i = 0; i < a.order(); i++) { - der.c_[i] = a.order()*(a.c_[i+1] - a.c_[i]); - } - return der; -} - -inline Bezier integral(const Bezier & a) { - Bezier inte(Bezier::Order(a.order()+1)); - - inte[0] = 0; - for(unsigned i = 0; i < inte.order(); i++) { - inte[i+1] = inte[i] + a[i]/(inte.order()); - } - return inte; -} - -inline OptInterval bounds_fast(Bezier const & b) { - OptInterval ret = Interval::from_array(&const_cast(b).c_[0], b.size()); - return ret; -} - -//TODO: better bounds exact -inline OptInterval bounds_exact(Bezier const & b) { - return bounds_exact(b.toSBasis()); -} - -inline OptInterval bounds_local(Bezier const & b, OptInterval i) { - //return bounds_local(b.toSBasis(), i); - if (i) { - return bounds_fast(portion(b, i->min(), i->max())); - } else { - return OptInterval(); - } -} +Bezier derivative(Bezier const &a); +Bezier integral(Bezier const &a); +OptInterval bounds_fast(Bezier const &b); +OptInterval bounds_exact(Bezier const &b); +OptInterval bounds_local(Bezier const &b, OptInterval const &i); -inline std::ostream &operator<< (std::ostream &out_file, const Bezier & b) { - out_file << "Bezier("; - for(unsigned i = 0; i < b.size(); i++) { - out_file << b[i] << ", "; +inline std::ostream &operator<< (std::ostream &os, const Bezier & b) { + os << "Bezier("; + for(unsigned i = 0; i < b.order(); i++) { + os << format_coord_nice(b[i]) << ", "; } - return out_file << ")"; + os << format_coord_nice(b[b.order()]) << ")"; + return os; } } diff --git a/src/2geom/cairo-path-sink.cpp b/src/2geom/cairo-path-sink.cpp new file mode 100644 index 000000000..244a08ba4 --- /dev/null +++ b/src/2geom/cairo-path-sink.cpp @@ -0,0 +1,123 @@ +/** + * @file + * @brief Path sink for Cairo contexts + *//* + * Copyright 2014 Krzysztof Kosiński + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, output to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + */ + +#include +#include <2geom/cairo-path-sink.h> +#include <2geom/elliptical-arc.h> + +namespace Geom { + +CairoPathSink::CairoPathSink(cairo_t *cr) + : _cr(cr) +{} + +void CairoPathSink::moveTo(Point const &p) +{ + cairo_move_to(_cr, p[X], p[Y]); + _current_point = p; +} + +void CairoPathSink::lineTo(Point const &p) +{ + cairo_line_to(_cr, p[X], p[Y]); + _current_point = p; +} + +void CairoPathSink::curveTo(Point const &p1, Point const &p2, Point const &p3) +{ + cairo_curve_to(_cr, p1[X], p1[Y], p2[X], p2[Y], p3[X], p3[Y]); + _current_point = p3; +} + +void CairoPathSink::quadTo(Point const &p1, Point const &p2) +{ + // degree-elevate to cubic Bezier, since Cairo doesn't do quad Beziers + // google "Bezier degree elevation" for more info + Point q1 = (1./3.) * _current_point + (2./3.) * p1; + Point q2 = (2./3.) * p1 + (1./3.) * p2; + // q3 = p2 + cairo_curve_to(_cr, q1[X], q1[Y], q2[X], q2[Y], p2[X], p2[Y]); + _current_point = p2; +} + +void CairoPathSink::arcTo(double rx, double ry, double angle, + bool large_arc, bool sweep, Point const &p) +{ + EllipticalArc arc(_current_point, rx, ry, angle, large_arc, sweep, p); + // Cairo only does circular arcs. + // To do elliptical arcs, we must use a temporary transform. + Affine uct = arc.unitCircleTransform(); + + // TODO move Cairo-2Geom matrix conversion into a common location + cairo_matrix_t cm; + cm.xx = uct[0]; + cm.xy = uct[2]; + cm.x0 = uct[4]; + cm.yx = uct[1]; + cm.yy = uct[3]; + cm.y0 = uct[5]; + + cairo_save(_cr); + cairo_transform(_cr, &cm); + if (sweep) { + cairo_arc(_cr, 0, 0, 1, arc.initialAngle(), arc.finalAngle()); + } else { + cairo_arc_negative(_cr, 0, 0, 1, arc.initialAngle(), arc.finalAngle()); + } + _current_point = p; + cairo_restore(_cr); + + /* Note that an extra linear segment will be inserted before the arc + * if Cairo considers the current point distinct from the initial point + * of the arc; we could partially alleviate this by not emitting + * linear segments that are followed by arc segments, but this would require + * buffering the input curves. */ +} + +void CairoPathSink::closePath() +{ + cairo_close_path(_cr); +} + +void CairoPathSink::flush() {} + +} // namespace Geom + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 : diff --git a/src/2geom/cairo-path-sink.h b/src/2geom/cairo-path-sink.h new file mode 100644 index 000000000..9fec7e0ab --- /dev/null +++ b/src/2geom/cairo-path-sink.h @@ -0,0 +1,87 @@ +/** + * @file + * @brief Path sink for Cairo contexts + *//* + * Copyright 2014 Krzysztof Kosiński + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + */ + +#ifndef LIB2GEOM_SEEN_CAIRO_PATH_SINK_H +#define LIB2GEOM_SEEN_CAIRO_PATH_SINK_H + +#include <2geom/path-sink.h> +#include + +namespace Geom { + + +/** @brief Output paths to a Cairo drawing context + * + * This class converts from 2Geom path representation to the Cairo representation. + * Use it to simplify visualizing the results of 2Geom operations with the Cairo library, + * for example: + * @code + * CairoPathSink sink(cr); + * sink.feed(pv); + * cairo_stroke(cr); + * @endcode + * + * Currently the flush method is a no-op, but this is not guaranteed + * to hold forever. + */ +class CairoPathSink + : public PathSink +{ +public: + CairoPathSink(cairo_t *cr); + + void moveTo(Point const &p); + void lineTo(Point const &p); + void curveTo(Point const &c0, Point const &c1, Point const &p); + void quadTo(Point const &c, Point const &p); + void arcTo(Coord rx, Coord ry, Coord angle, + bool large_arc, bool sweep, Point const &p); + void closePath(); + void flush(); + +private: + cairo_t *_cr; + Point _current_point; +}; + +} + +#endif // !LIB2GEOM_SEEN_CAIRO_PATH_SINK_H +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 : diff --git a/src/2geom/circle.cpp b/src/2geom/circle.cpp index d021882ea..0b1dddc8e 100644 --- a/src/2geom/circle.cpp +++ b/src/2geom/circle.cpp @@ -1,10 +1,11 @@ -/* - * Circle Curve - * +/** @file + * @brief Circle shape + *//* * Authors: - * Marco Cecchetti + * Marco Cecchetti + * Krzysztof Kosiński * - * Copyright 2008 authors + * Copyright 2008-2014 Authors * * This library is free software; you can redistribute it and/or * modify it either under the terms of the GNU Lesser General Public @@ -30,56 +31,54 @@ * the specific language governing rights and limitations. */ - #include <2geom/circle.h> #include <2geom/ellipse.h> #include <2geom/svg-elliptical-arc.h> #include <2geom/numeric/fitting-tool.h> #include <2geom/numeric/fitting-model.h> +namespace Geom { - -namespace Geom +void Circle::setCoefficients(Coord A, Coord B, Coord C, Coord D) { - -void Circle::set(double A, double B, double C, double D) -{ - if (A == 0) - { + if (A == 0) { THROW_RANGEERROR("square term coefficient == 0"); } //std::cerr << "B = " << B << " C = " << C << " D = " << D << std::endl; - double b = B / A; - double c = C / A; - double d = D / A; + Coord b = B / A; + Coord c = C / A; + Coord d = D / A; - m_centre[X] = -b/2; - m_centre[Y] = -c/2; - double r2 = m_centre[X] * m_centre[X] + m_centre[Y] * m_centre[Y] - d; + _center[X] = -b/2; + _center[Y] = -c/2; + Coord r2 = _center[X] * _center[X] + _center[Y] * _center[Y] - d; - if (r2 < 0) - { + if (r2 < 0) { THROW_RANGEERROR("ray^2 < 0"); } - m_ray = std::sqrt(r2); + _radius = std::sqrt(r2); } -void Circle::set(std::vector const& points) +void Circle::fit(std::vector const& points) { size_t sz = points.size(); - if (sz < 3) - { + if (sz < 2) { THROW_RANGEERROR("fitting error: too few points passed"); } + if (sz == 2) { + _center = points[0] * 0.5 + points[1] * 0.5; + _radius = distance(points[0], points[1]) / 2; + return; + } + NL::LFMCircle model; NL::least_squeares_fitter fitter(model, sz); - for (size_t i = 0; i < sz; ++i) - { + for (size_t i = 0; i < sz; ++i) { fitter.append(points[i]); } fitter.update(); @@ -93,11 +92,11 @@ void Circle::set(std::vector const& points) */ EllipticalArc * Circle::arc(Point const& initial, Point const& inner, Point const& final, - bool _svg_compliant) + bool svg_compliant) { // TODO native implementation! - Ellipse e(center(X), center(Y), ray(), ray(), 0); - return e.arc(initial, inner, final, _svg_compliant); + Ellipse e(_center[X], _center[Y], _radius, _radius, 0); + return e.arc(initial, inner, final, svg_compliant); } D2 Circle::toSBasis() @@ -108,13 +107,13 @@ D2 Circle::toSBasis() B[0] = cos(bo,4); B[1] = sin(bo,4); - B = B * m_ray + m_centre; + B = B * _radius + _center; return B; } void -Circle::getPath(std::vector &path_out) { +Circle::getPath(PathVector &path_out) { Path pb; D2 B = toSBasis(); diff --git a/src/2geom/circle.h b/src/2geom/circle.h index ca9241047..3c2115b12 100644 --- a/src/2geom/circle.h +++ b/src/2geom/circle.h @@ -1,11 +1,11 @@ -/** - * \file - * \brief Circles +/** @file + * @brief Circle shape *//* * Authors: - * Marco Cecchetti + * Marco Cecchetti + * Krzysztof Kosiński * - * Copyright 2008 authors + * Copyright 2008-2014 Authors * * This library is free software; you can redistribute it and/or * modify it either under the terms of the GNU Lesser General Public @@ -34,83 +34,72 @@ #ifndef LIB2GEOM_SEEN_CIRCLE_H #define LIB2GEOM_SEEN_CIRCLE_H -#include #include <2geom/point.h> -#include <2geom/exception.h> -#include <2geom/path.h> +#include <2geom/forward.h> +#include <2geom/transforms.h> namespace Geom { class EllipticalArc; +/** @brief Set of all points at a fixed distance from the center + * @ingroup Shapes */ class Circle + : MultipliableNoncommutative< Circle, Translate + , MultipliableNoncommutative< Circle, Rotate + , MultipliableNoncommutative< Circle, Zoom + > > > { - public: - Circle() - {} - - Circle(double cx, double cy, double r) - : m_centre(cx, cy), m_ray(r) - { - } - - Circle(Point center, double r) - : m_centre(center), m_ray(r) - { - } + Point _center; + Coord _radius; - Circle(double A, double B, double C, double D) - { - set(A, B, C, D); - } - - Circle(std::vector const& points) - { - set(points); - } +public: + Circle() {} + Circle(Coord cx, Coord cy, Coord r) + : _center(cx, cy), _radius(r) + {} + Circle(Point const ¢er, Coord r) + : _center(center), _radius(r) + {} - void set(double cx, double cy, double r) - { - m_centre[X] = cx; - m_centre[Y] = cy; - m_ray = r; + Circle(Coord A, Coord B, Coord C, Coord D) { + setCoefficients(A, B, C, D); } - // build a circle by its implicit equation: // Ax^2 + Ay^2 + Bx + Cy + D = 0 - void set(double A, double B, double C, double D); + void setCoefficients(Coord A, Coord B, Coord C, Coord D); - // build up the best fitting circle wrt the passed points - // prerequisite: at least 3 points must be passed - void set(std::vector const& points); + /** @brief Fit the circle to the passed points using the least squares method. + * @param points Samples at the perimeter of the circle */ + void fit(std::vector const &points); EllipticalArc * arc(Point const& initial, Point const& inner, Point const& final, - bool _svg_compliant = true); + bool svg_compliant = true); D2 toSBasis(); - void getPath(std::vector &path_out); + void getPath(PathVector &path_out); - Point center() const - { - return m_centre; - } + Point center() const { return _center; } + Coord center(Dim2 d) const { return _center[d]; } + Coord radius() const { return _radius; } - Coord center(Dim2 d) const - { - return m_centre[d]; - } + void setCenter(Point const &p) { _center = p; } + void setRadius(Coord c) { _radius = c; } - Coord ray() const - { - return m_ray; + Circle &operator*=(Translate const &t) { + _center *= t; + return *this; + } + Circle &operator*=(Rotate const &) { + return *this; + } + Circle &operator*=(Zoom const &z) { + _center *= z; + _radius *= z.scale(); + return *this; } - - - private: - Point m_centre; - Coord m_ray; }; } // end namespace Geom diff --git a/src/2geom/circulator.h b/src/2geom/circulator.h index 9671ce4a9..06e4d2c4e 100644 --- a/src/2geom/circulator.h +++ b/src/2geom/circulator.h @@ -1,5 +1,4 @@ -/** - * @file circulator.h +/** @file * @brief Circular iterator adapter *//* * Copyright 2006 MenTaLguY @@ -29,8 +28,8 @@ * */ -#ifndef SEEN_Circulator_H -#define SEEN_Circulator_H +#ifndef LIB2GEOM_SEEN_CIRCULATOR_H +#define LIB2GEOM_SEEN_CIRCULATOR_H #include @@ -137,7 +136,7 @@ Geom::Circulator operator+(int n, Geom::Circulator const &c) { return c + n; } -#endif // SEEN_Circulator_H +#endif // LIB2GEOM_SEEN_CIRCULATOR_H /* Local Variables: diff --git a/src/2geom/concepts.h b/src/2geom/concepts.h index c89c3a224..f571ddc60 100644 --- a/src/2geom/concepts.h +++ b/src/2geom/concepts.h @@ -35,8 +35,9 @@ #include <2geom/interval.h> #include <2geom/point.h> #include <2geom/rect.h> +#include <2geom/intersection.h> #include -#include +#include #include <2geom/forward.h> namespace Geom { @@ -71,11 +72,13 @@ struct FragmentConcept { SbType sb; void constraints() { t = T(o); - b = t.isZero(); - b = t.isConstant(); + b = t.isZero(d); + b = t.isConstant(d); b = t.isFinite(); o = t.at0(); o = t.at1(); + t.at0() = o; + t.at1() = o; o = t.valueAt(d); o = t(d); v = t.valueAndDerivatives(d, u-1); @@ -96,6 +99,34 @@ struct FragmentConcept { } }; +template +struct ShapeConcept { + typedef typename ShapeTraits::TimeType Time; + typedef typename ShapeTraits::IntervalType Interval; + typedef typename ShapeTraits::AffineClosureType AffineClosure; + //typedef typename ShapeTraits::IntersectionType Isect; + + T shape; + Time t; + Point p; + AffineClosure ac; + Affine m; + Coord c; + bool bool_; + + void constraints() { + p = shape.pointAt(t); + c = shape.valueAt(t, X); + //ivec = shape.intersect(other); + t = shape.nearestTime(p); + ac = shape; + ac *= m; + bool_ = (shape == shape); + bool_ = (shape != shape); + bool_ = shape.isDegenerate(); + } +}; + template inline T portion(const T& t, const Interval& i) { return portion(t, i.min(), i.max()); } diff --git a/src/2geom/conic_section_clipper.h b/src/2geom/conic_section_clipper.h index a02cda4d3..38bba338e 100644 --- a/src/2geom/conic_section_clipper.h +++ b/src/2geom/conic_section_clipper.h @@ -1,7 +1,6 @@ -/** - * \file - * \brief Conic section clipping with respect to a rectangle - * +/** @file + * @brief Conic section clipping with respect to a rectangle + *//* * Authors: * Marco Cecchetti * @@ -34,8 +33,8 @@ -#ifndef _2GEOM_CONIC_SECTION_CLIPPER_H_ -#define _2GEOM_CONIC_SECTION_CLIPPER_H_ +#ifndef LIB2GEOM_SEEN_CONIC_SECTION_CLIPPER_H +#define LIB2GEOM_SEEN_CONIC_SECTION_CLIPPER_H #undef CLIP_WITH_CAIRO_SUPPORT diff --git a/src/2geom/conic_section_clipper_cr.h b/src/2geom/conic_section_clipper_cr.h index 31f5a4269..6c62494de 100644 --- a/src/2geom/conic_section_clipper_cr.h +++ b/src/2geom/conic_section_clipper_cr.h @@ -1,7 +1,6 @@ -/** - * \file - * \brief Conic section clipping with respect to a rectangle - * +/** @file + * @brief Conic section clipping with respect to a rectangle + *//* * Authors: * Marco Cecchetti * @@ -39,8 +38,8 @@ //////////////////////////////////////////////////////////////////////////////// -#ifndef _2GEOM_CONIC_SECTION_CLIPPER_CR_H_ -#define _2GEOM_CONIC_SECTION_CLIPPER_CR_H_ +#ifndef LIB2GEOM_SEEN_CONIC_SECTION_CLIPPER_CR_H +#define LIB2GEOM_SEEN_CONIC_SECTION_CLIPPER_CR_H #define CLIP_WITH_CAIRO_SUPPORT diff --git a/src/2geom/conic_section_clipper_impl.cpp b/src/2geom/conic_section_clipper_impl.cpp index 2867e243c..c57307974 100644 --- a/src/2geom/conic_section_clipper_impl.cpp +++ b/src/2geom/conic_section_clipper_impl.cpp @@ -173,7 +173,7 @@ bool CLIPPER_CLASS::intersect (std::vector & crossing_points) const cpts.size()) // remove duplicates - std::sort (cpts.begin(), cpts.end(), Point::LexOrder()); + std::sort (cpts.begin(), cpts.end(), Point::LexLess()); cpts.erase (std::unique (cpts.begin(), cpts.end()), cpts.end()); @@ -203,7 +203,7 @@ bool CLIPPER_CLASS::intersect (std::vector & crossing_points) const inline double signed_triangle_area (Point const& p1, Point const& p2, Point const& p3) { - return (cross(p3, p2) - cross(p3, p1) + cross(p2, p1)); + return (cross(p2, p3) - cross(p1, p3) + cross(p1, p2)); } @@ -216,6 +216,8 @@ double signed_triangle_area (Point const& p1, Point const& p2, Point const& p3) */ bool CLIPPER_CLASS::are_paired (Point& M, const Point & P1, const Point & P2) const { + using std::swap; + /* * we looks for the points on the conic whose tangent is parallel to the * arc chord P1P2, they will be extrema of the conic arc P1P2 wrt the @@ -257,9 +259,8 @@ bool CLIPPER_CLASS::are_paired (Point& M, const Point & P1, const Point & P2) co if (sgn(side0) == sgn(side1)) { - if (std::fabs(side0) > std::fabs(side1)) - { - std::swap (extrema[0], extrema[1]); + if (std::fabs(side0) > std::fabs(side1)) { + swap(extrema[0], extrema[1]); } extrema.pop_back(); } @@ -371,6 +372,8 @@ void CLIPPER_CLASS::pairing (std::vector & paired_points, */ bool CLIPPER_CLASS::clip (std::vector & arcs) { + using std::swap; + arcs.clear(); std::vector crossing_points; std::vector paired_points; @@ -454,14 +457,14 @@ bool CLIPPER_CLASS::clip (std::vector & arcs) double angle = cs.axis_angle(); Line axis1 (*c, angle); rts = cs.roots (axis1); - if (rts[0] > rts[1]) std::swap (rts[0], rts[1]); + if (rts[0] > rts[1]) swap (rts[0], rts[1]); paired_points[0] = axis1.pointAt (rts[0]); paired_points[1] = axis1.pointAt (rts[1]); paired_points[2] = paired_points[1]; paired_points[3] = paired_points[0]; Line axis2 (*c, angle + M_PI/2); rts = cs.roots (axis2); - if (rts[0] > rts[1]) std::swap (rts[0], rts[1]); + if (rts[0] > rts[1]) swap (rts[0], rts[1]); inner_points.push_back (axis2.pointAt (rts[0])); inner_points.push_back (axis2.pointAt (rts[1])); } diff --git a/src/2geom/conic_section_clipper_impl.h b/src/2geom/conic_section_clipper_impl.h index 37415df97..e38a6d416 100644 --- a/src/2geom/conic_section_clipper_impl.h +++ b/src/2geom/conic_section_clipper_impl.h @@ -1,7 +1,6 @@ -/** - * \file - * \brief Conic section clipping with respect to a rectangle - * +/** @file + * @brief Conic section clipping with respect to a rectangle + *//* * Authors: * Marco Cecchetti * @@ -31,11 +30,8 @@ * the specific language governing rights and limitations. */ - - - -#ifndef _2GEOM_CONIC_SECTION_CLIPPER_IMPL_H_ -#define _2GEOM_CONIC_SECTION_CLIPPER_IMPL_H_ +#ifndef LIB2GEOM_SEEN_CONIC_SECTION_CLIPPER_IMPL_H +#define LIB2GEOM_SEEN_CONIC_SECTION_CLIPPER_IMPL_H #include <2geom/conicsec.h> @@ -336,13 +332,7 @@ void CLIPPER_CLASS::rsplit (std::list & points, } // end namespace Geom - - - -#endif // _2GEOM_CONIC_SECTION_CLIPPER_IMPL_H_ - - - +#endif // LIB2GEOM_SEEN_CONIC_SECTION_CLIPPER_IMPL_H /* Local Variables: diff --git a/src/2geom/conicsec.cpp b/src/2geom/conicsec.cpp index 367dc2503..889797de3 100644 --- a/src/2geom/conicsec.cpp +++ b/src/2geom/conicsec.cpp @@ -40,44 +40,16 @@ #include #include - - - - namespace Geom { LineSegment intersection(Line l, Rect r) { - Point p0, p1; - double a,b,c; - std::vector ifc = l.coefficients(); - a = ifc[0]; - b = ifc[1]; - c = ifc[2]; - if (fabs(b) > fabs(a)) { - p0 = Point(r[0][0], (-c - a*r[0][0])/b); - if (p0[1] < r[1][0]) - p0 = Point((-c - b*r[1][0])/a, r[1][0]); - if (p0[1] > r[1][1]) - p0 = Point((-c - b*r[1][1])/a, r[1][1]); - p1 = Point(r[0][1], (-c - a*r[0][1])/b); - if (p1[1] < r[1][0]) - p1 = Point((-c - b*r[1][0])/a, r[1][0]); - if (p1[1] > r[1][1]) - p1 = Point((-c - b*r[1][1])/a, r[1][1]); + boost::optional seg = l.clip(r); + if (seg) { + return *seg; } else { - p0 = Point((-c - b*r[1][0])/a, r[1][0]); - if (p0[0] < r[0][0]) - p0 = Point(r[0][0], (-c - a*r[0][0])/b); - if (p0[0] > r[0][1]) - p0 = Point(r[0][1], (-c - a*r[0][1])/b); - p1 = Point((-c - b*r[1][1])/a, r[1][1]); - if (p1[0] < r[0][0]) - p1 = Point(r[0][0], (-c - a*r[0][0])/b); - if (p1[0] > r[0][1]) - p1 = Point(r[0][1], (-c - a*r[0][1])/b); + return LineSegment(Point(0,0), Point(0,0)); } - return LineSegment(p0, p1); } static double det(Point a, Point b) { @@ -673,7 +645,7 @@ std::vector xAx::roots(Line const &l) const { Interval xAx::quad_ex(double a, double b, double c, Interval ivl) { double cx = -b*0.5/a; - Interval bnds((a*ivl[0]+b)*ivl[0]+c, (a*ivl[1]+b)*ivl[1]+c); + Interval bnds((a*ivl.min()+b)*ivl.min()+c, (a*ivl.max()+b)*ivl.max()+c); if(ivl.contains(cx)) bnds.expandTo((a*cx+b)*cx+c); return bnds; @@ -714,14 +686,14 @@ Interval xAx::extrema(Rect r) const { ext |= Interval(valueAt(r.corner(i))); return ext; } - double k = r[0][0]; - Interval ext = quad_ex(c[2], c[1]*k+c[4], (c[0]*k + c[3])*k + c[5], r[1]); - k = r[0][1]; - ext |= quad_ex(c[2], c[1]*k+c[4], (c[0]*k + c[3])*k + c[5], r[1]); - k = r[1][0]; - ext |= quad_ex(c[0], c[1]*k+c[3], (c[2]*k + c[4])*k + c[5], r[0]); - k = r[1][1]; - ext |= quad_ex(c[0], c[1]*k+c[3], (c[2]*k + c[4])*k + c[5], r[0]); + double k = r[X].min(); + Interval ext = quad_ex(c[2], c[1]*k+c[4], (c[0]*k + c[3])*k + c[5], r[Y]); + k = r[X].max(); + ext |= quad_ex(c[2], c[1]*k+c[4], (c[0]*k + c[3])*k + c[5], r[Y]); + k = r[Y].min(); + ext |= quad_ex(c[0], c[1]*k+c[3], (c[2]*k + c[4])*k + c[5], r[X]); + k = r[Y].max(); + ext |= quad_ex(c[0], c[1]*k+c[3], (c[2]*k + c[4])*k + c[5], r[X]); boost::optional B0 = bottom(); if (B0 && r.contains(*B0)) ext.expandTo(0); @@ -753,7 +725,7 @@ bool at_infinity (Point const& p) inline double signed_triangle_area (Point const& p1, Point const& p2, Point const& p3) { - return (cross(p3, p2) - cross(p3, p1) + cross(p2, p1)); + return (cross(p2, p3) - cross(p1, p3) + cross(p1, p2)); } @@ -801,6 +773,8 @@ void xAx::set(std::vector const& points) */ void xAx::set (const Point& _vertex, double _angle, double _dist1, double _dist2) { + using std::swap; + if (_dist2 == infinity() || _dist2 == -infinity()) // parabola { if (_dist1 == infinity()) // degenerate to a line @@ -842,7 +816,7 @@ void xAx::set (const Point& _vertex, double _angle, double _dist1, double _dist2 if (std::fabs(_dist1) > std::fabs(_dist2)) { - std::swap (_dist1, _dist2); + swap (_dist1, _dist2); } if (_dist1 < 0) { @@ -1442,38 +1416,35 @@ Rect xAx::arc_bound (const Point & P1, const Point & Q, const Point & P2) const if (sgn(Mside) == sgn(Qside)) { //std::cout << "BOUND: M.size() == 1" << std::endl; - if (M[0][dim] > B[dim][1]) - B[dim][1] = M[0][dim]; - else if (M[0][dim] < B[dim][0]) - B[dim][0] = M[0][dim]; + B[dim].expandTo(M[0][dim]); } } else if (M.size() == 2) { //std::cout << "BOUND: M.size() == 2" << std::endl; if (M[0][dim] > M[1][dim]) - std::swap (M[0], M[1]); + swap (M[0], M[1]); - if (M[0][dim] > B[dim][1]) + if (M[0][dim] > B[dim].max()) { double Mside = signed_triangle_area (P1, M[0], P2); if (sgn(Mside) == sgn(Qside)) - B[dim][1] = M[0][dim]; + B[dim].setMax(M[0][dim]); } - else if (M[1][dim] < B[dim][0]) + else if (M[1][dim] < B[dim].min()) { double Mside = signed_triangle_area (P1, M[1], P2); if (sgn(Mside) == sgn(Qside)) - B[dim][0] = M[1][dim]; + B[dim].setMin(M[1][dim]); } else { double Mside = signed_triangle_area (P1, M[0], P2); if (sgn(Mside) == sgn(Qside)) - B[dim][0] = M[0][dim]; + B[dim].setMin(M[0][dim]); Mside = signed_triangle_area (P1, M[1], P2); if (sgn(Mside) == sgn(Qside)) - B[dim][1] = M[1][dim]; + B[dim].setMax(M[1][dim]); } } } @@ -1486,7 +1457,7 @@ Rect xAx::arc_bound (const Point & P1, const Point & Q, const Point & P2) const * * P: the point to compute the nearest one */ -std::vector xAx::allNearestPoints (const Point &P) const +std::vector xAx::allNearestTimes (const Point &P) const { // TODO: manage the circle - centre case std::vector points; diff --git a/src/2geom/conicsec.h b/src/2geom/conicsec.h index ec9a430d9..e9c466978 100644 --- a/src/2geom/conicsec.h +++ b/src/2geom/conicsec.h @@ -1,7 +1,6 @@ -/** - * \file - * \brief Conic Section - * +/** @file + * @brief Conic Section + *//* * Authors: * Nathan Hurst * @@ -32,8 +31,8 @@ */ -#ifndef _2GEOM_CONIC_SECTION_H_ -#define _2GEOM_CONIC_SECTION_H_ +#ifndef LIB2GEOM_SEEN_CONICSEC_H +#define LIB2GEOM_SEEN_CONICSEC_H #include <2geom/exception.h> #include <2geom/angle.h> @@ -474,22 +473,22 @@ public: Rect arc_bound (const Point & P1, const Point & Q, const Point & P2) const; - std::vector allNearestPoints (const Point &P) const; + std::vector allNearestTimes (const Point &P) const; /* * Return the point on the conic section nearest to the passed point "P". * * P: the point to compute the nearest one */ - Point nearestPoint (const Point &P) const + Point nearestTime (const Point &P) const { - std::vector points = allNearestPoints (P); + std::vector points = allNearestTimes (P); if ( !points.empty() ) { return points.front(); } // else - THROW_LOGICALERROR ("nearestPoint: no nearest point found"); + THROW_LOGICALERROR ("nearestTime: no nearest point found"); return Point(); } @@ -509,8 +508,7 @@ inline std::ostream &operator<< (std::ostream &out_file, const xAx &x) { }; -#endif // _2GEOM_CONIC_SECTION_H_ - +#endif // LIB2GEOM_SEEN_CONICSEC_H /* Local Variables: diff --git a/src/2geom/conjugate_gradient.cpp b/src/2geom/conjugate_gradient.cpp deleted file mode 100644 index 588513414..000000000 --- a/src/2geom/conjugate_gradient.cpp +++ /dev/null @@ -1,143 +0,0 @@ -/* - * conjugate_gradient.cpp - * - * Copyright 2006 Nathan Hurst - * - * This library is free software; you can redistribute it and/or - * modify it either under the terms of the GNU Lesser General Public - * License version 2.1 as published by the Free Software Foundation - * (the "LGPL") or, at your option, under the terms of the Mozilla - * Public License Version 1.1 (the "MPL"). If you do not alter this - * notice, a recipient may use your version of this file under either - * the MPL or the LGPL. - * - * You should have received a copy of the LGPL along with this library - * in the file COPYING-LGPL-2.1; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * You should have received a copy of the MPL along with this library - * in the file COPYING-MPL-1.1 - * - * The contents of this file are subject to the Mozilla Public License - * Version 1.1 (the "License"); you may not use this file except in - * compliance with the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY - * OF ANY KIND, either express or implied. See the LGPL or the MPL for - * the specific language governing rights and limitations. - * - */ - -#include -#include -#include -#include -#include <2geom/conjugate_gradient.h> - -/* lifted wholely from wikipedia. */ - -namespace Geom -{ - -using std::valarray; - -static void -matrix_times_vector(valarray const &matrix, /* m * n */ - valarray const &vec, /* n */ - valarray &result) /* m */ -{ - unsigned n = vec.size(); - unsigned m = result.size(); - assert(m*n == matrix.size()); - const double* mp = &const_cast&>(matrix)[0]; - for (unsigned i = 0; i < m; i++) { - double res = 0; - for (unsigned j = 0; j < n; j++) - res += *mp++ * vec[j]; - result[i] = res; - } -} - -/** -// only used in commented code below -static double Linfty(valarray const &vec) { - return std::max(vec.max(), -vec.min()); -} -**/ - -double -inner(valarray const &x, - valarray const &y) { - double total = 0; - for(unsigned i = 0; i < x.size(); i++) - total += x[i]*y[i]; - return total;// (x*y).sum(); <- this is more concise, but ineff -} - -void -conjugate_gradient(double **A, - double *x, - double *b, - unsigned n, - double tol, - int max_iterations, - bool ortho1) { - valarray vA(n*n); - valarray vx(n); - valarray vb(n); - for(unsigned i=0;i const &A, - valarray &x, - valarray const &b, - unsigned n, double tol, - unsigned max_iterations, bool /*ortho1*/) { - valarray Ap(n), p(n), r(n); - matrix_times_vector(A,x,Ap); - r=b-Ap; - double r_r = inner(r,r); - unsigned k = 0; - tol *= tol; - while(k < max_iterations && r_r > tol) { - k++; - double r_r_new = r_r; - if(k == 1) - p = r; - else { - r_r_new = inner(r,r); - p = r + (r_r_new/r_r)*p; - } - matrix_times_vector(A, p, Ap); - double alpha_k = r_r_new / inner(p, Ap); - x += alpha_k*p; - r -= alpha_k*Ap; - r_r = r_r_new; - } - //printf("njh: %d iters, Linfty = %g L2 = %g\n", k, - //std::max(-r.min(), r.max()), sqrt(r_r)); - // x is solution -} - -} // namespace Geom - -/* - Local Variables: - mode:c++ - c-file-style:"stroustrup" - c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) - indent-tabs-mode:nil - fill-column:99 - End: -*/ -// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 : diff --git a/src/2geom/conjugate_gradient.h b/src/2geom/conjugate_gradient.h deleted file mode 100644 index 4f500c0e6..000000000 --- a/src/2geom/conjugate_gradient.h +++ /dev/null @@ -1,64 +0,0 @@ -/** - * @file - * @brief Routines for solving a system of linear equations using the conjugate gradient method - *//* - * Copyright 2006 Nathan Hurst - * - * This library is free software; you can redistribute it and/or - * modify it either under the terms of the GNU Lesser General Public - * License version 2.1 as published by the Free Software Foundation - * (the "LGPL") or, at your option, under the terms of the Mozilla - * Public License Version 1.1 (the "MPL"). If you do not alter this - * notice, a recipient may use your version of this file under either - * the MPL or the LGPL. - * - * You should have received a copy of the LGPL along with this library - * in the file COPYING-LGPL-2.1; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * You should have received a copy of the MPL along with this library - * in the file COPYING-MPL-1.1 - * - * The contents of this file are subject to the Mozilla Public License - * Version 1.1 (the "License"); you may not use this file except in - * compliance with the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY - * OF ANY KIND, either express or implied. See the LGPL or the MPL for - * the specific language governing rights and limitations. - * - */ - -#ifndef _2GEOM_CONJUGATE_GRADIENT_H -#define _2GEOM_CONJUGATE_GRADIENT_H - -#include - -namespace Geom -{ - -double -inner(std::valarray const &x, - std::valarray const &y); - -void -conjugate_gradient(std::valarray const &A, - std::valarray &x, - std::valarray const &b, - unsigned n, double tol, - unsigned max_iterations, bool ortho1); - -} // namespace Geom - -#endif // _2GEOM_CONJUGATE_GRADIENT_H - -/* - Local Variables: - mode:c++ - c-file-style:"stroustrup" - c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) - indent-tabs-mode:nil - fill-column:99 - End: -*/ -// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 : diff --git a/src/2geom/convex-cover.cpp b/src/2geom/convex-cover.cpp deleted file mode 100644 index 5e599fdde..000000000 --- a/src/2geom/convex-cover.cpp +++ /dev/null @@ -1,712 +0,0 @@ -/* - * convex-cover.cpp - * - * Copyright 2006 Nathan Hurst - * Copyright 2006 Michael G. Sloan - * - * This library is free software; you can redistribute it and/or - * modify it either under the terms of the GNU Lesser General Public - * License version 2.1 as published by the Free Software Foundation - * (the "LGPL") or, at your option, under the terms of the Mozilla - * Public License Version 1.1 (the "MPL"). If you do not alter this - * notice, a recipient may use your version of this file under either - * the MPL or the LGPL. - * - * You should have received a copy of the LGPL along with this library - * in the file COPYING-LGPL-2.1; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * You should have received a copy of the MPL along with this library - * in the file COPYING-MPL-1.1 - * - * The contents of this file are subject to the Mozilla Public License - * Version 1.1 (the "License"); you may not use this file except in - * compliance with the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY - * OF ANY KIND, either express or implied. See the LGPL or the MPL for - * the specific language governing rights and limitations. - * - */ - -#include <2geom/convex-cover.h> -#include <2geom/exception.h> -#include -#include -#include - -/** Todo: - + modify graham scan to work top to bottom, rather than around angles - + intersection - + minimum distance between convex hulls - + maximum distance between convex hulls - + hausdorf metric? - + check all degenerate cases carefully - + check all algorithms meet all invariants - + generalise rotating caliper algorithm (iterator/circulator?) -*/ - -using std::vector; -using std::map; -using std::pair; -using std::make_pair; - -namespace Geom{ - -/*** SignedTriangleArea - * returns the area of the triangle defined by p0, p1, p2. A clockwise triangle has positive area. - */ -double -SignedTriangleArea(Point p0, Point p1, Point p2) { - return cross((p1 - p0), (p2 - p0)); -} - -class angle_cmp{ -public: - Point o; - angle_cmp(Point o) : o(o) {} - -#if 0 - bool - operator()(Point a, Point b) { - // not remove this check or std::sort could crash - if (a == b) return false; - Point da = a - o; - Point db = b - o; - if (da == -db) return false; - -#if 1 - double aa = da[0]; - double ab = db[0]; - if((da[1] == 0) && (db[1] == 0)) - return da[0] < db[0]; - if(da[1] == 0) - return true; // infinite tangent - if(db[1] == 0) - return false; // infinite tangent - aa = da[0] / da[1]; - ab = db[0] / db[1]; - if(aa > ab) - return true; -#else - //assert((ata > atb) == (aa < ab)); - double aa = atan2(da); - double ab = atan2(db); - if(aa < ab) - return true; -#endif - if(aa == ab) - return L2sq(da) < L2sq(db); - return false; - } -#else - bool operator() (Point const& a, Point const& b) - { - // not remove this check or std::sort could generate - // a segmentation fault because it needs a strict '<' - // but due to round errors a == b doesn't mean dxy == dyx - if (a == b) return false; - Point da = a - o; - Point db = b - o; - if (da == -db) return false; - double dxy = da[X] * db[Y]; - double dyx = da[Y] * db[X]; - if (dxy > dyx) return true; - else if (dxy < dyx) return false; - return L2sq(da) < L2sq(db); - } -#endif -}; - -void -ConvexHull::find_pivot() { - // Find pivot P; - unsigned pivot = 0; - for (unsigned i = 1; i < boundary.size(); i++) - if(boundary[i] <= boundary[pivot]) - pivot = i; - - std::swap(boundary[0], boundary[pivot]); -} - -void -ConvexHull::angle_sort() { -// sort points by angle (resolve ties in favor of point farther from P); -// we leave the first one in place as our pivot - std::sort(boundary.begin()+1, boundary.end(), angle_cmp(boundary[0])); -} - - -void -ConvexHull::graham_scan() { - // prune out equal points. points are sorted, so equals are adjacent - std::vector::iterator e = - std::unique(boundary.begin(), boundary.end()); - boundary.resize(e - boundary.begin()); - for(unsigned int i = 2; i < boundary.size(); i++) { - - } - if (boundary.size() < 4) { - return; - } - unsigned stac = 2; - for(unsigned int i = 2; i < boundary.size(); i++) { - double o = SignedTriangleArea(boundary[stac-2], - boundary[stac-1], - boundary[i]); - if(o == 0) { // colinear - dangerous... - stac--; - } else if(o < 0) { // anticlockwise - } else { // remove concavity - while(o >= 0 && stac > 2) { - stac--; - o = SignedTriangleArea(boundary[stac-2], - boundary[stac-1], - boundary[i]); - } - } - boundary[stac++] = boundary[i]; - } - boundary.resize(stac); -} - -// following code is from marco. - -/* - * return true in case the oriented polyline p0, p1, p2 is a right turn - */ -inline -bool is_a_right_turn (Point const& p0, Point const& p1, Point const& p2) -{ - if (p1 == p2) return false; - Point q1 = p1 - p0; - Point q2 = p2 - p0; - if (q1 == -q2) return false; - return (cross (q1, q2) < 0); -} - -/* - * return true if p < q wrt the lexicographyc order induced by the coordinates - */ -struct lex_less -{ - bool operator() (Point const& p, Point const& q) - { - return ((p[Y] < q[Y]) || (p[Y] == q[Y] && p[X] < q[X])); - } -}; - -/* - * return true if p > q wrt the lexicographyc order induced by the coordinates - */ -struct lex_greater -{ - bool operator() (Point const& p, Point const& q) - { - return ((p[Y] > q[Y]) || (p[Y] == q[Y] && p[X] > q[X])); - } -}; - -/* - * Compute the convex hull of a set of points. - * The implementation is based on the Andrew's scan algorithm - * note: in the Bezier clipping for collinear normals it seems - * to be more stable wrt the Graham's scan algorithm and in general - * a bit quikier - */ -void ConvexHull::andrew_scan () -{ - vector & P = boundary; - size_t n = P.size(); - if (n < 2) return; - std::sort(P.begin(), P.end(), lex_less()); - if (n < 4) return; - // upper hull - size_t u = 2; - for (size_t i = 2; i < n; ++i) - { - while (u > 1 && !is_a_right_turn(P[u-2], P[u-1], P[i])) - { - --u; - } - std::swap(P[u], P[i]); - ++u; - } - std::sort(P.begin() + u, P.end(), lex_greater()); - std::rotate(P.begin(), P.begin() + 1, P.end()); - // lower hull - size_t l = u; - size_t k = u - 1; - for (size_t i = l; i < n; ++i) - { - while (l > k && !is_a_right_turn(P[l-2], P[l-1], P[i])) - { - --l; - } - std::swap(P[l], P[i]); - ++l; - } - P.resize(l); -} - -void -ConvexHull::graham() { - /*if(is_degenerate()) // nothing to do - return;*/ - //find_pivot(); - //angle_sort(); - //graham_scan(); - andrew_scan(); -} - -//Mathematically incorrect mod, but more useful. -int mod(int i, int l) { - return i >= 0 ? - i % l : (i % l) + l; -} -//OPT: usages can often be replaced by conditions - -/*** ConvexHull::left - * Tests if a point is left (outside) of a particular segment, n. */ -bool -ConvexHull::is_left(Point p, int n) { - return SignedTriangleArea((*this)[n], (*this)[n+1], p) > 0; -} - -/*** ConvexHull::strict_left - * Tests if a point is left (outside) of a particular segment, n. */ -bool -ConvexHull::is_strict_left(Point p, int n) { - return SignedTriangleArea((*this)[n], (*this)[n+1], p) >= 0; -} - -/*** ConvexHull::find_left - * May return any number n where the segment n -> n + 1 (possibly looped around) in the hull such - * that the point is on the wrong side to be within the hull. Returns -1 if it is within the hull.*/ -int -ConvexHull::find_left(Point p) { - int l = boundary.size(); //Who knows if C++ is smart enough to optimize this? - for(int i = 0; i < l; i++) { - if(is_left(p, i)) return i; - } - return -1; -} - - -/*** ConvexHull::find_positive - * May return any number n where the segment n -> n + 1 (possibly looped around) in the hull such - * that the point is on the wrong side to be within the hull. Returns -1 if it is within the hull.*/ -int -ConvexHull::find_strict_left(Point p) { - int l = boundary.size(); //Who knows if C++ is smart enough to optimize this? - for(int i = 0; i < l; i++) { - if(is_strict_left(p, i)) return i; - } - return -1; -} - -//OPT: do a spread iteration - quasi-random with no repeats and full coverage. - -/*** ConvexHull::contains_point - * In order to test whether a point is inside a convex hull we can travel once around the outside making - * sure that each triangle made from an edge and the point has positive area. */ -bool -ConvexHull::contains_point(Point p) { - if(size() == 0) return false; - return find_left(p) == -1; -} - -/*** ConvexHull::strict_contains_point - * In order to test whether a point is strictly inside (not on the boundary) a convex hull we can travel once around the outside making - * sure that each triangle made from an edge and the point has positive area. */ -bool -ConvexHull::strict_contains_point(Point p) { - if(size() == 0) return false; - return find_strict_left(p) == -1; -} - -/*** ConvexHull::add_point - * to add a point we need to find whether the new point extends the boundary, and if so, what it - * obscures. Tarjan? Jarvis?*/ -void -ConvexHull::merge(Point p) { - std::vector out; - - int l = boundary.size(); - - if(l < 2) { - if(boundary.empty() || boundary[0] != p) - boundary.push_back(p); - return; - } - - bool pushed = false; - - bool pre = is_left(p, -1); - for(int i = 0; i < l; i++) { - bool cur = is_left(p, i); - if(pre) { - if(cur) { - if(!pushed) { - out.push_back(p); - pushed = true; - } - continue; - } - else if(!pushed) { - out.push_back(p); - pushed = true; - } - } - out.push_back(boundary[i]); - pre = cur; - } - - boundary = out; -} -//OPT: quickly find an obscured point and find the bounds by extending from there. then push all points not within the bounds in order. - //OPT: use binary searches to find the actual starts/ends, use known rights as boundaries. may require cooperation of find_left algo. - -/*** ConvexHull::is_clockwise - * We require that successive pairs of edges always turn right. - * We return false on collinear points - * proposed algorithm: walk successive edges and require triangle area is positive. - */ -bool -ConvexHull::is_clockwise() const { - if(is_degenerate()) - return true; - Point first = boundary[0]; - Point second = boundary[1]; - for(std::vector::const_iterator it(boundary.begin()+2), e(boundary.end()); - it != e;) { - if(SignedTriangleArea(first, second, *it) > 0) - return false; - first = second; - second = *it; - ++it; - } - return true; -} - -/*** ConvexHull::top_point_first - * We require that the first point in the convex hull has the least y coord, and that off all such points on the hull, it has the least x coord. - * proposed algorithm: track lexicographic minimum while walking the list. - */ -bool -ConvexHull::top_point_first() const { - if(size() <= 1) return true; - std::vector::const_iterator pivot = boundary.begin(); - for(std::vector::const_iterator it(boundary.begin()+1), - e(boundary.end()); - it != e; it++) { - if((*it)[1] < (*pivot)[1]) - pivot = it; - else if(((*it)[1] == (*pivot)[1]) && - ((*it)[0] < (*pivot)[0])) - pivot = it; - } - return pivot == boundary.begin(); -} -//OPT: since the Y values are orderly there should be something like a binary search to do this. - -bool -ConvexHull::meets_invariants() const { - return is_clockwise() && top_point_first(); -} - -/*** ConvexHull::is_degenerate - * We allow three degenerate cases: empty, 1 point and 2 points. In many cases these should be handled explicitly. - */ -bool -ConvexHull::is_degenerate() const { - return boundary.size() < 3; -} - - -int sgn(double x) { - if(x == 0) return 0; - return (x<0)?-1:1; -} - -bool same_side(Point L[2], Point xs[4]) { - int side = 0; - for(int i = 0; i < 4; i++) { - int sn = sgn(SignedTriangleArea(L[0], L[1], xs[i])); - if(sn && !side) - side = sn; - else if(sn != side) return false; - } - return true; -} - -/** find bridging pairs between two convex hulls. - * this code is based on Hormoz Pirzadeh's masters thesis. There is room for optimisation: - * 1. reduce recomputation - * 2. use more efficient angle code - * 3. write as iterator - */ -std::vector > bridges(ConvexHull a, ConvexHull b) { - vector > ret; - - // 1. find maximal points on a and b - int ai = 0, bi = 0; - // 2. find first copodal pair - double ap_angle = atan2(a[ai+1] - a[ai]); - double bp_angle = atan2(b[bi+1] - b[bi]); - Point L[2] = {a[ai], b[bi]}; - while(ai < int(a.size()) || bi < int(b.size())) { - if(ap_angle == bp_angle) { - // In the case of parallel support lines, we must consider all four pairs of copodal points - { - assert(0); // untested - Point xs[4] = {a[ai-1], a[ai+1], b[bi-1], b[bi+1]}; - if(same_side(L, xs)) ret.push_back(make_pair(ai, bi)); - xs[2] = b[bi]; - xs[3] = b[bi+2]; - if(same_side(L, xs)) ret.push_back(make_pair(ai, bi)); - xs[0] = a[ai]; - xs[1] = a[ai+2]; - if(same_side(L, xs)) ret.push_back(make_pair(ai, bi)); - xs[2] = b[bi-1]; - xs[3] = b[bi+1]; - if(same_side(L, xs)) ret.push_back(make_pair(ai, bi)); - } - ai++; - ap_angle += angle_between(a[ai] - a[ai-1], a[ai+1] - a[ai]); - L[0] = a[ai]; - bi++; - bp_angle += angle_between(b[bi] - b[bi-1], b[bi+1] - b[bi]); - L[1] = b[bi]; - std::cout << "parallel\n"; - } else if(ap_angle < bp_angle) { - ai++; - ap_angle += angle_between(a[ai] - a[ai-1], a[ai+1] - a[ai]); - L[0] = a[ai]; - Point xs[4] = {a[ai-1], a[ai+1], b[bi-1], b[bi+1]}; - if(same_side(L, xs)) ret.push_back(make_pair(ai, bi)); - } else { - bi++; - bp_angle += angle_between(b[bi] - b[bi-1], b[bi+1] - b[bi]); - L[1] = b[bi]; - Point xs[4] = {a[ai-1], a[ai+1], b[bi-1], b[bi+1]}; - if(same_side(L, xs)) ret.push_back(make_pair(ai, bi)); - } - } - return ret; -} - -unsigned find_bottom_right(ConvexHull const &a) { - unsigned it = 1; - while(it < a.boundary.size() && - a.boundary[it][Y] > a.boundary[it-1][Y]) - it++; - return it-1; -} - -/*** ConvexHull sweepline_intersection(ConvexHull a, ConvexHull b); - * find the intersection between two convex hulls. The intersection is also a convex hull. - * (Proof: take any two points both in a and in b. Any point between them is in a by convexity, - * and in b by convexity, thus in both. Need to prove still finite bounds.) - * This algorithm works by sweeping a line down both convex hulls in parallel, working out the left and right edges of the new hull. - */ -ConvexHull sweepline_intersection(ConvexHull const &a, ConvexHull const &b) { - ConvexHull ret; - - unsigned al = 0; - unsigned bl = 0; - - while(al+1 < a.boundary.size() && - (a.boundary[al+1][Y] > b.boundary[bl][Y])) { - al++; - } - while(bl+1 < b.boundary.size() && - (b.boundary[bl+1][Y] > a.boundary[al][Y])) { - bl++; - } - // al and bl now point to the top of the first pair of edges that overlap in y value - //double sweep_y = std::min(a.boundary[al][Y], - // b.boundary[bl][Y]); - return ret; -} - -/*** ConvexHull intersection(ConvexHull a, ConvexHull b); - * find the intersection between two convex hulls. The intersection is also a convex hull. - * (Proof: take any two points both in a and in b. Any point between them is in a by convexity, - * and in b by convexity, thus in both. Need to prove still finite bounds.) - */ -ConvexHull intersection(ConvexHull /*a*/, ConvexHull /*b*/) { - ConvexHull ret; - /* - int ai = 0, bi = 0; - int aj = a.boundary.size() - 1; - int bj = b.boundary.size() - 1; - */ - /*while (true) { - if(a[ai] - }*/ - return ret; -} - -template -T idx_to_pair(pair p, int idx) { - return idx?p.second:p.first; -} - -/*** ConvexHull merge(ConvexHull a, ConvexHull b); - * find the smallest convex hull that surrounds a and b. - */ -ConvexHull merge(ConvexHull a, ConvexHull b) { - ConvexHull ret; - - std::cout << "---\n"; - std::vector > bpair = bridges(a, b); - - // Given our list of bridges {(pb1, qb1), ..., (pbk, qbk)} - // we start with the highest point in p0, q0, say it is p0. - // then the merged hull is p0, ..., pb1, qb1, ..., qb2, pb2, ... - // In other words, either of the two polygons vertices are added in order until the vertex coincides with a bridge point, at which point we swap. - - unsigned state = (a[0][Y] < b[0][Y])?0:1; - ret.boundary.reserve(a.size() + b.size()); - ConvexHull chs[2] = {a, b}; - unsigned idx = 0; - - for(unsigned k = 0; k < bpair.size(); k++) { - unsigned limit = idx_to_pair(bpair[k], state); - std::cout << bpair[k].first << " , " << bpair[k].second << "; " - << idx << ", " << limit << ", s: " - << state - << " \n"; - while(idx <= limit) { - ret.boundary.push_back(chs[state][idx++]); - } - state = 1-state; - idx = idx_to_pair(bpair[k], state); - } - while(idx < chs[state].size()) { - ret.boundary.push_back(chs[state][idx++]); - } - return ret; -} - -ConvexHull graham_merge(ConvexHull a, ConvexHull b) { - ConvexHull result; - - // we can avoid the find pivot step because of top_point_first - if(b.boundary[0] <= a.boundary[0]) - std::swap(a, b); - - result.boundary = a.boundary; - result.boundary.insert(result.boundary.end(), - b.boundary.begin(), b.boundary.end()); - -/** if we modified graham scan to work top to bottom as proposed in lect754.pdf we could replace the - angle sort with a simple merge sort type algorithm. furthermore, we could do the graham scan - online, avoiding a bunch of memory copies. That would probably be linear. -- njh*/ - result.angle_sort(); - result.graham_scan(); - - return result; -} - -ConvexHull andrew_merge(ConvexHull a, ConvexHull b) { - ConvexHull result; - - // we can avoid the find pivot step because of top_point_first - if(b.boundary[0] <= a.boundary[0]) - std::swap(a, b); - - result.boundary = a.boundary; - result.boundary.insert(result.boundary.end(), - b.boundary.begin(), b.boundary.end()); - -/** if we modified graham scan to work top to bottom as proposed in lect754.pdf we could replace the - angle sort with a simple merge sort type algorithm. furthermore, we could do the graham scan - online, avoiding a bunch of memory copies. That would probably be linear. -- njh*/ - result.andrew_scan(); - - return result; -} - -//TODO: reinstate -/*ConvexCover::ConvexCover(Path const &sp) : path(&sp) { - cc.reserve(sp.size()); - for(Geom::Path::const_iterator it(sp.begin()), end(sp.end()); it != end; ++it) { - cc.push_back(ConvexHull((*it).begin(), (*it).end())); - } -}*/ - -double ConvexHull::centroid_and_area(Geom::Point& centroid) const { - const unsigned n = boundary.size(); - if (n < 2) - return 0; - if(n < 3) { - centroid = (boundary[0] + boundary[1])/2; - return 0; - } - Geom::Point centroid_tmp(0,0); - double atmp = 0; - for (unsigned i = n-1, j = 0; j < n; i = j, j++) { - const double ai = cross(boundary[j], boundary[i]); - atmp += ai; - centroid_tmp += (boundary[j] + boundary[i])*ai; // first moment. - } - if (atmp != 0) { - centroid = centroid_tmp / (3 * atmp); - } - return atmp / 2; -} - -// TODO: This can be made lg(n) using golden section/fibonacci search three starting points, say 0, -// n/2, n-1 construct a new point, say (n/2 + n)/2 throw away the furthest boundary point iterate -// until interval is a single value -Point const * ConvexHull::furthest(Point direction) const { - Point const * p = &boundary[0]; - double d = dot(*p, direction); - for(unsigned i = 1; i < boundary.size(); i++) { - double dd = dot(boundary[i], direction); - if(d < dd) { - p = &boundary[i]; - d = dd; - } - } - return p; -} - - -// returns (a, (b,c)), three points which define the narrowest diameter of the hull as the pair of -// lines going through b,c, and through a, parallel to b,c TODO: This can be made linear time by -// moving point tc incrementally from the previous value (it can only move in one direction). It -// is currently n*O(furthest) -double ConvexHull::narrowest_diameter(Point &a, Point &b, Point &c) { - Point tb = boundary.back(); - double d = std::numeric_limits::max(); - for(unsigned i = 0; i < boundary.size(); i++) { - Point tc = boundary[i]; - Point n = -rot90(tb-tc); - Point ta = *furthest(n); - double td = dot(n, ta-tb)/dot(n,n); - if(td < d) { - a = ta; - b = tb; - c = tc; - d = td; - } - tb = tc; - } - return d; -} - -}; - -/* - Local Variables: - mode:c++ - c-file-style:"stroustrup" - c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) - indent-tabs-mode:nil - fill-column:99 - End: -*/ -// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 : diff --git a/src/2geom/convex-cover.h b/src/2geom/convex-cover.h deleted file mode 100644 index d290b7e80..000000000 --- a/src/2geom/convex-cover.h +++ /dev/null @@ -1,204 +0,0 @@ -/** - * \file - * \brief Dynamic convex hull structure - * - * Copyright 2006 Nathan Hurst - * Copyright 2006 Michael G. Sloan - * - * This library is free software; you can redistribute it and/or - * modify it either under the terms of the GNU Lesser General Public - * License version 2.1 as published by the Free Software Foundation - * (the "LGPL") or, at your option, under the terms of the Mozilla - * Public License Version 1.1 (the "MPL"). If you do not alter this - * notice, a recipient may use your version of this file under either - * the MPL or the LGPL. - * - * You should have received a copy of the LGPL along with this library - * in the file COPYING-LGPL-2.1; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * You should have received a copy of the MPL along with this library - * in the file COPYING-MPL-1.1 - * - * The contents of this file are subject to the Mozilla Public License - * Version 1.1 (the "License"); you may not use this file except in - * compliance with the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY - * OF ANY KIND, either express or implied. See the LGPL or the MPL for - * the specific language governing rights and limitations. - * - */ - -#ifndef GEOM_CONVEX_COVER_H -#define GEOM_CONVEX_COVER_H - -#include <2geom/point.h> -#include - -namespace Geom{ - -/* A convex cover is a sequence of convex polygons that completely cover the path. For now a - * convex hull class is included here (the convex-hull header is wrong) - */ - -/** ConvexHull - * A convexhull is a convex region - every point between two points in the convex hull is also in - * the convex hull. It is defined by a set of points travelling in a clockwise direction. We require the first point to be top most, and of the topmost, leftmost. - - * An empty hull has no points, we allow a single point or two points degenerate cases. - - * We could provide the centroid as a member for efficient direction determination. We can update the - * centroid with all operations with the same time complexity as the operation. - */ - -class ConvexHull{ -public: // XXX: should be private :) - // extracts the convex hull of boundary. internal use only - void find_pivot(); - void angle_sort(); - void graham_scan(); - void andrew_scan(); - void graham(); -public: - std::vector boundary; - //Point centroid; - - void merge(Point p); - bool contains_point(Point p); - bool strict_contains_point(Point p); - - inline size_t size() const { return boundary.size();} - inline Point operator[](int i) const { - - int l = boundary.size(); - if(l == 0) return Point(); - return boundary[i >= 0 ? i % l : (i % l) + l]; - } - - /*inline Point &operator[](unsigned i) { - int l = boundary.size(); - if(l == 0) return Point(); - return boundary[i >= 0 ? i % l : i % l + l]; - }*/ - -public: - ConvexHull() {} - ConvexHull(std::vector const & points) : - boundary (points) - { - graham(); - } - - template - ConvexHull(T b, T e) :boundary(b,e) {} - - ~ConvexHull() - { - } - -public: - /** Is the convex hull clockwise? We use the definition of clockwise from point.h - **/ - bool is_clockwise() const; - bool top_point_first() const; - bool meets_invariants() const; - - // contains no points - bool empty() const { return boundary.empty();} - - // contains exactly one point - bool singular() const { return boundary.size() == 1;} - - // all points are on a line - bool linear() const { return boundary.size() == 2;} - bool is_degenerate() const; - - // area of the convex hull - double centroid_and_area(Geom::Point& centroid) const; - double area() const { - Point tmp; - return centroid_and_area(tmp); - } - - // furthest point in a direction (lg time) - Point const * furthest(Point direction) const; - - bool is_left(Point p, int n); - bool is_strict_left(Point p, int n); - int find_left(Point p); - int find_strict_left(Point p); - double narrowest_diameter(Point &a, Point &b, Point &c); - -}; -/** @brief Output operator for points. - * Prints out all the coordinates. */ -inline std::ostream &operator<< (std::ostream &out_file, const Geom::ConvexHull &in_cvx) { - out_file << "ConvexHull("; - for(unsigned i = 0; i < in_cvx.size(); i++) { - out_file << in_cvx.boundary[i] << ", "; - } - out_file << ")"; - return out_file; -} - -// do two convex hulls intersect? -bool intersectp(ConvexHull a, ConvexHull b); - -std::vector > bridges(ConvexHull a, ConvexHull b); - -// find the convex hull intersection -ConvexHull intersection(ConvexHull a, ConvexHull b); -ConvexHull sweepline_intersection(ConvexHull const &a, ConvexHull const &b); - -// find the convex hull of a set of convex hulls -ConvexHull merge(ConvexHull a, ConvexHull b); - -// naive approach -ConvexHull graham_merge(ConvexHull a, ConvexHull b); - -// naive approach -ConvexHull andrew_merge(ConvexHull a, ConvexHull b); - -unsigned find_bottom_right(ConvexHull const &a); - -/*** Arbitrary transform operator. - * Take a convex hull and apply an arbitrary convexity preserving transform. - * we should be concerned about singular tranforms here. - */ -template ConvexHull operator*(ConvexHull const &p, T const &m) { - ConvexHull pr; - - pr.boundary.reserve(p.boundary.size()); - - for(unsigned i = 0; i < p.boundary.size(); i++) { - pr.boundary.push_back(p.boundary[i]*m); - } - return pr; -} - -ConvexHull clip(ConvexHull const & ch, Point n, double d); - -//TODO: reinstate -/*class ConvexCover{ -public: - Path const* path; - std::vector cc; - - ConvexCover(Path const &sp); -};*/ - -}; - -#endif //2GEOM_CONVEX_COVER_H - -/* - Local Variables: - mode:c++ - c-file-style:"stroustrup" - c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) - indent-tabs-mode:nil - fill-column:99 - End: -*/ -// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 : diff --git a/src/2geom/convex-hull.cpp b/src/2geom/convex-hull.cpp new file mode 100644 index 000000000..4f5e06733 --- /dev/null +++ b/src/2geom/convex-hull.cpp @@ -0,0 +1,746 @@ +/** @file + * @brief Convex hull of a set of points + *//* + * Authors: + * Nathan Hurst + * Michael G. Sloan + * Krzysztof Kosiński + * Copyright 2006-2015 Authors + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + */ + +#include <2geom/convex-hull.h> +#include <2geom/exception.h> +#include +#include +#include +#include +#include + +/** Todo: + + modify graham scan to work top to bottom, rather than around angles + + intersection + + minimum distance between convex hulls + + maximum distance between convex hulls + + hausdorf metric? + + check all degenerate cases carefully + + check all algorithms meet all invariants + + generalise rotating caliper algorithm (iterator/circulator?) +*/ + +using std::vector; +using std::map; +using std::pair; +using std::make_pair; +using std::swap; + +namespace Geom { + +ConvexHull::ConvexHull(Point const &a, Point const &b) + : _boundary(2) + , _lower(0) +{ + _boundary[0] = a; + _boundary[1] = b; + std::sort(_boundary.begin(), _boundary.end(), Point::LexLess()); + _construct(); +} + +ConvexHull::ConvexHull(Point const &a, Point const &b, Point const &c) + : _boundary(3) + , _lower(0) +{ + _boundary[0] = a; + _boundary[1] = b; + _boundary[2] = c; + std::sort(_boundary.begin(), _boundary.end(), Point::LexLess()); + _construct(); +} + +ConvexHull::ConvexHull(Point const &a, Point const &b, Point const &c, Point const &d) + : _boundary(4) + , _lower(0) +{ + _boundary[0] = a; + _boundary[1] = b; + _boundary[2] = c; + _boundary[3] = d; + std::sort(_boundary.begin(), _boundary.end(), Point::LexLess()); + _construct(); +} + +ConvexHull::ConvexHull(std::vector const &pts) + : _lower(0) +{ + //if (pts.size() > 16) { // arbitrary threshold + // _prune(pts.begin(), pts.end(), _boundary); + //} else { + _boundary = pts; + std::sort(_boundary.begin(), _boundary.end(), Point::LexLess()); + //} + _construct(); +} + +bool ConvexHull::_is_clockwise_turn(Point const &a, Point const &b, Point const &c) +{ + if (b == c) return false; + return cross(b-a, c-a) > 0; +} + +void ConvexHull::_construct() +{ + // _boundary must already be sorted in LexLess order + if (_boundary.empty()) { + _lower = 0; + return; + } + if (_boundary.size() == 1 || (_boundary.size() == 2 && _boundary[0] == _boundary[1])) { + _boundary.resize(1); + _lower = 1; + return; + } + if (_boundary.size() == 2) { + _lower = 2; + return; + } + + std::size_t k = 2; + for (std::size_t i = 2; i < _boundary.size(); ++i) { + while (k >= 2 && !_is_clockwise_turn(_boundary[k-2], _boundary[k-1], _boundary[i])) { + --k; + } + std::swap(_boundary[k++], _boundary[i]); + } + + _lower = k; + std::sort(_boundary.begin() + k, _boundary.end(), Point::LexGreater()); + _boundary.push_back(_boundary.front()); + for (std::size_t i = _lower; i < _boundary.size(); ++i) { + while (k > _lower && !_is_clockwise_turn(_boundary[k-2], _boundary[k-1], _boundary[i])) { + --k; + } + std::swap(_boundary[k++], _boundary[i]); + } + + _boundary.resize(k-1); +} + +double ConvexHull::area() const +{ + if (size() <= 2) return 0; + + double a = 0; + for (std::size_t i = 0; i < size()-1; ++i) { + a += cross(_boundary[i], _boundary[i+1]); + } + a += cross(_boundary.back(), _boundary.front()); + return fabs(a * 0.5); +} + +OptRect ConvexHull::bounds() const +{ + OptRect ret; + if (empty()) return ret; + ret = Rect(left(), top(), right(), bottom()); + return ret; +} + +Point ConvexHull::topPoint() const +{ + Point ret; + ret[Y] = std::numeric_limits::infinity(); + + for (UpperIterator i = upperHull().begin(); i != upperHull().end(); ++i) { + if (ret[Y] >= i->y()) { + ret = *i; + } else { + break; + } + } + + return ret; +} + +Point ConvexHull::bottomPoint() const +{ + Point ret; + ret[Y] = -std::numeric_limits::infinity(); + + for (LowerIterator j = lowerHull().begin(); j != lowerHull().end(); ++j) { + if (ret[Y] <= j->y()) { + ret = *j; + } else { + break; + } + } + + return ret; +} + +template +bool below_x_monotonic_polyline(Point const &p, Iter first, Iter last, Lex lex) +{ + typename Lex::Secondary above; + Iter f = std::lower_bound(first, last, p, lex); + if (f == last) return false; + if (f == first) { + if (p == *f) return true; + return false; + } + + Point a = *(f-1), b = *f; + if (a[X] == b[X]) { + if (above(p[Y], a[Y]) || above(b[Y], p[Y])) return false; + } else { + // TODO: maybe there is a more numerically stable method + Coord y = lerp((p[X] - a[X]) / (b[X] - a[X]), a[Y], b[Y]); + if (above(p[Y], y)) return false; + } + return true; +} + +bool ConvexHull::contains(Point const &p) const +{ + if (_boundary.empty()) return false; + if (_boundary.size() == 1) { + if (_boundary[0] == p) return true; + return false; + } + + // 1. verify that the point is in the relevant X range + if (p[X] < _boundary[0][X] || p[X] > _boundary[_lower-1][X]) return false; + + // 2. check whether it is below the upper hull + UpperIterator ub = upperHull().begin(), ue = upperHull().end(); + if (!below_x_monotonic_polyline(p, ub, ue, Point::LexLess())) return false; + + // 3. check whether it is above the lower hull + LowerIterator lb = lowerHull().begin(), le = lowerHull().end(); + if (!below_x_monotonic_polyline(p, lb, le, Point::LexGreater())) return false; + + return true; +} + +bool ConvexHull::contains(Rect const &r) const +{ + for (unsigned i = 0; i < 4; ++i) { + if (!contains(r.corner(i))) return false; + } + return true; +} + +bool ConvexHull::contains(ConvexHull const &ch) const +{ + // TODO: requires interiorContains. + // We have to check all points of ch, and each point takes logarithmic time. + // If there are more points in ch that here, it is faster to make the check + // the other way around. + /*if (ch.size() > size()) { + for (iterator i = begin(); i != end(); ++i) { + if (ch.interiorContains(*i)) return false; + } + return true; + }*/ + + for (iterator i = ch.begin(); i != ch.end(); ++i) { + if (!contains(*i)) return false; + } + return true; +} + +void ConvexHull::swap(ConvexHull &other) +{ + _boundary.swap(other._boundary); + std::swap(_lower, other._lower); +} + +void ConvexHull::swap(std::vector &pts) +{ + _boundary.swap(pts); + _lower = 0; + std::sort(_boundary.begin(), _boundary.end(), Point::LexLess()); + _construct(); +} + +#if 0 +/*** SignedTriangleArea + * returns the area of the triangle defined by p0, p1, p2. A clockwise triangle has positive area. + */ +double +SignedTriangleArea(Point p0, Point p1, Point p2) { + return cross((p1 - p0), (p2 - p0)); +} + +class angle_cmp{ +public: + Point o; + angle_cmp(Point o) : o(o) {} + +#if 0 + bool + operator()(Point a, Point b) { + // not remove this check or std::sort could crash + if (a == b) return false; + Point da = a - o; + Point db = b - o; + if (da == -db) return false; + +#if 1 + double aa = da[0]; + double ab = db[0]; + if((da[1] == 0) && (db[1] == 0)) + return da[0] < db[0]; + if(da[1] == 0) + return true; // infinite tangent + if(db[1] == 0) + return false; // infinite tangent + aa = da[0] / da[1]; + ab = db[0] / db[1]; + if(aa > ab) + return true; +#else + //assert((ata > atb) == (aa < ab)); + double aa = atan2(da); + double ab = atan2(db); + if(aa < ab) + return true; +#endif + if(aa == ab) + return L2sq(da) < L2sq(db); + return false; + } +#else + bool operator() (Point const& a, Point const& b) + { + // not remove this check or std::sort could generate + // a segmentation fault because it needs a strict '<' + // but due to round errors a == b doesn't mean dxy == dyx + if (a == b) return false; + Point da = a - o; + Point db = b - o; + if (da == -db) return false; + double dxy = da[X] * db[Y]; + double dyx = da[Y] * db[X]; + if (dxy > dyx) return true; + else if (dxy < dyx) return false; + return L2sq(da) < L2sq(db); + } +#endif +}; + +//Mathematically incorrect mod, but more useful. +int mod(int i, int l) { + return i >= 0 ? + i % l : (i % l) + l; +} +//OPT: usages can often be replaced by conditions + +/*** ConvexHull::add_point + * to add a point we need to find whether the new point extends the boundary, and if so, what it + * obscures. Tarjan? Jarvis?*/ +void +ConvexHull::merge(Point p) { + std::vector out; + + int len = boundary.size(); + + if(len < 2) { + if(boundary.empty() || boundary[0] != p) + boundary.push_back(p); + return; + } + + bool pushed = false; + + bool pre = is_left(p, -1); + for(int i = 0; i < len; i++) { + bool cur = is_left(p, i); + if(pre) { + if(cur) { + if(!pushed) { + out.push_back(p); + pushed = true; + } + continue; + } + else if(!pushed) { + out.push_back(p); + pushed = true; + } + } + out.push_back(boundary[i]); + pre = cur; + } + + boundary = out; +} +//OPT: quickly find an obscured point and find the bounds by extending from there. then push all points not within the bounds in order. + //OPT: use binary searches to find the actual starts/ends, use known rights as boundaries. may require cooperation of find_left algo. + +/*** ConvexHull::is_clockwise + * We require that successive pairs of edges always turn right. + * We return false on collinear points + * proposed algorithm: walk successive edges and require triangle area is positive. + */ +bool +ConvexHull::is_clockwise() const { + if(is_degenerate()) + return true; + Point first = boundary[0]; + Point second = boundary[1]; + for(std::vector::const_iterator it(boundary.begin()+2), e(boundary.end()); + it != e;) { + if(SignedTriangleArea(first, second, *it) > 0) + return false; + first = second; + second = *it; + ++it; + } + return true; +} + +/*** ConvexHull::top_point_first + * We require that the first point in the convex hull has the least y coord, and that off all such points on the hull, it has the least x coord. + * proposed algorithm: track lexicographic minimum while walking the list. + */ +bool +ConvexHull::top_point_first() const { + if(size() <= 1) return true; + std::vector::const_iterator pivot = boundary.begin(); + for(std::vector::const_iterator it(boundary.begin()+1), + e(boundary.end()); + it != e; it++) { + if((*it)[1] < (*pivot)[1]) + pivot = it; + else if(((*it)[1] == (*pivot)[1]) && + ((*it)[0] < (*pivot)[0])) + pivot = it; + } + return pivot == boundary.begin(); +} +//OPT: since the Y values are orderly there should be something like a binary search to do this. + +bool +ConvexHull::meets_invariants() const { + return is_clockwise() && top_point_first(); +} + +/*** ConvexHull::is_degenerate + * We allow three degenerate cases: empty, 1 point and 2 points. In many cases these should be handled explicitly. + */ +bool +ConvexHull::is_degenerate() const { + return boundary.size() < 3; +} + + +int sgn(double x) { + if(x == 0) return 0; + return (x<0)?-1:1; +} + +bool same_side(Point L[2], Point xs[4]) { + int side = 0; + for(int i = 0; i < 4; i++) { + int sn = sgn(SignedTriangleArea(L[0], L[1], xs[i])); + if(sn && !side) + side = sn; + else if(sn != side) return false; + } + return true; +} + +/** find bridging pairs between two convex hulls. + * this code is based on Hormoz Pirzadeh's masters thesis. There is room for optimisation: + * 1. reduce recomputation + * 2. use more efficient angle code + * 3. write as iterator + */ +std::vector > bridges(ConvexHull a, ConvexHull b) { + vector > ret; + + // 1. find maximal points on a and b + int ai = 0, bi = 0; + // 2. find first copodal pair + double ap_angle = atan2(a[ai+1] - a[ai]); + double bp_angle = atan2(b[bi+1] - b[bi]); + Point L[2] = {a[ai], b[bi]}; + while(ai < int(a.size()) || bi < int(b.size())) { + if(ap_angle == bp_angle) { + // In the case of parallel support lines, we must consider all four pairs of copodal points + { + assert(0); // untested + Point xs[4] = {a[ai-1], a[ai+1], b[bi-1], b[bi+1]}; + if(same_side(L, xs)) ret.push_back(make_pair(ai, bi)); + xs[2] = b[bi]; + xs[3] = b[bi+2]; + if(same_side(L, xs)) ret.push_back(make_pair(ai, bi)); + xs[0] = a[ai]; + xs[1] = a[ai+2]; + if(same_side(L, xs)) ret.push_back(make_pair(ai, bi)); + xs[2] = b[bi-1]; + xs[3] = b[bi+1]; + if(same_side(L, xs)) ret.push_back(make_pair(ai, bi)); + } + ai++; + ap_angle += angle_between(a[ai] - a[ai-1], a[ai+1] - a[ai]); + L[0] = a[ai]; + bi++; + bp_angle += angle_between(b[bi] - b[bi-1], b[bi+1] - b[bi]); + L[1] = b[bi]; + std::cout << "parallel\n"; + } else if(ap_angle < bp_angle) { + ai++; + ap_angle += angle_between(a[ai] - a[ai-1], a[ai+1] - a[ai]); + L[0] = a[ai]; + Point xs[4] = {a[ai-1], a[ai+1], b[bi-1], b[bi+1]}; + if(same_side(L, xs)) ret.push_back(make_pair(ai, bi)); + } else { + bi++; + bp_angle += angle_between(b[bi] - b[bi-1], b[bi+1] - b[bi]); + L[1] = b[bi]; + Point xs[4] = {a[ai-1], a[ai+1], b[bi-1], b[bi+1]}; + if(same_side(L, xs)) ret.push_back(make_pair(ai, bi)); + } + } + return ret; +} + +unsigned find_bottom_right(ConvexHull const &a) { + unsigned it = 1; + while(it < a.boundary.size() && + a.boundary[it][Y] > a.boundary[it-1][Y]) + it++; + return it-1; +} + +/*** ConvexHull sweepline_intersection(ConvexHull a, ConvexHull b); + * find the intersection between two convex hulls. The intersection is also a convex hull. + * (Proof: take any two points both in a and in b. Any point between them is in a by convexity, + * and in b by convexity, thus in both. Need to prove still finite bounds.) + * This algorithm works by sweeping a line down both convex hulls in parallel, working out the left and right edges of the new hull. + */ +ConvexHull sweepline_intersection(ConvexHull const &a, ConvexHull const &b) { + ConvexHull ret; + + unsigned al = 0; + unsigned bl = 0; + + while(al+1 < a.boundary.size() && + (a.boundary[al+1][Y] > b.boundary[bl][Y])) { + al++; + } + while(bl+1 < b.boundary.size() && + (b.boundary[bl+1][Y] > a.boundary[al][Y])) { + bl++; + } + // al and bl now point to the top of the first pair of edges that overlap in y value + //double sweep_y = std::min(a.boundary[al][Y], + // b.boundary[bl][Y]); + return ret; +} + +/*** ConvexHull intersection(ConvexHull a, ConvexHull b); + * find the intersection between two convex hulls. The intersection is also a convex hull. + * (Proof: take any two points both in a and in b. Any point between them is in a by convexity, + * and in b by convexity, thus in both. Need to prove still finite bounds.) + */ +ConvexHull intersection(ConvexHull /*a*/, ConvexHull /*b*/) { + ConvexHull ret; + /* + int ai = 0, bi = 0; + int aj = a.boundary.size() - 1; + int bj = b.boundary.size() - 1; + */ + /*while (true) { + if(a[ai] + }*/ + return ret; +} + +template +T idx_to_pair(pair p, int idx) { + return idx?p.second:p.first; +} + +/*** ConvexHull merge(ConvexHull a, ConvexHull b); + * find the smallest convex hull that surrounds a and b. + */ +ConvexHull merge(ConvexHull a, ConvexHull b) { + ConvexHull ret; + + std::cout << "---\n"; + std::vector > bpair = bridges(a, b); + + // Given our list of bridges {(pb1, qb1), ..., (pbk, qbk)} + // we start with the highest point in p0, q0, say it is p0. + // then the merged hull is p0, ..., pb1, qb1, ..., qb2, pb2, ... + // In other words, either of the two polygons vertices are added in order until the vertex coincides with a bridge point, at which point we swap. + + unsigned state = (a[0][Y] < b[0][Y])?0:1; + ret.boundary.reserve(a.size() + b.size()); + ConvexHull chs[2] = {a, b}; + unsigned idx = 0; + + for(unsigned k = 0; k < bpair.size(); k++) { + unsigned limit = idx_to_pair(bpair[k], state); + std::cout << bpair[k].first << " , " << bpair[k].second << "; " + << idx << ", " << limit << ", s: " + << state + << " \n"; + while(idx <= limit) { + ret.boundary.push_back(chs[state][idx++]); + } + state = 1-state; + idx = idx_to_pair(bpair[k], state); + } + while(idx < chs[state].size()) { + ret.boundary.push_back(chs[state][idx++]); + } + return ret; +} + +ConvexHull graham_merge(ConvexHull a, ConvexHull b) { + ConvexHull result; + + // we can avoid the find pivot step because of top_point_first + if(b.boundary[0] <= a.boundary[0]) + swap(a, b); + + result.boundary = a.boundary; + result.boundary.insert(result.boundary.end(), + b.boundary.begin(), b.boundary.end()); + +/** if we modified graham scan to work top to bottom as proposed in lect754.pdf we could replace the + angle sort with a simple merge sort type algorithm. furthermore, we could do the graham scan + online, avoiding a bunch of memory copies. That would probably be linear. -- njh*/ + result.angle_sort(); + result.graham_scan(); + + return result; +} + +ConvexHull andrew_merge(ConvexHull a, ConvexHull b) { + ConvexHull result; + + // we can avoid the find pivot step because of top_point_first + if(b.boundary[0] <= a.boundary[0]) + swap(a, b); + + result.boundary = a.boundary; + result.boundary.insert(result.boundary.end(), + b.boundary.begin(), b.boundary.end()); + +/** if we modified graham scan to work top to bottom as proposed in lect754.pdf we could replace the + angle sort with a simple merge sort type algorithm. furthermore, we could do the graham scan + online, avoiding a bunch of memory copies. That would probably be linear. -- njh*/ + result.andrew_scan(); + + return result; +} + +//TODO: reinstate +/*ConvexCover::ConvexCover(Path const &sp) : path(&sp) { + cc.reserve(sp.size()); + for(Geom::Path::const_iterator it(sp.begin()), end(sp.end()); it != end; ++it) { + cc.push_back(ConvexHull((*it).begin(), (*it).end())); + } +}*/ + +double ConvexHull::centroid_and_area(Geom::Point& centroid) const { + const unsigned n = boundary.size(); + if (n < 2) + return 0; + if(n < 3) { + centroid = (boundary[0] + boundary[1])/2; + return 0; + } + Geom::Point centroid_tmp(0,0); + double atmp = 0; + for (unsigned i = n-1, j = 0; j < n; i = j, j++) { + const double ai = cross(boundary[j], boundary[i]); + atmp += ai; + centroid_tmp += (boundary[j] + boundary[i])*ai; // first moment. + } + if (atmp != 0) { + centroid = centroid_tmp / (3 * atmp); + } + return atmp / 2; +} + +// TODO: This can be made lg(n) using golden section/fibonacci search three starting points, say 0, +// n/2, n-1 construct a new point, say (n/2 + n)/2 throw away the furthest boundary point iterate +// until interval is a single value +Point const * ConvexHull::furthest(Point direction) const { + Point const * p = &boundary[0]; + double d = dot(*p, direction); + for(unsigned i = 1; i < boundary.size(); i++) { + double dd = dot(boundary[i], direction); + if(d < dd) { + p = &boundary[i]; + d = dd; + } + } + return p; +} + + +// returns (a, (b,c)), three points which define the narrowest diameter of the hull as the pair of +// lines going through b,c, and through a, parallel to b,c TODO: This can be made linear time by +// moving point tc incrementally from the previous value (it can only move in one direction). It +// is currently n*O(furthest) +double ConvexHull::narrowest_diameter(Point &a, Point &b, Point &c) { + Point tb = boundary.back(); + double d = std::numeric_limits::max(); + for(unsigned i = 0; i < boundary.size(); i++) { + Point tc = boundary[i]; + Point n = -rot90(tb-tc); + Point ta = *furthest(n); + double td = dot(n, ta-tb)/dot(n,n); + if(td < d) { + a = ta; + b = tb; + c = tc; + d = td; + } + tb = tc; + } + return d; +} +#endif + +}; + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 : diff --git a/src/2geom/convex-hull.h b/src/2geom/convex-hull.h new file mode 100644 index 000000000..4f4d10bd6 --- /dev/null +++ b/src/2geom/convex-hull.h @@ -0,0 +1,346 @@ +/** @file + * @brief Convex hull data structures + *//* + * Copyright 2006 Nathan Hurst + * Copyright 2006 Michael G. Sloan + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + */ + +#ifndef LIB2GEOM_SEEN_CONVEX_HULL_H +#define LIB2GEOM_SEEN_CONVEX_HULL_H + +#include <2geom/point.h> +#include <2geom/rect.h> +#include +#include +#include +#include +#include + +namespace Geom { + +namespace { + +/** @brief Iterator for the lower convex hull. + * This iterator allows us to avoid duplicating any points in the hull + * boundary and still express most algorithms in a concise way. */ +class ConvexHullLowerIterator + : public boost::random_access_iterator_helper + < ConvexHullLowerIterator + , Point + , std::ptrdiff_t + , Point const * + , Point const & + > +{ +public: + typedef ConvexHullLowerIterator Self; + ConvexHullLowerIterator() + : _data(NULL) + , _size(0) + , _x(0) + {} + ConvexHullLowerIterator(std::vector const &pts, std::size_t x) + : _data(&pts[0]) + , _size(pts.size()) + , _x(x) + {} + + Self &operator++() { + *this += 1; + return *this; + } + Self &operator--() { + *this -= 1; + return *this; + } + Self &operator+=(std::ptrdiff_t d) { + _x += d; + return *this; + } + Self &operator-=(std::ptrdiff_t d) { + _x -= d; + return *this; + } + std::ptrdiff_t operator-(Self const &other) const { + return _x - other._x; + } + Point const &operator*() const { + if (_x < _size) { + return _data[_x]; + } else { + return *_data; + } + } + bool operator==(Self const &other) const { + return _data == other._data && _x == other._x; + } + bool operator<(Self const &other) const { + return _data == other._data && _x < other._x; + } + +private: + Point const *_data; + std::size_t _size; + std::size_t _x; +}; + +} // end anonymous namespace + +/** + * @brief Convex hull based on the Andrew's monotone chain algorithm. + * @ingroup Shapes + */ +class ConvexHull { +public: + typedef std::vector::const_iterator iterator; + typedef std::vector::const_iterator const_iterator; + typedef std::vector::const_iterator UpperIterator; + typedef ConvexHullLowerIterator LowerIterator; + + /// @name Construct a convex hull. + /// @{ + + /// Create an empty convex hull. + ConvexHull() {} + /// Construct a singular convex hull. + explicit ConvexHull(Point const &a) + : _boundary(1, a) + , _lower(1) + {} + /// Construct a convex hull of two points. + ConvexHull(Point const &a, Point const &b); + /// Construct a convex hull of three points. + ConvexHull(Point const &a, Point const &b, Point const &c); + /// Construct a convex hull of four points. + ConvexHull(Point const &a, Point const &b, Point const &c, Point const &d); + /// Create a convex hull of a vector of points. + ConvexHull(std::vector const &pts); + + /// Create a convex hull of a range of points. + template + ConvexHull(Iter first, Iter last) + : _lower(0) + { + _prune(first, last, _boundary); + _construct(); + } + /// @} + + /// @name Inspect basic properties. + /// @{ + + /// Check for emptiness. + bool empty() const { return _boundary.empty(); } + /// Get the number of points in the hull. + size_t size() const { return _boundary.size(); } + /// Check whether the hull contains only one point. + bool isSingular() const { return _boundary.size() == 1; } + /// Check whether the hull is a line. + bool isLinear() const { return _boundary.size() == 2; } + /// Check whether the hull has zero area. + bool isDegenerate() const { return _boundary.size() < 3; } + /// Calculate the area of the convex hull. + double area() const; + //Point centroid() const; + //double areaAndCentroid(Point &c); + //FatLine maxDiameter() const; + //FatLine minDiameter() const; + /// @} + + /// @name Inspect bounds and extreme points. + /// @{ + + /// Compute the bounding rectangle of the convex hull. + OptRect bounds() const; + + /// Get the leftmost (minimum X) coordinate of the hull. + Coord left() const { return _boundary[0][X]; } + /// Get the rightmost (maximum X) coordinate of the hull. + Coord right() const { return _boundary[_lower-1][X]; } + /// Get the topmost (minimum Y) coordinate of the hull. + Coord top() const { return topPoint()[Y]; } + /// Get the bottommost (maximum Y) coordinate of the hull. + Coord bottom() const { return bottomPoint()[Y]; } + + /// Get the leftmost (minimum X) point of the hull. + /// If the leftmost edge is vertical, the top point of the edge is returned. + Point leftPoint() const { return _boundary[0]; } + /// Get the rightmost (maximum X) point of the hull. + /// If the rightmost edge is vertical, the bottom point edge is returned. + Point rightPoint() const { return _boundary[_lower-1]; } + /// Get the topmost (minimum Y) point of the hull. + /// If the topmost edge is horizontal, the right point of the edge is returned. + Point topPoint() const; + /// Get the bottommost (maximum Y) point of the hull. + /// If the bottommost edge is horizontal, the left point of the edge is returned. + Point bottomPoint() const; + ///@} + + /// @name Iterate over points. + /// @{ + /** @brief Get the begin iterator to the points that form the hull. + * Points are are returned beginning the the leftmost one, going along + * the upper (minimum Y) side, and then along the bottom. + * Thus the points are always ordered clockwise. No point is + * repeated. */ + iterator begin() const { return _boundary.begin(); } + /// Get the end iterator to the points that form the hull. + iterator end() const { return _boundary.end(); } + /// Get the first, leftmost point in the hull. + Point const &front() const { return _boundary.front(); } + /// Get the penultimate point of the lower hull. + Point const &back() const { return _boundary.back(); } + Point const &operator[](std::size_t i) const { + return _boundary[i]; + } + + /** @brief Get an iterator range to the upper part of the hull. + * This returns a range that includes the leftmost point, + * all points of the upper hull, and the rightmost point. */ + boost::iterator_range upperHull() const { + boost::iterator_range r(_boundary.begin(), _boundary.begin() + _lower); + return r; + } + + /** @brief Get an iterator range to the lower part of the hull. + * This returns a range that includes the leftmost point, + * all points of the lower hull, and the rightmost point. */ + boost::iterator_range lowerHull() const { + if (_boundary.empty()) { + boost::iterator_range r(LowerIterator(_boundary, 0), + LowerIterator(_boundary, 0)); + return r; + } + if (_boundary.size() == 1) { + boost::iterator_range r(LowerIterator(_boundary, 0), + LowerIterator(_boundary, 1)); + return r; + } + boost::iterator_range r(LowerIterator(_boundary, _lower - 1), + LowerIterator(_boundary, _boundary.size() + 1)); + return r; + } + /// @} + + /// @name Check for containment and intersection. + /// @{ + /** @brief Check whether the given point is inside the hull. + * This takes logarithmic time. */ + bool contains(Point const &p) const; + /** @brief Check whether the given axis-aligned rectangle is inside the hull. + * A rectangle is inside the hull if all of its corners are inside. */ + bool contains(Rect const &r) const; + /// Check whether the given convex hull is completely contained in this one. + bool contains(ConvexHull const &other) const; + //bool interiorContains(Point const &p) const; + //bool interiorContains(Rect const &r) const; + //bool interiorContains(ConvexHull const &other) const; + //bool intersects(Rect const &r) const; + //bool intersects(ConvexHull const &other) const; + + //ConvexHull &operator|=(ConvexHull const &other); + //ConvexHull &operator&=(ConvexHull const &other); + //ConvexHull &operator*=(Affine const &m); + + //ConvexHull &expand(Point const &p); + //void unifyWith(ConvexHull const &other); + //void intersectWith(ConvexHull const &other); + /// @} + + void swap(ConvexHull &other); + void swap(std::vector &pts); + +private: + void _construct(); + static bool _is_clockwise_turn(Point const &a, Point const &b, Point const &c); + + /// Take a vector of points and produce a pruned sorted vector. + template + static void _prune(Iter first, Iter last, std::vector &out) { + boost::optional ymin, ymax, xmin, xmax; + for (Iter i = first; i != last; ++i) { + Point p = *i; + if (!ymin || Point::LexLess()(p, *ymin)) { + ymin = p; + } + if (!xmin || Point::LexLess()(p, *xmin)) { + xmin = p; + } + if (!ymax || Point::LexGreater()(p, *ymax)) { + ymax = p; + } + if (!xmax || Point::LexGreater()(p, *xmax)) { + xmax = p; + } + } + if (!ymin) return; + + ConvexHull qhull(*xmin, *xmax, *ymin, *ymax); + for (Iter i = first; i != last; ++i) { + if (qhull.contains(*i)) continue; + out.push_back(*i); + } + + out.push_back(*xmin); + out.push_back(*xmax); + out.push_back(*ymin); + out.push_back(*ymax); + std::sort(out.begin(), out.end(), Point::LexLess()); + out.erase(std::unique(out.begin(), out.end()), out.end()); + } + + /// Sequence of points forming the convex hull polygon. + std::vector _boundary; + /// Index one past the rightmost point, where the lower part of the boundary starts. + std::size_t _lower; +}; + +/** @brief Output operator for convex hulls. + * Prints out all the coordinates. */ +inline std::ostream &operator<< (std::ostream &out_file, const Geom::ConvexHull &in_cvx) { + out_file << "ConvexHull("; + for(unsigned i = 0; i < in_cvx.size(); i++) { + out_file << in_cvx[i] << ", "; + } + out_file << ")"; + return out_file; +} + +} // end namespace Geom + +#endif // LIB2GEOM_SEEN_CONVEX_HULL_H + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 : diff --git a/src/2geom/coord.cpp b/src/2geom/coord.cpp new file mode 100644 index 000000000..9ee8066f2 --- /dev/null +++ b/src/2geom/coord.cpp @@ -0,0 +1,3688 @@ +/** @file + * @brief Conversion between Coord and strings + *//* + * Authors: + * Krzysztof Kosiński + * + * Copyright 2014 Authors + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + */ + +// Most of the code in this file is derived from: +// https://code.google.com/p/double-conversion/ +// The copyright notice for that code is attached below. +// +// Copyright 2010 the V8 project authors. All rights reserved. +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following +// disclaimer in the documentation and/or other materials provided +// with the distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#include <2geom/coord.h> +#include +#include +#include +#include +#include +#include +#include + +#ifndef ASSERT +#define ASSERT(condition) \ + assert(condition); +#endif +#ifndef UNIMPLEMENTED +#define UNIMPLEMENTED() (abort()) +#endif +#ifndef UNREACHABLE +#define UNREACHABLE() (abort()) +#endif + +#define UINT64_2PART_C(a, b) (((static_cast(a) << 32) + 0x##b##u)) + +#ifndef ARRAY_SIZE +#define ARRAY_SIZE(a) \ + ((sizeof(a) / sizeof(*(a))) / \ + static_cast(!(sizeof(a) % sizeof(*(a))))) +#endif + +#ifndef DISALLOW_COPY_AND_ASSIGN +#define DISALLOW_COPY_AND_ASSIGN(TypeName) \ + TypeName(const TypeName&); \ + void operator=(const TypeName&) +#endif + +#ifndef DISALLOW_IMPLICIT_CONSTRUCTORS +#define DISALLOW_IMPLICIT_CONSTRUCTORS(TypeName) \ + TypeName(); \ + DISALLOW_COPY_AND_ASSIGN(TypeName) +#endif + +#if defined(__GNUC__) +#define DOUBLE_CONVERSION_UNUSED __attribute__((unused)) +#else +#define DOUBLE_CONVERSION_UNUSED +#endif + +namespace Geom { + +namespace { + +inline int StrLength(const char* string) { + size_t length = strlen(string); + ASSERT(length == static_cast(static_cast(length))); + return static_cast(length); +} + +template +class Vector { + public: + Vector() : start_(NULL), length_(0) {} + Vector(T* data, int length) : start_(data), length_(length) { + ASSERT(length == 0 || (length > 0 && data != NULL)); + } + + Vector SubVector(int from, int to) { + ASSERT(to <= length_); + ASSERT(from < to); + ASSERT(0 <= from); + return Vector(start() + from, to - from); + } + int length() const { return length_; } + bool is_empty() const { return length_ == 0; } + + T* start() const { return start_; } + + T& operator[](int index) const { + ASSERT(0 <= index && index < length_); + return start_[index]; + } + T& first() { return start_[0]; } + T& last() { return start_[length_ - 1]; } + + private: + T* start_; + int length_; +}; + +template +inline Dest BitCast(const Source& source) { + DOUBLE_CONVERSION_UNUSED + typedef char VerifySizesAreEqual[sizeof(Dest) == sizeof(Source) ? 1 : -1]; + Dest dest; + memmove(&dest, &source, sizeof(dest)); + return dest; +} + +template +inline Dest BitCast(Source* source) { + return BitCast(reinterpret_cast(source)); +} + +// We assume that doubles and uint64_t have the same endianness. +static uint64_t double_to_uint64(double d) { return BitCast(d); } +static double uint64_to_double(uint64_t d64) { return BitCast(d64); } + +// This "Do It Yourself Floating Point" class +class DiyFp { + public: + static const int kSignificandSize = 64; + + DiyFp() : f_(0), e_(0) {} + DiyFp(uint64_t f, int e) : f_(f), e_(e) {} + + void Subtract(const DiyFp& other) { + ASSERT(e_ == other.e_); + ASSERT(f_ >= other.f_); + f_ -= other.f_; + } + + static DiyFp Minus(const DiyFp& a, const DiyFp& b) { + DiyFp result = a; + result.Subtract(b); + return result; + } + + void Multiply(const DiyFp& other) { + const uint64_t kM32 = 0xFFFFFFFFU; + uint64_t a = f_ >> 32; + uint64_t b = f_ & kM32; + uint64_t c = other.f_ >> 32; + uint64_t d = other.f_ & kM32; + uint64_t ac = a * c; + uint64_t bc = b * c; + uint64_t ad = a * d; + uint64_t bd = b * d; + uint64_t tmp = (bd >> 32) + (ad & kM32) + (bc & kM32); + // By adding 1U << 31 to tmp we round the final result. + // Halfway cases will be round up. + tmp += 1U << 31; + uint64_t result_f = ac + (ad >> 32) + (bc >> 32) + (tmp >> 32); + e_ += other.e_ + 64; + f_ = result_f; + } + + static DiyFp Times(const DiyFp& a, const DiyFp& b) { + DiyFp result = a; + result.Multiply(b); + return result; + } + + void Normalize() { + ASSERT(f_ != 0); + uint64_t f = f_; + int e = e_; + + const uint64_t k10MSBits = UINT64_2PART_C(0xFFC00000, 00000000); + while ((f & k10MSBits) == 0) { + f <<= 10; + e -= 10; + } + while ((f & kUint64MSB) == 0) { + f <<= 1; + e--; + } + f_ = f; + e_ = e; + } + + static DiyFp Normalize(const DiyFp& a) { + DiyFp result = a; + result.Normalize(); + return result; + } + + uint64_t f() const { return f_; } + int e() const { return e_; } + + void set_f(uint64_t new_value) { f_ = new_value; } + void set_e(int new_value) { e_ = new_value; } + + private: + static const uint64_t kUint64MSB = UINT64_2PART_C(0x80000000, 00000000); + + uint64_t f_; + int e_; +}; + +class Double { + public: + static const uint64_t kSignMask = UINT64_2PART_C(0x80000000, 00000000); + static const uint64_t kExponentMask = UINT64_2PART_C(0x7FF00000, 00000000); + static const uint64_t kSignificandMask = UINT64_2PART_C(0x000FFFFF, FFFFFFFF); + static const uint64_t kHiddenBit = UINT64_2PART_C(0x00100000, 00000000); + static const int kPhysicalSignificandSize = 52; // Excludes the hidden bit. + static const int kSignificandSize = 53; + + Double() : d64_(0) {} + explicit Double(double d) : d64_(double_to_uint64(d)) {} + explicit Double(uint64_t d64) : d64_(d64) {} + explicit Double(DiyFp diy_fp) + : d64_(DiyFpToUint64(diy_fp)) {} + + DiyFp AsDiyFp() const { + ASSERT(Sign() > 0); + ASSERT(!IsSpecial()); + return DiyFp(Significand(), Exponent()); + } + + DiyFp AsNormalizedDiyFp() const { + ASSERT(value() > 0.0); + uint64_t f = Significand(); + int e = Exponent(); + + // The current double could be a denormal. + while ((f & kHiddenBit) == 0) { + f <<= 1; + e--; + } + // Do the final shifts in one go. + f <<= DiyFp::kSignificandSize - kSignificandSize; + e -= DiyFp::kSignificandSize - kSignificandSize; + return DiyFp(f, e); + } + + uint64_t AsUint64() const { + return d64_; + } + + double NextDouble() const { + if (d64_ == kInfinity) return Double(kInfinity).value(); + if (Sign() < 0 && Significand() == 0) { + // -0.0 + return 0.0; + } + if (Sign() < 0) { + return Double(d64_ - 1).value(); + } else { + return Double(d64_ + 1).value(); + } + } + + double PreviousDouble() const { + if (d64_ == (kInfinity | kSignMask)) return -Double::Infinity(); + if (Sign() < 0) { + return Double(d64_ + 1).value(); + } else { + if (Significand() == 0) return -0.0; + return Double(d64_ - 1).value(); + } + } + + int Exponent() const { + if (IsDenormal()) return kDenormalExponent; + + uint64_t d64 = AsUint64(); + int biased_e = + static_cast((d64 & kExponentMask) >> kPhysicalSignificandSize); + return biased_e - kExponentBias; + } + + uint64_t Significand() const { + uint64_t d64 = AsUint64(); + uint64_t significand = d64 & kSignificandMask; + if (!IsDenormal()) { + return significand + kHiddenBit; + } else { + return significand; + } + } + + bool IsDenormal() const { + uint64_t d64 = AsUint64(); + return (d64 & kExponentMask) == 0; + } + + // We consider denormals not to be special. + // Hence only Infinity and NaN are special. + bool IsSpecial() const { + uint64_t d64 = AsUint64(); + return (d64 & kExponentMask) == kExponentMask; + } + + bool IsNan() const { + uint64_t d64 = AsUint64(); + return ((d64 & kExponentMask) == kExponentMask) && + ((d64 & kSignificandMask) != 0); + } + + bool IsInfinite() const { + uint64_t d64 = AsUint64(); + return ((d64 & kExponentMask) == kExponentMask) && + ((d64 & kSignificandMask) == 0); + } + + int Sign() const { + uint64_t d64 = AsUint64(); + return (d64 & kSignMask) == 0? 1: -1; + } + + DiyFp UpperBoundary() const { + ASSERT(Sign() > 0); + return DiyFp(Significand() * 2 + 1, Exponent() - 1); + } + + void NormalizedBoundaries(DiyFp* out_m_minus, DiyFp* out_m_plus) const { + ASSERT(value() > 0.0); + DiyFp v = this->AsDiyFp(); + DiyFp m_plus = DiyFp::Normalize(DiyFp((v.f() << 1) + 1, v.e() - 1)); + DiyFp m_minus; + if (LowerBoundaryIsCloser()) { + m_minus = DiyFp((v.f() << 2) - 1, v.e() - 2); + } else { + m_minus = DiyFp((v.f() << 1) - 1, v.e() - 1); + } + m_minus.set_f(m_minus.f() << (m_minus.e() - m_plus.e())); + m_minus.set_e(m_plus.e()); + *out_m_plus = m_plus; + *out_m_minus = m_minus; + } + + bool LowerBoundaryIsCloser() const { + bool physical_significand_is_zero = ((AsUint64() & kSignificandMask) == 0); + return physical_significand_is_zero && (Exponent() != kDenormalExponent); + } + + double value() const { return uint64_to_double(d64_); } + + static int SignificandSizeForOrderOfMagnitude(int order) { + if (order >= (kDenormalExponent + kSignificandSize)) { + return kSignificandSize; + } + if (order <= kDenormalExponent) return 0; + return order - kDenormalExponent; + } + + static double Infinity() { + return Double(kInfinity).value(); + } + + static double NaN() { + return Double(kNaN).value(); + } + + private: + static const int kExponentBias = 0x3FF + kPhysicalSignificandSize; + static const int kDenormalExponent = -kExponentBias + 1; + static const int kMaxExponent = 0x7FF - kExponentBias; + static const uint64_t kInfinity = UINT64_2PART_C(0x7FF00000, 00000000); + static const uint64_t kNaN = UINT64_2PART_C(0x7FF80000, 00000000); + + const uint64_t d64_; + + static uint64_t DiyFpToUint64(DiyFp diy_fp) { + uint64_t significand = diy_fp.f(); + int exponent = diy_fp.e(); + while (significand > kHiddenBit + kSignificandMask) { + significand >>= 1; + exponent++; + } + if (exponent >= kMaxExponent) { + return kInfinity; + } + if (exponent < kDenormalExponent) { + return 0; + } + while (exponent > kDenormalExponent && (significand & kHiddenBit) == 0) { + significand <<= 1; + exponent--; + } + uint64_t biased_exponent; + if (exponent == kDenormalExponent && (significand & kHiddenBit) == 0) { + biased_exponent = 0; + } else { + biased_exponent = static_cast(exponent + kExponentBias); + } + return (significand & kSignificandMask) | + (biased_exponent << kPhysicalSignificandSize); + } + + DISALLOW_COPY_AND_ASSIGN(Double); +}; + +template +static int BitSize(S value) { + (void) value; // Mark variable as used. + return 8 * sizeof(value); +} + +class Bignum { + public: + // 3584 = 128 * 28. We can represent 2^3584 > 10^1000 accurately. + // This bignum can encode much bigger numbers, since it contains an + // exponent. + static const int kMaxSignificantBits = 3584; + + Bignum() + : bigits_(bigits_buffer_, kBigitCapacity), used_digits_(0), exponent_(0) + { + for (int i = 0; i < kBigitCapacity; ++i) { + bigits_[i] = 0; + } + } + void AssignUInt16(uint16_t value) { + ASSERT(kBigitSize >= BitSize(value)); + Zero(); + if (value == 0) return; + + EnsureCapacity(1); + bigits_[0] = value; + used_digits_ = 1; + } + void AssignUInt64(uint64_t value) { + const int kUInt64Size = 64; + + Zero(); + if (value == 0) return; + + int needed_bigits = kUInt64Size / kBigitSize + 1; + EnsureCapacity(needed_bigits); + for (int i = 0; i < needed_bigits; ++i) { + bigits_[i] = value & kBigitMask; + value = value >> kBigitSize; + } + used_digits_ = needed_bigits; + Clamp(); + } + void AssignBignum(const Bignum& other) { + exponent_ = other.exponent_; + for (int i = 0; i < other.used_digits_; ++i) { + bigits_[i] = other.bigits_[i]; + } + // Clear the excess digits (if there were any). + for (int i = other.used_digits_; i < used_digits_; ++i) { + bigits_[i] = 0; + } + used_digits_ = other.used_digits_; + } + + void AssignDecimalString(Vector value); + void AssignHexString(Vector value); + + void AssignPowerUInt16(uint16_t base, int exponent); + + void AddUInt16(uint16_t operand); + void AddUInt64(uint64_t operand); + void AddBignum(const Bignum& other); + // Precondition: this >= other. + void SubtractBignum(const Bignum& other); + + void Square(); + void ShiftLeft(int shift_amount); + void MultiplyByUInt32(uint32_t factor); + void MultiplyByUInt64(uint64_t factor); + void MultiplyByPowerOfTen(int exponent); + void Times10() { return MultiplyByUInt32(10); } + // Pseudocode: + // int result = this / other; + // this = this % other; + // In the worst case this function is in O(this/other). + uint16_t DivideModuloIntBignum(const Bignum& other); + + bool ToHexString(char* buffer, int buffer_size) const; + + // Returns + // -1 if a < b, + // 0 if a == b, and + // +1 if a > b. + static int Compare(const Bignum& a, const Bignum& b); + static bool Equal(const Bignum& a, const Bignum& b) { + return Compare(a, b) == 0; + } + static bool LessEqual(const Bignum& a, const Bignum& b) { + return Compare(a, b) <= 0; + } + static bool Less(const Bignum& a, const Bignum& b) { + return Compare(a, b) < 0; + } + // Returns Compare(a + b, c); + static int PlusCompare(const Bignum& a, const Bignum& b, const Bignum& c); + // Returns a + b == c + static bool PlusEqual(const Bignum& a, const Bignum& b, const Bignum& c) { + return PlusCompare(a, b, c) == 0; + } + // Returns a + b <= c + static bool PlusLessEqual(const Bignum& a, const Bignum& b, const Bignum& c) { + return PlusCompare(a, b, c) <= 0; + } + // Returns a + b < c + static bool PlusLess(const Bignum& a, const Bignum& b, const Bignum& c) { + return PlusCompare(a, b, c) < 0; + } + private: + typedef uint32_t Chunk; + typedef uint64_t DoubleChunk; + + static const int kChunkSize = sizeof(Chunk) * 8; + static const int kDoubleChunkSize = sizeof(DoubleChunk) * 8; + // With bigit size of 28 we loose some bits, but a double still fits easily + // into two chunks, and more importantly we can use the Comba multiplication. + static const int kBigitSize = 28; + static const Chunk kBigitMask = (1 << kBigitSize) - 1; + // Every instance allocates kBigitLength chunks on the stack. Bignums cannot + // grow. There are no checks if the stack-allocated space is sufficient. + static const int kBigitCapacity = kMaxSignificantBits / kBigitSize; + + void EnsureCapacity(int size) { + if (size > kBigitCapacity) { + UNREACHABLE(); + } + } + void Align(const Bignum& other); + void Clamp(); + bool IsClamped() const; + void Zero(); + // Requires this to have enough capacity (no tests done). + // Updates used_digits_ if necessary. + // shift_amount must be < kBigitSize. + void BigitsShiftLeft(int shift_amount); + // BigitLength includes the "hidden" digits encoded in the exponent. + int BigitLength() const { return used_digits_ + exponent_; } + Chunk BigitAt(int index) const; + void SubtractTimes(const Bignum& other, int factor); + + Chunk bigits_buffer_[kBigitCapacity]; + // A vector backed by bigits_buffer_. This way accesses to the array are + // checked for out-of-bounds errors. + Vector bigits_; + int used_digits_; + // The Bignum's value equals value(bigits_) * 2^(exponent_ * kBigitSize). + int exponent_; + + DISALLOW_COPY_AND_ASSIGN(Bignum); +}; + +static uint64_t ReadUInt64(Vector buffer, + int from, + int digits_to_read) { + uint64_t result = 0; + for (int i = from; i < from + digits_to_read; ++i) { + int digit = buffer[i] - '0'; + ASSERT(0 <= digit && digit <= 9); + result = result * 10 + digit; + } + return result; +} + + +void Bignum::AssignDecimalString(Vector value) { + // 2^64 = 18446744073709551616 > 10^19 + const int kMaxUint64DecimalDigits = 19; + Zero(); + int length = value.length(); + int pos = 0; + // Let's just say that each digit needs 4 bits. + while (length >= kMaxUint64DecimalDigits) { + uint64_t digits = ReadUInt64(value, pos, kMaxUint64DecimalDigits); + pos += kMaxUint64DecimalDigits; + length -= kMaxUint64DecimalDigits; + MultiplyByPowerOfTen(kMaxUint64DecimalDigits); + AddUInt64(digits); + } + uint64_t digits = ReadUInt64(value, pos, length); + MultiplyByPowerOfTen(length); + AddUInt64(digits); + Clamp(); +} + + +static int HexCharValue(char c) { + if ('0' <= c && c <= '9') return c - '0'; + if ('a' <= c && c <= 'f') return 10 + c - 'a'; + ASSERT('A' <= c && c <= 'F'); + return 10 + c - 'A'; +} + + +void Bignum::AssignHexString(Vector value) { + Zero(); + int length = value.length(); + + int needed_bigits = length * 4 / kBigitSize + 1; + EnsureCapacity(needed_bigits); + int string_index = length - 1; + for (int i = 0; i < needed_bigits - 1; ++i) { + // These bigits are guaranteed to be "full". + Chunk current_bigit = 0; + for (int j = 0; j < kBigitSize / 4; j++) { + current_bigit += HexCharValue(value[string_index--]) << (j * 4); + } + bigits_[i] = current_bigit; + } + used_digits_ = needed_bigits - 1; + + Chunk most_significant_bigit = 0; // Could be = 0; + for (int j = 0; j <= string_index; ++j) { + most_significant_bigit <<= 4; + most_significant_bigit += HexCharValue(value[j]); + } + if (most_significant_bigit != 0) { + bigits_[used_digits_] = most_significant_bigit; + used_digits_++; + } + Clamp(); +} + + +void Bignum::AddUInt64(uint64_t operand) { + if (operand == 0) return; + Bignum other; + other.AssignUInt64(operand); + AddBignum(other); +} + + +void Bignum::AddBignum(const Bignum& other) { + ASSERT(IsClamped()); + ASSERT(other.IsClamped()); + + Align(other); + + EnsureCapacity(1 + std::max(BigitLength(), other.BigitLength()) - exponent_); + Chunk carry = 0; + int bigit_pos = other.exponent_ - exponent_; + ASSERT(bigit_pos >= 0); + for (int i = 0; i < other.used_digits_; ++i) { + Chunk sum = bigits_[bigit_pos] + other.bigits_[i] + carry; + bigits_[bigit_pos] = sum & kBigitMask; + carry = sum >> kBigitSize; + bigit_pos++; + } + + while (carry != 0) { + Chunk sum = bigits_[bigit_pos] + carry; + bigits_[bigit_pos] = sum & kBigitMask; + carry = sum >> kBigitSize; + bigit_pos++; + } + used_digits_ = std::max(bigit_pos, used_digits_); + ASSERT(IsClamped()); +} + + +void Bignum::SubtractBignum(const Bignum& other) { + ASSERT(IsClamped()); + ASSERT(other.IsClamped()); + // We require this to be bigger than other. + ASSERT(LessEqual(other, *this)); + + Align(other); + + int offset = other.exponent_ - exponent_; + Chunk borrow = 0; + int i; + for (i = 0; i < other.used_digits_; ++i) { + ASSERT((borrow == 0) || (borrow == 1)); + Chunk difference = bigits_[i + offset] - other.bigits_[i] - borrow; + bigits_[i + offset] = difference & kBigitMask; + borrow = difference >> (kChunkSize - 1); + } + while (borrow != 0) { + Chunk difference = bigits_[i + offset] - borrow; + bigits_[i + offset] = difference & kBigitMask; + borrow = difference >> (kChunkSize - 1); + ++i; + } + Clamp(); +} + + +void Bignum::ShiftLeft(int shift_amount) { + if (used_digits_ == 0) return; + exponent_ += shift_amount / kBigitSize; + int local_shift = shift_amount % kBigitSize; + EnsureCapacity(used_digits_ + 1); + BigitsShiftLeft(local_shift); +} + + +void Bignum::MultiplyByUInt32(uint32_t factor) { + if (factor == 1) return; + if (factor == 0) { + Zero(); + return; + } + if (used_digits_ == 0) return; + + ASSERT(kDoubleChunkSize >= kBigitSize + 32 + 1); + DoubleChunk carry = 0; + for (int i = 0; i < used_digits_; ++i) { + DoubleChunk product = static_cast(factor) * bigits_[i] + carry; + bigits_[i] = static_cast(product & kBigitMask); + carry = (product >> kBigitSize); + } + while (carry != 0) { + EnsureCapacity(used_digits_ + 1); + bigits_[used_digits_] = carry & kBigitMask; + used_digits_++; + carry >>= kBigitSize; + } +} + + +void Bignum::MultiplyByUInt64(uint64_t factor) { + if (factor == 1) return; + if (factor == 0) { + Zero(); + return; + } + ASSERT(kBigitSize < 32); + uint64_t carry = 0; + uint64_t low = factor & 0xFFFFFFFF; + uint64_t high = factor >> 32; + for (int i = 0; i < used_digits_; ++i) { + uint64_t product_low = low * bigits_[i]; + uint64_t product_high = high * bigits_[i]; + uint64_t tmp = (carry & kBigitMask) + product_low; + bigits_[i] = tmp & kBigitMask; + carry = (carry >> kBigitSize) + (tmp >> kBigitSize) + + (product_high << (32 - kBigitSize)); + } + while (carry != 0) { + EnsureCapacity(used_digits_ + 1); + bigits_[used_digits_] = carry & kBigitMask; + used_digits_++; + carry >>= kBigitSize; + } +} + + +void Bignum::MultiplyByPowerOfTen(int exponent) { + const uint64_t kFive27 = UINT64_2PART_C(0x6765c793, fa10079d); + const uint16_t kFive1 = 5; + const uint16_t kFive2 = kFive1 * 5; + const uint16_t kFive3 = kFive2 * 5; + const uint16_t kFive4 = kFive3 * 5; + const uint16_t kFive5 = kFive4 * 5; + const uint16_t kFive6 = kFive5 * 5; + const uint32_t kFive7 = kFive6 * 5; + const uint32_t kFive8 = kFive7 * 5; + const uint32_t kFive9 = kFive8 * 5; + const uint32_t kFive10 = kFive9 * 5; + const uint32_t kFive11 = kFive10 * 5; + const uint32_t kFive12 = kFive11 * 5; + const uint32_t kFive13 = kFive12 * 5; + const uint32_t kFive1_to_12[] = + { kFive1, kFive2, kFive3, kFive4, kFive5, kFive6, + kFive7, kFive8, kFive9, kFive10, kFive11, kFive12 }; + + ASSERT(exponent >= 0); + if (exponent == 0) return; + if (used_digits_ == 0) return; + + int remaining_exponent = exponent; + while (remaining_exponent >= 27) { + MultiplyByUInt64(kFive27); + remaining_exponent -= 27; + } + while (remaining_exponent >= 13) { + MultiplyByUInt32(kFive13); + remaining_exponent -= 13; + } + if (remaining_exponent > 0) { + MultiplyByUInt32(kFive1_to_12[remaining_exponent - 1]); + } + ShiftLeft(exponent); +} + + +void Bignum::Square() { + ASSERT(IsClamped()); + int product_length = 2 * used_digits_; + EnsureCapacity(product_length); + + if ((1 << (2 * (kChunkSize - kBigitSize))) <= used_digits_) { + UNIMPLEMENTED(); + } + DoubleChunk accumulator = 0; + // First shift the digits so we don't overwrite them. + int copy_offset = used_digits_; + for (int i = 0; i < used_digits_; ++i) { + bigits_[copy_offset + i] = bigits_[i]; + } + // We have two loops to avoid some 'if's in the loop. + for (int i = 0; i < used_digits_; ++i) { + // Process temporary digit i with power i. + // The sum of the two indices must be equal to i. + int bigit_index1 = i; + int bigit_index2 = 0; + // Sum all of the sub-products. + while (bigit_index1 >= 0) { + Chunk chunk1 = bigits_[copy_offset + bigit_index1]; + Chunk chunk2 = bigits_[copy_offset + bigit_index2]; + accumulator += static_cast(chunk1) * chunk2; + bigit_index1--; + bigit_index2++; + } + bigits_[i] = static_cast(accumulator) & kBigitMask; + accumulator >>= kBigitSize; + } + for (int i = used_digits_; i < product_length; ++i) { + int bigit_index1 = used_digits_ - 1; + int bigit_index2 = i - bigit_index1; + + while (bigit_index2 < used_digits_) { + Chunk chunk1 = bigits_[copy_offset + bigit_index1]; + Chunk chunk2 = bigits_[copy_offset + bigit_index2]; + accumulator += static_cast(chunk1) * chunk2; + bigit_index1--; + bigit_index2++; + } + bigits_[i] = static_cast(accumulator) & kBigitMask; + accumulator >>= kBigitSize; + } + + ASSERT(accumulator == 0); + + used_digits_ = product_length; + exponent_ *= 2; + Clamp(); +} + + +void Bignum::AssignPowerUInt16(uint16_t base, int power_exponent) { + ASSERT(base != 0); + ASSERT(power_exponent >= 0); + if (power_exponent == 0) { + AssignUInt16(1); + return; + } + Zero(); + int shifts = 0; + + while ((base & 1) == 0) { + base >>= 1; + shifts++; + } + int bit_size = 0; + int tmp_base = base; + while (tmp_base != 0) { + tmp_base >>= 1; + bit_size++; + } + int final_size = bit_size * power_exponent; + + EnsureCapacity(final_size / kBigitSize + 2); + + // Left to Right exponentiation. + int mask = 1; + while (power_exponent >= mask) mask <<= 1; + + mask >>= 2; + uint64_t this_value = base; + + bool delayed_multipliciation = false; + const uint64_t max_32bits = 0xFFFFFFFF; + while (mask != 0 && this_value <= max_32bits) { + this_value = this_value * this_value; + // Verify that there is enough space in this_value to perform the + // multiplication. The first bit_size bits must be 0. + if ((power_exponent & mask) != 0) { + uint64_t base_bits_mask = + ~((static_cast(1) << (64 - bit_size)) - 1); + bool high_bits_zero = (this_value & base_bits_mask) == 0; + if (high_bits_zero) { + this_value *= base; + } else { + delayed_multipliciation = true; + } + } + mask >>= 1; + } + AssignUInt64(this_value); + if (delayed_multipliciation) { + MultiplyByUInt32(base); + } + + // Now do the same thing as a bignum. + while (mask != 0) { + Square(); + if ((power_exponent & mask) != 0) { + MultiplyByUInt32(base); + } + mask >>= 1; + } + + // And finally add the saved shifts. + ShiftLeft(shifts * power_exponent); +} + + +uint16_t Bignum::DivideModuloIntBignum(const Bignum& other) { + ASSERT(IsClamped()); + ASSERT(other.IsClamped()); + ASSERT(other.used_digits_ > 0); + + if (BigitLength() < other.BigitLength()) { + return 0; + } + + Align(other); + + uint16_t result = 0; + + while (BigitLength() > other.BigitLength()) { + ASSERT(other.bigits_[other.used_digits_ - 1] >= ((1 << kBigitSize) / 16)); + ASSERT(bigits_[used_digits_ - 1] < 0x10000); + result += static_cast(bigits_[used_digits_ - 1]); + SubtractTimes(other, bigits_[used_digits_ - 1]); + } + + ASSERT(BigitLength() == other.BigitLength()); + + Chunk this_bigit = bigits_[used_digits_ - 1]; + Chunk other_bigit = other.bigits_[other.used_digits_ - 1]; + + if (other.used_digits_ == 1) { + int quotient = this_bigit / other_bigit; + bigits_[used_digits_ - 1] = this_bigit - other_bigit * quotient; + ASSERT(quotient < 0x10000); + result += static_cast(quotient); + Clamp(); + return result; + } + + int division_estimate = this_bigit / (other_bigit + 1); + ASSERT(division_estimate < 0x10000); + result += static_cast(division_estimate); + SubtractTimes(other, division_estimate); + + if (other_bigit * (division_estimate + 1) > this_bigit) { + return result; + } + + while (LessEqual(other, *this)) { + SubtractBignum(other); + result++; + } + return result; +} + + +template +static int SizeInHexChars(S number) { + ASSERT(number > 0); + int result = 0; + while (number != 0) { + number >>= 4; + result++; + } + return result; +} + + +static char HexCharOfValue(int value) { + ASSERT(0 <= value && value <= 16); + if (value < 10) return static_cast(value + '0'); + return static_cast(value - 10 + 'A'); +} + + +bool Bignum::ToHexString(char* buffer, int buffer_size) const { + ASSERT(IsClamped()); + // Each bigit must be printable as separate hex-character. + ASSERT(kBigitSize % 4 == 0); + const int kHexCharsPerBigit = kBigitSize / 4; + + if (used_digits_ == 0) { + if (buffer_size < 2) return false; + buffer[0] = '0'; + buffer[1] = '\0'; + return true; + } + // We add 1 for the terminating '\0' character. + int needed_chars = (BigitLength() - 1) * kHexCharsPerBigit + + SizeInHexChars(bigits_[used_digits_ - 1]) + 1; + if (needed_chars > buffer_size) return false; + int string_index = needed_chars - 1; + buffer[string_index--] = '\0'; + for (int i = 0; i < exponent_; ++i) { + for (int j = 0; j < kHexCharsPerBigit; ++j) { + buffer[string_index--] = '0'; + } + } + for (int i = 0; i < used_digits_ - 1; ++i) { + Chunk current_bigit = bigits_[i]; + for (int j = 0; j < kHexCharsPerBigit; ++j) { + buffer[string_index--] = HexCharOfValue(current_bigit & 0xF); + current_bigit >>= 4; + } + } + // And finally the last bigit. + Chunk most_significant_bigit = bigits_[used_digits_ - 1]; + while (most_significant_bigit != 0) { + buffer[string_index--] = HexCharOfValue(most_significant_bigit & 0xF); + most_significant_bigit >>= 4; + } + return true; +} + + +Bignum::Chunk Bignum::BigitAt(int index) const { + if (index >= BigitLength()) return 0; + if (index < exponent_) return 0; + return bigits_[index - exponent_]; +} + + +int Bignum::Compare(const Bignum& a, const Bignum& b) { + ASSERT(a.IsClamped()); + ASSERT(b.IsClamped()); + int bigit_length_a = a.BigitLength(); + int bigit_length_b = b.BigitLength(); + if (bigit_length_a < bigit_length_b) return -1; + if (bigit_length_a > bigit_length_b) return +1; + for (int i = bigit_length_a - 1; i >= std::min(a.exponent_, b.exponent_); --i) { + Chunk bigit_a = a.BigitAt(i); + Chunk bigit_b = b.BigitAt(i); + if (bigit_a < bigit_b) return -1; + if (bigit_a > bigit_b) return +1; + } + return 0; +} + + +int Bignum::PlusCompare(const Bignum& a, const Bignum& b, const Bignum& c) { + ASSERT(a.IsClamped()); + ASSERT(b.IsClamped()); + ASSERT(c.IsClamped()); + if (a.BigitLength() < b.BigitLength()) { + return PlusCompare(b, a, c); + } + if (a.BigitLength() + 1 < c.BigitLength()) return -1; + if (a.BigitLength() > c.BigitLength()) return +1; + + if (a.exponent_ >= b.BigitLength() && a.BigitLength() < c.BigitLength()) { + return -1; + } + + Chunk borrow = 0; + // Starting at min_exponent all digits are == 0. So no need to compare them. + int min_exponent = std::min(std::min(a.exponent_, b.exponent_), c.exponent_); + for (int i = c.BigitLength() - 1; i >= min_exponent; --i) { + Chunk chunk_a = a.BigitAt(i); + Chunk chunk_b = b.BigitAt(i); + Chunk chunk_c = c.BigitAt(i); + Chunk sum = chunk_a + chunk_b; + if (sum > chunk_c + borrow) { + return +1; + } else { + borrow = chunk_c + borrow - sum; + if (borrow > 1) return -1; + borrow <<= kBigitSize; + } + } + if (borrow == 0) return 0; + return -1; +} + + +void Bignum::Clamp() { + while (used_digits_ > 0 && bigits_[used_digits_ - 1] == 0) { + used_digits_--; + } + if (used_digits_ == 0) { + // Zero. + exponent_ = 0; + } +} + + +bool Bignum::IsClamped() const { + return used_digits_ == 0 || bigits_[used_digits_ - 1] != 0; +} + + +void Bignum::Zero() { + for (int i = 0; i < used_digits_; ++i) { + bigits_[i] = 0; + } + used_digits_ = 0; + exponent_ = 0; +} + + +void Bignum::Align(const Bignum& other) { + if (exponent_ > other.exponent_) { + int zero_digits = exponent_ - other.exponent_; + EnsureCapacity(used_digits_ + zero_digits); + for (int i = used_digits_ - 1; i >= 0; --i) { + bigits_[i + zero_digits] = bigits_[i]; + } + for (int i = 0; i < zero_digits; ++i) { + bigits_[i] = 0; + } + used_digits_ += zero_digits; + exponent_ -= zero_digits; + ASSERT(used_digits_ >= 0); + ASSERT(exponent_ >= 0); + } +} + + +void Bignum::BigitsShiftLeft(int shift_amount) { + ASSERT(shift_amount < kBigitSize); + ASSERT(shift_amount >= 0); + Chunk carry = 0; + for (int i = 0; i < used_digits_; ++i) { + Chunk new_carry = bigits_[i] >> (kBigitSize - shift_amount); + bigits_[i] = ((bigits_[i] << shift_amount) + carry) & kBigitMask; + carry = new_carry; + } + if (carry != 0) { + bigits_[used_digits_] = carry; + used_digits_++; + } +} + + +void Bignum::SubtractTimes(const Bignum& other, int factor) { + ASSERT(exponent_ <= other.exponent_); + if (factor < 3) { + for (int i = 0; i < factor; ++i) { + SubtractBignum(other); + } + return; + } + Chunk borrow = 0; + int exponent_diff = other.exponent_ - exponent_; + for (int i = 0; i < other.used_digits_; ++i) { + DoubleChunk product = static_cast(factor) * other.bigits_[i]; + DoubleChunk remove = borrow + product; + Chunk difference = bigits_[i + exponent_diff] - (remove & kBigitMask); + bigits_[i + exponent_diff] = difference & kBigitMask; + borrow = static_cast((difference >> (kChunkSize - 1)) + + (remove >> kBigitSize)); + } + for (int i = other.used_digits_ + exponent_diff; i < used_digits_; ++i) { + if (borrow == 0) return; + Chunk difference = bigits_[i] - borrow; + bigits_[i] = difference & kBigitMask; + borrow = difference >> (kChunkSize - 1); + } + Clamp(); +} + +class PowersOfTenCache { +public: + static const int kDecimalExponentDistance; + + static const int kMinDecimalExponent; + static const int kMaxDecimalExponent; + + static void GetCachedPowerForBinaryExponentRange(int min_exponent, + int max_exponent, + DiyFp* power, + int* decimal_exponent); + + static void GetCachedPowerForDecimalExponent(int requested_exponent, + DiyFp* power, + int* found_exponent); +}; + +struct CachedPower { + uint64_t significand; + int16_t binary_exponent; + int16_t decimal_exponent; +}; + +static const CachedPower kCachedPowers[] = { + {UINT64_2PART_C(0xfa8fd5a0, 081c0288), -1220, -348}, + {UINT64_2PART_C(0xbaaee17f, a23ebf76), -1193, -340}, + {UINT64_2PART_C(0x8b16fb20, 3055ac76), -1166, -332}, + {UINT64_2PART_C(0xcf42894a, 5dce35ea), -1140, -324}, + {UINT64_2PART_C(0x9a6bb0aa, 55653b2d), -1113, -316}, + {UINT64_2PART_C(0xe61acf03, 3d1a45df), -1087, -308}, + {UINT64_2PART_C(0xab70fe17, c79ac6ca), -1060, -300}, + {UINT64_2PART_C(0xff77b1fc, bebcdc4f), -1034, -292}, + {UINT64_2PART_C(0xbe5691ef, 416bd60c), -1007, -284}, + {UINT64_2PART_C(0x8dd01fad, 907ffc3c), -980, -276}, + {UINT64_2PART_C(0xd3515c28, 31559a83), -954, -268}, + {UINT64_2PART_C(0x9d71ac8f, ada6c9b5), -927, -260}, + {UINT64_2PART_C(0xea9c2277, 23ee8bcb), -901, -252}, + {UINT64_2PART_C(0xaecc4991, 4078536d), -874, -244}, + {UINT64_2PART_C(0x823c1279, 5db6ce57), -847, -236}, + {UINT64_2PART_C(0xc2109436, 4dfb5637), -821, -228}, + {UINT64_2PART_C(0x9096ea6f, 3848984f), -794, -220}, + {UINT64_2PART_C(0xd77485cb, 25823ac7), -768, -212}, + {UINT64_2PART_C(0xa086cfcd, 97bf97f4), -741, -204}, + {UINT64_2PART_C(0xef340a98, 172aace5), -715, -196}, + {UINT64_2PART_C(0xb23867fb, 2a35b28e), -688, -188}, + {UINT64_2PART_C(0x84c8d4df, d2c63f3b), -661, -180}, + {UINT64_2PART_C(0xc5dd4427, 1ad3cdba), -635, -172}, + {UINT64_2PART_C(0x936b9fce, bb25c996), -608, -164}, + {UINT64_2PART_C(0xdbac6c24, 7d62a584), -582, -156}, + {UINT64_2PART_C(0xa3ab6658, 0d5fdaf6), -555, -148}, + {UINT64_2PART_C(0xf3e2f893, dec3f126), -529, -140}, + {UINT64_2PART_C(0xb5b5ada8, aaff80b8), -502, -132}, + {UINT64_2PART_C(0x87625f05, 6c7c4a8b), -475, -124}, + {UINT64_2PART_C(0xc9bcff60, 34c13053), -449, -116}, + {UINT64_2PART_C(0x964e858c, 91ba2655), -422, -108}, + {UINT64_2PART_C(0xdff97724, 70297ebd), -396, -100}, + {UINT64_2PART_C(0xa6dfbd9f, b8e5b88f), -369, -92}, + {UINT64_2PART_C(0xf8a95fcf, 88747d94), -343, -84}, + {UINT64_2PART_C(0xb9447093, 8fa89bcf), -316, -76}, + {UINT64_2PART_C(0x8a08f0f8, bf0f156b), -289, -68}, + {UINT64_2PART_C(0xcdb02555, 653131b6), -263, -60}, + {UINT64_2PART_C(0x993fe2c6, d07b7fac), -236, -52}, + {UINT64_2PART_C(0xe45c10c4, 2a2b3b06), -210, -44}, + {UINT64_2PART_C(0xaa242499, 697392d3), -183, -36}, + {UINT64_2PART_C(0xfd87b5f2, 8300ca0e), -157, -28}, + {UINT64_2PART_C(0xbce50864, 92111aeb), -130, -20}, + {UINT64_2PART_C(0x8cbccc09, 6f5088cc), -103, -12}, + {UINT64_2PART_C(0xd1b71758, e219652c), -77, -4}, + {UINT64_2PART_C(0x9c400000, 00000000), -50, 4}, + {UINT64_2PART_C(0xe8d4a510, 00000000), -24, 12}, + {UINT64_2PART_C(0xad78ebc5, ac620000), 3, 20}, + {UINT64_2PART_C(0x813f3978, f8940984), 30, 28}, + {UINT64_2PART_C(0xc097ce7b, c90715b3), 56, 36}, + {UINT64_2PART_C(0x8f7e32ce, 7bea5c70), 83, 44}, + {UINT64_2PART_C(0xd5d238a4, abe98068), 109, 52}, + {UINT64_2PART_C(0x9f4f2726, 179a2245), 136, 60}, + {UINT64_2PART_C(0xed63a231, d4c4fb27), 162, 68}, + {UINT64_2PART_C(0xb0de6538, 8cc8ada8), 189, 76}, + {UINT64_2PART_C(0x83c7088e, 1aab65db), 216, 84}, + {UINT64_2PART_C(0xc45d1df9, 42711d9a), 242, 92}, + {UINT64_2PART_C(0x924d692c, a61be758), 269, 100}, + {UINT64_2PART_C(0xda01ee64, 1a708dea), 295, 108}, + {UINT64_2PART_C(0xa26da399, 9aef774a), 322, 116}, + {UINT64_2PART_C(0xf209787b, b47d6b85), 348, 124}, + {UINT64_2PART_C(0xb454e4a1, 79dd1877), 375, 132}, + {UINT64_2PART_C(0x865b8692, 5b9bc5c2), 402, 140}, + {UINT64_2PART_C(0xc83553c5, c8965d3d), 428, 148}, + {UINT64_2PART_C(0x952ab45c, fa97a0b3), 455, 156}, + {UINT64_2PART_C(0xde469fbd, 99a05fe3), 481, 164}, + {UINT64_2PART_C(0xa59bc234, db398c25), 508, 172}, + {UINT64_2PART_C(0xf6c69a72, a3989f5c), 534, 180}, + {UINT64_2PART_C(0xb7dcbf53, 54e9bece), 561, 188}, + {UINT64_2PART_C(0x88fcf317, f22241e2), 588, 196}, + {UINT64_2PART_C(0xcc20ce9b, d35c78a5), 614, 204}, + {UINT64_2PART_C(0x98165af3, 7b2153df), 641, 212}, + {UINT64_2PART_C(0xe2a0b5dc, 971f303a), 667, 220}, + {UINT64_2PART_C(0xa8d9d153, 5ce3b396), 694, 228}, + {UINT64_2PART_C(0xfb9b7cd9, a4a7443c), 720, 236}, + {UINT64_2PART_C(0xbb764c4c, a7a44410), 747, 244}, + {UINT64_2PART_C(0x8bab8eef, b6409c1a), 774, 252}, + {UINT64_2PART_C(0xd01fef10, a657842c), 800, 260}, + {UINT64_2PART_C(0x9b10a4e5, e9913129), 827, 268}, + {UINT64_2PART_C(0xe7109bfb, a19c0c9d), 853, 276}, + {UINT64_2PART_C(0xac2820d9, 623bf429), 880, 284}, + {UINT64_2PART_C(0x80444b5e, 7aa7cf85), 907, 292}, + {UINT64_2PART_C(0xbf21e440, 03acdd2d), 933, 300}, + {UINT64_2PART_C(0x8e679c2f, 5e44ff8f), 960, 308}, + {UINT64_2PART_C(0xd433179d, 9c8cb841), 986, 316}, + {UINT64_2PART_C(0x9e19db92, b4e31ba9), 1013, 324}, + {UINT64_2PART_C(0xeb96bf6e, badf77d9), 1039, 332}, + {UINT64_2PART_C(0xaf87023b, 9bf0ee6b), 1066, 340}, +}; + +static const int kCachedPowersLength = ARRAY_SIZE(kCachedPowers); +static const int kCachedPowersOffset = 348; // -1 * the first decimal_exponent. +static const double kD_1_LOG2_10 = 0.30102999566398114; // 1 / lg(10) +// Difference between the decimal exponents in the table above. +const int PowersOfTenCache::kDecimalExponentDistance = 8; +const int PowersOfTenCache::kMinDecimalExponent = -348; +const int PowersOfTenCache::kMaxDecimalExponent = 340; + +void PowersOfTenCache::GetCachedPowerForBinaryExponentRange( + int min_exponent, + int max_exponent, + DiyFp* power, + int* decimal_exponent) { + int kQ = DiyFp::kSignificandSize; + double k = ceil((min_exponent + kQ - 1) * kD_1_LOG2_10); + int foo = kCachedPowersOffset; + int index = + (foo + static_cast(k) - 1) / kDecimalExponentDistance + 1; + ASSERT(0 <= index && index < kCachedPowersLength); + CachedPower cached_power = kCachedPowers[index]; + ASSERT(min_exponent <= cached_power.binary_exponent); + (void) max_exponent; // Mark variable as used. + ASSERT(cached_power.binary_exponent <= max_exponent); + *decimal_exponent = cached_power.decimal_exponent; + *power = DiyFp(cached_power.significand, cached_power.binary_exponent); +} + + +void PowersOfTenCache::GetCachedPowerForDecimalExponent(int requested_exponent, + DiyFp* power, + int* found_exponent) { + ASSERT(kMinDecimalExponent <= requested_exponent); + ASSERT(requested_exponent < kMaxDecimalExponent + kDecimalExponentDistance); + int index = + (requested_exponent + kCachedPowersOffset) / kDecimalExponentDistance; + CachedPower cached_power = kCachedPowers[index]; + *power = DiyFp(cached_power.significand, cached_power.binary_exponent); + *found_exponent = cached_power.decimal_exponent; + ASSERT(*found_exponent <= requested_exponent); + ASSERT(requested_exponent < *found_exponent + kDecimalExponentDistance); +} + +enum BignumDtoaMode { + BIGNUM_DTOA_SHORTEST, + BIGNUM_DTOA_FIXED, + BIGNUM_DTOA_PRECISION +}; + +static int NormalizedExponent(uint64_t significand, int exponent) { + ASSERT(significand != 0); + while ((significand & Double::kHiddenBit) == 0) { + significand = significand << 1; + exponent = exponent - 1; + } + return exponent; +} + +static int EstimatePower(int exponent); + +static void InitialScaledStartValues(uint64_t significand, + int exponent, + bool lower_boundary_is_closer, + int estimated_power, + bool need_boundary_deltas, + Bignum* numerator, + Bignum* denominator, + Bignum* delta_minus, + Bignum* delta_plus); + +static void FixupMultiply10(int estimated_power, bool is_even, + int* decimal_point, + Bignum* numerator, Bignum* denominator, + Bignum* delta_minus, Bignum* delta_plus); + +static void GenerateShortestDigits(Bignum* numerator, Bignum* denominator, + Bignum* delta_minus, Bignum* delta_plus, + bool is_even, + Vector buffer, int* length); + +static void BignumToFixed(int requested_digits, int* decimal_point, + Bignum* numerator, Bignum* denominator, + Vector(buffer), int* length); + +static void GenerateCountedDigits(int count, int* decimal_point, + Bignum* numerator, Bignum* denominator, + Vector(buffer), int* length); + + +void BignumDtoa(double v, BignumDtoaMode mode, int requested_digits, + Vector buffer, int* length, int* decimal_point) { + ASSERT(v > 0); + ASSERT(!Double(v).IsSpecial()); + uint64_t significand; + int exponent; + bool lower_boundary_is_closer; + + significand = Double(v).Significand(); + exponent = Double(v).Exponent(); + lower_boundary_is_closer = Double(v).LowerBoundaryIsCloser(); + + bool need_boundary_deltas = + (mode == BIGNUM_DTOA_SHORTEST); + + bool is_even = (significand & 1) == 0; + int normalized_exponent = NormalizedExponent(significand, exponent); + // estimated_power might be too low by 1. + int estimated_power = EstimatePower(normalized_exponent); + + if (mode == BIGNUM_DTOA_FIXED && -estimated_power - 1 > requested_digits) { + buffer[0] = '\0'; + *length = 0; + *decimal_point = -requested_digits; + return; + } + + Bignum numerator; + Bignum denominator; + Bignum delta_minus; + Bignum delta_plus; + + ASSERT(Bignum::kMaxSignificantBits >= 324*4); + InitialScaledStartValues(significand, exponent, lower_boundary_is_closer, + estimated_power, need_boundary_deltas, + &numerator, &denominator, + &delta_minus, &delta_plus); + + FixupMultiply10(estimated_power, is_even, decimal_point, + &numerator, &denominator, + &delta_minus, &delta_plus); + + switch (mode) { + case BIGNUM_DTOA_SHORTEST: + GenerateShortestDigits(&numerator, &denominator, + &delta_minus, &delta_plus, + is_even, buffer, length); + break; + case BIGNUM_DTOA_FIXED: + BignumToFixed(requested_digits, decimal_point, + &numerator, &denominator, + buffer, length); + break; + case BIGNUM_DTOA_PRECISION: + GenerateCountedDigits(requested_digits, decimal_point, + &numerator, &denominator, + buffer, length); + break; + default: + UNREACHABLE(); + } + buffer[*length] = '\0'; +} + +static void GenerateShortestDigits(Bignum* numerator, Bignum* denominator, + Bignum* delta_minus, Bignum* delta_plus, + bool is_even, + Vector buffer, int* length) { + if (Bignum::Equal(*delta_minus, *delta_plus)) { + delta_plus = delta_minus; + } + *length = 0; + for (;;) { + uint16_t digit; + digit = numerator->DivideModuloIntBignum(*denominator); + ASSERT(digit <= 9); + + buffer[(*length)++] = static_cast(digit + '0'); + + bool in_delta_room_minus; + bool in_delta_room_plus; + if (is_even) { + in_delta_room_minus = Bignum::LessEqual(*numerator, *delta_minus); + } else { + in_delta_room_minus = Bignum::Less(*numerator, *delta_minus); + } + if (is_even) { + in_delta_room_plus = + Bignum::PlusCompare(*numerator, *delta_plus, *denominator) >= 0; + } else { + in_delta_room_plus = + Bignum::PlusCompare(*numerator, *delta_plus, *denominator) > 0; + } + if (!in_delta_room_minus && !in_delta_room_plus) { + numerator->Times10(); + delta_minus->Times10(); + + if (delta_minus != delta_plus) { + delta_plus->Times10(); + } + } else if (in_delta_room_minus && in_delta_room_plus) { + + int compare = Bignum::PlusCompare(*numerator, *numerator, *denominator); + if (compare < 0) { + // Remaining digits are less than .5. -> Round down (== do nothing). + } else if (compare > 0) { + // Remaining digits are more than .5 of denominator. -> Round up. + ASSERT(buffer[(*length) - 1] != '9'); + buffer[(*length) - 1]++; + } else { + if ((buffer[(*length) - 1] - '0') % 2 == 0) { + // Round down => Do nothing. + } else { + ASSERT(buffer[(*length) - 1] != '9'); + buffer[(*length) - 1]++; + } + } + return; + } else if (in_delta_room_minus) { + return; + } else { // in_delta_room_plus + // Round up + ASSERT(buffer[(*length) -1] != '9'); + buffer[(*length) - 1]++; + return; + } + } +} + +static void GenerateCountedDigits(int count, int* decimal_point, + Bignum* numerator, Bignum* denominator, + Vector buffer, int* length) { + ASSERT(count >= 0); + for (int i = 0; i < count - 1; ++i) { + uint16_t digit; + digit = numerator->DivideModuloIntBignum(*denominator); + ASSERT(digit <= 9); + + buffer[i] = static_cast(digit + '0'); + numerator->Times10(); + } + + uint16_t digit; + digit = numerator->DivideModuloIntBignum(*denominator); + if (Bignum::PlusCompare(*numerator, *numerator, *denominator) >= 0) { + digit++; + } + ASSERT(digit <= 10); + buffer[count - 1] = static_cast(digit + '0'); + + for (int i = count - 1; i > 0; --i) { + if (buffer[i] != '0' + 10) break; + buffer[i] = '0'; + buffer[i - 1]++; + } + if (buffer[0] == '0' + 10) { + buffer[0] = '1'; + (*decimal_point)++; + } + *length = count; +} + +static void BignumToFixed(int requested_digits, int* decimal_point, + Bignum* numerator, Bignum* denominator, + Vector(buffer), int* length) +{ + if (-(*decimal_point) > requested_digits) { + *decimal_point = -requested_digits; + *length = 0; + return; + } else if (-(*decimal_point) == requested_digits) { + ASSERT(*decimal_point == -requested_digits); + + denominator->Times10(); + if (Bignum::PlusCompare(*numerator, *numerator, *denominator) >= 0) { + buffer[0] = '1'; + *length = 1; + (*decimal_point)++; + } else { + *length = 0; + } + return; + } else { + int needed_digits = (*decimal_point) + requested_digits; + GenerateCountedDigits(needed_digits, decimal_point, + numerator, denominator, + buffer, length); + } +} + +static int EstimatePower(int exponent) { + const double k1Log10 = 0.30102999566398114; // 1/lg(10) + + // For doubles len(f) == 53 (don't forget the hidden bit). + const int kSignificandSize = Double::kSignificandSize; + double estimate = ceil((exponent + kSignificandSize - 1) * k1Log10 - 1e-10); + return static_cast(estimate); +} + +static void InitialScaledStartValuesPositiveExponent( + uint64_t significand, int exponent, + int estimated_power, bool need_boundary_deltas, + Bignum* numerator, Bignum* denominator, + Bignum* delta_minus, Bignum* delta_plus) +{ + ASSERT(estimated_power >= 0); + + numerator->AssignUInt64(significand); + numerator->ShiftLeft(exponent); + denominator->AssignPowerUInt16(10, estimated_power); + + if (need_boundary_deltas) { + denominator->ShiftLeft(1); + numerator->ShiftLeft(1); + delta_plus->AssignUInt16(1); + delta_plus->ShiftLeft(exponent); + delta_minus->AssignUInt16(1); + delta_minus->ShiftLeft(exponent); + } +} + +static void InitialScaledStartValuesNegativeExponentPositivePower( + uint64_t significand, int exponent, + int estimated_power, bool need_boundary_deltas, + Bignum* numerator, Bignum* denominator, + Bignum* delta_minus, Bignum* delta_plus) +{ + numerator->AssignUInt64(significand); + denominator->AssignPowerUInt16(10, estimated_power); + denominator->ShiftLeft(-exponent); + + if (need_boundary_deltas) { + denominator->ShiftLeft(1); + numerator->ShiftLeft(1); + delta_plus->AssignUInt16(1); + delta_minus->AssignUInt16(1); + } +} + +static void InitialScaledStartValuesNegativeExponentNegativePower( + uint64_t significand, int exponent, + int estimated_power, bool need_boundary_deltas, + Bignum* numerator, Bignum* denominator, + Bignum* delta_minus, Bignum* delta_plus) +{ + Bignum* power_ten = numerator; + power_ten->AssignPowerUInt16(10, -estimated_power); + + if (need_boundary_deltas) { + delta_plus->AssignBignum(*power_ten); + delta_minus->AssignBignum(*power_ten); + } + + ASSERT(numerator == power_ten); + numerator->MultiplyByUInt64(significand); + + denominator->AssignUInt16(1); + denominator->ShiftLeft(-exponent); + + if (need_boundary_deltas) { + numerator->ShiftLeft(1); + denominator->ShiftLeft(1); + } +} + +static void InitialScaledStartValues(uint64_t significand, + int exponent, + bool lower_boundary_is_closer, + int estimated_power, + bool need_boundary_deltas, + Bignum* numerator, + Bignum* denominator, + Bignum* delta_minus, + Bignum* delta_plus) +{ + if (exponent >= 0) { + InitialScaledStartValuesPositiveExponent( + significand, exponent, estimated_power, need_boundary_deltas, + numerator, denominator, delta_minus, delta_plus); + } else if (estimated_power >= 0) { + InitialScaledStartValuesNegativeExponentPositivePower( + significand, exponent, estimated_power, need_boundary_deltas, + numerator, denominator, delta_minus, delta_plus); + } else { + InitialScaledStartValuesNegativeExponentNegativePower( + significand, exponent, estimated_power, need_boundary_deltas, + numerator, denominator, delta_minus, delta_plus); + } + + if (need_boundary_deltas && lower_boundary_is_closer) { + denominator->ShiftLeft(1); // *2 + numerator->ShiftLeft(1); // *2 + delta_plus->ShiftLeft(1); // *2 + } +} + +static void FixupMultiply10(int estimated_power, bool is_even, + int* decimal_point, + Bignum* numerator, Bignum* denominator, + Bignum* delta_minus, Bignum* delta_plus) { + bool in_range; + if (is_even) { + in_range = Bignum::PlusCompare(*numerator, *delta_plus, *denominator) >= 0; + } else { + in_range = Bignum::PlusCompare(*numerator, *delta_plus, *denominator) > 0; + } + if (in_range) { + *decimal_point = estimated_power + 1; + } else { + *decimal_point = estimated_power; + numerator->Times10(); + if (Bignum::Equal(*delta_minus, *delta_plus)) { + delta_minus->Times10(); + delta_plus->AssignBignum(*delta_minus); + } else { + delta_minus->Times10(); + delta_plus->Times10(); + } + } +} + +enum FastDtoaMode { + FAST_DTOA_SHORTEST, + FAST_DTOA_PRECISION +}; + +static const int kFastDtoaMaximalLength = 17; + +bool FastDtoa(double d, + FastDtoaMode mode, + int requested_digits, + Vector buffer, + int* length, + int* decimal_point); + +static const int kMinimalTargetExponent = -60; +static const int kMaximalTargetExponent = -32; + +static bool RoundWeed(Vector buffer, int length, + uint64_t distance_too_high_w, uint64_t unsafe_interval, + uint64_t rest, uint64_t ten_kappa, uint64_t unit) +{ + uint64_t small_distance = distance_too_high_w - unit; + uint64_t big_distance = distance_too_high_w + unit; + + ASSERT(rest <= unsafe_interval); + while (rest < small_distance && // Negated condition 1 + unsafe_interval - rest >= ten_kappa && // Negated condition 2 + (rest + ten_kappa < small_distance || // buffer{-1} > w_high + small_distance - rest >= rest + ten_kappa - small_distance)) { + buffer[length - 1]--; + rest += ten_kappa; + } + + if (rest < big_distance && + unsafe_interval - rest >= ten_kappa && + (rest + ten_kappa < big_distance || + big_distance - rest > rest + ten_kappa - big_distance)) { + return false; + } + + return (2 * unit <= rest) && (rest <= unsafe_interval - 4 * unit); +} + +static bool RoundWeedCounted(Vector buffer, int length, + uint64_t rest, uint64_t ten_kappa, uint64_t unit, + int* kappa) +{ + ASSERT(rest < ten_kappa); + + if (unit >= ten_kappa) return false; + if (ten_kappa - unit <= unit) return false; + if ((ten_kappa - rest > rest) && (ten_kappa - 2 * rest >= 2 * unit)) { + return true; + } + + if ((rest > unit) && (ten_kappa - (rest - unit) <= (rest - unit))) { + buffer[length - 1]++; + for (int i = length - 1; i > 0; --i) { + if (buffer[i] != '0' + 10) break; + buffer[i] = '0'; + buffer[i - 1]++; + } + if (buffer[0] == '0' + 10) { + buffer[0] = '1'; + (*kappa) += 1; + } + return true; + } + return false; +} + +static unsigned int const kSmallPowersOfTen[] = + {0, 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, + 1000000000}; + +static void BiggestPowerTen(uint32_t number, + int number_bits, + uint32_t* power, + int* exponent_plus_one) { + ASSERT(number < (1u << (number_bits + 1))); + + int exponent_plus_one_guess = ((number_bits + 1) * 1233 >> 12); + exponent_plus_one_guess++; + + if (number < kSmallPowersOfTen[exponent_plus_one_guess]) { + exponent_plus_one_guess--; + } + *power = kSmallPowersOfTen[exponent_plus_one_guess]; + *exponent_plus_one = exponent_plus_one_guess; +} + +static bool DigitGen(DiyFp low, DiyFp w, DiyFp high, Vector buffer, + int* length, int* kappa) +{ + ASSERT(low.e() == w.e() && w.e() == high.e()); + ASSERT(low.f() + 1 <= high.f() - 1); + ASSERT(kMinimalTargetExponent <= w.e() && w.e() <= kMaximalTargetExponent); + + uint64_t unit = 1; + DiyFp too_low = DiyFp(low.f() - unit, low.e()); + DiyFp too_high = DiyFp(high.f() + unit, high.e()); + DiyFp unsafe_interval = DiyFp::Minus(too_high, too_low); + DiyFp one = DiyFp(static_cast(1) << -w.e(), w.e()); + + uint32_t integrals = static_cast(too_high.f() >> -one.e()); + uint64_t fractionals = too_high.f() & (one.f() - 1); + uint32_t divisor; + int divisor_exponent_plus_one; + BiggestPowerTen(integrals, DiyFp::kSignificandSize - (-one.e()), + &divisor, &divisor_exponent_plus_one); + *kappa = divisor_exponent_plus_one; + *length = 0; + + while (*kappa > 0) { + int digit = integrals / divisor; + ASSERT(digit <= 9); + buffer[*length] = static_cast('0' + digit); + (*length)++; + integrals %= divisor; + (*kappa)--; + + uint64_t rest = + (static_cast(integrals) << -one.e()) + fractionals; + + if (rest < unsafe_interval.f()) { + return RoundWeed(buffer, *length, DiyFp::Minus(too_high, w).f(), + unsafe_interval.f(), rest, + static_cast(divisor) << -one.e(), unit); + } + divisor /= 10; + } + + ASSERT(one.e() >= -60); + ASSERT(fractionals < one.f()); + ASSERT(UINT64_2PART_C(0xFFFFFFFF, FFFFFFFF) / 10 >= one.f()); + + for (;;) { + fractionals *= 10; + unit *= 10; + unsafe_interval.set_f(unsafe_interval.f() * 10); + // Integer division by one. + int digit = static_cast(fractionals >> -one.e()); + ASSERT(digit <= 9); + buffer[*length] = static_cast('0' + digit); + (*length)++; + fractionals &= one.f() - 1; // Modulo by one. + (*kappa)--; + if (fractionals < unsafe_interval.f()) { + return RoundWeed(buffer, *length, DiyFp::Minus(too_high, w).f() * unit, + unsafe_interval.f(), fractionals, one.f(), unit); + } + } +} + +static bool DigitGenCounted(DiyFp w, int requested_digits, Vector buffer, + int* length, int* kappa) +{ + ASSERT(kMinimalTargetExponent <= w.e() && w.e() <= kMaximalTargetExponent); + ASSERT(kMinimalTargetExponent >= -60); + ASSERT(kMaximalTargetExponent <= -32); + + uint64_t w_error = 1; + DiyFp one = DiyFp(static_cast(1) << -w.e(), w.e()); + uint32_t integrals = static_cast(w.f() >> -one.e()); + uint64_t fractionals = w.f() & (one.f() - 1); + uint32_t divisor; + int divisor_exponent_plus_one; + BiggestPowerTen(integrals, DiyFp::kSignificandSize - (-one.e()), + &divisor, &divisor_exponent_plus_one); + *kappa = divisor_exponent_plus_one; + *length = 0; + + while (*kappa > 0) { + int digit = integrals / divisor; + ASSERT(digit <= 9); + buffer[*length] = static_cast('0' + digit); + (*length)++; + requested_digits--; + integrals %= divisor; + (*kappa)--; + if (requested_digits == 0) break; + divisor /= 10; + } + + if (requested_digits == 0) { + uint64_t rest = + (static_cast(integrals) << -one.e()) + fractionals; + return RoundWeedCounted(buffer, *length, rest, + static_cast(divisor) << -one.e(), w_error, + kappa); + } + + ASSERT(one.e() >= -60); + ASSERT(fractionals < one.f()); + ASSERT(UINT64_2PART_C(0xFFFFFFFF, FFFFFFFF) / 10 >= one.f()); + + while (requested_digits > 0 && fractionals > w_error) { + fractionals *= 10; + w_error *= 10; + // Integer division by one. + int digit = static_cast(fractionals >> -one.e()); + ASSERT(digit <= 9); + buffer[*length] = static_cast('0' + digit); + (*length)++; + requested_digits--; + fractionals &= one.f() - 1; // Modulo by one. + (*kappa)--; + } + if (requested_digits != 0) return false; + return RoundWeedCounted(buffer, *length, fractionals, one.f(), w_error, + kappa); +} + +static bool Grisu3(double v, FastDtoaMode mode, Vector buffer, + int* length, int* decimal_exponent) +{ + DiyFp w = Double(v).AsNormalizedDiyFp(); + DiyFp boundary_minus, boundary_plus; + + ASSERT(mode == FAST_DTOA_SHORTEST); + Double(v).NormalizedBoundaries(&boundary_minus, &boundary_plus); + + ASSERT(boundary_plus.e() == w.e()); + DiyFp ten_mk; // Cached power of ten: 10^-k + int mk; // -k + int ten_mk_minimal_binary_exponent = + kMinimalTargetExponent - (w.e() + DiyFp::kSignificandSize); + int ten_mk_maximal_binary_exponent = + kMaximalTargetExponent - (w.e() + DiyFp::kSignificandSize); + PowersOfTenCache::GetCachedPowerForBinaryExponentRange( + ten_mk_minimal_binary_exponent, + ten_mk_maximal_binary_exponent, + &ten_mk, &mk); + + ASSERT((kMinimalTargetExponent <= w.e() + ten_mk.e() + + DiyFp::kSignificandSize) && + (kMaximalTargetExponent >= w.e() + ten_mk.e() + + DiyFp::kSignificandSize)); + + DiyFp scaled_w = DiyFp::Times(w, ten_mk); + ASSERT(scaled_w.e() == + boundary_plus.e() + ten_mk.e() + DiyFp::kSignificandSize); + + DiyFp scaled_boundary_minus = DiyFp::Times(boundary_minus, ten_mk); + DiyFp scaled_boundary_plus = DiyFp::Times(boundary_plus, ten_mk); + + int kappa; + bool result = DigitGen(scaled_boundary_minus, scaled_w, scaled_boundary_plus, + buffer, length, &kappa); + *decimal_exponent = -mk + kappa; + return result; +} + +static bool Grisu3Counted(double v, int requested_digits, Vector buffer, + int* length, int* decimal_exponent) +{ + DiyFp w = Double(v).AsNormalizedDiyFp(); + DiyFp ten_mk; // Cached power of ten: 10^-k + int mk; // -k + int ten_mk_minimal_binary_exponent = + kMinimalTargetExponent - (w.e() + DiyFp::kSignificandSize); + int ten_mk_maximal_binary_exponent = + kMaximalTargetExponent - (w.e() + DiyFp::kSignificandSize); + PowersOfTenCache::GetCachedPowerForBinaryExponentRange( + ten_mk_minimal_binary_exponent, + ten_mk_maximal_binary_exponent, + &ten_mk, &mk); + ASSERT((kMinimalTargetExponent <= w.e() + ten_mk.e() + + DiyFp::kSignificandSize) && + (kMaximalTargetExponent >= w.e() + ten_mk.e() + + DiyFp::kSignificandSize)); + + DiyFp scaled_w = DiyFp::Times(w, ten_mk); + + int kappa; + bool result = DigitGenCounted(scaled_w, requested_digits, + buffer, length, &kappa); + *decimal_exponent = -mk + kappa; + return result; +} + + +bool FastDtoa(double v, + FastDtoaMode mode, + int requested_digits, + Vector buffer, + int* length, + int* decimal_point) { + ASSERT(v > 0); + ASSERT(!Double(v).IsSpecial()); + + bool result = false; + int decimal_exponent = 0; + switch (mode) { + case FAST_DTOA_SHORTEST: + result = Grisu3(v, mode, buffer, length, &decimal_exponent); + break; + case FAST_DTOA_PRECISION: + result = Grisu3Counted(v, requested_digits, + buffer, length, &decimal_exponent); + break; + default: + UNREACHABLE(); + } + if (result) { + *decimal_point = *length + decimal_exponent; + buffer[*length] = '\0'; + } + return result; +} + +// Represents a 128bit type. This class should be replaced by a native type on +// platforms that support 128bit integers. +class UInt128 { + public: + UInt128() : high_bits_(0), low_bits_(0) { } + UInt128(uint64_t high, uint64_t low) : high_bits_(high), low_bits_(low) { } + + void Multiply(uint32_t multiplicand) { + uint64_t accumulator; + + accumulator = (low_bits_ & kMask32) * multiplicand; + uint32_t part = static_cast(accumulator & kMask32); + accumulator >>= 32; + accumulator = accumulator + (low_bits_ >> 32) * multiplicand; + low_bits_ = (accumulator << 32) + part; + accumulator >>= 32; + accumulator = accumulator + (high_bits_ & kMask32) * multiplicand; + part = static_cast(accumulator & kMask32); + accumulator >>= 32; + accumulator = accumulator + (high_bits_ >> 32) * multiplicand; + high_bits_ = (accumulator << 32) + part; + ASSERT((accumulator >> 32) == 0); + } + + void Shift(int shift_amount) { + ASSERT(-64 <= shift_amount && shift_amount <= 64); + if (shift_amount == 0) { + return; + } else if (shift_amount == -64) { + high_bits_ = low_bits_; + low_bits_ = 0; + } else if (shift_amount == 64) { + low_bits_ = high_bits_; + high_bits_ = 0; + } else if (shift_amount <= 0) { + high_bits_ <<= -shift_amount; + high_bits_ += low_bits_ >> (64 + shift_amount); + low_bits_ <<= -shift_amount; + } else { + low_bits_ >>= shift_amount; + low_bits_ += high_bits_ << (64 - shift_amount); + high_bits_ >>= shift_amount; + } + } + + // Modifies *this to *this MOD (2^power). + // Returns *this DIV (2^power). + int DivModPowerOf2(int power) { + if (power >= 64) { + int result = static_cast(high_bits_ >> (power - 64)); + high_bits_ -= static_cast(result) << (power - 64); + return result; + } else { + uint64_t part_low = low_bits_ >> power; + uint64_t part_high = high_bits_ << (64 - power); + int result = static_cast(part_low + part_high); + high_bits_ = 0; + low_bits_ -= part_low << power; + return result; + } + } + + bool IsZero() const { + return high_bits_ == 0 && low_bits_ == 0; + } + + int BitAt(int position) { + if (position >= 64) { + return static_cast(high_bits_ >> (position - 64)) & 1; + } else { + return static_cast(low_bits_ >> position) & 1; + } + } + + private: + static const uint64_t kMask32 = 0xFFFFFFFF; + // Value == (high_bits_ << 64) + low_bits_ + uint64_t high_bits_; + uint64_t low_bits_; +}; + + +static const int kDoubleSignificandSize = 53; // Includes the hidden bit. + + +static void FillDigits32FixedLength(uint32_t number, int requested_length, + Vector buffer, int* length) { + for (int i = requested_length - 1; i >= 0; --i) { + buffer[(*length) + i] = '0' + number % 10; + number /= 10; + } + *length += requested_length; +} + + +static void FillDigits32(uint32_t number, Vector buffer, int* length) { + int number_length = 0; + // We fill the digits in reverse order and exchange them afterwards. + while (number != 0) { + int digit = number % 10; + number /= 10; + buffer[(*length) + number_length] = static_cast('0' + digit); + number_length++; + } + // Exchange the digits. + int i = *length; + int j = *length + number_length - 1; + while (i < j) { + char tmp = buffer[i]; + buffer[i] = buffer[j]; + buffer[j] = tmp; + i++; + j--; + } + *length += number_length; +} + + +static void FillDigits64FixedLength(uint64_t number, + Vector buffer, int* length) { + const uint32_t kTen7 = 10000000; + // For efficiency cut the number into 3 uint32_t parts, and print those. + uint32_t part2 = static_cast(number % kTen7); + number /= kTen7; + uint32_t part1 = static_cast(number % kTen7); + uint32_t part0 = static_cast(number / kTen7); + + FillDigits32FixedLength(part0, 3, buffer, length); + FillDigits32FixedLength(part1, 7, buffer, length); + FillDigits32FixedLength(part2, 7, buffer, length); +} + + +static void FillDigits64(uint64_t number, Vector buffer, int* length) { + const uint32_t kTen7 = 10000000; + // For efficiency cut the number into 3 uint32_t parts, and print those. + uint32_t part2 = static_cast(number % kTen7); + number /= kTen7; + uint32_t part1 = static_cast(number % kTen7); + uint32_t part0 = static_cast(number / kTen7); + + if (part0 != 0) { + FillDigits32(part0, buffer, length); + FillDigits32FixedLength(part1, 7, buffer, length); + FillDigits32FixedLength(part2, 7, buffer, length); + } else if (part1 != 0) { + FillDigits32(part1, buffer, length); + FillDigits32FixedLength(part2, 7, buffer, length); + } else { + FillDigits32(part2, buffer, length); + } +} + + +static void RoundUp(Vector buffer, int* length, int* decimal_point) { + // An empty buffer represents 0. + if (*length == 0) { + buffer[0] = '1'; + *decimal_point = 1; + *length = 1; + return; + } + + buffer[(*length) - 1]++; + for (int i = (*length) - 1; i > 0; --i) { + if (buffer[i] != '0' + 10) { + return; + } + buffer[i] = '0'; + buffer[i - 1]++; + } + + if (buffer[0] == '0' + 10) { + buffer[0] = '1'; + (*decimal_point)++; + } +} + +static void FillFractionals(uint64_t fractionals, int exponent, + int fractional_count, Vector buffer, + int* length, int* decimal_point) +{ + ASSERT(-128 <= exponent && exponent <= 0); + + if (-exponent <= 64) { + ASSERT(fractionals >> 56 == 0); + int point = -exponent; + for (int i = 0; i < fractional_count; ++i) { + if (fractionals == 0) break; + fractionals *= 5; + point--; + int digit = static_cast(fractionals >> point); + ASSERT(digit <= 9); + buffer[*length] = static_cast('0' + digit); + (*length)++; + fractionals -= static_cast(digit) << point; + } + + if (((fractionals >> (point - 1)) & 1) == 1) { + RoundUp(buffer, length, decimal_point); + } + } else { // We need 128 bits. + ASSERT(64 < -exponent && -exponent <= 128); + UInt128 fractionals128 = UInt128(fractionals, 0); + fractionals128.Shift(-exponent - 64); + int point = 128; + for (int i = 0; i < fractional_count; ++i) { + if (fractionals128.IsZero()) break; + fractionals128.Multiply(5); + point--; + int digit = fractionals128.DivModPowerOf2(point); + ASSERT(digit <= 9); + buffer[*length] = static_cast('0' + digit); + (*length)++; + } + if (fractionals128.BitAt(point - 1) == 1) { + RoundUp(buffer, length, decimal_point); + } + } +} + + +// Removes leading and trailing zeros. +// If leading zeros are removed then the decimal point position is adjusted. +static void TrimZeros(Vector buffer, int* length, int* decimal_point) { + while (*length > 0 && buffer[(*length) - 1] == '0') { + (*length)--; + } + int first_non_zero = 0; + while (first_non_zero < *length && buffer[first_non_zero] == '0') { + first_non_zero++; + } + if (first_non_zero != 0) { + for (int i = first_non_zero; i < *length; ++i) { + buffer[i - first_non_zero] = buffer[i]; + } + *length -= first_non_zero; + *decimal_point -= first_non_zero; + } +} + + +bool FastFixedDtoa(double v, + int fractional_count, + Vector buffer, + int* length, + int* decimal_point) { + const uint32_t kMaxUInt32 = 0xFFFFFFFF; + uint64_t significand = Double(v).Significand(); + int exponent = Double(v).Exponent(); + + if (exponent > 20) return false; + if (fractional_count > 20) return false; + *length = 0; + + if (exponent + kDoubleSignificandSize > 64) { + const uint64_t kFive17 = UINT64_2PART_C(0xB1, A2BC2EC5); // 5^17 + uint64_t divisor = kFive17; + int divisor_power = 17; + uint64_t dividend = significand; + uint32_t quotient; + uint64_t remainder; + + if (exponent > divisor_power) { + dividend <<= exponent - divisor_power; + quotient = static_cast(dividend / divisor); + remainder = (dividend % divisor) << divisor_power; + } else { + divisor <<= divisor_power - exponent; + quotient = static_cast(dividend / divisor); + remainder = (dividend % divisor) << exponent; + } + FillDigits32(quotient, buffer, length); + FillDigits64FixedLength(remainder, buffer, length); + *decimal_point = *length; + } else if (exponent >= 0) { + // 0 <= exponent <= 11 + significand <<= exponent; + FillDigits64(significand, buffer, length); + *decimal_point = *length; + } else if (exponent > -kDoubleSignificandSize) { + uint64_t integrals = significand >> -exponent; + uint64_t fractionals = significand - (integrals << -exponent); + if (integrals > kMaxUInt32) { + FillDigits64(integrals, buffer, length); + } else { + FillDigits32(static_cast(integrals), buffer, length); + } + *decimal_point = *length; + FillFractionals(fractionals, exponent, fractional_count, + buffer, length, decimal_point); + } else if (exponent < -128) { + // This configuration (with at most 20 digits) means that all digits must be + // 0. + ASSERT(fractional_count <= 20); + buffer[0] = '\0'; + *length = 0; + *decimal_point = -fractional_count; + } else { + *decimal_point = 0; + FillFractionals(significand, exponent, fractional_count, + buffer, length, decimal_point); + } + TrimZeros(buffer, length, decimal_point); + buffer[*length] = '\0'; + if ((*length) == 0) { + *decimal_point = -fractional_count; + } + return true; +} + +static const int kMaxExactDoubleIntegerDecimalDigits = 15; +static const int kMaxUint64DecimalDigits = 19; + +static const int kMaxDecimalPower = 309; +static const int kMinDecimalPower = -324; + +// 2^64 = 18446744073709551616 +static const uint64_t kMaxUint64 = UINT64_2PART_C(0xFFFFFFFF, FFFFFFFF); +static const int kMaxSignificantDecimalDigits = 780; + +static Vector TrimLeadingZeros(Vector buffer) { + for (int i = 0; i < buffer.length(); i++) { + if (buffer[i] != '0') { + return buffer.SubVector(i, buffer.length()); + } + } + return Vector(buffer.start(), 0); +} + + +static Vector TrimTrailingZeros(Vector buffer) { + for (int i = buffer.length() - 1; i >= 0; --i) { + if (buffer[i] != '0') { + return buffer.SubVector(0, i + 1); + } + } + return Vector(buffer.start(), 0); +} + + +static void CutToMaxSignificantDigits(Vector buffer, + int exponent, + char* significant_buffer, + int* significant_exponent) { + for (int i = 0; i < kMaxSignificantDecimalDigits - 1; ++i) { + significant_buffer[i] = buffer[i]; + } + + ASSERT(buffer[buffer.length() - 1] != '0'); + + significant_buffer[kMaxSignificantDecimalDigits - 1] = '1'; + *significant_exponent = + exponent + (buffer.length() - kMaxSignificantDecimalDigits); +} + +static void TrimAndCut(Vector buffer, int exponent, + char* buffer_copy_space, int space_size, + Vector* trimmed, int* updated_exponent) { + Vector left_trimmed = TrimLeadingZeros(buffer); + Vector right_trimmed = TrimTrailingZeros(left_trimmed); + exponent += left_trimmed.length() - right_trimmed.length(); + if (right_trimmed.length() > kMaxSignificantDecimalDigits) { + (void) space_size; // Mark variable as used. + ASSERT(space_size >= kMaxSignificantDecimalDigits); + CutToMaxSignificantDigits(right_trimmed, exponent, + buffer_copy_space, updated_exponent); + *trimmed = Vector(buffer_copy_space, + kMaxSignificantDecimalDigits); + } else { + *trimmed = right_trimmed; + *updated_exponent = exponent; + } +} + +static uint64_t ReadUint64(Vector buffer, + int* number_of_read_digits) { + uint64_t result = 0; + int i = 0; + while (i < buffer.length() && result <= (kMaxUint64 / 10 - 1)) { + int digit = buffer[i++] - '0'; + ASSERT(0 <= digit && digit <= 9); + result = 10 * result + digit; + } + *number_of_read_digits = i; + return result; +} + +static void ReadDiyFp(Vector buffer, + DiyFp* result, + int* remaining_decimals) { + int read_digits; + uint64_t significand = ReadUint64(buffer, &read_digits); + if (buffer.length() == read_digits) { + *result = DiyFp(significand, 0); + *remaining_decimals = 0; + } else { + // Round the significand. + if (buffer[read_digits] >= '5') { + significand++; + } + // Compute the binary exponent. + int exponent = 0; + *result = DiyFp(significand, exponent); + *remaining_decimals = buffer.length() - read_digits; + } +} + +static DiyFp AdjustmentPowerOfTen(int exponent) { + ASSERT(0 < exponent); + ASSERT(exponent < PowersOfTenCache::kDecimalExponentDistance); + // Simply hardcode the remaining powers for the given decimal exponent + // distance. + ASSERT(PowersOfTenCache::kDecimalExponentDistance == 8); + switch (exponent) { + case 1: return DiyFp(UINT64_2PART_C(0xa0000000, 00000000), -60); + case 2: return DiyFp(UINT64_2PART_C(0xc8000000, 00000000), -57); + case 3: return DiyFp(UINT64_2PART_C(0xfa000000, 00000000), -54); + case 4: return DiyFp(UINT64_2PART_C(0x9c400000, 00000000), -50); + case 5: return DiyFp(UINT64_2PART_C(0xc3500000, 00000000), -47); + case 6: return DiyFp(UINT64_2PART_C(0xf4240000, 00000000), -44); + case 7: return DiyFp(UINT64_2PART_C(0x98968000, 00000000), -40); + default: + UNREACHABLE(); + } +} + +static bool DiyFpStrtod(Vector buffer, + int exponent, + double* result) { + DiyFp input; + int remaining_decimals; + ReadDiyFp(buffer, &input, &remaining_decimals); + + const int kDenominatorLog = 3; + const int kDenominator = 1 << kDenominatorLog; + // Move the remaining decimals into the exponent. + exponent += remaining_decimals; + int error = (remaining_decimals == 0 ? 0 : kDenominator / 2); + + int old_e = input.e(); + input.Normalize(); + error <<= old_e - input.e(); + + ASSERT(exponent <= PowersOfTenCache::kMaxDecimalExponent); + if (exponent < PowersOfTenCache::kMinDecimalExponent) { + *result = 0.0; + return true; + } + DiyFp cached_power; + int cached_decimal_exponent; + PowersOfTenCache::GetCachedPowerForDecimalExponent(exponent, + &cached_power, + &cached_decimal_exponent); + + if (cached_decimal_exponent != exponent) { + int adjustment_exponent = exponent - cached_decimal_exponent; + DiyFp adjustment_power = AdjustmentPowerOfTen(adjustment_exponent); + input.Multiply(adjustment_power); + if (kMaxUint64DecimalDigits - buffer.length() >= adjustment_exponent) { + // The product of input with the adjustment power fits into a 64 bit + // integer. + ASSERT(DiyFp::kSignificandSize == 64); + } else { + // The adjustment power is exact. There is hence only an error of 0.5. + error += kDenominator / 2; + } + } + + input.Multiply(cached_power); + + int error_b = kDenominator / 2; + int error_ab = (error == 0 ? 0 : 1); // We round up to 1. + int fixed_error = kDenominator / 2; + error += error_b + error_ab + fixed_error; + + old_e = input.e(); + input.Normalize(); + error <<= old_e - input.e(); + + int order_of_magnitude = DiyFp::kSignificandSize + input.e(); + int effective_significand_size = + Double::SignificandSizeForOrderOfMagnitude(order_of_magnitude); + int precision_digits_count = + DiyFp::kSignificandSize - effective_significand_size; + if (precision_digits_count + kDenominatorLog >= DiyFp::kSignificandSize) { + int shift_amount = (precision_digits_count + kDenominatorLog) - + DiyFp::kSignificandSize + 1; + input.set_f(input.f() >> shift_amount); + input.set_e(input.e() + shift_amount); + error = (error >> shift_amount) + 1 + kDenominator; + precision_digits_count -= shift_amount; + } + + ASSERT(DiyFp::kSignificandSize == 64); + ASSERT(precision_digits_count < 64); + uint64_t one64 = 1; + uint64_t precision_bits_mask = (one64 << precision_digits_count) - 1; + uint64_t precision_bits = input.f() & precision_bits_mask; + uint64_t half_way = one64 << (precision_digits_count - 1); + precision_bits *= kDenominator; + half_way *= kDenominator; + DiyFp rounded_input(input.f() >> precision_digits_count, + input.e() + precision_digits_count); + if (precision_bits >= half_way + error) { + rounded_input.set_f(rounded_input.f() + 1); + } + + *result = Double(rounded_input).value(); + if (half_way - error < precision_bits && precision_bits < half_way + error) { + return false; + } else { + return true; + } +} + +static int CompareBufferWithDiyFp(Vector buffer, + int exponent, + DiyFp diy_fp) { + ASSERT(buffer.length() + exponent <= kMaxDecimalPower + 1); + ASSERT(buffer.length() + exponent > kMinDecimalPower); + ASSERT(buffer.length() <= kMaxSignificantDecimalDigits); + ASSERT(((kMaxDecimalPower + 1) * 333 / 100) < Bignum::kMaxSignificantBits); + + Bignum buffer_bignum; + Bignum diy_fp_bignum; + buffer_bignum.AssignDecimalString(buffer); + diy_fp_bignum.AssignUInt64(diy_fp.f()); + if (exponent >= 0) { + buffer_bignum.MultiplyByPowerOfTen(exponent); + } else { + diy_fp_bignum.MultiplyByPowerOfTen(-exponent); + } + if (diy_fp.e() > 0) { + diy_fp_bignum.ShiftLeft(diy_fp.e()); + } else { + buffer_bignum.ShiftLeft(-diy_fp.e()); + } + return Bignum::Compare(buffer_bignum, diy_fp_bignum); +} + +static bool ComputeGuess(Vector trimmed, int exponent, + double* guess) +{ + if (trimmed.length() == 0) { + *guess = 0.0; + return true; + } + if (exponent + trimmed.length() - 1 >= kMaxDecimalPower) { + *guess = Double::Infinity(); + return true; + } + if (exponent + trimmed.length() <= kMinDecimalPower) { + *guess = 0.0; + return true; + } + + if (DiyFpStrtod(trimmed, exponent, guess)) { + return true; + } + if (*guess == Double::Infinity()) { + return true; + } + return false; +} + +double Strtod(Vector buffer, int exponent) +{ + char copy_buffer[kMaxSignificantDecimalDigits]; + Vector trimmed; + int updated_exponent; + TrimAndCut(buffer, exponent, copy_buffer, kMaxSignificantDecimalDigits, + &trimmed, &updated_exponent); + exponent = updated_exponent; + + double guess; + bool is_correct = ComputeGuess(trimmed, exponent, &guess); + if (is_correct) return guess; + + DiyFp upper_boundary = Double(guess).UpperBoundary(); + int comparison = CompareBufferWithDiyFp(trimmed, exponent, upper_boundary); + if (comparison < 0) { + return guess; + } else if (comparison > 0) { + return Double(guess).NextDouble(); + } else if ((Double(guess).Significand() & 1) == 0) { + // Round towards even. + return guess; + } else { + return Double(guess).NextDouble(); + } +} + +class DoubleToStringConverter { +public: + static const int kMaxFixedDigitsBeforePoint = 60; + static const int kMaxFixedDigitsAfterPoint = 60; + static const int kMaxExponentialDigits = 120; + static const int kMinPrecisionDigits = 1; + static const int kMaxPrecisionDigits = 120; + + enum Flags { + NO_FLAGS = 0, + EMIT_POSITIVE_EXPONENT_SIGN = 1, + EMIT_TRAILING_DECIMAL_POINT = 2, + EMIT_TRAILING_ZERO_AFTER_POINT = 4, + UNIQUE_ZERO = 8 + }; + + DoubleToStringConverter(int flags, + const char* infinity_symbol, + const char* nan_symbol, + char exponent_character, + int decimal_in_shortest_low, + int decimal_in_shortest_high, + int max_leading_padding_zeroes_in_precision_mode, + int max_trailing_padding_zeroes_in_precision_mode) + : flags_(flags), + infinity_symbol_(infinity_symbol), + nan_symbol_(nan_symbol), + exponent_character_(exponent_character), + decimal_in_shortest_low_(decimal_in_shortest_low), + decimal_in_shortest_high_(decimal_in_shortest_high), + max_leading_padding_zeroes_in_precision_mode_( + max_leading_padding_zeroes_in_precision_mode), + max_trailing_padding_zeroes_in_precision_mode_( + max_trailing_padding_zeroes_in_precision_mode) { + // When 'trailing zero after the point' is set, then 'trailing point' + // must be set too. + ASSERT(((flags & EMIT_TRAILING_DECIMAL_POINT) != 0) || + !((flags & EMIT_TRAILING_ZERO_AFTER_POINT) != 0)); + } + + bool ToShortest(double value, std::string &s) const { + return ToShortestIeeeNumber(value, s, SHORTEST); + } + + bool ToFixed(double value, + int requested_digits, + std::string &s) const; + + bool ToExponential(double value, + int requested_digits, + std::string &s) const; + + bool ToPrecision(double value, + int precision, + std::string &s) const; + + enum DtoaMode { + SHORTEST, + FIXED, // Produce a fixed number of digits after the decimal point + PRECISION // Fixed number of digits (independent of the decimal point) + }; + + static const int kBase10MaximalLength = 17; + + // The result should be interpreted as buffer * 10^(point-length). + static void DoubleToAscii(double v, + DtoaMode mode, + int requested_digits, + char* buffer, + int buffer_length, + bool* sign, + int* length, + int* point); + + private: + // Implementation for ToShortest. + bool ToShortestIeeeNumber(double value, + std::string &s, + DtoaMode mode) const; + + bool HandleSpecialValues(double value, std::string &s) const; + + void CreateExponentialRepresentation(const char* decimal_digits, + int length, + int exponent, + std::string &s) const; + + void CreateDecimalRepresentation(const char* decimal_digits, + int length, + int decimal_point, + int digits_after_point, + std::string &s) const; + + const int flags_; + const char* const infinity_symbol_; + const char* const nan_symbol_; + const char exponent_character_; + const int decimal_in_shortest_low_; + const int decimal_in_shortest_high_; + const int max_leading_padding_zeroes_in_precision_mode_; + const int max_trailing_padding_zeroes_in_precision_mode_; + + DISALLOW_IMPLICIT_CONSTRUCTORS(DoubleToStringConverter); +}; + + +class StringToDoubleConverter { + public: + enum Flags { + NO_FLAGS = 0, + ALLOW_HEX = 1, + ALLOW_OCTALS = 2, + ALLOW_TRAILING_JUNK = 4, + ALLOW_LEADING_SPACES = 8, + ALLOW_TRAILING_SPACES = 16, + ALLOW_SPACES_AFTER_SIGN = 32 + }; + + StringToDoubleConverter(int flags, + double empty_string_value, + double junk_string_value, + const char* infinity_symbol, + const char* nan_symbol) + : flags_(flags), + empty_string_value_(empty_string_value), + junk_string_value_(junk_string_value), + infinity_symbol_(infinity_symbol), + nan_symbol_(nan_symbol) { + } + + double StringToDouble(const char* buffer, + int length, + int* processed_characters_count) const; + + private: + const int flags_; + const double empty_string_value_; + const double junk_string_value_; + const char* const infinity_symbol_; + const char* const nan_symbol_; + + double StringToIeee(const char *start_pointer, + int length, + int* processed_characters_count) const; + + DISALLOW_IMPLICIT_CONSTRUCTORS(StringToDoubleConverter); +}; + +bool DoubleToStringConverter::HandleSpecialValues( + double value, + std::string &result) const { + Double double_inspect(value); + if (double_inspect.IsInfinite()) { + if (infinity_symbol_ == NULL) return false; + if (value < 0) { + result += '-'; + } + result += infinity_symbol_; + return true; + } + if (double_inspect.IsNan()) { + if (nan_symbol_ == NULL) return false; + result = nan_symbol_; + return true; + } + return false; +} + + +void DoubleToStringConverter::CreateExponentialRepresentation( + const char* decimal_digits, + int length, + int exponent, + std::string &result) const { + ASSERT(length != 0); + result += decimal_digits[0]; + if (length != 1) { + result += '.'; + result.append(&decimal_digits[1], length-1); + } + result += exponent_character_; + if (exponent < 0) { + result += '-'; + exponent = -exponent; + } else { + if ((flags_ & EMIT_POSITIVE_EXPONENT_SIGN) != 0) { + result += '+'; + } + } + if (exponent == 0) { + result += '0'; + return; + } + ASSERT(exponent < 1e4); + const int kMaxExponentLength = 5; + char buffer[kMaxExponentLength + 1]; + buffer[kMaxExponentLength] = '\0'; + int first_char_pos = kMaxExponentLength; + while (exponent > 0) { + buffer[--first_char_pos] = '0' + (exponent % 10); + exponent /= 10; + } + result.append(&buffer[first_char_pos], + kMaxExponentLength - first_char_pos); +} + + +void DoubleToStringConverter::CreateDecimalRepresentation( + const char* decimal_digits, + int length, + int decimal_point, + int digits_after_point, + std::string &result) const { + // Create a representation that is padded with zeros if needed. + if (decimal_point <= 0) { + // "0.00000decimal_rep". + result += '0'; + if (digits_after_point > 0) { + result += '.'; + result.append(-decimal_point, '0'); + ASSERT(length <= digits_after_point - (-decimal_point)); + result.append(decimal_digits, length); + int remaining_digits = digits_after_point - (-decimal_point) - length; + result.append(remaining_digits, '0'); + } + } else if (decimal_point >= length) { + // "decimal_rep0000.00000" or "decimal_rep.0000" + result.append(decimal_digits, length); + result.append(decimal_point - length, '0'); + if (digits_after_point > 0) { + result += '.'; + result.append(digits_after_point, '0'); + } + } else { + // "decima.l_rep000" + ASSERT(digits_after_point > 0); + result.append(decimal_digits, decimal_point); + result += '.'; + ASSERT(length - decimal_point <= digits_after_point); + result.append(&decimal_digits[decimal_point], length - decimal_point); + int remaining_digits = digits_after_point - (length - decimal_point); + result.append(remaining_digits, '0'); + } + if (digits_after_point == 0) { + if ((flags_ & EMIT_TRAILING_DECIMAL_POINT) != 0) { + result += '.'; + } + if ((flags_ & EMIT_TRAILING_ZERO_AFTER_POINT) != 0) { + result += '0'; + } + } +} + + +bool DoubleToStringConverter::ToShortestIeeeNumber( + double value, + std::string &result, + DoubleToStringConverter::DtoaMode mode) const { + ASSERT(mode == SHORTEST); + if (Double(value).IsSpecial()) { + return HandleSpecialValues(value, result); + } + + int decimal_point; + bool sign; + const int kDecimalRepCapacity = kBase10MaximalLength + 1; + char decimal_rep[kDecimalRepCapacity]; + int decimal_rep_length; + + DoubleToAscii(value, mode, 0, decimal_rep, kDecimalRepCapacity, + &sign, &decimal_rep_length, &decimal_point); + + bool unique_zero = (flags_ & UNIQUE_ZERO) != 0; + if (sign && (value != 0.0 || !unique_zero)) { + result += '-'; + } + + int exponent = decimal_point - 1; + if ((decimal_in_shortest_low_ <= exponent) && + (exponent < decimal_in_shortest_high_)) { + CreateDecimalRepresentation(decimal_rep, decimal_rep_length, decimal_point, + std::max(0, decimal_rep_length - decimal_point), + result); + } else { + CreateExponentialRepresentation(decimal_rep, decimal_rep_length, exponent, result); + } + return true; +} + + +bool DoubleToStringConverter::ToFixed(double value, + int requested_digits, + std::string &result) const +{ + ASSERT(kMaxFixedDigitsBeforePoint == 60); + const double kFirstNonFixed = 1e60; + + if (Double(value).IsSpecial()) { + return HandleSpecialValues(value, result); + } + + if (requested_digits > kMaxFixedDigitsAfterPoint) return false; + if (value >= kFirstNonFixed || value <= -kFirstNonFixed) return false; + + // Find a sufficiently precise decimal representation of n. + int decimal_point; + bool sign; + // Add space for the '\0' byte. + const int kDecimalRepCapacity = + kMaxFixedDigitsBeforePoint + kMaxFixedDigitsAfterPoint + 1; + char decimal_rep[kDecimalRepCapacity]; + int decimal_rep_length; + DoubleToAscii(value, FIXED, requested_digits, + decimal_rep, kDecimalRepCapacity, + &sign, &decimal_rep_length, &decimal_point); + + bool unique_zero = ((flags_ & UNIQUE_ZERO) != 0); + if (sign && (value != 0.0 || !unique_zero)) { + result += '-'; + } + + CreateDecimalRepresentation(decimal_rep, decimal_rep_length, decimal_point, + requested_digits, result); + return true; +} + + +bool DoubleToStringConverter::ToExponential( + double value, + int requested_digits, + std::string &result) const { + if (Double(value).IsSpecial()) { + return HandleSpecialValues(value, result); + } + + if (requested_digits < -1) return false; + if (requested_digits > kMaxExponentialDigits) return false; + + int decimal_point; + bool sign; + // Add space for digit before the decimal point and the '\0' character. + const int kDecimalRepCapacity = kMaxExponentialDigits + 2; + ASSERT(kDecimalRepCapacity > kBase10MaximalLength); + char decimal_rep[kDecimalRepCapacity]; + int decimal_rep_length; + + if (requested_digits == -1) { + DoubleToAscii(value, SHORTEST, 0, + decimal_rep, kDecimalRepCapacity, + &sign, &decimal_rep_length, &decimal_point); + } else { + DoubleToAscii(value, PRECISION, requested_digits + 1, + decimal_rep, kDecimalRepCapacity, + &sign, &decimal_rep_length, &decimal_point); + ASSERT(decimal_rep_length <= requested_digits + 1); + + for (int i = decimal_rep_length; i < requested_digits + 1; ++i) { + decimal_rep[i] = '0'; + } + decimal_rep_length = requested_digits + 1; + } + + bool unique_zero = ((flags_ & UNIQUE_ZERO) != 0); + if (sign && (value != 0.0 || !unique_zero)) { + result += '-'; + } + + int exponent = decimal_point - 1; + CreateExponentialRepresentation(decimal_rep, + decimal_rep_length, + exponent, result); + return true; +} + + +bool DoubleToStringConverter::ToPrecision(double value, + int precision, + std::string &result) const { + if (Double(value).IsSpecial()) { + return HandleSpecialValues(value, result); + } + + if (precision < kMinPrecisionDigits || precision > kMaxPrecisionDigits) { + return false; + } + + // Find a sufficiently precise decimal representation of n. + int decimal_point; + bool sign; + // Add one for the terminating null character. + const int kDecimalRepCapacity = kMaxPrecisionDigits + 1; + char decimal_rep[kDecimalRepCapacity]; + int decimal_rep_length; + + DoubleToAscii(value, PRECISION, precision, + decimal_rep, kDecimalRepCapacity, + &sign, &decimal_rep_length, &decimal_point); + ASSERT(decimal_rep_length <= precision); + + bool unique_zero = ((flags_ & UNIQUE_ZERO) != 0); + if (sign && (value != 0.0 || !unique_zero)) { + result += '-'; + } + + // The exponent if we print the number as x.xxeyyy. That is with the + // decimal point after the first digit. + int exponent = decimal_point - 1; + + int extra_zero = ((flags_ & EMIT_TRAILING_ZERO_AFTER_POINT) != 0) ? 1 : 0; + if ((-decimal_point + 1 > max_leading_padding_zeroes_in_precision_mode_) || + (decimal_point - precision + extra_zero > + max_trailing_padding_zeroes_in_precision_mode_)) { + for (int i = decimal_rep_length; i < precision; ++i) { + decimal_rep[i] = '0'; + } + + CreateExponentialRepresentation(decimal_rep, + precision, + exponent, + result); + } else { + CreateDecimalRepresentation(decimal_rep, decimal_rep_length, decimal_point, + std::max(0, precision - decimal_point), + result); + } + return true; +} + + +static BignumDtoaMode DtoaToBignumDtoaMode( + DoubleToStringConverter::DtoaMode dtoa_mode) { + switch (dtoa_mode) { + case DoubleToStringConverter::SHORTEST: return BIGNUM_DTOA_SHORTEST; + case DoubleToStringConverter::FIXED: return BIGNUM_DTOA_FIXED; + case DoubleToStringConverter::PRECISION: return BIGNUM_DTOA_PRECISION; + default: + UNREACHABLE(); + } +} + + +void DoubleToStringConverter::DoubleToAscii(double v, DtoaMode mode, int requested_digits, + char* buffer, int buffer_length, + bool* sign, int* length, int* point) +{ + Vector vector(buffer, buffer_length); + ASSERT(!Double(v).IsSpecial()); + ASSERT(mode == SHORTEST || requested_digits >= 0); + + if (Double(v).Sign() < 0) { + *sign = true; + v = -v; + } else { + *sign = false; + } + + if (mode == PRECISION && requested_digits == 0) { + vector[0] = '\0'; + *length = 0; + return; + } + + if (v == 0) { + vector[0] = '0'; + vector[1] = '\0'; + *length = 1; + *point = 1; + return; + } + + bool fast_worked; + switch (mode) { + case SHORTEST: + fast_worked = FastDtoa(v, FAST_DTOA_SHORTEST, 0, vector, length, point); + break; + case FIXED: + fast_worked = FastFixedDtoa(v, requested_digits, vector, length, point); + break; + case PRECISION: + fast_worked = FastDtoa(v, FAST_DTOA_PRECISION, requested_digits, + vector, length, point); + break; + default: + fast_worked = false; + UNREACHABLE(); + } + if (fast_worked) return; + + // If the fast dtoa didn't succeed use the slower bignum version. + BignumDtoaMode bignum_mode = DtoaToBignumDtoaMode(mode); + BignumDtoa(v, bignum_mode, requested_digits, vector, length, point); + vector[*length] = '\0'; +} + +template +static bool ConsumeSubString(Iterator* current, + Iterator end, + const char* substring) { + ASSERT(**current == *substring); + for (substring++; *substring != '\0'; substring++) { + ++*current; + if (*current == end || **current != *substring) return false; + } + ++*current; + return true; +} + +const int kMaxSignificantDigits = 772; + +static const char kWhitespaceTable7[] = { 32, 13, 10, 9, 11, 12 }; +static const int kWhitespaceTable7Length = ARRAY_SIZE(kWhitespaceTable7); + +static bool isWhitespace(int x) { + if (x < 128) { + for (int i = 0; i < kWhitespaceTable7Length; i++) { + if (kWhitespaceTable7[i] == x) return true; + } + } + return false; +} + +// Returns true if a nonspace found and false if the end has reached. +template +static inline bool AdvanceToNonspace(Iterator* current, Iterator end) { + while (*current != end) { + if (!isWhitespace(**current)) return true; + ++*current; + } + return false; +} + +static bool isDigit(int x, int radix) { + return (x >= '0' && x <= '9' && x < '0' + radix) + || (radix > 10 && x >= 'a' && x < 'a' + radix - 10) + || (radix > 10 && x >= 'A' && x < 'A' + radix - 10); +} + +static double SignedZero(bool sign) { + return sign ? -0.0 : 0.0; +} + +static bool IsDecimalDigitForRadix(int c, int radix) { + return '0' <= c && c <= '9' && (c - '0') < radix; +} + +static bool IsCharacterDigitForRadix(int c, int radix, char a_character) { + return radix > 10 && c >= a_character && c < a_character + radix - 10; +} + +template +static double RadixStringToIeee(Iterator* current, Iterator end, + bool sign, bool allow_trailing_junk, double junk_string_value, + bool* result_is_junk) +{ + ASSERT(*current != end); + + const int kSignificandSize = Double::kSignificandSize; + + *result_is_junk = true; + + // Skip leading 0s. + while (**current == '0') { + ++(*current); + if (*current == end) { + *result_is_junk = false; + return SignedZero(sign); + } + } + + int64_t number = 0; + int exponent = 0; + const int radix = (1 << radix_log_2); + + do { + int digit; + if (IsDecimalDigitForRadix(**current, radix)) { + digit = static_cast(**current) - '0'; + } else if (IsCharacterDigitForRadix(**current, radix, 'a')) { + digit = static_cast(**current) - 'a' + 10; + } else if (IsCharacterDigitForRadix(**current, radix, 'A')) { + digit = static_cast(**current) - 'A' + 10; + } else { + if (allow_trailing_junk || !AdvanceToNonspace(current, end)) { + break; + } else { + return junk_string_value; + } + } + + number = number * radix + digit; + int overflow = static_cast(number >> kSignificandSize); + if (overflow != 0) { + // Overflow occurred. Need to determine which direction to round the + // result. + int overflow_bits_count = 1; + while (overflow > 1) { + overflow_bits_count++; + overflow >>= 1; + } + + int dropped_bits_mask = ((1 << overflow_bits_count) - 1); + int dropped_bits = static_cast(number) & dropped_bits_mask; + number >>= overflow_bits_count; + exponent = overflow_bits_count; + + bool zero_tail = true; + for (;;) { + ++(*current); + if (*current == end || !isDigit(**current, radix)) break; + zero_tail = zero_tail && **current == '0'; + exponent += radix_log_2; + } + + if (!allow_trailing_junk && AdvanceToNonspace(current, end)) { + return junk_string_value; + } + + int middle_value = (1 << (overflow_bits_count - 1)); + if (dropped_bits > middle_value) { + number++; // Rounding up. + } else if (dropped_bits == middle_value) { + // Rounding to even to consistency with decimals: half-way case rounds + // up if significant part is odd and down otherwise. + if ((number & 1) != 0 || !zero_tail) { + number++; // Rounding up. + } + } + + // Rounding up may cause overflow. + if ((number & ((int64_t)1 << kSignificandSize)) != 0) { + exponent++; + number >>= 1; + } + break; + } + ++(*current); + } while (*current != end); + + ASSERT(number < ((int64_t)1 << kSignificandSize)); + ASSERT(static_cast(static_cast(number)) == number); + + *result_is_junk = false; + + if (exponent == 0) { + if (sign) { + if (number == 0) return -0.0; + number = -number; + } + return static_cast(number); + } + + ASSERT(number != 0); + return Double(DiyFp(number, exponent)).value(); +} + +double StringToDoubleConverter::StringToIeee( + const char *input, + int length, + int* processed_characters_count) const { + const char *current = input; + const char *end = input + length; + + *processed_characters_count = 0; + + const bool allow_trailing_junk = (flags_ & ALLOW_TRAILING_JUNK) != 0; + const bool allow_leading_spaces = (flags_ & ALLOW_LEADING_SPACES) != 0; + const bool allow_trailing_spaces = (flags_ & ALLOW_TRAILING_SPACES) != 0; + const bool allow_spaces_after_sign = (flags_ & ALLOW_SPACES_AFTER_SIGN) != 0; + + if (current == end) return empty_string_value_; + + if (allow_leading_spaces || allow_trailing_spaces) { + if (!AdvanceToNonspace(¤t, end)) { + *processed_characters_count = static_cast(current - input); + return empty_string_value_; + } + if (!allow_leading_spaces && (input != current)) { + return junk_string_value_; + } + } + + const int kBufferSize = kMaxSignificantDigits + 10; + char buffer[kBufferSize]; // NOLINT: size is known at compile time. + int buffer_pos = 0; + + int exponent = 0; + int significant_digits = 0; + int insignificant_digits = 0; + bool nonzero_digit_dropped = false; + + bool sign = false; + + if (*current == '+' || *current == '-') { + sign = (*current == '-'); + ++current; + const char *next_non_space = current; + + if (!AdvanceToNonspace(&next_non_space, end)) return junk_string_value_; + if (!allow_spaces_after_sign && (current != next_non_space)) { + return junk_string_value_; + } + current = next_non_space; + } + + if (infinity_symbol_ != NULL) { + if (*current == infinity_symbol_[0]) { + if (!ConsumeSubString(¤t, end, infinity_symbol_)) { + return junk_string_value_; + } + + if (!(allow_trailing_spaces || allow_trailing_junk) && (current != end)) { + return junk_string_value_; + } + if (!allow_trailing_junk && AdvanceToNonspace(¤t, end)) { + return junk_string_value_; + } + + ASSERT(buffer_pos == 0); + *processed_characters_count = static_cast(current - input); + return sign ? -Double::Infinity() : Double::Infinity(); + } + } + + if (nan_symbol_ != NULL) { + if (*current == nan_symbol_[0]) { + if (!ConsumeSubString(¤t, end, nan_symbol_)) { + return junk_string_value_; + } + + if (!(allow_trailing_spaces || allow_trailing_junk) && (current != end)) { + return junk_string_value_; + } + if (!allow_trailing_junk && AdvanceToNonspace(¤t, end)) { + return junk_string_value_; + } + + ASSERT(buffer_pos == 0); + *processed_characters_count = static_cast(current - input); + return sign ? -Double::NaN() : Double::NaN(); + } + } + + bool leading_zero = false; + if (*current == '0') { + ++current; + if (current == end) { + *processed_characters_count = static_cast(current - input); + return SignedZero(sign); + } + + leading_zero = true; + + // It could be hexadecimal value. + if ((flags_ & ALLOW_HEX) && (*current == 'x' || *current == 'X')) { + ++current; + if (current == end || !isDigit(*current, 16)) { + return junk_string_value_; // "0x". + } + + bool result_is_junk; + double result = RadixStringToIeee<4>(¤t, + end, + sign, + allow_trailing_junk, + junk_string_value_, + &result_is_junk); + if (!result_is_junk) { + if (allow_trailing_spaces) AdvanceToNonspace(¤t, end); + *processed_characters_count = static_cast(current - input); + } + return result; + } + + // Ignore leading zeros in the integer part. + while (*current == '0') { + ++current; + if (current == end) { + *processed_characters_count = static_cast(current - input); + return SignedZero(sign); + } + } + } + + bool octal = leading_zero && (flags_ & ALLOW_OCTALS) != 0; + + // Copy significant digits of the integer part (if any) to the buffer. + while (*current >= '0' && *current <= '9') { + if (significant_digits < kMaxSignificantDigits) { + ASSERT(buffer_pos < kBufferSize); + buffer[buffer_pos++] = static_cast(*current); + significant_digits++; + // Will later check if it's an octal in the buffer. + } else { + insignificant_digits++; // Move the digit into the exponential part. + nonzero_digit_dropped = nonzero_digit_dropped || *current != '0'; + } + octal = octal && *current < '8'; + ++current; + if (current == end) goto parsing_done; + } + + if (significant_digits == 0) { + octal = false; + } + + if (*current == '.') { + if (octal && !allow_trailing_junk) return junk_string_value_; + if (octal) goto parsing_done; + + ++current; + if (current == end) { + if (significant_digits == 0 && !leading_zero) { + return junk_string_value_; + } else { + goto parsing_done; + } + } + + if (significant_digits == 0) { + // octal = false; + // Integer part consists of 0 or is absent. Significant digits start after + // leading zeros (if any). + while (*current == '0') { + ++current; + if (current == end) { + *processed_characters_count = static_cast(current - input); + return SignedZero(sign); + } + exponent--; // Move this 0 into the exponent. + } + } + + // There is a fractional part. + // We don't emit a '.', but adjust the exponent instead. + while (*current >= '0' && *current <= '9') { + if (significant_digits < kMaxSignificantDigits) { + ASSERT(buffer_pos < kBufferSize); + buffer[buffer_pos++] = static_cast(*current); + significant_digits++; + exponent--; + } else { + // Ignore insignificant digits in the fractional part. + nonzero_digit_dropped = nonzero_digit_dropped || *current != '0'; + } + ++current; + if (current == end) goto parsing_done; + } + } + + if (!leading_zero && exponent == 0 && significant_digits == 0) { + // If leading_zeros is true then the string contains zeros. + // If exponent < 0 then string was [+-]\.0*... + // If significant_digits != 0 the string is not equal to 0. + // Otherwise there are no digits in the string. + return junk_string_value_; + } + + // Parse exponential part. + if (*current == 'e' || *current == 'E') { + if (octal && !allow_trailing_junk) return junk_string_value_; + if (octal) goto parsing_done; + ++current; + if (current == end) { + if (allow_trailing_junk) { + goto parsing_done; + } else { + return junk_string_value_; + } + } + char sign = '+'; + if (*current == '+' || *current == '-') { + sign = static_cast(*current); + ++current; + if (current == end) { + if (allow_trailing_junk) { + goto parsing_done; + } else { + return junk_string_value_; + } + } + } + + if (current == end || *current < '0' || *current > '9') { + if (allow_trailing_junk) { + goto parsing_done; + } else { + return junk_string_value_; + } + } + + const int max_exponent = INT_MAX / 2; + ASSERT(-max_exponent / 2 <= exponent && exponent <= max_exponent / 2); + int num = 0; + do { + // Check overflow. + int digit = *current - '0'; + if (num >= max_exponent / 10 + && !(num == max_exponent / 10 && digit <= max_exponent % 10)) { + num = max_exponent; + } else { + num = num * 10 + digit; + } + ++current; + } while (current != end && *current >= '0' && *current <= '9'); + + exponent += (sign == '-' ? -num : num); + } + + if (!(allow_trailing_spaces || allow_trailing_junk) && (current != end)) { + return junk_string_value_; + } + if (!allow_trailing_junk && AdvanceToNonspace(¤t, end)) { + return junk_string_value_; + } + if (allow_trailing_spaces) { + AdvanceToNonspace(¤t, end); + } + + parsing_done: + exponent += insignificant_digits; + + if (octal) { + double result; + bool result_is_junk; + char* start = buffer; + result = RadixStringToIeee<3>(&start, + buffer + buffer_pos, + sign, + allow_trailing_junk, + junk_string_value_, + &result_is_junk); + ASSERT(!result_is_junk); + *processed_characters_count = static_cast(current - input); + return result; + } + + if (nonzero_digit_dropped) { + buffer[buffer_pos++] = '1'; + exponent--; + } + + ASSERT(buffer_pos < kBufferSize); + buffer[buffer_pos] = '\0'; + + double converted = Strtod(Vector(buffer, buffer_pos), exponent); + *processed_characters_count = static_cast(current - input); + return sign? -converted: converted; +} + + +double StringToDoubleConverter::StringToDouble( + const char* buffer, + int length, + int* processed_characters_count) const { + return StringToIeee(buffer, length, processed_characters_count); +} + +} // end anonymous namespace + +std::string format_coord_shortest(Coord x) +{ + char buf[20]; + bool sign; + int length, point; + + DoubleToStringConverter::DoubleToAscii(x, DoubleToStringConverter::SHORTEST, + 0, buf, 20, &sign, &length, &point); + + int exponent = point - length; + + std::string ret; + ret.reserve(32); + + if (sign) { + ret += '-'; + } + + if (exponent == 0) { + // return digits without any changes + ret += buf; + } else if (point >= 0 && point <= length) { + // insert decimal point + ret.append(buf, point); + ret += '.'; + ret.append(&buf[point], length - point); + } else if (exponent > 0 && exponent <= 2) { + // add trailing zeroes + ret += buf; + ret.append(exponent, '0'); + } else if (point >= -3 && point <= -1) { + // add leading zeroes + ret += '.'; + ret.append(-point, '0'); + ret += buf; + } else { + // exponential form + ret += buf; + ret += 'e'; + if (exponent < 0) { + ret += '-'; + exponent = -exponent; + } + + /* Convert exponent by hand. + * Using ostringstream is ~3x slower */ + int const buflen = 6; + int i = 0; + char expdigits[buflen+1]; + expdigits[buflen] = 0; + + for (; exponent && i < buflen; ++i) { + expdigits[buflen - 1 - i] = '0' + (exponent % 10); + exponent /= 10; + } + ret.append(&expdigits[buflen - i]); + } + + return ret; +} + +std::string format_coord_nice(Coord x) +{ + static DoubleToStringConverter conv( + DoubleToStringConverter::UNIQUE_ZERO, + "Inf", "NaN", 'e', -6, 21, 0, 0); + std::string ret; + ret.reserve(32); + conv.ToShortest(x, ret); + return ret; +} + +Coord parse_coord(std::string const &s) +{ + static StringToDoubleConverter conv( + StringToDoubleConverter::ALLOW_LEADING_SPACES | + StringToDoubleConverter::ALLOW_TRAILING_SPACES | + StringToDoubleConverter::ALLOW_SPACES_AFTER_SIGN, + 0.0, nan(""), "Inf", "NaN"); + int dummy; + return conv.StringToDouble(s.c_str(), s.length(), &dummy); +} + +} // namespace Geom + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 : diff --git a/src/2geom/coord.h b/src/2geom/coord.h index 78a852f32..416e6443d 100644 --- a/src/2geom/coord.h +++ b/src/2geom/coord.h @@ -1,6 +1,5 @@ -/** - * \file - * \brief Defines the Coord "real" type with sufficient precision for coordinates. +/** @file + * @brief Integral and real coordinate types and some basic utilities *//* * Copyright 2006 Nathan Hurst * @@ -34,14 +33,45 @@ #include #include +#include +#include #include #include <2geom/forward.h> namespace Geom { -/** @brief 2D axis enumeration (X or Y). */ +/// 2D axis enumeration (X or Y). enum Dim2 { X=0, Y=1 }; +/// Get the other (perpendicular) dimension. +inline Dim2 other_dimension(Dim2 d) { return d == Y ? X : Y; } + +// TODO: make a smarter implementation with C++11 +template +struct D2Traits { + typedef typename T::D1Value D1Value; + typedef typename T::D1Reference D1Reference; + typedef typename T::D1ConstReference D1ConstReference; +}; + +// for use with things such as transform_iterator +template +struct GetX { + typedef typename D2Traits::D1Value result_type; + typedef T argument_type; + typename D2Traits::D1Value operator()(T const &a) const { + return a[X]; + } +}; +template +struct GetY { + typedef typename D2Traits::D1Value result_type; + typedef T argument_type; + typename D2Traits::D1Value operator()(T const &a) const { + return a[Y]; + } +}; + /** * @brief Floating point type used to store coordinates. * @@ -60,8 +90,32 @@ inline Coord infinity() { return std::numeric_limits::infinity(); } inline bool are_near(Coord a, Coord b, double eps=EPSILON) { return a-b <= eps && a-b >= -eps; } inline bool rel_error_bound(Coord a, Coord b, double eps=EPSILON) { return a <= eps*b && a >= -eps*b; } +/// Numerically stable linear interpolation. +inline Coord lerp(Coord t, Coord a, Coord b) { + return (1 - t) * a + t * b; +} + template -struct CoordTraits {}; +struct CoordTraits { + typedef D2 PointType; + typedef GenericInterval IntervalType; + typedef GenericOptInterval OptIntervalType; + typedef GenericRect RectType; + typedef GenericOptRect OptRectType; + + typedef + boost::equality_comparable< IntervalType + , boost::orable< IntervalType + > > + IntervalOps; + + typedef + boost::equality_comparable< RectType + , boost::orable< RectType + , boost::orable< RectType, OptRectType + > > > + RectOps; +}; // NOTE: operator helpers for Rect and Interval are defined here. // This is to avoid increasing their size through multiple inheritance. @@ -120,6 +174,21 @@ struct CoordTraits { RectOps; }; +/** @brief Convert coordinate to shortest possible string + * @return The shortest string that parses back to the original value. */ +std::string format_coord_shortest(Coord x); + +/** @brief Convert coordinate to human-readable string + * Unlike format_coord_shortest, this function will not omit a leading zero + * before a decimal point or use small negative exponents. The output format + * is similar to Javascript functions. */ +std::string format_coord_nice(Coord x); + +/** @brief Parse coordinate string + * When using this function in conjunction with format_coord_shortest() + * or format_coord_nice(), the value is guaranteed to be preserved exactly. */ +Coord parse_coord(std::string const &s); + } // end namespace Geom #endif // LIB2GEOM_SEEN_COORD_H diff --git a/src/2geom/crossing.cpp b/src/2geom/crossing.cpp index 513327271..e27a2fc43 100644 --- a/src/2geom/crossing.cpp +++ b/src/2geom/crossing.cpp @@ -28,7 +28,7 @@ double wrap_dist(double from, double to, double size, bool rev) { } } /* -CrossingGraph create_crossing_graph(std::vector const &p, Crossings const &crs) { +CrossingGraph create_crossing_graph(PathVector const &p, Crossings const &crs) { std::vector locs; CrossingGraph ret; for(unsigned i = 0; i < crs.size(); i++) { diff --git a/src/2geom/crossing.h b/src/2geom/crossing.h index d5012ae2b..be41fe893 100644 --- a/src/2geom/crossing.h +++ b/src/2geom/crossing.h @@ -33,14 +33,14 @@ * */ -#ifndef __GEOM_CROSSING_H -#define __GEOM_CROSSING_H +#ifndef LIB2GEOM_SEEN_CROSSING_H +#define LIB2GEOM_SEEN_CROSSING_H #include #include <2geom/rect.h> #include <2geom/sweep.h> #include -#include <2geom/path.h> +#include <2geom/pathvector.h> namespace Geom { @@ -99,7 +99,7 @@ struct TimeOrder { }; class Path; -CrossingGraph create_crossing_graph(std::vector const &p, Crossings const &crs); +CrossingGraph create_crossing_graph(PathVector const &p, Crossings const &crs); */ /*inline bool are_near(Crossing a, Crossing b) { @@ -143,11 +143,24 @@ std::vector bounds(Path const &a); inline void sort_crossings(Crossings &cr, unsigned ix) { std::sort(cr.begin(), cr.end(), CrossingOrder(ix)); } +template +struct CrossingTraits { + typedef std::vector VectorT; + static inline VectorT init(T const &x) { return VectorT(1, x); } +}; +template <> +struct CrossingTraits { + typedef PathVector VectorT; + static inline VectorT vector_one(Path const &x) { return VectorT(x); } +}; + template struct Crosser { + typedef typename CrossingTraits::VectorT VectorT; virtual ~Crosser() {} - virtual Crossings crossings(T const &a, T const &b) { return crossings(std::vector(1,a), std::vector(1,b))[0]; } - virtual CrossingSet crossings(std::vector const &a, std::vector const &b) { + virtual Crossings crossings(T const &a, T const &b) { + return crossings(CrossingTraits::vector_one(a), CrossingTraits::vector_one(b))[0]; } + virtual CrossingSet crossings(VectorT const &a, VectorT const &b) { CrossingSet results(a.size() + b.size(), Crossings()); std::vector > cull = sweep_bounds(bounds(a), bounds(b)); @@ -185,7 +198,7 @@ CrossingSet reverse_tb(CrossingSet const &cr, unsigned split, std::vector -#include <2geom/nearest-point.h> +#include <2geom/exception.h> +#include <2geom/nearest-time.h> #include <2geom/sbasis-geometric.h> +#include <2geom/sbasis-to-bezier.h> #include <2geom/ord.h> +#include <2geom/path-sink.h> + +//#include namespace Geom { -int CurveHelpers::root_winding(Curve const &c, Point p) { - std::vector ts = c.roots(p[Y], Y); - - if(ts.empty()) return 0; - - double const fudge = 0.01; //fudge factor used on first and last - - std::sort(ts.begin(), ts.end()); - - // winding determined by crossings at roots - int wind=0; - // previous time - double pt = ts.front() - fudge; - for ( std::vector::iterator ti = ts.begin() - ; ti != ts.end() - ; ++ti ) - { - double t = *ti; - if ( t <= 0. || t >= 1. ) continue; //skip endpoint roots - if ( c.valueAt(t, X) > p[X] ) { // root is ray intersection - // Get t of next: - std::vector::iterator next = ti; - ++next; - double nt; - if(next == ts.end()) nt = t + fudge; else nt = *next; - - // Check before in time and after in time for positions - // Currently we're using the average times between next and previous segs - Cmp after_to_ray = cmp(c.valueAt((t + nt) / 2, Y), p[Y]); - Cmp before_to_ray = cmp(c.valueAt((t + pt) / 2, Y), p[Y]); - // if y is included, these will have opposite values, giving order. - Cmp dt = cmp(after_to_ray, before_to_ray); - if(dt != EQUAL_TO) //Should always be true, but yah never know.. - wind += dt; - pt = t; - } - } - - return wind; -} - -Coord Curve::nearestPoint(Point const& p, Coord a, Coord b) const +Coord Curve::nearestTime(Point const& p, Coord a, Coord b) const { - return nearest_point(p, toSBasis(), a, b); + return nearest_time(p, toSBasis(), a, b); } -std::vector Curve::allNearestPoints(Point const& p, Coord from, Coord to) const +std::vector Curve::allNearestTimes(Point const& p, Coord from, Coord to) const { - return all_nearest_points(p, toSBasis(), from, to); + return all_nearest_times(p, toSBasis(), from, to); } Coord Curve::length(Coord tolerance) const @@ -95,6 +59,97 @@ Coord Curve::length(Coord tolerance) const return ::Geom::length(toSBasis(), tolerance); } +int Curve::winding(Point const &p) const +{ + try { + std::vector ts = roots(p[Y], Y); + if(ts.empty()) return 0; + std::sort(ts.begin(), ts.end()); + + // skip endpoint roots when they are local maxima on the Y axis + // this follows the convention used in other winding routines, + // i.e. that the bottommost coordinate is not part of the shape + bool ingore_0 = unitTangentAt(0)[Y] <= 0; + bool ignore_1 = unitTangentAt(1)[Y] >= 0; + + int wind = 0; + for (std::size_t i = 0; i < ts.size(); ++i) { + Coord t = ts[i]; + //std::cout << t << std::endl; + if ((t == 0 && ingore_0) || (t == 1 && ignore_1)) continue; + if (valueAt(t, X) > p[X]) { // root is ray intersection + Point tangent = unitTangentAt(t); + if (tangent[Y] > 0) { + // at the point of intersection, curve goes in +Y direction, + // so it winds in the direction of positive angles + ++wind; + } else if (tangent[Y] < 0) { + --wind; + } + } + } + return wind; + } catch (InfiniteSolutions const &e) { + // this means we encountered a line segment exactly coincident with the point + // skip, since this will be taken care of by endpoint roots in other segments + return 0; + } +} + +std::vector Curve::intersect(Curve const &/*other*/, Coord /*eps*/) const +{ + // TODO: approximate as Bezier + THROW_NOTIMPLEMENTED(); +} + +std::vector Curve::intersectSelf(Coord eps) const +{ + std::vector result; + // Monotonic segments cannot have self-intersections. + // Thus, we can split the curve at roots and intersect the portions. + std::vector splits; + std::auto_ptr deriv(derivative()); + splits = deriv->roots(0, X); + if (splits.empty()) { + return result; + } + deriv.reset(); + splits.push_back(1.); + + boost::ptr_vector parts; + Coord previous = 0; + for (unsigned i = 0; i < splits.size(); ++i) { + if (splits[i] == 0.) continue; + parts.push_back(portion(previous, splits[i])); + previous = splits[i]; + } + + Coord prev_i = 0; + for (unsigned i = 0; i < parts.size()-1; ++i) { + Interval dom_i(prev_i, splits[i]); + prev_i = splits[i]; + + Coord prev_j = 0; + for (unsigned j = i+1; j < parts.size(); ++j) { + Interval dom_j(prev_j, splits[j]); + prev_j = splits[j]; + + std::vector xs = parts[i].intersect(parts[j], eps); + for (unsigned k = 0; k < xs.size(); ++k) { + // to avoid duplicated intersections, skip values at exactly 1 + if (xs[k].first == 1. || xs[k].second == 1.) continue; + + Coord ti = dom_i.valueAt(xs[k].first); + Coord tj = dom_j.valueAt(xs[k].second); + + CurveIntersection real(ti, tj, xs[k].point()); + result.push_back(real); + } + } + } + return result; +} + Point Curve::unitTangentAt(Coord t, unsigned n) const { std::vector derivs = pointAndDerivatives(t, n); @@ -108,6 +163,16 @@ Point Curve::unitTangentAt(Coord t, unsigned n) const return Point (0,0); }; +void Curve::feed(PathSink &sink, bool moveto_initial) const +{ + std::vector pts; + sbasis_to_bezier(pts, toSBasis(), 2); //TODO: use something better! + if (moveto_initial) { + sink.moveTo(initialPoint()); + } + sink.curveTo(pts[0], pts[1], pts[2]); +} + } // namespace Geom /* diff --git a/src/2geom/curve.h b/src/2geom/curve.h index 172fd7ddc..893dc6bdb 100644 --- a/src/2geom/curve.h +++ b/src/2geom/curve.h @@ -35,27 +35,23 @@ */ -#ifndef _2GEOM_CURVE_H_ -#define _2GEOM_CURVE_H_ +#ifndef LIB2GEOM_SEEN_CURVE_H +#define LIB2GEOM_SEEN_CURVE_H #include +#include #include <2geom/coord.h> #include <2geom/point.h> #include <2geom/interval.h> #include <2geom/sbasis.h> #include <2geom/d2.h> #include <2geom/affine.h> +#include <2geom/intersection.h> -namespace Geom -{ - -class Curve; - -struct CurveHelpers { -protected: - static int root_winding(Curve const &c, Point p); -}; +namespace Geom { +class PathSink; +typedef Intersection<> CurveIntersection; /** * @brief Abstract continuous curve on a plane defined on [0,1]. @@ -77,7 +73,9 @@ protected: * * @ingroup Curves */ -class Curve : private CurveHelpers { +class Curve + : boost::equality_comparable +{ public: virtual ~Curve() {} @@ -86,26 +84,38 @@ public: /** @brief Retrieve the start of the curve. * @return The point corresponding to \f$\mathbf{C}(0)\f$. */ virtual Point initialPoint() const = 0; + /** Retrieve the end of the curve. * @return The point corresponding to \f$\mathbf{C}(1)\f$. */ virtual Point finalPoint() const = 0; + /** @brief Check whether the curve has exactly zero length. * @return True if the curve's initial point is exactly the same as its final point, and it contains - * no other points (its value set contains only one element). - */ + * no other points (its value set contains only one element). */ virtual bool isDegenerate() const = 0; + + /** @brief Get the interval of allowed time values. + * @return \f$[0, 1]\f$ */ + virtual Interval timeRange() const { + Interval tr(0, 1); + return tr; + } + /** @brief Evaluate the curve at a specified time value. * @param t Time value * @return \f$\mathbf{C}(t)\f$ */ virtual Point pointAt(Coord t) const { return pointAndDerivatives(t, 0).front(); } + /** @brief Evaluate one of the coordinates at the specified time value. * @param t Time value * @param d The dimension to evaluate * @return The specified coordinate of \f$\mathbf{C}(t)\f$ */ virtual Coord valueAt(Coord t, Dim2 d) const { return pointAt(t)[d]; } + /** @brief Evaluate the function at the specified time value. Allows curves to be used * as functors. */ virtual Point operator() (Coord t) const { return pointAt(t); } + /** @brief Evaluate the curve and its derivatives. * This will return a vector that contains the value of the curve and the specified number * of derivatives. However, the returned vector might contain less elements than specified @@ -125,6 +135,7 @@ public: * type. * @param p New starting point of the curve */ virtual void setInitial(Point const &v) = 0; + /** @brief Change the ending point of the curve. * After calling this method, it is guaranteed that \f$\mathbf{C}(0) = \mathbf{p}\f$, * and the curve is still continuous. The precise new shape of the curve varies @@ -140,12 +151,15 @@ public: * but it might not be the smallest such rectangle. This method is usually fast. * @return A rectangle that contains all points belonging to the curve. */ virtual Rect boundsFast() const = 0; + /** @brief Compute the curve's exact bounding box. * This method can be dramatically slower than boundsExact() depending on the curve type. * @return The smallest possible rectangle containing all of the curve's points. */ virtual Rect boundsExact() const = 0; + // I have no idea what the 'deg' parameter is for, so this is undocumented for now. virtual OptRect boundsLocal(OptInterval const &i, unsigned deg) const = 0; + /** @brief Compute the bounding box of a part of the curve. * Since this method returns the smallest possible bounding rectangle of the specified portion, * it can also be rather slow. @@ -163,21 +177,21 @@ public: * @return Pointer to a newly allocated curve, identical to the original */ virtual Curve *duplicate() const = 0; + /** @brief Transform this curve by an affine transformation. + * Because of this method, all curve types must be closed under affine + * transformations. + * @param m Affine describing the affine transformation */ + virtual void transform(Affine const &m) = 0; + /** @brief Create a curve transformed by an affine transformation. - * This method returns a new curve instead modifying the existing one, because some curve - * types are not closed under affine transformations. The returned curve may be of different - * underlying type (as is the case for horizontal and vertical line segments). + * This method returns a new curve instead modifying the existing one. * @param m Affine describing the affine transformation * @return Pointer to a new, transformed curve */ - virtual Curve *transformed(Affine const &m) const = 0; - - /** @brief Translate the curve (i.e. displace by Point) - * This method modifies the curve; all curve types are closed under - * translations (the result can be expressed in its own curve type). - * This function yields the same result as transformed(m). - * @param p Point by which to translate the curve - * @return reference to self */ - virtual Curve &operator*=(Translate const &m) = 0; + virtual Curve *transformed(Affine const &m) const { + Curve *ret = duplicate(); + ret->transform(m); + return ret; + } /** @brief Create a curve that corresponds to a part of this curve. * For \f$a > b\f$, the returned portion will be reversed with respect to the original. @@ -190,13 +204,16 @@ public: * - \f$\mathbf{D}[ [0, 1] ] = \mathbf{C}[ [a?b] ]\f$, * where \f$[a?b] = [\min(a, b), \max(a, b)]\f$ */ virtual Curve *portion(Coord a, Coord b) const = 0; + /** @brief A version of that accepts an Interval. */ Curve *portion(Interval const &i) const { return portion(i.min(), i.max()); } + /** @brief Create a reversed version of this curve. * The result corresponds to portion(1, 0), but this method might be faster. * @return Pointer to a new curve \f$\mathbf{D}\f$ such that * \f$\forall_{x \in [0, 1]} \mathbf{D}(x) = \mathbf{C}(1-x)\f$ */ virtual Curve *reverse() const { return portion(1, 0); } + /** @brief Create a derivative of this curve. * It's best to think of the derivative in physical terms: if the curve describes * the position of some object on the plane from time \f$t=0\f$ to \f$t=1\f$ as said in the @@ -215,22 +232,26 @@ public: * @param b Maximum time value to consider; \f$a < b\f$ * @return \f$q \in [a, b]: ||\mathbf{C}(q) - \mathbf{p}|| = \inf(\{r \in \mathbb{R} : ||\mathbf{C}(r) - \mathbf{p}||\})\f$ */ - virtual Coord nearestPoint( Point const& p, Coord a = 0, Coord b = 1 ) const; + virtual Coord nearestTime( Point const& p, Coord a = 0, Coord b = 1 ) const; + /** @brief A version that takes an Interval. */ - Coord nearestPoint(Point const &p, Interval const &i) const { - return nearestPoint(p, i.min(), i.max()); + Coord nearestTime(Point const &p, Interval const &i) const { + return nearestTime(p, i.min(), i.max()); } + /** @brief Compute time values at which the curve comes closest to a specified point. * @param p Query point * @param a Minimum time value to consider * @param b Maximum time value to consider; \f$a < b\f$ * @return Vector of points closest and equally far away from the query point */ - virtual std::vector allNearestPoints( Point const& p, Coord from = 0, + virtual std::vector allNearestTimes( Point const& p, Coord from = 0, Coord to = 1 ) const; + /** @brief A version that takes an Interval. */ - std::vector allNearestPoints(Point const &p, Interval const &i) { - return allNearestPoints(p, i.min(), i.max()); + std::vector allNearestTimes(Point const &p, Interval const &i) { + return allNearestTimes(p, i.min(), i.max()); } + /** @brief Compute the arc length of this curve. * For a curve \f$\mathbf{C}(t) = (C_x(t), C_y(t))\f$, arc length is defined for 2D curves as * \f[ \ell = \int_{0}^{1} \sqrt { [C_x'(t)]^2 + [C_y'(t)]^2 }\, \text{d}t \f] @@ -242,13 +263,28 @@ public: * @param tolerance Maximum allowed error * @return Total distance the curve's value travels on the plane when going from 0 to 1 */ virtual Coord length(Coord tolerance=0.01) const; + /** @brief Computes time values at which the curve intersects an axis-aligned line. * @param v The coordinate of the line * @param d Which axis the coordinate is on. X means a vertical line, Y a horizontal line. */ virtual std::vector roots(Coord v, Dim2 d) const = 0; - /** @brief Compute the winding number of the curve at the specified point. - * @todo Does this makes sense for curves at all? */ - virtual int winding(Point const &p) const { return root_winding(*this, p); } + + /** @brief Compute the partial winding number of this curve. + * The partial winding number is equal to the difference between the number + * of roots at which the curve goes in the +Y direction and the number of roots + * at which the curve goes in the -Y direction. This method is mainly useful + * for implementing path winding calculation. It will ignore roots which + * are local maxima on the Y axis. + * @param p Point where the winding number should be determined + * @return Winding number contribution at p */ + virtual int winding(Point const &p) const; + + /// Compute intersections with another curve. + virtual std::vector intersect(Curve const &other, Coord eps = EPSILON) const; + + /// Compute intersections of this curve with itself. + virtual std::vector intersectSelf(Coord eps = EPSILON) const; + /** @brief Compute a vector tangent to the curve. * This will return an unit vector (a Point with length() equal to 1) that denotes a vector * tangent to the curve. This vector is defined as @@ -266,6 +302,7 @@ public: Point tangent = - c_reverse->unitTangentAt(0); delete c_reverse; @endcode */ virtual Point unitTangentAt(Coord t, unsigned n = 3) const; + /** @brief Convert the curve to a symmetric power basis polynomial. * Symmetric power basis polynomials (S-basis for short) are numerical representations * of curves with excellent numerical properties. Most high level operations provided by 2Geom @@ -281,15 +318,22 @@ public: * of this curve. For example, for Bezier curves it returns the curve's order * multiplied by 2. */ virtual int degreesOfFreedom() const { return 0;} + /** @brief Test equality of two curves. + * Equality means that for any time value, the evaluation of either curve will yield + * the same value. This means non-degenerate curves are not equal to their reverses. + * Note that this tests for exact equality. * @return True if the curves are identical, false otherwise */ - virtual bool operator==(Curve const &c) const { return this == &c;} + virtual bool operator==(Curve const &c) const = 0; + + /** @brief Feed the curve to a PathSink */ + virtual void feed(PathSink &sink, bool moveto_initial) const; /// @} }; inline -Coord nearest_point(Point const& p, Curve const& c) { - return c.nearestPoint(p); +Coord nearest_time(Point const& p, Curve const& c) { + return c.nearestTime(p); } // for make benefit glorious library of Boost Pointer Container diff --git a/src/2geom/curves.h b/src/2geom/curves.h index 319b1924d..6022c71d8 100644 --- a/src/2geom/curves.h +++ b/src/2geom/curves.h @@ -1,10 +1,9 @@ -/** - * \file - * \brief Include all curve types +/** @file + * @brief Include all curve types *//* * Authors: - * MenTaLguY - * Marco Cecchetti + * MenTaLguY + * Marco Cecchetti * * Copyright 2007-2008 authors * @@ -38,7 +37,6 @@ #include <2geom/curve.h> #include <2geom/sbasis-curve.h> #include <2geom/bezier-curve.h> -#include <2geom/hvlinesegment.h> #include <2geom/elliptical-arc.h> #include <2geom/svg-elliptical-arc.h> diff --git a/src/2geom/d2-sbasis.cpp b/src/2geom/d2-sbasis.cpp index 486ada9a2..ebec16fdd 100644 --- a/src/2geom/d2-sbasis.cpp +++ b/src/2geom/d2-sbasis.cpp @@ -200,7 +200,7 @@ Point unitTangentAt(D2 const & a, Coord t, unsigned n) static void set_first_point(Piecewise > &f, Point a){ if ( f.empty() ){ - f.concat(Piecewise >(D2(Linear(a[X]),Linear(a[Y])))); + f.concat(Piecewise >(D2(SBasis(Linear(a[X])), SBasis(Linear(a[Y]))))); return; } for (unsigned dim=0; dim<2; dim++){ @@ -213,7 +213,7 @@ static void set_first_point(Piecewise > &f, Point a){ } static void set_last_point(Piecewise > &f, Point a){ if ( f.empty() ){ - f.concat(Piecewise >(D2(Linear(a[X]),Linear(a[Y])))); + f.concat(Piecewise >(D2(SBasis(Linear(a[X])), SBasis(Linear(a[Y]))))); return; } for (unsigned dim=0; dim<2; dim++){ diff --git a/src/2geom/d2-sbasis.h b/src/2geom/d2-sbasis.h index 965ec8746..a0769b314 100644 --- a/src/2geom/d2-sbasis.h +++ b/src/2geom/d2-sbasis.h @@ -35,11 +35,11 @@ * */ -#ifdef SEEN_LIB2GEOM_D2_H /*This is intentional: we don't actually want anyone to +#ifdef LIB2GEOM_SEEN_D2_H /*This is intentional: we don't actually want anyone to include this, other than D2.h. If somone else tries, D2 won't be defined. If it is, this will already be included. */ -#ifndef SEEN_LIB2GEOM_D2_SBASIS_H -#define SEEN_LIB2GEOM_D2_SBASIS_H +#ifndef LIB2GEOM_SEEN_D2_SBASIS_H +#define LIB2GEOM_SEEN_D2_SBASIS_H #include <2geom/sbasis.h> #include <2geom/sbasis-2d.h> @@ -149,8 +149,8 @@ std::vector > level_sets( D2 const &f, std::vector } -#endif -#endif +#endif // LIB2GEOM_SEEN_D2_SBASIS_H +#endif // LIB2GEOM_SEEN_D2_H /* diff --git a/src/2geom/d2.h b/src/2geom/d2.h index 5fc955854..714319f99 100644 --- a/src/2geom/d2.h +++ b/src/2geom/d2.h @@ -29,18 +29,19 @@ * */ -#ifndef SEEN_LIB2GEOM_D2_H -#define SEEN_LIB2GEOM_D2_H +#ifndef LIB2GEOM_SEEN_D2_H +#define LIB2GEOM_SEEN_D2_H +#include +#include +#include #include <2geom/point.h> #include <2geom/interval.h> #include <2geom/affine.h> #include <2geom/rect.h> - -#include #include <2geom/concepts.h> -namespace Geom{ +namespace Geom { /** * The D2 class takes two instances of a scalar data type and treats them * like a point. All operations which make sense on a point are defined for D2. @@ -55,6 +56,11 @@ class D2{ T f[2]; public: + + typedef T D1Value; + typedef T &D1Reference; + typedef T const &D1ConstReference; + D2() {f[X] = f[Y] = T();} explicit D2(Point const &a) { f[X] = T(a[X]); f[Y] = T(a[Y]); @@ -65,10 +71,38 @@ class D2{ f[Y] = b; } + template + D2(Iter first, Iter last) { + typedef typename std::iterator_traits::value_type V; + typedef typename boost::transform_iterator, Iter> XIter; + typedef typename boost::transform_iterator, Iter> YIter; + + XIter xfirst(first, GetX()), xlast(last, GetX()); + f[X] = T(xfirst, xlast); + YIter yfirst(first, GetY()), ylast(last, GetY()); + f[Y] = T(yfirst, ylast); + } + + D2(std::vector const &vec) { + typedef Point V; + typedef std::vector::const_iterator Iter; + typedef boost::transform_iterator, Iter> XIter; + typedef boost::transform_iterator, Iter> YIter; + + XIter xfirst(vec.begin(), GetX()), xlast(vec.end(), GetX()); + f[X] = T(xfirst, xlast); + YIter yfirst(vec.begin(), GetY()), ylast(vec.end(), GetY()); + f[Y] = T(yfirst, ylast); + } + //TODO: ask mental about operator= as seen in Point T& operator[](unsigned i) { return f[i]; } T const & operator[](unsigned i) const { return f[i]; } + Point point(unsigned i) const { + Point ret(f[X][i], f[Y][i]); + return ret; + } //IMPL: FragmentConcept typedef Point output_type; @@ -429,7 +463,7 @@ inline std::ostream &operator<< (std::ostream &out_file, const Geom::D2 &in_d #include <2geom/d2-sbasis.h> -namespace Geom{ +namespace Geom { //Some D2 Fragment implementation which requires rect: template @@ -447,8 +481,10 @@ OptRect bounds_local(const D2 &a, const OptInterval &t) { boost::function_requires >(); return OptRect(bounds_local(a[X], t), bounds_local(a[Y], t)); } -}; +} // end namespace Geom + +#endif /* Local Variables: mode:c++ @@ -459,4 +495,3 @@ OptRect bounds_local(const D2 &a, const OptInterval &t) { End: */ // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 : -#endif diff --git a/src/2geom/ellipse.cpp b/src/2geom/ellipse.cpp index 2686844b2..4e26707ef 100644 --- a/src/2geom/ellipse.cpp +++ b/src/2geom/ellipse.cpp @@ -1,10 +1,11 @@ -/* - * Ellipse Curve - * +/** @file + * @brief Ellipse shape + *//* * Authors: - * Marco Cecchetti + * Marco Cecchetti + * Krzysztof Kosiński * - * Copyright 2008 authors + * Copyright 2008-2014 Authors * * This library is free software; you can redistribute it and/or * modify it either under the terms of the GNU Lesser General Public @@ -30,33 +31,28 @@ * the specific language governing rights and limitations. */ - #include <2geom/ellipse.h> #include <2geom/svg-elliptical-arc.h> #include <2geom/numeric/fitting-tool.h> #include <2geom/numeric/fitting-model.h> -using std::swap; +namespace Geom { -namespace Geom -{ - -void Ellipse::set(double A, double B, double C, double D, double E, double F) +void Ellipse::setCoefficients(double A, double B, double C, double D, double E, double F) { double den = 4*A*C - B*B; - if ( den == 0 ) - { - THROW_LOGICALERROR("den == 0, while computing ellipse centre"); + if (den == 0) { + THROW_RANGEERROR("den == 0, while computing ellipse centre"); } - m_centre[X] = (B*E - 2*C*D) / den; - m_centre[Y] = (B*D - 2*A*E) / den; + _center[X] = (B*E - 2*C*D) / den; + _center[Y] = (B*D - 2*A*E) / den; // evaluate the a coefficient of the ellipse equation in normal form // E(x,y) = a*(x-cx)^2 + b*(x-cx)*(y-cy) + c*(y-cy)^2 = 1 // where b = a*B , c = a*C, (cx,cy) == centre - double num = A * sqr(m_centre[X]) - + B * m_centre[X] * m_centre[Y] - + C * sqr(m_centre[Y]) + double num = A * sqr(_center[X]) + + B * _center[X] * _center[Y] + + C * sqr(_center[Y]) - F; @@ -64,73 +60,74 @@ void Ellipse::set(double A, double B, double C, double D, double E, double F) double rot = std::atan2( -B, -(A - C) )/2; // std::cerr << "rot = " << rot << std::endl; bool swap_axes = false; - if ( are_near(rot, 0) ) rot = 0; - if ( are_near(rot, M_PI/2) || rot < 0 ) - { + + if (rot >= M_PI/2 || rot < 0) { swap_axes = true; } // evaluate the length of the ellipse rays - double cosrot = std::cos(rot); - double sinrot = std::sin(rot); + double sinrot, cosrot; + sincos(rot, sinrot, cosrot); double cos2 = cosrot * cosrot; double sin2 = sinrot * sinrot; double cossin = cosrot * sinrot; den = A * cos2 + B * cossin + C * sin2; - if ( den == 0 ) - { - THROW_LOGICALERROR("den == 0, while computing 'rx' coefficient"); + if (den == 0) { + THROW_RANGEERROR("den == 0, while computing 'rx' coefficient"); } - double rx2 = num/den; - if ( rx2 < 0 ) - { - THROW_LOGICALERROR("rx2 < 0, while computing 'rx' coefficient"); + double rx2 = num / den; + if (rx2 < 0) { + THROW_RANGEERROR("rx2 < 0, while computing 'rx' coefficient"); } double rx = std::sqrt(rx2); den = C * cos2 - B * cossin + A * sin2; - if ( den == 0 ) - { - THROW_LOGICALERROR("den == 0, while computing 'ry' coefficient"); + if (den == 0) { + THROW_RANGEERROR("den == 0, while computing 'ry' coefficient"); } - double ry2 = num/den; - if ( ry2 < 0 ) - { - THROW_LOGICALERROR("ry2 < 0, while computing 'rx' coefficient"); + double ry2 = num / den; + if (ry2 < 0) { + THROW_RANGEERROR("ry2 < 0, while computing 'rx' coefficient"); } double ry = std::sqrt(ry2); // the solution is not unique so we choose always the ellipse // with a rotation angle between 0 and PI/2 - if ( swap_axes ) swap(rx, ry); - if ( are_near(rot, M_PI/2) - || are_near(rot, -M_PI/2) - || are_near(rx, ry) ) - { + if (swap_axes) { + std::swap(rx, ry); + } + + if (rx == ry) { rot = 0; } - else if ( rot < 0 ) - { + if (rot < 0) { rot += M_PI/2; } - m_ray[X] = rx; - m_ray[Y] = ry; - m_angle = rot; + _rays[X] = rx; + _rays[Y] = ry; + _angle = rot; +} + + +Affine Ellipse::unitCircleTransform() const +{ + Affine ret = Scale(ray(X), ray(Y)) * Rotate(_angle); + ret.setTranslation(center()); + return ret; } -std::vector Ellipse::implicit_form_coefficients() const +std::vector Ellipse::coefficients() const { - if (ray(X) == 0 || ray(Y) == 0) - { - THROW_LOGICALERROR("a degenerate ellipse doesn't own an implicit form"); + if (ray(X) == 0 || ray(Y) == 0) { + THROW_RANGEERROR("a degenerate ellipse doesn't have an implicit form"); } std::vector coeff(6); - double cosrot = std::cos(rot_angle()); - double sinrot = std::sin(rot_angle()); + double cosrot, sinrot; + sincos(_angle, sinrot, cosrot); double cos2 = cosrot * cosrot; double sin2 = sinrot * sinrot; double cossin = cosrot * sinrot; @@ -150,18 +147,16 @@ std::vector Ellipse::implicit_form_coefficients() const } -void Ellipse::set(std::vector const& points) +void Ellipse::fit(std::vector const &points) { size_t sz = points.size(); - if (sz < 5) - { + if (sz < 5) { THROW_RANGEERROR("fitting error: too few points passed"); } NL::LFMEllipse model; NL::least_squeares_fitter fitter(model, sz); - for (size_t i = 0; i < sz; ++i) - { + for (size_t i = 0; i < sz; ++i) { fitter.append(points[i]); } fitter.update(); @@ -172,12 +167,12 @@ void Ellipse::set(std::vector const& points) EllipticalArc * -Ellipse::arc(Point const& initial, Point const& inner, Point const& final, +Ellipse::arc(Point const &ip, Point const &inner, Point const &fp, bool _svg_compliant) { - Point sp_cp = initial - center(); - Point ep_cp = final - center(); - Point ip_cp = inner - center(); + Point sp_cp = ip - center(); + Point ep_cp = fp - center(); + Point ip_cp = inner - center(); double angle1 = angle_between(sp_cp, ep_cp); double angle2 = angle_between(sp_cp, ip_cp); @@ -186,28 +181,19 @@ Ellipse::arc(Point const& initial, Point const& inner, Point const& final, bool large_arc_flag = true; bool sweep_flag = true; - if ( angle1 > 0 ) - { - if ( angle2 > 0 && angle3 > 0 ) - { + if (angle1 > 0) { + if (angle2 > 0 && angle3 > 0) { large_arc_flag = false; sweep_flag = true; - } - else - { + } else { large_arc_flag = true; sweep_flag = false; } - } - else - { - if ( angle2 < 0 && angle3 < 0 ) - { + } else { + if (angle2 < 0 && angle3 < 0) { large_arc_flag = false; sweep_flag = false; - } - else - { + } else { large_arc_flag = true; sweep_flag = true; } @@ -215,66 +201,73 @@ Ellipse::arc(Point const& initial, Point const& inner, Point const& final, EllipticalArc *ret_arc; if (_svg_compliant) { - ret_arc = new SVGEllipticalArc(initial, ray(X), ray(Y), rot_angle(), - large_arc_flag, sweep_flag, final); + ret_arc = new SVGEllipticalArc(ip, ray(X), ray(Y), rotationAngle(), + large_arc_flag, sweep_flag, fp); } else { - ret_arc = new EllipticalArc(initial, ray(X), ray(Y), rot_angle(), - large_arc_flag, sweep_flag, final); + ret_arc = new EllipticalArc(ip, ray(X), ray(Y), rotationAngle(), + large_arc_flag, sweep_flag, fp); } return ret_arc; } -Ellipse Ellipse::transformed(Affine const& m) const +Ellipse &Ellipse::operator*=(Rotate const &r) { - double cosrot = std::cos(rot_angle()); - double sinrot = std::sin(rot_angle()); - Affine A( ray(X) * cosrot, ray(X) * sinrot, - -ray(Y) * sinrot, ray(Y) * cosrot, - 0, 0 ); - Point new_center = center() * m; - Affine M = m.withoutTranslation(); - Affine AM = A * M; - if ( are_near(std::sqrt(fabs(AM.det())), 0) ) - { + _angle += r.angle(); + // keep the angle in the first quadrant + if (_angle < 0) { + _angle += M_PI; + } + if (_angle >= M_PI/2) { + std::swap(_rays[X], _rays[Y]); + _angle -= M_PI/2; + } + _center *= r; + return *this; +} + +Ellipse &Ellipse::operator*=(Affine const& m) +{ + Rotate a(_angle); + Affine mwot = m.withoutTranslation(); + Affine am = a * mwot; + if (are_near(am.descrim(), 0)) { double angle; - if (AM[0] != 0) - { - angle = std::atan2(AM[2], AM[0]); - } - else if (AM[1] != 0) - { - angle = std::atan2(AM[3], AM[1]); - } - else - { + if (am[0] != 0) { + angle = std::atan2(am[2], am[0]); + } else if (am[1] != 0) { + angle = std::atan2(am[3], am[1]); + } else { angle = M_PI/2; } - Point V(std::cos(angle), std::sin(angle)); - V *= AM; - double rx = L2(V); - angle = atan2(V); - return Ellipse(new_center[X], new_center[Y], rx, 0, angle); + Point v; + sincos(angle, v[X], v[Y]); + v *= am; + _angle = atan2(v); + _center *= m; + _rays[X] = L2(v); + _rays[Y] = 0; + return *this; } - std::vector coeff = implicit_form_coefficients(); - Affine Q( coeff[0], coeff[1]/2, + std::vector coeff = coefficients(); + Affine q( coeff[0], coeff[1]/2, coeff[1]/2, coeff[2], 0, 0 ); - Affine invm = M.inverse(); - Q = invm * Q ; - swap( invm[1], invm[2] ); - Q *= invm; - Ellipse e(Q[0], 2*Q[1], Q[3], 0, 0, -1); - e.m_centre = new_center; + Affine invm = mwot.inverse(); + q = invm * q ; + std::swap(invm[1], invm[2]); + q *= invm; + setCoefficients(q[0], 2*q[1], q[3], 0, 0, -1); + _center *= m; - return e; + return *this; } Ellipse::Ellipse(Geom::Circle const &c) { - m_centre = c.center(); - m_ray[X] = m_ray[Y] = c.ray(); + _center = c.center(); + _rays[X] = _rays[Y] = c.radius(); } } // end namespace Geom diff --git a/src/2geom/ellipse.h b/src/2geom/ellipse.h index c971c6065..a67969933 100644 --- a/src/2geom/ellipse.h +++ b/src/2geom/ellipse.h @@ -1,9 +1,9 @@ -/** - * \file - * \brief Ellipse Curve - * +/** @file + * @brief Ellipse shape + *//* * Authors: - * Marco Cecchetti + * Marco Cecchetti + * Krzysztof Kosiński * * Copyright 2008 authors * @@ -32,104 +32,109 @@ */ -#ifndef _2GEOM_ELLIPSE_H_ -#define _2GEOM_ELLIPSE_H_ +#ifndef LIB2GEOM_SEEN_ELLIPSE_H +#define LIB2GEOM_SEEN_ELLIPSE_H #include -#include <2geom/point.h> +#include <2geom/angle.h> #include <2geom/exception.h> -#include <2geom/affine.h> +#include <2geom/point.h> +#include <2geom/transforms.h> -namespace Geom -{ +namespace Geom { class EllipticalArc; class Circle; +/** @brief Set of points with a constant sum of distances from two foci + * @ingroup Shapes */ class Ellipse + : boost::multipliable< Ellipse, Translate + , boost::multipliable< Ellipse, Scale + , boost::multipliable< Ellipse, Rotate + , boost::multipliable< Ellipse, Zoom + , boost::multipliable< Ellipse, Affine + > > > > > { - public: - Ellipse(): - m_centre(), - m_ray(), - m_angle(0) + Point _center; + Point _rays; + Angle _angle; +public: + Ellipse() {} + Ellipse(Point const &c, Point const &r, Coord angle) + : _center(c) + , _rays(r) + , _angle(angle) {} - - Ellipse(double cx, double cy, double rx, double ry, double a) - : m_centre(cx, cy), m_ray(rx, ry), m_angle(a) - { - } - - // build an ellipse by its implicit equation: - // Ax^2 + Bxy + Cy^2 + Dx + Ey + F = 0 - Ellipse(double A, double B, double C, double D, double E, double F) - { - set(A, B, C, D, E, F); - } - - Ellipse(std::vector const& points) - { - set(points); + Ellipse(Coord cx, Coord cy, Coord rx, Coord ry, Coord angle) + : _center(cx, cy) + , _rays(rx, ry) + , _angle(angle) + {} + Ellipse(double A, double B, double C, double D, double E, double F) { + setCoefficients(A, B, C, D, E, F); } - Ellipse(Geom::Circle const &c); - void set(double cx, double cy, double rx, double ry, double a) - { - m_centre[X] = cx; - m_centre[Y] = cy; - m_ray[X] = rx; - m_ray[Y] = ry; - m_angle = a; + void set(Point const &c, Point const &r, Coord angle) { + _center = c; + _rays = r; + _angle = angle; + } + void set(Coord cx, Coord cy, Coord rx, Coord ry, Coord a) { + _center[X] = cx; + _center[Y] = cy; + _rays[X] = rx; + _rays[Y] = ry; + _angle = a; } // build an ellipse by its implicit equation: // Ax^2 + Bxy + Cy^2 + Dx + Ey + F = 0 - void set(double A, double B, double C, double D, double E, double F); + void setCoefficients(double A, double B, double C, double D, double E, double F); // biuld up the best fitting ellipse wrt the passed points // prerequisite: at least 5 points must be passed - void set(std::vector const& points); + void fit(std::vector const& points); - EllipticalArc * - arc(Point const& initial, Point const& inner, Point const& final, bool svg_compliant = true); + EllipticalArc *arc(Point const &ip, Point const &inner, Point const &fp, + bool svg_compliant = true); - Point center() const - { - return m_centre; - } + Point center() const { return _center; } + Coord center(Dim2 d) const { return _center[d]; } + Point rays() const { return _rays; } + Coord ray(Dim2 d) const { return _rays[d]; } + Angle rotationAngle() const { return _angle; } - Coord center(Dim2 d) const - { - return m_centre[d]; - } + /** @brief Compute the transform that maps the unit circle to this ellipse. + * Each ellipse can be interpreted as a translated, scaled and rotate unit circle. + * This function returns the transform that maps the unit circle to this ellipse. + * @return Transform from unit circle to the ellipse */ + Affine unitCircleTransform() const; - Coord ray(Dim2 d) const - { - return m_ray[d]; - } + std::vector coefficients() const; - Coord rot_angle() const - { - return m_angle; + Ellipse &operator*=(Translate const &t) { + _center *= t; + return *this; } - - std::vector implicit_form_coefficients() const; - - Ellipse transformed(Affine const& m) const; - - private: - Point m_centre, m_ray; - double m_angle; + Ellipse &operator*=(Scale const &s) { + _center *= s; + _rays *= s; + return *this; + } + Ellipse &operator*=(Zoom const &z) { + _center *= z; + _rays *= z.scale(); + return *this; + } + Ellipse &operator*=(Rotate const &r); + Ellipse &operator*=(Affine const &m); }; - } // end namespace Geom - - -#endif // _2GEOM_ELLIPSE_H_ - +#endif // LIB2GEOM_SEEN_ELLIPSE_H /* Local Variables: diff --git a/src/2geom/elliptical-arc.cpp b/src/2geom/elliptical-arc.cpp index c96d5f1a6..601f0c8c8 100644 --- a/src/2geom/elliptical-arc.cpp +++ b/src/2geom/elliptical-arc.cpp @@ -34,11 +34,12 @@ #include #include -#include <2geom/elliptical-arc.h> -#include <2geom/ellipse.h> -#include <2geom/sbasis-geometric.h> #include <2geom/bezier-curve.h> +#include <2geom/ellipse.h> +#include <2geom/elliptical-arc.h> +#include <2geom/path-sink.h> #include <2geom/poly.h> +#include <2geom/sbasis-geometric.h> #include <2geom/transforms.h> #include <2geom/utils.h> @@ -46,7 +47,6 @@ #include <2geom/numeric/fitting-tool.h> #include <2geom/numeric/fitting-model.h> - namespace Geom { @@ -93,6 +93,8 @@ namespace Geom Rect EllipticalArc::boundsExact() const { + using std::swap; + double extremes[4]; double sinrot, cosrot; sincos(_rot_angle, sinrot, cosrot); @@ -109,11 +111,11 @@ Rect EllipticalArc::boundsExact() const arc_extremes[0] = initialPoint()[X]; arc_extremes[1] = finalPoint()[X]; if ( arc_extremes[0] < arc_extremes[1] ) - std::swap(arc_extremes[0], arc_extremes[1]); + swap(arc_extremes[0], arc_extremes[1]); arc_extremes[2] = initialPoint()[Y]; arc_extremes[3] = finalPoint()[Y]; if ( arc_extremes[2] < arc_extremes[3] ) - std::swap(arc_extremes[2], arc_extremes[3]); + swap(arc_extremes[2], arc_extremes[3]); if ( !are_near(initialPoint(), finalPoint()) ) { for (unsigned i = 0; i < 4; ++i) { @@ -266,8 +268,12 @@ std::vector EllipticalArc::roots(Coord v, Dim2 d) const } double rotx, roty; - sincos(_rot_angle, roty, rotx); /// \todo sin and cos are calculated in many places in this function, optimize this a bit! - if (d == X) roty = -roty; + if (d == X) { + sincos(_rot_angle, roty, rotx); + roty = -roty; + } else { + sincos(_rot_angle, rotx, roty); + } double rxrotx = ray(X) * rotx; double c_v = center(d) - v; @@ -428,7 +434,7 @@ Curve *EllipticalArc::reverse() const { } #ifdef HAVE_GSL // GSL is required for function "solve_reals" -std::vector EllipticalArc::allNearestPoints( Point const& p, double from, double to ) const +std::vector EllipticalArc::allNearestTimes( Point const& p, double from, double to ) const { std::vector result; @@ -446,7 +452,7 @@ std::vector EllipticalArc::allNearestPoints( Point const& p, double from else if ( are_near(ray(X), 0) || are_near(ray(Y), 0) ) { LineSegment seg(pointAt(from), pointAt(to)); - Point np = seg.pointAt( seg.nearestPoint(p) ); + Point np = seg.pointAt( seg.nearestTime(p) ); if ( are_near(ray(Y), 0) ) { if ( are_near(_rot_angle, M_PI/2) @@ -570,7 +576,7 @@ std::vector EllipticalArc::allNearestPoints( Point const& p, double from double mindistsq1 = std::numeric_limits::max(); double mindistsq2 = std::numeric_limits::max(); - double dsq; + double dsq = 0; unsigned int mi1 = 0, mi2 = 0; for ( unsigned int i = 0; i < real_sol.size(); ++i ) { @@ -887,16 +893,50 @@ D2 EllipticalArc::toSBasis() const return arc; } - -Curve *EllipticalArc::transformed(Affine const& m) const +void EllipticalArc::transform(Affine const& m) { + if (isChord()) { + _initial_point *= m; + _final_point *= m; + _center = middle_point(_initial_point, _final_point); + _rays = Point(0,0); + _rot_angle = 0; + return; + } + + // TODO avoid allocating a new arc here Ellipse e(center(X), center(Y), ray(X), ray(Y), _rot_angle); - Ellipse et = e.transformed(m); + e *= m; Point inner_point = pointAt(0.5); - return et.arc( initialPoint() * m, - inner_point * m, - finalPoint() * m, - isSVGCompliant() ); + EllipticalArc *arc = e.arc(initialPoint() * m, + inner_point * m, + finalPoint() * m, + isSVGCompliant()); + *this = *arc; + delete arc; +} + +bool EllipticalArc::operator==(Curve const &c) const +{ + EllipticalArc const *other = dynamic_cast(&c); + if (!other) return false; + if (_initial_point != other->_initial_point) return false; + if (_final_point != other->_final_point) return false; + // TODO: all arcs with ellipse rays which are too small + // and fall back to a line should probably be equal + if (_rays != other->_rays) return false; + if (_rot_angle != other->_rot_angle) return false; + if (_large_arc != other->_large_arc) return false; + if (_sweep != other->_sweep) return false; + return true; +} + +void EllipticalArc::feed(PathSink &sink, bool moveto_initial) const +{ + if (moveto_initial) { + sink.moveTo(_initial_point); + } + sink.arcTo(_rays[X], _rays[Y], _rot_angle, _large_arc, _sweep, _final_point); } Coord EllipticalArc::map_to_01(Coord angle) const diff --git a/src/2geom/elliptical-arc.h b/src/2geom/elliptical-arc.h index 5527aa6bc..342b8c8c9 100644 --- a/src/2geom/elliptical-arc.h +++ b/src/2geom/elliptical-arc.h @@ -34,8 +34,8 @@ * the specific language governing rights and limitations. */ -#ifndef _2GEOM_ELLIPTICAL_ARC_H_ -#define _2GEOM_ELLIPTICAL_ARC_H_ +#ifndef LIB2GEOM_SEEN_ELLIPTICAL_ARC_H +#define LIB2GEOM_SEEN_ELLIPTICAL_ARC_H #include #include <2geom/angle.h> @@ -71,9 +71,9 @@ public: * @param sweep If true, the clockwise arc is chosen, otherwise the counter-clockwise * arc is chosen * @param fp Final point of the arc */ - EllipticalArc( Point ip, Coord rx, Coord ry, + EllipticalArc( Point const &ip, Coord rx, Coord ry, Coord rot_angle, bool large_arc, bool sweep, - Point fp + Point const &fp ) : AngleInterval(0,0,sweep) , _initial_point(ip) @@ -137,7 +137,7 @@ public: * recalculations of the center and extreme angles. * @param ip New initial point * @param fp New final point */ - void setExtremes(Point const &ip, Point const &fp) { + void setEndpoints(Point const &ip, Point const &fp) { _initial_point = ip; _final_point = fp; _updateCenterAndAngles(isSVGCompliant()); @@ -182,6 +182,11 @@ public: /** @brief Check whether the arc adheres to SVG 1.1 implementation guidelines */ virtual bool isSVGCompliant() const { return false; } + /// Check whether both rays are nonzero + bool isChord() const { + return _rays[0] == 0 || _rays[Y] == 0; + } + std::pair subdivide(Coord t) const { EllipticalArc* arc1 = static_cast(portion(0, t)); EllipticalArc* arc2 = static_cast(portion(t, 1)); @@ -193,7 +198,6 @@ public: } // implementation of overloads goes here -#ifndef DOXYGEN_SHOULD_SKIP_THIS virtual Point initialPoint() const { return _initial_point; } virtual Point finalPoint() const { return _final_point; } virtual Curve* duplicate() const { return new EllipticalArc(*this); } @@ -206,7 +210,7 @@ public: _updateCenterAndAngles(isSVGCompliant()); } virtual bool isDegenerate() const { - return ( are_near(ray(X), 0) || are_near(ray(Y), 0) ); + return _initial_point == _final_point; } virtual Rect boundsFast() const { return boundsExact(); @@ -218,17 +222,17 @@ public: } virtual std::vector roots(double v, Dim2 d) const; #ifdef HAVE_GSL - virtual std::vector allNearestPoints( Point const& p, double from = 0, double to = 1 ) const; + virtual std::vector allNearestTimes( Point const& p, double from = 0, double to = 1 ) const; #endif - virtual double nearestPoint( Point const& p, double from = 0, double to = 1 ) const { + virtual double nearestTime( Point const& p, double from = 0, double to = 1 ) const { if ( are_near(ray(X), ray(Y)) && are_near(center(), p) ) { return from; } - return allNearestPoints(p, from, to).front(); + return allNearestTimes(p, from, to).front(); } virtual int degreesOfFreedom() const { return 7; } virtual Curve *derivative() const; - virtual Curve *transformed(Affine const &m) const; + virtual void transform(Affine const &m); virtual Curve &operator*=(Translate const &m) { _initial_point += m.vector(); _final_point += m.vector(); @@ -251,7 +255,8 @@ public: } virtual Curve* portion(double f, double t) const; virtual Curve* reverse() const; -#endif + virtual bool operator==(Curve const &c) const; + virtual void feed(PathSink &sink, bool moveto_initial) const; protected: void _updateCenterAndAngles(bool svg); @@ -267,7 +272,7 @@ private: } // end namespace Geom -#endif // _2GEOM_ELLIPTICAL_ARC_H_ +#endif // LIB2GEOM_SEEN_ELLIPTICAL_ARC_H /* Local Variables: diff --git a/src/2geom/exception.h b/src/2geom/exception.h index 12736d639..ab6f82142 100644 --- a/src/2geom/exception.h +++ b/src/2geom/exception.h @@ -38,8 +38,8 @@ * */ -#ifndef LIB2GEOM_EXCEPTION_HEADER -#define LIB2GEOM_EXCEPTION_HEADER +#ifndef LIB2GEOM_SEEN_EXCEPTION_H +#define LIB2GEOM_SEEN_EXCEPTION_H #include #include diff --git a/src/2geom/forward.h b/src/2geom/forward.h index 70cac1f7d..f3ab657e8 100644 --- a/src/2geom/forward.h +++ b/src/2geom/forward.h @@ -32,10 +32,8 @@ * the specific language governing rights and limitations. */ -#ifndef SEEN_GEOM_FORWARD_H -#define SEEN_GEOM_FORWARD_H - -#include // include this dependency so PathVector can be defined more explicitly +#ifndef LIB2GEOM_SEEN_FORWARD_H +#define LIB2GEOM_SEEN_FORWARD_H namespace Geom { @@ -79,7 +77,10 @@ class SVGEllipticalArc; // paths and path sequences class Path; -typedef std::vector PathVector; +class PathVector; +struct PathPosition; +class PathInterval; +struct PathVectorPosition; // errors class Exception; @@ -103,11 +104,6 @@ class Zoom; template class D2; template class Piecewise; -class Shape; -class Region; -class Hat; -class Tri; - // misc class SVGPathSink; template class SVGPathGenerator; diff --git a/src/2geom/generic-interval.h b/src/2geom/generic-interval.h index f6d4718de..716390e57 100644 --- a/src/2geom/generic-interval.h +++ b/src/2geom/generic-interval.h @@ -90,13 +90,24 @@ public: } /// @} - /// @name Inspect endpoints. + /// @name Inspect contained values. /// @{ C min() const { return _b[0]; } C max() const { return _b[1]; } C extent() const { return max() - min(); } C middle() const { return (max() + min()) / 2; } bool isSingular() const { return min() == max(); } + C operator[](unsigned i) const { assert(i < 2); return _b[i]; } + C clamp(C val) const { + if (val < min()) return min(); + if (val > max()) return max(); + return val; + } + /// Return the closer end of the interval. + C nearestEnd(C val) const { + C dmin = std::abs(val - min()), dmax = std::abs(val - max()); + return dmin <= dmax ? min() : max(); + } /// @} /// @name Test coordinates and other intervals for inclusion. @@ -138,6 +149,16 @@ public: _b[1] = val; } } + /// Set both ends of the interval simultaneously + void setEnds(C a, C b) { + if (a <= b) { + _b[0] = a; + _b[1] = b; + } else { + _b[0] = b; + _b[1] = a; + } + } /** @brief Extend the interval to include the given number. */ void expandTo(C val) { if(val < _b[0]) _b[0] = val; @@ -271,6 +292,8 @@ public: /** @brief Check whether this interval is empty. */ bool isEmpty() { return !*this; }; + /// Alias of isEmpty() for STL similarity. + bool empty() { return !*this; } /** @brief Union with another interval, gracefully handling empty ones. */ void unionWith(GenericOptInterval const &a) { @@ -317,14 +340,14 @@ inline GenericOptInterval operator&(GenericInterval const &a, GenericInter return GenericOptInterval(a) & GenericOptInterval(b); } -//#ifdef _GLIBCXX_IOSTREAM +#ifdef _GLIBCXX_IOSTREAM template inline std::ostream &operator<< (std::ostream &os, Geom::GenericInterval const &I) { os << "Interval("<::OptRectType OptCRect; typedef boost::optional Base; public: + typedef CInterval D1Value; + typedef CInterval &D1Reference; + typedef CInterval const &D1ConstReference; + /// @name Create potentially empty rectangles. /// @{ GenericOptRect() : Base() {} @@ -483,13 +513,13 @@ inline bool GenericRect::contains(OptCRect const &r) const { return !r || contains(*r); } -//#ifdef _GLIBCXX_IOSTREAM +#ifdef _GLIBCXX_IOSTREAM template inline std::ostream &operator<<(std::ostream &out, GenericRect const &r) { out << "X: " << r[X] << " Y: " << r[Y]; return out; } -//#endif +#endif } // end namespace Geom diff --git a/src/2geom/geom.cpp b/src/2geom/geom.cpp index d3cf0ca73..bf9b0a721 100644 --- a/src/2geom/geom.cpp +++ b/src/2geom/geom.cpp @@ -10,8 +10,17 @@ #include #include <2geom/rect.h> +using std::swap; + namespace Geom { +enum IntersectorKind { + intersects = 0, + parallel, + coincident, + no_intersection +}; + /** * Finds the intersection of the two (infinite) lines * defined by the points p such that dot(n0, p) == d0 and dot(n1, p) == d1. @@ -305,7 +314,7 @@ rect_line_intersect(Geom::Point const &c0, Geom::Point const &c1, Point dir1 (results[1] - results[0]); Point dir2 (p1 - p0); if (dot(dir1, dir2) < 0) { - std::swap(results[0], results[1]); + swap(results[0], results[1]); } } @@ -363,7 +372,7 @@ int centroid(std::vector const &p, Geom::Point& centroid, double &a Geom::Point centroid_tmp(0,0); double atmp = 0; for (unsigned i = n-1, j = 0; j < n; i = j, j++) { - const double ai = -cross(p[j], p[i]); + const double ai = cross(p[j], p[i]); atmp += ai; centroid_tmp += (p[j] + p[i])*ai; // first moment. } diff --git a/src/2geom/geom.h b/src/2geom/geom.h index 5aeded23d..6ba812254 100644 --- a/src/2geom/geom.h +++ b/src/2geom/geom.h @@ -44,52 +44,10 @@ namespace Geom { -enum IntersectorKind { - intersects = 0, - parallel, - coincident, - no_intersection -}; - -int -intersector_ccw(const Geom::Point& p0, const Geom::Point& p1, - const Geom::Point& p2); - -/* intersectors */ - -#if 0 -// Use the new routines provided in line.h - -IntersectorKind -line_intersection(Geom::Point const &n0, double const d0, - Geom::Point const &n1, double const d1, - Geom::Point &result); - -IntersectorKind -segment_intersect(Geom::Point const &p00, Geom::Point const &p01, - Geom::Point const &p10, Geom::Point const &p11, - Geom::Point &result); - -IntersectorKind -line_twopoint_intersect(Geom::Point const &p00, Geom::Point const &p01, - Geom::Point const &p10, Geom::Point const &p11, - Geom::Point &result); -#endif - -#if 0 -std::vector -rect_line_intersect(Geom::Point const &E, Geom::Point const &F, - Geom::Point const &p0, Geom::Point const &p1); -#endif - boost::optional rect_line_intersect(Geom::Rect &r, Geom::LineSegment ls); -boost::optional -rect_line_intersect(Geom::Rect &r, - Geom::Line l); - int centroid(std::vector const &p, Geom::Point& centroid, double &area); } diff --git a/src/2geom/hvlinesegment.h b/src/2geom/hvlinesegment.h deleted file mode 100644 index d2b9d6310..000000000 --- a/src/2geom/hvlinesegment.h +++ /dev/null @@ -1,283 +0,0 @@ -/** - * \file - * \brief Horizontal and vertical line segment - *//* - * Authors: - * Marco Cecchetti - * Krzysztof Kosiński - * Copyright 2008-2011 Authors - * - * This library is free software; you can redistribute it and/or - * modify it either under the terms of the GNU Lesser General Public - * License version 2.1 as published by the Free Software Foundation - * (the "LGPL") or, at your option, under the terms of the Mozilla - * Public License Version 1.1 (the "MPL"). If you do not alter this - * notice, a recipient may use your version of this file under either - * the MPL or the LGPL. - * - * You should have received a copy of the LGPL along with this library - * in the file COPYING-LGPL-2.1; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * You should have received a copy of the MPL along with this library - * in the file COPYING-MPL-1.1 - * - * The contents of this file are subject to the Mozilla Public License - * Version 1.1 (the "License"); you may not use this file except in - * compliance with the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY - * OF ANY KIND, either express or implied. See the LGPL or the MPL for - * the specific language governing rights and limitations. - */ - -#ifndef LIB2GEOM_SEEN_HVLINESEGMENT_H -#define LIB2GEOM_SEEN_HVLINESEGMENT_H - -#include <2geom/bezier-curve.h> - -namespace Geom -{ - -template -class AxisLineSegment : public LineSegment -{ -public: - static const Dim2 other_axis = static_cast((axis + 1) % 2); -#ifndef DOXYGEN_SHOULD_SKIP_THIS - virtual void setInitial(Point const &p) { - Point f = finalPoint(); - f[axis] = p[axis]; - LineSegment::setInitial(p); - LineSegment::setFinal(f); - } - virtual void setFinal(Point const &p) { - Point i = initialPoint(); - i[axis] = p[axis]; - LineSegment::setFinal(p); - LineSegment::setInitial(i); - } - virtual Rect boundsFast() const { return boundsExact(); } - virtual Rect boundsExact() const { Rect r(initialPoint(), finalPoint()); return r; } - virtual int degreesOfFreedom() const { return 3; } - virtual std::vector roots(Coord v, Dim2 d) const { - std::vector result; - if (d == axis) { - if ( v >= initialPoint()[axis] && v <= finalPoint()[axis] ) { - Coord t = 0; - if (!isDegenerate()) - t = (v - initialPoint()[axis]) / (finalPoint()[axis] - initialPoint()[axis]); - result.push_back(t); - } - } else { - if (v == initialPoint()[other_axis]) { - if (!isDegenerate()) - THROW_INFINITESOLUTIONS(0); - result.push_back(0); - } - } - return result; - } - virtual Coord nearestPoint( Point const &p, Coord from = 0, Coord to = 1 ) const { - if ( from > to ) std::swap(from, to); - Coord xfrom = valueAt(from, axis); - Coord xto = valueAt(to, axis); - if ( xfrom > xto ) { - std::swap(xfrom, xto); - std::swap(from, to); - } - if ( p[axis] > xfrom && p[axis] < xto ) { - return (p[axis] - initialPoint()[axis]) / (finalPoint()[axis] - initialPoint()[axis]); - } - else if ( p[X] <= xfrom ) - return from; - else - return to; - } - virtual Point pointAt(Coord t) const { - if ( t < 0 || t > 1 ) - THROW_RANGEERROR("AxisLineSegment: Time value out of range"); - Point ret = initialPoint() + t * (finalPoint() - initialPoint()); - return ret; - } - virtual Coord valueAt(Coord t, Dim2 d) const { - if ( t < 0 || t > 1 ) - THROW_RANGEERROR("AxisLineSegment: Time value out of range"); - if (d != axis) return initialPoint()[other_axis]; - return initialPoint()[axis] + t * (finalPoint()[axis] - initialPoint()[axis]); - } - virtual std::vector pointAndDerivatives(Coord t, unsigned n) const { - std::vector result; - result.push_back(pointAt(t)); - if (n > 0) { - Point der = finalPoint() - initialPoint(); - result.push_back( der ); - } - if (n > 1) { - /* higher order derivatives are zero, - * so the other n-1 vector elements are (0,0) */ - result.insert( result.end(), n-1, Point(0, 0) ); - } - return result; - } -#endif -protected: - AxisLineSegment(Point const &p0, Point const &p1) : LineSegment(p0, p1) {} - AxisLineSegment() {} -}; - -class HLineSegment : public AxisLineSegment -{ -public: - HLineSegment() {} - HLineSegment(Coord x0, Coord x1, Coord y) - : AxisLineSegment(Point(x0, y), Point(x1, y)) - {} - - HLineSegment(Point const& p, Coord len) - : AxisLineSegment(p, Point(p[X] + len, p[Y])) - {} - - HLineSegment(Point const& p0, Point const& p1) - : AxisLineSegment(p0, p1) - { - if ( p0[Y] != p1[Y] ) { - THROW_RANGEERROR("HLineSegment::HLineSegment passed points should " - "have the same Y value"); - } - } - - Coord getY() { return initialPoint()[Y]; } - void setInitialX(Coord x) { - LineSegment::setInitial(Point(x, initialPoint()[Y])); - } - void setFinalX(Coord x) { - LineSegment::setFinal(Point(x, initialPoint()[Y])); - } - void setY(Coord y) { - LineSegment::setInitial( Point(initialPoint()[X], y) ); - LineSegment::setFinal( Point(finalPoint()[X], y) ); - } - std::pair subdivide(Coord t) const { - std::pair result; - Point p = pointAt(t); - result.first.setInitial(initialPoint()); - result.first.setFinal(p); - result.second.setInitial(p); - result.second.setFinal(finalPoint()); - return result; - } - -#ifndef DOXYGEN_SHOULD_SKIP_THIS - virtual Curve* duplicate() const { return new HLineSegment(*this); } - virtual Curve *portion(Coord f, Coord t) const { - Point ip = pointAt(f); - Point ep = pointAt(t); - return new HLineSegment(ip[X], ep[X], ip[Y]); - } - virtual Curve *reverse() const { - Point ip = initialPoint(); - return new HLineSegment(finalPoint()[X], ip[X], ip[Y]); - } - virtual Curve *transformed(Affine const & m) const { - Point ip = initialPoint() * m; - Point ep = finalPoint() * m; - // cannot afford to lose precision here since it can lead to discontinuous paths - if (m.isZoom(0)) { - return new HLineSegment(ip[X], ep[X], ip[Y]); - } else { - return new LineSegment(ip, ep); - } - } - virtual Curve *derivative() const { - Coord x = finalPoint()[X] - initialPoint()[X]; - return new HLineSegment(x, x, 0); - } -#endif -}; // end class HLineSegment - - -class VLineSegment : public AxisLineSegment -{ -public: - VLineSegment() {} - - VLineSegment(Coord x, Coord y0, Coord y1) - : AxisLineSegment(Point(x, y0), Point(x, y1)) - {} - - VLineSegment(Point const& _p, Coord _length) - : AxisLineSegment(_p, Point(_p[X], _p[Y] + _length)) - {} - - VLineSegment(Point const& _p0, Point const& _p1) - : AxisLineSegment(_p0, _p1) - { - if ( _p0[X] != _p1[X] ) { - THROW_RANGEERROR("VLineSegment::VLineSegment passed points should " - "have the same X value"); - } - } - - Coord getX() { return initialPoint()[X]; } - void setInitialY(Coord _y) { - LineSegment::setInitial( Point(initialPoint()[X], _y) ); - } - void setFinalY(Coord _y) { - LineSegment::setFinal( Point(finalPoint()[Y], _y) ); - } - void setX(Coord _x) { - LineSegment::setInitial( Point(_x, initialPoint()[Y]) ); - LineSegment::setFinal( Point(_x, finalPoint()[Y]) ); - } - std::pair subdivide(Coord t) const { - std::pair result; - Point p = pointAt(t); - result.first.setInitial(initialPoint()); - result.first.setFinal(p); - result.second.setInitial(p); - result.second.setFinal(finalPoint()); - return result; - } - -#ifndef DOXYGEN_SHOULD_SKIP_THIS - virtual Curve *duplicate() const { return new VLineSegment(*this); } - virtual Curve *portion(Coord f, Coord t) const { - Point ip = pointAt(f); - Coord epy = valueAt(t, Y); - return new VLineSegment(ip[X], ip[Y], epy); - } - virtual Curve *reverse() const { - Point ip = initialPoint(); - return new VLineSegment(ip[X], finalPoint()[Y], ip[Y]); - } - virtual Curve *transformed(Affine const & m) const { - Point ip = initialPoint() * m; - Point ep = finalPoint() * m; - if (m.isZoom()) { - return new VLineSegment(ip[X], ip[Y], ep[Y]); - } else { - return new LineSegment(ip, ep); - } - } - virtual Curve* derivative() const { - Coord y = finalPoint()[Y] - initialPoint()[Y]; - return new VLineSegment(0, y, y); - } -#endif -}; // end class VLineSegment - -} // end namespace Geom - -#endif // LIB2GEOM_SEEN_HVLINESEGMENT_H - -/* - Local Variables: - mode:c++ - c-file-style:"stroustrup" - c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) - indent-tabs-mode:nil - fill-column:99 - End: -*/ -// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 : diff --git a/src/2geom/int-point.h b/src/2geom/int-point.h index 1a16ecb7a..7c737b1d7 100644 --- a/src/2geom/int-point.h +++ b/src/2geom/int-point.h @@ -120,30 +120,53 @@ public: } /// @} - /** @brief Lexicographical ordering functor. */ - template struct LexOrder; + /** @brief Lexicographical ordering functor. + * @param d The more significant dimension */ + template struct LexLess; + /** @brief Lexicographical ordering functor. + * @param d The more significant dimension */ + template struct LexGreater; /** @brief Lexicographical ordering functor with runtime dimension. */ - class LexOrderRt { - public: - LexOrderRt(Dim2 d) : dim(d) {} - inline bool operator()(IntPoint const &a, IntPoint const &b); + struct LexLessRt { + LexLessRt(Dim2 d) : dim(d) {} + inline bool operator()(IntPoint const &a, IntPoint const &b) const; + private: + Dim2 dim; + }; + /** @brief Lexicographical ordering functor with runtime dimension. */ + struct LexGreaterRt { + LexGreaterRt(Dim2 d) : dim(d) {} + inline bool operator()(IntPoint const &a, IntPoint const &b) const; private: Dim2 dim; }; }; -template<> struct IntPoint::LexOrder { - bool operator()(IntPoint const &a, IntPoint const &b) { +template<> struct IntPoint::LexLess { + bool operator()(IntPoint const &a, IntPoint const &b) const { return a[X] < b[X] || (a[X] == b[X] && a[Y] < b[Y]); } }; -template<> struct IntPoint::LexOrder { - bool operator()(IntPoint const &a, IntPoint const &b) { +template<> struct IntPoint::LexLess { + bool operator()(IntPoint const &a, IntPoint const &b) const { return a[Y] < b[Y] || (a[Y] == b[Y] && a[X] < b[X]); } }; -inline bool IntPoint::LexOrderRt::operator()(IntPoint const &a, IntPoint const &b) { - return dim ? IntPoint::LexOrder()(a, b) : IntPoint::LexOrder()(a, b); +template<> struct IntPoint::LexGreater { + bool operator()(IntPoint const &a, IntPoint const &b) const { + return a[X] > b[X] || (a[X] == b[X] && a[Y] > b[Y]); + } +}; +template<> struct IntPoint::LexGreater { + bool operator()(IntPoint const &a, IntPoint const &b) const { + return a[Y] > b[Y] || (a[Y] == b[Y] && a[X] > b[X]); + } +}; +inline bool IntPoint::LexLessRt::operator()(IntPoint const &a, IntPoint const &b) const { + return dim ? IntPoint::LexLess()(a, b) : IntPoint::LexLess()(a, b); +} +inline bool IntPoint::LexGreaterRt::operator()(IntPoint const &a, IntPoint const &b) const { + return dim ? IntPoint::LexGreater()(a, b) : IntPoint::LexGreater()(a, b); } } // namespace Geom diff --git a/src/2geom/intersection-graph.cpp b/src/2geom/intersection-graph.cpp new file mode 100644 index 000000000..abe462e3f --- /dev/null +++ b/src/2geom/intersection-graph.cpp @@ -0,0 +1,296 @@ +/** + * \file + * \brief Intersection graph for Boolean operations + *//* + * Authors: + * Krzysztof Kosiński + * + * Copyright 2015 Authors + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + */ + +#include <2geom/intersection-graph.h> +#include <2geom/path.h> +#include <2geom/pathvector.h> +#include + +namespace Geom { + +struct IntersectionVertexLess { + bool operator()(IntersectionVertex const &a, IntersectionVertex const &b) const { + return a.pos < b.pos; + } +}; + +/** @class PathIntersectionGraph + * @brief Intermediate data for computing Boolean operations on paths. + * + * This class implements the Greiner-Hormann clipping algorithm, + * with improvements by Foster and Overfelt. + * + * @ingroup Paths + */ + +PathIntersectionGraph::PathIntersectionGraph(PathVector const &a, PathVector const &b, Coord precision) + : _a(a) + , _b(b) +{ + if (a.empty() || b.empty()) return; + + // all paths must be closed, otherwise we will miss some intersections + for (std::size_t i = 0; i < a.size(); ++i) { + _a[i].close(); + } + for (std::size_t i = 0; i < b.size(); ++i) { + _b[i].close(); + } + + std::vector pxs = _a.intersect(_b, precision); + if (pxs.empty()) return; + if (pxs.size() % 2) return; + + // prepare intersection lists for each path component + for (std::size_t i = 0; i < _a.size(); ++i) { + _xalists.push_back(new IntersectionList()); + } + for (std::size_t i = 0; i < _b.size(); ++i) { + _xblists.push_back(new IntersectionList()); + } + + for (std::size_t i = 0; i < pxs.size(); ++i) { + IntersectionVertex *xa, *xb; + xa = new IntersectionVertex(); + xb = new IntersectionVertex(); + xa->processed = xb->processed = false; + xa->pos = pxs[i].first; + xb->pos = pxs[i].second; + xa->p = xb->p = pxs[i].point(); + xa->neighbor = xb; + xb->neighbor = xa; + _xs.push_back(xa); + _xs.push_back(xb); + _xalists[xa->pos.path_index].push_back(*xa); + _xblists[xb->pos.path_index].push_back(*xb); + } + + for (std::size_t i = 0; i < _xalists.size(); ++i) { + _xalists[i].sort(IntersectionVertexLess()); + } + for (std::size_t i = 0; i < _xblists.size(); ++i) { + _xblists[i].sort(IntersectionVertexLess()); + } + + typedef IntersectionList::iterator Iter; + + // determine in/out/on flags using winding + for (unsigned npv = 0; npv < 2; ++npv) { + boost::ptr_vector &ls = npv ? _xblists : _xalists; + PathVector const &pv = npv ? b : a; + PathVector const &other = npv ? a : b; + + for (unsigned li = 0; li < ls.size(); ++li) { + for (Iter i = ls[li].begin(); i != ls[li].end(); ++i) { + Iter n = boost::next(i); + if (n == ls[li].end()) { + n = ls[li].begin(); + } + std::size_t pi = i->pos.path_index; + + PathInterval ival = forward_interval(i->pos, n->pos, pv[pi].size()); + PathPosition mid = ival.inside(precision); + + // TODO check for degenerate cases + // requires changes in the winding routine + int w = other.winding(pv[pi].pointAt(mid)); + if (w % 2) { + i->next = POINT_INSIDE; + n->previous = POINT_INSIDE; + } else { + i->next = POINT_OUTSIDE; + n->previous = POINT_OUTSIDE; + } + } + + // assign exit / entry flags + for (Iter i = ls[li].begin(); i != ls[li].end(); ++i) { + i->entry = ((i->next == POINT_INSIDE) && (i->previous == POINT_OUTSIDE)); + } + } + } +} + +PathVector PathIntersectionGraph::getUnion() +{ + PathVector result = _getResult(false, false); + _handleNonintersectingPaths(result, 0, false); + _handleNonintersectingPaths(result, 1, false); + return result; +} + +PathVector PathIntersectionGraph::getIntersection() +{ + PathVector result = _getResult(true, true); + _handleNonintersectingPaths(result, 0, true); + _handleNonintersectingPaths(result, 1, true); + return result; +} + +PathVector PathIntersectionGraph::_getResult(bool enter_a, bool enter_b) +{ + typedef IntersectionList::iterator Iter; + PathVector result; + if (_xs.empty()) return result; + + // reset processed status + for (unsigned npv = 0; npv < 2; ++npv) { + boost::ptr_vector &ls = npv ? _xblists : _xalists; + for (std::size_t li = 0; li < ls.size(); ++li) { + for (Iter k = ls[li].begin(); k != ls[li].end(); ++k) { + k->processed = false; + } + } + } + + unsigned n_processed = 0; + + while (true) { + PathVector const *cur = &_a, *other = &_b; + boost::ptr_vector *lscur = &_xalists, *lsother = &_xblists; + + // find unprocessed intersection + Iter i; + if (!_findUnprocessed(i)) break; + + result.push_back(Path(i->p)); + result.back().setStitching(true); + + while (!i->processed) { + Iter prev = i; + std::size_t pi = i->pos.path_index; + // determine which direction to go + // union: always go outside + // intersection: always go inside + // a minus b: go inside in b, outside in a + // b minus a: go inside in a, outside in b + bool reverse = false; + if (cur == &_a) { + reverse = i->entry ^ enter_a; + } else { + reverse = i->entry ^ enter_b; + } + + // get next intersection + if (reverse) { + if (i == (*lscur)[pi].begin()) { + i = (*lscur)[pi].end(); + } + --i; + } else { + ++i; + if (i == (*lscur)[pi].end()) { + i = (*lscur)[pi].begin(); + } + } + + // append portion of path + PathInterval ival = PathInterval::from_direction( + prev->pos.asPathPosition(), i->pos.asPathPosition(), + reverse, (*cur)[pi].size()); + + (*cur)[pi].appendPortionTo(result.back(), ival, prev->p, i->p); + + // mark both vertices as processed + prev->processed = true; + i->processed = true; + n_processed += 2; + + // switch to the other path + i = (*lsother)[i->neighbor->pos.path_index].iterator_to(*i->neighbor); + std::swap(lscur, lsother); + std::swap(cur, other); + } + + assert(!result.back().empty()); + } + + assert(n_processed == _xs.size()); + + return result; +} + +void PathIntersectionGraph::_handleNonintersectingPaths(PathVector &result, int which, bool inside) +{ + /* Every component that has any intersections will be processed by _getResult. + * Here we take care of paths that don't have any intersections. They are either + * completely inside or completely outside the other pathvector. We test this by + * evaluating the winding rule at the initial point. If inside is true and + * the path is inside, we add it to the result. + */ + boost::ptr_vector const &ls = which ? _xblists : _xalists; + PathVector const &cur = which ? _b : _a; + PathVector const &other = which ? _a : _b; + + for (std::size_t i = 0; i < cur.size(); ++i) { + if (!ls.empty() && !ls[i].empty()) continue; + + int w = other.winding(cur[i].initialPoint()); + bool path_inside = w % 2 != 0; + if (path_inside == inside) { + result.push_back(cur[i]); + } + } +} + +bool PathIntersectionGraph::_findUnprocessed(IntersectionList::iterator &result) +{ + typedef IntersectionList::iterator Iter; + + Iter it; + + for (std::size_t k = 0; k < _xalists.size(); ++k) { + it = _xalists[k].begin(); + for (; it != _xalists[k].end(); ++it) { + if (!it->processed) { + result = it; + return true; + } + } + } + + return false; +} + +} // namespace Geom + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 : diff --git a/src/2geom/intersection-graph.h b/src/2geom/intersection-graph.h new file mode 100644 index 000000000..2fe858c5d --- /dev/null +++ b/src/2geom/intersection-graph.h @@ -0,0 +1,106 @@ +/** + * \file + * \brief Path intersection graph + *//* + * Authors: + * Krzysztof Kosiński + * + * Copyright 2015 Authors + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + */ + +#ifndef SEEN_LIB2GEOM_INTERSECTION_GRAPH_H +#define SEEN_LIB2GEOM_INTERSECTION_GRAPH_H + +#include +#include +#include +#include +#include <2geom/forward.h> +#include <2geom/pathvector.h> + +namespace Geom { + +enum InOutFlag { + POINT_INSIDE, + POINT_OUTSIDE, + POINT_ON_EDGE +}; + +struct IntersectionVertex { + boost::intrusive::list_member_hook<> _hook; + PathVectorPosition pos; + Point p; // guarantees that endpoints are exact + IntersectionVertex *neighbor; + bool entry; // going in +t direction enters the other path + InOutFlag previous; + InOutFlag next; + bool processed; // TODO: use intrusive unprocessed list instead +}; + +typedef boost::intrusive::list + < IntersectionVertex + , boost::intrusive::member_hook + < IntersectionVertex + , boost::intrusive::list_member_hook<> + , &IntersectionVertex::_hook + > + > IntersectionList; + + +class PathIntersectionGraph +{ + // this is called PathIntersectionGraph so that we can also have a class for polygons, + // e.g. PolygonIntersectionGraph, which is going to be significantly faster +public: + PathIntersectionGraph(PathVector const &a, PathVector const &b, Coord precision = EPSILON); + + PathVector getUnion(); + PathVector getIntersection(); + +private: + PathVector _getResult(bool enter_a, bool enter_b); + void _handleNonintersectingPaths(PathVector &result, int which, bool inside); + bool _findUnprocessed(IntersectionList::iterator &result); + + PathVector _a, _b; + boost::ptr_vector _xs; + boost::ptr_vector _xalists; + boost::ptr_vector _xblists; +}; + +} // namespace Geom + +#endif // SEEN_LIB2GEOM_PATH_GRAPH_H +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 : diff --git a/src/2geom/intersection.h b/src/2geom/intersection.h new file mode 100644 index 000000000..848797682 --- /dev/null +++ b/src/2geom/intersection.h @@ -0,0 +1,117 @@ +/** + * \file + * \brief Intersection utilities + *//* + * Authors: + * Krzysztof Kosiński + * + * Copyright 2015 Authors + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + */ + +#ifndef SEEN_LIB2GEOM_INTERSECTION_H +#define SEEN_LIB2GEOM_INTERSECTION_H + +#include <2geom/coord.h> +#include <2geom/point.h> + +namespace Geom { + + +/** @brief Intersection between two shapes. + */ +template +class Intersection +{ +public: + /** @brief Construct from shape references and time values. + * By default, the intersection point will be halfway between the evaluated + * points on the two shapes. */ + template + Intersection(TA const &sa, TB const &sb, TimeA const &ta, TimeB const &tb) + : first(ta) + , second(tb) + , _point(lerp(0.5, sa.pointAt(ta), sb.pointAt(tb))) + {} + + /// Additionally report the intersection point. + Intersection(TimeA const &ta, TimeB const &tb, Point const &p) + : first(ta) + , second(tb) + , _point(p) + {} + + /// Intersection point, as calculated by the intersection algorithm. + Point point() const { + return _point; + } + /// Implicit conversion to Point. + operator Point() const { + return _point; + } + + friend inline void swap(Intersection &a, Intersection &b) { + using std::swap; + swap(a.first, b.first); + swap(a.second, b.second); + swap(a._point, b._point); + } + +public: + /// First shape and time value. + TimeA first; + /// Second shape and time value. + TimeB second; +private: + // Recalculation of the intersection point from the time values is in many cases + // less precise than the value obtained directly from the intersection algorithm, + // so we need to store it. + Point _point; +}; + + +// TODO: move into new header +template +struct ShapeTraits { + typedef Coord TimeType; + typedef Interval IntervalType; + typedef T AffineClosureType; + typedef Intersection<> IntersectionType; +}; + + +} // namespace Geom + +#endif // SEEN_LIB2GEOM_INTERSECTION_H +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 : diff --git a/src/2geom/interval.h b/src/2geom/interval.h index 1714435be..09ea46923 100644 --- a/src/2geom/interval.h +++ b/src/2geom/interval.h @@ -91,19 +91,23 @@ public: } /// @} - /// @name Inspect endpoints. + /// @name Inspect contained values. /// @{ - /** @brief Access endpoints by value. - * @deprecated Use min() and max() instead */ - Coord operator[](unsigned i) const { return _b[i]; } - /** @brief Access endpoints by reference. - * @deprecated Use min() and max() instead - * @todo Remove Interval index operator, which can be used to break the invariant */ - Coord& operator[](unsigned i) { return _b[i]; } - + /** @brief Check whether both endpoints are finite. */ bool isFinite() const { return IS_FINITE(min()) && IS_FINITE(max()); } + /** @brief Map the interval [0,1] onto this one. + * This method simply performs 1D linear interpolation between endpoints. */ + Coord valueAt(Coord t) { + return lerp(t, min(), max()); + } + /** @brief Find closest time in [0,1] that maps to the given value. */ + Coord nearestTime(Coord t) { + if (t < min()) return 0; + if (t > max()) return 1; + return (t - min()) / extent(); + } /// @} /// @name Test coordinates and other intervals for inclusion. @@ -114,7 +118,16 @@ public: /** @brief Check whether the interior of the interval includes the given interval. * Interior means all numbers in the interval except its ends. */ bool interiorContains(Interval const &val) const { return min() < val.min() && val.max() < max(); } - /** @brief Check whether the interiors of the intervals have any common elements. A single point in common is not considered an intersection. */ + /// Check whether the number is contained in the union of the interior and the lower boundary. + bool lowerContains(Coord val) { return min() <= val && val < max(); } + /// Check whether the given interval is contained in the union of the interior and the lower boundary. + bool lowerContains(Interval const &val) const { return min() <= val.min() && val.max() < max(); } + /// Check whether the number is contained in the union of the interior and the upper boundary. + bool upperContains(Coord val) { return min() < val && val <= max(); } + /// Check whether the given interval is contained in the union of the interior and the upper boundary. + bool upperContains(Interval const &val) const { return min() < val.min() && val.max() <= max(); } + /** @brief Check whether the interiors of the intervals have any common elements. + * A single point in common is not considered an intersection. */ bool interiorIntersects(Interval const &val) const { return std::max(min(), val.min()) < std::min(max(), val.max()); } @@ -125,16 +138,18 @@ public: // IMPL: ScalableConcept /** @brief Scale an interval */ Interval &operator*=(Coord s) { + using std::swap; _b[0] *= s; _b[1] *= s; - if(s < 0) std::swap(_b[0], _b[1]); + if(s < 0) swap(_b[0], _b[1]); return *this; } /** @brief Scale an interval by the inverse of the specified value */ Interval &operator/=(Coord s) { + using std::swap; _b[0] /= s; _b[1] /= s; - if(s < 0) std::swap(_b[0], _b[1]); + if(s < 0) swap(_b[0], _b[1]); return *this; } /** @brief Multiply two intervals. diff --git a/src/2geom/line.cpp b/src/2geom/line.cpp index 097365245..35cf2d379 100644 --- a/src/2geom/line.cpp +++ b/src/2geom/line.cpp @@ -28,11 +28,9 @@ * the specific language governing rights and limitations. */ - -#include <2geom/line.h> - #include - +#include <2geom/line.h> +#include <2geom/math-utils.h> namespace Geom { @@ -41,12 +39,18 @@ namespace Geom * @class Line * @brief Infinite line on a plane. * - * Every line in 2Geom has a special point on it, called the origin. The direction of the line - * is stored as a unit vector (versor). This way a line can be interpreted as a function - * \f$ f: (-\infty, \infty) \to \mathbb{R}^2\f$. Zero corresponds to the origin point, - * positive values to the points in the direction of the unit vector, and negative values - * to points in the opposite direction. - * + * A line is specified as two points through which it passes. Lines can be interpreted as functions + * \f$ f: (-\infty, \infty) \to \mathbb{R}^2\f$. Zero corresponds to the first (origin) point, + * one corresponds to the second (final) point. All other points are computed as a linear + * interpolation between those two: \f$p = (1-t) a + t b\f$. Many such functions have the same + * image and therefore represent the same lines; for example, adding \f$b-a\f$ to both points + * yields the same line. + * + * 2Geom can represent the same line in many ways by design: using a different representation + * would lead to precision loss. For example, a line from (1e30, 1e30) to (10,0) would actually + * evaluate to (0,0) at time 1 if it was stored as origin and normalized versor, + * or origin and angle. + * * @ingroup Primitives */ @@ -54,35 +58,50 @@ namespace Geom * A line is a set of points that satisfies the line equation * \f$Ax + By + C = 0\f$. This function changes the line so that its points * satisfy the line equation with the given coefficients. */ -void Line::setCoefficients (double a, double b, double c) { +void Line::setCoefficients (Coord a, Coord b, Coord c) +{ if (a == 0 && b == 0) { if (c != 0) { THROW_LOGICALERROR("the passed coefficients gives the empty set"); } - m_versor = Point(0,0); - m_origin = Point(0,0); - } else { - double l = hypot(a,b); - a /= l; - b /= l; - c /= l; - Point N(a, b); - m_versor = N.ccw(); - m_origin = -c * N; - } + _initial = Point(0,0); + _final = Point(0,0); + return; + } + if (a == 0) { + // b must be nonzero + _initial = Point(0, c / b); + _final = _initial; + _final[X] = 1; + return; + } + if (b == 0) { + _initial = Point(c / a, 0); + _final = _initial; + _final[Y] = 1; + return; + } + + _initial = Point(c / a, 0); + _final = Point(0, c / b); +} + +void Line::coefficients(Coord &a, Coord &b, Coord &c) const +{ + Point v = versor().cw(); + a = v[X]; + b = v[Y]; + c = cross(_initial, _final); } /** @brief Get the line equation coefficients of this line. * @return Vector with three values corresponding to the A, B and C * coefficients of the line equation for this line. */ -std::vector Line::coefficients() const { - std::vector coeff; - coeff.reserve(3); - Point N = versor().cw(); - coeff.push_back (N[X]); - coeff.push_back (N[Y]); - double d = - dot (N, origin()); - coeff.push_back (d); +std::vector Line::coefficients() const +{ + Coord c[3]; + coefficients(c[0], c[1], c[2]); + std::vector coeff(c, c+3); return coeff; } @@ -91,87 +110,153 @@ std::vector Line::coefficients() const { * @param d Which axis the coordinate is on. X means a vertical line, Y means a horizontal line. * @return Time values at which this line intersects the query line. */ std::vector Line::roots(Coord v, Dim2 d) const { - if (d < 0 || d > 1) - THROW_RANGEERROR("Line::roots, dimension argument out of range"); std::vector result; - if ( m_versor[d] != 0 ) - { - result.push_back( (v - m_origin[d]) / m_versor[d] ); + Coord r = root(v, d); + if (IS_FINITE(r)) { + result.push_back(r); } - // TODO: else ? return result; } +Coord Line::root(Coord v, Dim2 d) const +{ + assert(d == X || d == Y); + Point vs = versor(); + if (vs[d] != 0) { + return (v - _initial[d]) / vs[d]; + } else { + return nan(""); + } +} + +boost::optional Line::clip(Rect const &r) const +{ + Point v = versor(); + // handle horizontal and vertical lines first, + // since the root-based code below will break for them + for (unsigned i = 0; i < 2; ++i) { + Dim2 d = (Dim2) i; + Dim2 o = other_dimension(d); + if (v[d] != 0) continue; + if (r[d].contains(_initial[d])) { + Point a, b; + a[o] = r[o].min(); + b[o] = r[o].max(); + a[d] = b[d] = _initial[d]; + if (v[o] > 0) { + return LineSegment(a, b); + } else { + return LineSegment(b, a); + } + } else { + return boost::none; + } + } + + Interval xpart(root(r[X].min(), X), root(r[X].max(), X)); + Interval ypart(root(r[Y].min(), Y), root(r[Y].max(), Y)); + if (!xpart.isFinite() || !ypart.isFinite()) { + return boost::none; + } + + OptInterval common = xpart & ypart; + if (common) { + Point p1 = pointAt(common->min()), p2 = pointAt(common->max()); + LineSegment result(r.clamp(p1), r.clamp(p2)); + return result; + } else { + return boost::none; + } + + /* old implementation using coefficients: + + if (fabs(b) > fabs(a)) { + p0 = Point(r[X].min(), (-c - a*r[X].min())/b); + if (p0[Y] < r[Y].min()) + p0 = Point((-c - b*r[Y].min())/a, r[Y].min()); + if (p0[Y] > r[Y].max()) + p0 = Point((-c - b*r[Y].max())/a, r[Y].max()); + p1 = Point(r[X].max(), (-c - a*r[X].max())/b); + if (p1[Y] < r[Y].min()) + p1 = Point((-c - b*r[Y].min())/a, r[Y].min()); + if (p1[Y] > r[Y].max()) + p1 = Point((-c - b*r[Y].max())/a, r[Y].max()); + } else { + p0 = Point((-c - b*r[Y].min())/a, r[Y].min()); + if (p0[X] < r[X].min()) + p0 = Point(r[X].min(), (-c - a*r[X].min())/b); + if (p0[X] > r[X].max()) + p0 = Point(r[X].max(), (-c - a*r[X].max())/b); + p1 = Point((-c - b*r[Y].max())/a, r[Y].max()); + if (p1[X] < r[X].min()) + p1 = Point(r[X].min(), (-c - a*r[X].min())/b); + if (p1[X] > r[X].max()) + p1 = Point(r[X].max(), (-c - a*r[X].max())/b); + } + return LineSegment(p0, p1); */ +} + /** @brief Get a time value corresponding to a point. * @param p Point on the line. If the point is not on the line, * the returned value will be meaningless. * @return Time value t such that \f$f(t) = p\f$. * @see timeAtProjection */ -Coord Line::timeAt(Point const& _point) const { - Coord t; - if ( m_versor[X] != 0 ) { - t = (_point[X] - m_origin[X]) / m_versor[X]; - } - else if ( m_versor[Y] != 0 ) { - t = (_point[Y] - m_origin[Y]) / m_versor[Y]; +Coord Line::timeAt(Point const &p) const +{ + Point v = versor(); + // degenerate case + if (v[X] == 0 && v[Y] == 0) { + return 0; } - else { // degenerate case - t = 0; + + // use the coordinate that will give better precision + if (fabs(v[X]) > fabs(v[Y])) { + return (p[X] - _initial[X]) / v[X]; + } else { + return (p[Y] - _initial[Y]) / v[Y]; } - return t; } namespace detail { inline -OptCrossing intersection_impl(Point const& V1, Point const O1, - Point const& V2, Point const O2 ) +OptCrossing intersection_impl(Point const &v1, Point const &o1, + Point const &v2, Point const &o2) { - double detV1V2 = V1[X] * V2[Y] - V2[X] * V1[Y]; - if (are_near(detV1V2, 0)) return OptCrossing(); + Coord cp = cross(v1, v2); + if (cp == 0) return OptCrossing(); - Point B = O2 - O1; - double detBV2 = B[X] * V2[Y] - V2[X] * B[Y]; - double detV1B = B[X] * V1[Y] - V1[X] * B[Y]; - double inv_detV1V2 = 1 / detV1V2; + Point odiff = o2 - o1; Crossing c; - c.ta = detBV2 * inv_detV1V2; - c.tb = detV1B * inv_detV1V2; -// std::cerr << "ta = " << c.ta << std::endl; -// std::cerr << "tb = " << c.tb << std::endl; - return OptCrossing(c); + c.ta = cross(odiff, v2) / cp; + c.tb = cross(odiff, v1) / cp; + return c; } OptCrossing intersection_impl(Ray const& r1, Line const& l2, unsigned int i) { + using std::swap; + OptCrossing crossing = intersection_impl(r1.versor(), r1.origin(), l2.versor(), l2.origin() ); - if (crossing) - { - if (crossing->ta < 0) - { + if (crossing) { + if (crossing->ta < 0) { return OptCrossing(); - } - else - { - if (i != 0) - { - std::swap(crossing->ta, crossing->tb); + } else { + if (i != 0) { + swap(crossing->ta, crossing->tb); } return crossing; } } - if (are_near(r1.origin(), l2)) - { + if (are_near(r1.origin(), l2)) { THROW_INFINITESOLUTIONS(); - } - else - { + } else { return OptCrossing(); } } @@ -181,34 +266,29 @@ OptCrossing intersection_impl( LineSegment const& ls1, Line const& l2, unsigned int i ) { + using std::swap; + OptCrossing crossing = intersection_impl(ls1.finalPoint() - ls1.initialPoint(), ls1.initialPoint(), l2.versor(), l2.origin() ); - if (crossing) - { + if (crossing) { if ( crossing->getTime(0) < 0 || crossing->getTime(0) > 1 ) { return OptCrossing(); - } - else - { - if (i != 0) - { - std::swap((*crossing).ta, (*crossing).tb); + } else { + if (i != 0) { + swap((*crossing).ta, (*crossing).tb); } return crossing; } } - if (are_near(ls1.initialPoint(), l2)) - { + if (are_near(ls1.initialPoint(), l2)) { THROW_INFINITESOLUTIONS(); - } - else - { + } else { return OptCrossing(); } } @@ -218,6 +298,8 @@ OptCrossing intersection_impl( LineSegment const& ls1, Ray const& r2, unsigned int i ) { + using std::swap; + Point direction = ls1.finalPoint() - ls1.initialPoint(); OptCrossing crossing = intersection_impl( direction, @@ -225,57 +307,40 @@ OptCrossing intersection_impl( LineSegment const& ls1, r2.versor(), r2.origin() ); - if (crossing) - { + if (crossing) { if ( (crossing->getTime(0) < 0) || (crossing->getTime(0) > 1) || (crossing->getTime(1) < 0) ) { return OptCrossing(); - } - else - { - if (i != 0) - { - std::swap(crossing->ta, crossing->tb); + } else { + if (i != 0) { + swap(crossing->ta, crossing->tb); } return crossing; } } - if ( are_near(r2.origin(), ls1) ) - { + if ( are_near(r2.origin(), ls1) ) { bool eqvs = (dot(direction, r2.versor()) > 0); - if ( are_near(ls1.initialPoint(), r2.origin()) && !eqvs ) - { + if ( are_near(ls1.initialPoint(), r2.origin()) && !eqvs) { crossing->ta = crossing->tb = 0; return crossing; - } - else if ( are_near(ls1.finalPoint(), r2.origin()) && eqvs ) - { - if (i == 0) - { + } else if ( are_near(ls1.finalPoint(), r2.origin()) && eqvs) { + if (i == 0) { crossing->ta = 1; crossing->tb = 0; - } - else - { + } else { crossing->ta = 0; crossing->tb = 1; } return crossing; - } - else - { + } else { THROW_INFINITESOLUTIONS(); } - } - else if ( are_near(ls1.initialPoint(), r2) ) - { + } else if ( are_near(ls1.initialPoint(), r2) ) { THROW_INFINITESOLUTIONS(); - } - else - { + } else { OptCrossing no_crossing; return no_crossing; } @@ -287,24 +352,16 @@ OptCrossing intersection_impl( LineSegment const& ls1, OptCrossing intersection(Line const& l1, Line const& l2) { - OptCrossing crossing = - detail::intersection_impl( l1.versor(), l1.origin(), - l2.versor(), l2.origin() ); - if (crossing) - { - return crossing; - } - if (are_near(l1.origin(), l2)) - { + OptCrossing c = detail::intersection_impl( + l1.versor(), l1.origin(), + l2.versor(), l2.origin()); + + if (!c && distance(l1.origin(), l2) == 0) { THROW_INFINITESOLUTIONS(); } - else - { - return crossing; - } + return c; } - OptCrossing intersection(Ray const& r1, Ray const& r2) { OptCrossing crossing = @@ -416,64 +473,6 @@ OptCrossing intersection( LineSegment const& ls1, LineSegment const& ls2 ) } } - -boost::optional clip (Line const& l, Rect const& r) -{ - typedef boost::optional opt_linesegment; - LineSegment result; - //size_t index = 0; - std::vector points; - LineSegment ls (r.corner(0), r.corner(1)); - try - { - OptCrossing oc = intersection (ls, l); - if (oc) - { - points.push_back (l.pointAt (oc->tb)); - } - } - catch (InfiniteSolutions const &e) - { - return opt_linesegment(ls); - } - - for (size_t i = 2; i < 5; ++i) - { - ls.setInitial (ls[1]); - ls.setFinal (r.corner(i)); - try - { - OptCrossing oc = intersection (ls, l); - if (oc) - { - points.push_back (l.pointAt (oc->tb)); - if (points.size() > 1) - { - size_t sz = points.size(); - if (!are_near (points[sz - 2], points[sz - 1], 1e-10)) - { - result.setInitial (points[sz - 2]); - result.setFinal (points[sz - 1]); - return opt_linesegment(result); - } - } - } - } - catch (InfiniteSolutions const &e) - { - return opt_linesegment(ls); - } - } - if ( !points.empty() ) - { - result.setInitial (points[0]); - result.setFinal (points[0]); - return opt_linesegment(result); - } - return opt_linesegment(); -} - - Line make_angle_bisector_line(Line const& l1, Line const& l2) { OptCrossing crossing; diff --git a/src/2geom/line.h b/src/2geom/line.h index cbd68fa08..2c47b4486 100644 --- a/src/2geom/line.h +++ b/src/2geom/line.h @@ -35,7 +35,6 @@ #define LIB2GEOM_SEEN_LINE_H #include -#include #include #include <2geom/bezier-curve.h> // for LineSegment #include <2geom/rect.h> @@ -43,36 +42,48 @@ #include <2geom/exception.h> #include <2geom/ray.h> #include <2geom/angle.h> +#include <2geom/intersection.h> namespace Geom { -class Line { +// class docs in cpp file +class Line + : boost::equality_comparable1 > +{ private: - Point m_origin; - Point m_versor; + Point _initial; + Point _final; public: /// @name Creating lines. /// @{ - /** @brief Create a default horizontal line. */ + /** @brief Create a default horizontal line. + * Creates a line with unit speed going in +X direction. */ Line() - : m_origin(0,0), m_versor(1,0) + : _initial(0,0), _final(1,0) {} /** @brief Create a line with the specified inclination. - * @param _origin One of the points on the line + * @param origin One of the points on the line * @param angle Angle of the line in mathematical convention */ - Line(Point const& _origin, Coord angle ) - : m_origin(_origin) + Line(Point const &origin, Coord angle) + : _initial(origin) { - sincos(angle, m_versor[Y], m_versor[X]); + Point v; + sincos(angle, v[Y], v[X]); + _final = _initial + v; } /** @brief Create a line going through two points. - * @param A First point - * @param B Second point */ - Line(Point const& A, Point const& B) { - setPoints(A, B); - } + * The first point will be at time 0, while the second one + * will be at time 1. + * @param a Initial point + * @param b First point */ + Line(Point const &a, Point const &b) + : _initial(a) + , _final(b) + {} /** @brief Create a line based on the coefficients of its equation. @see Line::setCoefficients() */ @@ -80,30 +91,30 @@ public: setCoefficients(a, b, c); } - /** @brief Create a line by extending a line segment. */ - explicit Line(LineSegment const& _segment) { - setPoints(_segment.initialPoint(), _segment.finalPoint()); - } + /// Create a line by extending a line segment. + explicit Line(LineSegment const &seg) + : _initial(seg.initialPoint()) + , _final(seg.finalPoint()) + {} - /** @brief Create a line by extending a ray. */ - explicit Line(Ray const& _ray) - : m_origin(_ray.origin()), m_versor(_ray.versor()) + /// Create a line by extending a ray. + explicit Line(Ray const &r) + : _initial(r.origin()) + , _final(r.origin() + r.versor()) {} - // huh? - static Line from_normal_distance(Point n, double c) { - Point P = n * c / dot(n,n); - Line l(P, P+rot90(n)); + /// Create a line normal to a vector at a specified distance from origin. + static Line from_normal_distance(Point const &n, Coord c) { + Point start = c * n.normalized(); + Line l(start, start + rot90(n)); return l; } /** @brief Create a line from origin and unit vector. * Note that each line direction has two possible unit vectors. * @param o Point through which the line will pass * @param v Unit vector of the line's direction */ - static Line from_origin_and_versor(Point o, Point v) { - Line l; - l.m_origin = o; - l.m_versor = v; + static Line from_origin_and_versor(Point const &o, Point const &v) { + Line l(o, o + v); return l; } @@ -114,63 +125,99 @@ public: /// @name Retrieve and set the line's parameters. /// @{ - /** @brief Get the line's origin point. */ - Point origin() const { return m_origin; } - /** @brief Get the line's direction unit vector. */ - Point versor() const { return m_versor; } - // return the angle described by rotating the X-axis in cw direction - // until it overlaps the line - // the returned value is in the interval [0, PI[ + + /// Get the line's origin point. + Point origin() const { return _initial; } + /** @brief Get the line's direction vector. + * Note that the retrieved vector is not normalized to unit length. */ + Point versor() const { return _final - _initial; } + /// Angle the line makes with the X axis, in mathematical convention. Coord angle() const { - double a = std::atan2(m_versor[Y], m_versor[X]); + Point d = _final - _initial; + double a = std::atan2(d[Y], d[X]); if (a < 0) a += M_PI; if (a == M_PI) a = 0; return a; } - void setOrigin(Point const& _point) { - m_origin = _point; + /** @brief Set the point at zero time. + * The orientation remains unchanged, modulo numeric errors during addition. */ + void setOrigin(Point const &p) { + Point d = p - _initial; + _initial = p; + _final += d; } - void setVersor(Point const& _versor) { - m_versor = _versor; + /** @brief Set the speed of the line. + * Origin remains unchanged. */ + void setVersor(Point const &v) { + _final = _initial + v; } - void setAngle(Coord _angle) { - sincos(_angle, m_versor[Y], m_versor[X]); + /** @brief Set the angle the line makes with the X axis. + * Origin remains unchanged. */ + void setAngle(Coord angle) { + Point v; + sincos(angle, v[Y], v[X]); + v *= distance(_initial, _final); + _final = _initial + v; } - /** @brief Set a line based on two points it should pass through. */ - void setPoints(Point const& A, Point const& B) { - m_origin = A; - if ( are_near(A, B) ) - m_versor = Point(0,0); - else - m_versor = B - A; - m_versor.normalize(); + /// Set a line based on two points it should pass through. + void setPoints(Point const &a, Point const &b) { + _initial = a; + _final = b; } - void setCoefficients (double a, double b, double c); + /** @brief Set the coefficients of the line equation. + * The line equation is: \f$ax + by = c\f$. Points that satisfy the equation + * are on the line. */ + void setCoefficients(double a, double b, double c); + + /** @brief Get the coefficients of the line equation as a vector. + * @return STL vector @a v such that @a v[0] contains \f$a\f$, @a v[1] contains \f$b\f$, + * and @a v[2] contains \f$c\f$. */ std::vector coefficients() const; - /** @brief Check if the line has any points. + /// Get the coefficients of the line equation by reference. + void coefficients(Coord &a, Coord &b, Coord &c) const; + + /** @brief Check if the line has more than one point. * A degenerate line can be created if the line is created from a line equation * that has no solutions. - * @return True if the line has no points */ + * @return True if the line has no points or exactly one point */ bool isDegenerate() const { - return ( m_versor[X] == 0 && m_versor[Y] == 0 ); + return _initial == _final; + } + + /** @brief Reparametrize the line so that it has unit speed. */ + void normalize() { + Point v = _final - _initial; + v.normalize(); + _final = _initial + v; + } + /** @brief Return a new line reparametrized for unit speed. */ + Line normalized() const { + Point v = _final - _initial; + v.normalize(); + Line ret(_initial, _initial + v); + return ret; } /// @} /// @name Evaluate the line as a function. ///@{ + Point initialPoint() const { + return _initial; + } + Point finalPoint() const { + return _final; + } Point pointAt(Coord t) const { - return m_origin + m_versor * t; + return lerp(t, _initial, _final);; } Coord valueAt(Coord t, Dim2 d) const { - if (d < 0 || d > 1) - THROW_RANGEERROR("Line::valueAt, dimension argument out of range"); - return m_origin[d] + m_versor[d] * t; + return lerp(t, _initial[d], _final[d]); } Coord timeAt(Point const &p) const; @@ -180,27 +227,29 @@ public: * @return Time value corresponding to a point closest to @c p. */ Coord timeAtProjection(Point const& p) const { if ( isDegenerate() ) return 0; - return dot( p - m_origin, m_versor ); + Point v = versor(); + return dot(p - _initial, v) / dot(v, v); } /** @brief Find a point on the line closest to the query point. * This is an alias for timeAtProjection(). */ - Coord nearestPoint(Point const& _point) const { - return timeAtProjection(_point); + Coord nearestTime(Point const &p) const { + return timeAtProjection(p); } std::vector roots(Coord v, Dim2 d) const; + Coord root(Coord v, Dim2 d) const; /// @} /// @name Create other objects based on this line. /// @{ - /** @brief Create a line containing the same points, but with negated time values. - * @return Line \f$g\f$ such that \f$g(t) = f(-t)\f$ */ - Line reverse() const - { - Line result; - result.setOrigin(m_origin); - result.setVersor(-m_versor); + void reverse() { + std::swap(_final, _initial); + } + /** @brief Create a line containing the same points, but in opposite direction. + * @return Line \f$g\f$ such that \f$g(t) = f(1-t)\f$ */ + Line reversed() const { + Line result(_final, _initial); return result; } @@ -219,6 +268,9 @@ public: return LineSegment(pointAt(f), pointAt(t)); } + /// Return the portion of the line that is inside the given rectangle + boost::optional clip(Rect const &r) const; + /** @brief Create a ray starting at the specified time value. * The created ray will go in the direction of the line's versor (in the direction * of increasing time values). @@ -227,7 +279,7 @@ public: Ray ray(Coord t) { Ray result; result.setOrigin(pointAt(t)); - result.setVersor(m_versor); + result.setVersor(versor()); return result; } @@ -235,88 +287,126 @@ public: * The new line will always be degenerate. Its origin will be equal to this * line's versor. */ Line derivative() const { - Line result; - result.setOrigin(m_versor); - result.setVersor(Point(0,0)); + Point v = versor(); + Line result(v, v); return result; } - /** @brief Create a line transformed by an affine transformation. */ + /// Create a line transformed by an affine transformation. Line transformed(Affine const& m) const { - return Line(m_origin * m, (m_origin + m_versor) * m); + Line l(_initial * m, _final * m); + return l; } - /** @brief Get a vector normal to the line. + /** @brief Get a unit vector normal to the line. * If Y grows upwards, then this is the left normal. If Y grows downwards, * then this is the right normal. */ Point normal() const { - return rot90(m_versor); + return rot90(versor()).normalized(); } // what does this do? Point normalAndDist(double & dist) const { Point n = normal(); - dist = -dot(n, m_origin); + dist = -dot(n, _initial); return n; } - friend inline std::ostream &operator<< (std::ostream &out_file, const Geom::Line &in_line); -/// @} -}; // end class Line + /// Compute an affine matrix representing a reflection about the line. + Affine reflection() const { + Point v = versor().normalized(); + Coord x2 = v[X]*v[X], y2 = v[Y]*v[Y], xy = v[X]*v[Y]; + Affine m(x2-y2, 2.*xy, + 2.*xy, y2-x2, + _initial[X], _initial[Y]); + m = Translate(-_initial) * m; + return m; + } -/** @brief Output operator for lines. - * Prints out representation (point + versor) - */ -inline std::ostream &operator<< (std::ostream &out_file, const Geom::Line &in_line) { - out_file << "X: " << in_line.m_origin[X] << " Y: " << in_line.m_origin[Y] - << " dX: " << in_line.m_versor[X] << " dY: " << in_line.m_versor[Y]; - return out_file; -} + /** @brief Compute an affine which transforms all points on the line to zero X or Y coordinate. + * This operation is useful in reducing intersection problems to root-finding problems. + * There are many affines which do this transformation. This function returns one that + * preserves angles, areas and distances - a rotation combined with a translation, and + * additionaly moves the initial point of the line to (0,0). This way it works without + * problems even for lines perpendicular to the target, though may in some cases have + * lower precision than e.g. a shear transform. + * @param d Which coordinate of points on the line should be zero after the transformation */ + Affine rotationToZero(Dim2 d) const { + Point v = versor(); + if (d == X) { + std::swap(v[X], v[Y]); + } else { + v[Y] = -v[Y]; + } + Affine m = Translate(-_initial) * Rotate(v); + return m; + } + /** @brief Compute a rotation affine which transforms the line to one of the axes. + * @param d Which line should be the axis */ + Affine rotationToAxis(Dim2 d) const { + Affine m = rotationToZero(other_dimension(d)); + return m; + } + /// @} -inline -double distance(Point const& _point, Line const& _line) -{ - if ( _line.isDegenerate() ) - { - return ::Geom::distance( _point, _line.origin() ); + //std::vector intersect(Line const &other, Coord precision = EPSILON) const; + + Line &operator*=(Affine const &m) { + _initial *= m; + _final *= m; + return *this; } - else - { - return fabs( dot(_point - _line.origin(), _line.versor().ccw()) ); + bool operator==(Line const &other) const { + if (distance(pointAt(nearestTime(other._initial)), other._initial) != 0) return false; + if (distance(pointAt(nearestTime(other._final)), other._final) != 0) return false; + return true; } -} +}; // end class Line +/// @brief Compute distance from point to line. +/// @relates Line inline -bool are_near(Point const& _point, Line const& _line, double eps = EPSILON) +double distance(Point const &p, Line const &line) { - return are_near(distance(_point, _line), 0, eps); + if (line.isDegenerate()) { + return ::Geom::distance(p, line.initialPoint()); + } else { + Coord t = line.nearestTime(p); + return ::Geom::distance(line.pointAt(t), p); + } } inline -bool are_parallel(Line const& l1, Line const& l2, double eps = EPSILON) +bool are_near(Point const &p, Line const &line, double eps = EPSILON) { - return ( are_near(l1.versor(), l2.versor(), eps) - || are_near(l1.versor(), -l2.versor(), eps) ); + return are_near(distance(p, line), 0, eps); } inline -bool are_same(Line const& l1, Line const& l2, double eps = EPSILON) +bool are_parallel(Line const &l1, Line const &l2, double eps = EPSILON) { - return are_parallel(l1, l2, eps) && are_near(l1.origin(), l2, eps); + return are_near(cross(l1.versor(), l2.versor()), 0, eps); } +/** @brief Test whether two lines are approximately the same. + * This tests for being parallel and the origin of one line being close to the other, + * so it tests whether the images of the lines are similar, not whether the same time values + * correspond to similar points. For example a line from (1,1) to (2,2) and a line from + * (-1,-1) to (0,0) will the the same, because their images match, even though there is + * no time value for which the lines give similar points. + * @relates Line */ inline -bool are_orthogonal(Line const& l1, Line const& l2, double eps = EPSILON) +bool are_same(Line const &l1, Line const &l2, double eps = EPSILON) { - return ( are_near(l1.versor(), l2.versor().cw(), eps) - || are_near(l1.versor(), l2.versor().ccw(), eps) ); + return are_parallel(l1, l2, eps) && are_near(l1.origin(), l2, eps); } +/// Test whether two lines are perpendicular. +/// @relates Line inline -bool are_collinear(Point const& p1, Point const& p2, Point const& p3, - double eps = EPSILON) +bool are_orthogonal(Line const &l1, Line const &l2, double eps = EPSILON) { - return are_near( cross(p3, p2) - cross(p3, p1) + cross(p2, p1), 0, eps); + return are_near(dot(l1.versor(), l2.versor()), 0, eps); } // evaluate the angle between l1 and l2 rotating l1 in cw direction @@ -332,36 +422,34 @@ double angle_between(Line const& l1, Line const& l2) } inline -double distance(Point const& _point, LineSegment const& _segment) +double distance(Point const &p, LineSegment const &seg) { - double t = _segment.nearestPoint(_point); - return L2(_point - _segment.pointAt(t)); + double t = seg.nearestTime(p); + return distance(p, seg.pointAt(t)); } inline -bool are_near(Point const& _point, LineSegment const& _segment, - double eps = EPSILON) +bool are_near(Point const &p, LineSegment const &seg, double eps = EPSILON) { - return are_near(distance(_point, _segment), 0, eps); + return are_near(distance(p, seg), 0, eps); } // build a line passing by _point and orthogonal to _line inline -Line make_orthogonal_line(Point const& _point, Line const& _line) +Line make_orthogonal_line(Point const &p, Line const &line) { - Line l; - l.setOrigin(_point); - l.setVersor(_line.versor().cw()); + Point d = line.versor().cw(); + Line l(p, p + d); return l; } // build a line passing by _point and parallel to _line inline -Line make_parallel_line(Point const& _point, Line const& _line) +Line make_parallel_line(Point const &p, Line const &line) { - Line l(_line); - l.setOrigin(_point); - return l; + Line result(line); + result.setOrigin(p); + return result; } // build a line passing by the middle point of _segment and orthogonal to it. @@ -373,31 +461,31 @@ Line make_bisector_line(LineSegment const& _segment) // build the bisector line of the angle between ray(O,A) and ray(O,B) inline -Line make_angle_bisector_line(Point const& A, Point const& O, Point const& B) +Line make_angle_bisector_line(Point const &A, Point const &O, Point const &B) { - Point M = middle_point(A,B); - if (are_near(O,M)) { - Line l(A,B); - M += (make_orthogonal_line(O,l)).versor(); - } - return Line(O,M); + AngleInterval ival(Angle(A-O), Angle(B-O)); + Angle bisect = ival.angleAt(0.5); + return Line(O, bisect); } // prj(P) = rot(v, Point( rot(-v, P-O)[X], 0 )) + O inline -Point projection(Point const& _point, Line const& _line) +Point projection(Point const &p, Line const &line) { - return _line.pointAt( _line.nearestPoint(_point) ); + return line.pointAt(line.nearestTime(p)); } inline -LineSegment projection(LineSegment const& _segment, Line const& _line) +LineSegment projection(LineSegment const &seg, Line const &line) { - return _line.segment( _line.nearestPoint(_segment.initialPoint()), - _line.nearestPoint(_segment.finalPoint()) ); + return line.segment(line.nearestTime(seg.initialPoint()), + line.nearestTime(seg.finalPoint())); } -boost::optional clip (Line const& l, Rect const& r); +inline +boost::optional clip(Line const &l, Rect const &r) { + return l.clip(r); +} namespace detail diff --git a/src/2geom/linear.h b/src/2geom/linear.h index 8c154364e..cd7108835 100644 --- a/src/2geom/linear.h +++ b/src/2geom/linear.h @@ -1,7 +1,7 @@ /** * \file * \brief Linear fragment function class - * + *//* * Authors: * Nathan Hurst * Michael Sloan @@ -32,12 +32,12 @@ * the specific language governing rights and limitations. */ -#ifndef SEEN_LINEAR_H -#define SEEN_LINEAR_H +#ifndef LIB2GEOM_SEEN_LINEAR_H +#define LIB2GEOM_SEEN_LINEAR_H + #include <2geom/interval.h> #include <2geom/math-utils.h> - //#define USE_SBASIS_OF #ifdef USE_SBASIS_OF @@ -46,48 +46,60 @@ #else -namespace Geom{ - -inline double lerp(double t, double a, double b) { return a*(1-t) + b*t; } +namespace Geom { class SBasis; -class Linear{ +/** + * @brief Linear function fragment + * @ingroup Fragments + */ +class Linear { public: double a[2]; Linear() {a[0]=0; a[1]=0;} Linear(double aa, double b) {a[0] = aa; a[1] = b;} Linear(double aa) {a[0] = aa; a[1] = aa;} - double operator[](const int i) const { - assert(i >= 0); + double operator[](unsigned i) const { assert(i < 2); return a[i]; } - double& operator[](const int i) { - assert(i >= 0); + double &operator[](unsigned i) { assert(i < 2); return a[i]; } //IMPL: FragmentConcept typedef double output_type; - inline bool isZero(double eps=EPSILON) const { return are_near(a[0], 0., eps) && are_near(a[1], 0., eps); } - inline bool isConstant(double eps=EPSILON) const { return are_near(a[0], a[1], eps); } - inline bool isFinite() const { return IS_FINITE(a[0]) && IS_FINITE(a[1]); } - - inline double at0() const { return a[0]; } - inline double at1() const { return a[1]; } - - inline double valueAt(double t) const { return lerp(t, a[0], a[1]); } - inline double operator()(double t) const { return valueAt(t); } + bool isZero(double eps=EPSILON) const { return are_near(a[0], 0., eps) && are_near(a[1], 0., eps); } + bool isConstant(double eps=EPSILON) const { return are_near(a[0], a[1], eps); } + bool isFinite() const { return IS_FINITE(a[0]) && IS_FINITE(a[1]); } + + Coord at0() const { return a[0]; } + Coord &at0() { return a[0]; } + Coord at1() const { return a[1]; } + Coord &at1() { return a[1]; } + + double valueAt(double t) const { return lerp(t, a[0], a[1]); } + double operator()(double t) const { return valueAt(t); } + + // not very useful, but required for ShapeConcept + std::vector valueAndDerivatives(Coord t, unsigned n) { + std::vector result(n+1, 0.0); + result[0] = valueAt(t); + if (n >= 1) { + result[1] = a[1] - a[0]; + } + return result; + } //defined in sbasis.h inline SBasis toSBasis() const; - inline OptInterval bounds_exact() const { return Interval(a[0], a[1]); } - inline OptInterval bounds_fast() const { return bounds_exact(); } - inline OptInterval bounds_local(double u, double v) const { return Interval(valueAt(u), valueAt(v)); } + OptInterval bounds_exact() const { return Interval(a[0], a[1]); } + OptInterval bounds_fast() const { return bounds_exact(); } + OptInterval bounds_local(double u, double v) const { return Interval(valueAt(u), valueAt(v)); } double tri() const { return a[1] - a[0]; @@ -98,6 +110,10 @@ public: }; inline Linear reverse(Linear const &a) { return Linear(a[1], a[0]); } +inline Linear portion(Linear const &a, Coord from, Coord to) { + Linear result(a.valueAt(from), a.valueAt(to)); + return result; +} //IMPL: AddableConcept inline Linear operator+(Linear const & a, Linear const & b) { @@ -158,7 +174,7 @@ inline Linear operator/=(Linear & a, double b) { } #endif -#endif //SEEN_LINEAR_H +#endif //LIB2GEOM_SEEN_LINEAR_H /* Local Variables: diff --git a/src/2geom/nearest-point.cpp b/src/2geom/nearest-point.cpp deleted file mode 100644 index c5dfc133c..000000000 --- a/src/2geom/nearest-point.cpp +++ /dev/null @@ -1,287 +0,0 @@ -/* - * nearest point routines for D2 and Piecewise> - * - * Authors: - * - * Marco Cecchetti - * - * Copyright 2007-2008 authors - * - * This library is free software; you can redistribute it and/or - * modify it either under the terms of the GNU Lesser General Public - * License version 2.1 as published by the Free Software Foundation - * (the "LGPL") or, at your option, under the terms of the Mozilla - * Public License Version 1.1 (the "MPL"). If you do not alter this - * notice, a recipient may use your version of this file under either - * the MPL or the LGPL. - * - * You should have received a copy of the LGPL along with this library - * in the file COPYING-LGPL-2.1; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * You should have received a copy of the MPL along with this library - * in the file COPYING-MPL-1.1 - * - * The contents of this file are subject to the Mozilla Public License - * Version 1.1 (the "License"); you may not use this file except in - * compliance with the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY - * OF ANY KIND, either express or implied. See the LGPL or the MPL for - * the specific language governing rights and limitations. - */ - - -#include <2geom/nearest-point.h> -#include - - -namespace Geom -{ - -//////////////////////////////////////////////////////////////////////////////// -// D2 versions - -/* - * Return the parameter t of a nearest point on the portion of the curve "c", - * related to the interval [from, to], to the point "p". - * The needed curve derivative "dc" is passed as parameter. - * The function return the first nearest point to "p" that is found. - */ - -double nearest_point( Point const& p, - D2 const& c, - D2 const& dc, - double from, double to ) -{ - if ( from > to ) std::swap(from, to); - if ( from < 0 || to > 1 ) - { - THROW_RANGEERROR("[from,to] interval out of bounds"); - } - if (c.isConstant()) return from; - SBasis dd = dot(c - p, dc); - //std::cout << dd << std::endl; - std::vector zeros = Geom::roots(dd); - - double closest = from; - double min_dist_sq = L2sq(c(from) - p); - for ( size_t i = 0; i < zeros.size(); ++i ) - { - double distsq = L2sq(c(zeros[i]) - p); - if ( min_dist_sq > L2sq(c(zeros[i]) - p) ) - { - closest = zeros[i]; - min_dist_sq = distsq; - } - } - if ( min_dist_sq > L2sq( c(to) - p ) ) - closest = to; - return closest; - -} - -/* - * Return the parameters t of all the nearest points on the portion of - * the curve "c", related to the interval [from, to], to the point "p". - * The needed curve derivative "dc" is passed as parameter. - */ - -std::vector -all_nearest_points( Point const& p, - D2 const& c, - D2 const& dc, - double from, double to ) -{ - std::swap(from, to); - if ( from > to ) std::swap(from, to); - if ( from < 0 || to > 1 ) - { - THROW_RANGEERROR("[from,to] interval out of bounds"); - } - - std::vector result; - if (c.isConstant()) - { - result.push_back(from); - return result; - } - SBasis dd = dot(c - p, dc); - - std::vector zeros = Geom::roots(dd); - std::vector candidates; - candidates.push_back(from); - candidates.insert(candidates.end(), zeros.begin(), zeros.end()); - candidates.push_back(to); - std::vector distsq; - distsq.reserve(candidates.size()); - for ( unsigned int i = 0; i < candidates.size(); ++i ) - { - distsq.push_back( L2sq(c(candidates[i]) - p) ); - } - unsigned int closest = 0; - double dsq = distsq[0]; - for ( unsigned int i = 1; i < candidates.size(); ++i ) - { - if ( dsq > distsq[i] ) - { - closest = i; - dsq = distsq[i]; - } - } - for ( unsigned int i = 0; i < candidates.size(); ++i ) - { - if( distsq[closest] == distsq[i] ) - { - result.push_back(candidates[i]); - } - } - return result; -} - - -//////////////////////////////////////////////////////////////////////////////// -// Piecewise< D2 > versions - - -double nearest_point( Point const& p, - Piecewise< D2 > const& c, - double from, double to ) -{ - if ( from > to ) std::swap(from, to); - if ( from < c.cuts[0] || to > c.cuts[c.size()] ) - { - THROW_RANGEERROR("[from,to] interval out of bounds"); - } - - unsigned int si = c.segN(from); - unsigned int ei = c.segN(to); - if ( si == ei ) - { - double nearest= - nearest_point(p, c[si], c.segT(from, si), c.segT(to, si)); - return c.mapToDomain(nearest, si); - } - double t; - double nearest = nearest_point(p, c[si], c.segT(from, si)); - unsigned int ni = si; - double dsq; - double mindistsq = distanceSq(p, c[si](nearest)); - Rect bb(Geom::Point(0,0),Geom::Point(0,0)); - for ( unsigned int i = si + 1; i < ei; ++i ) - { - bb = *bounds_fast(c[i]); - dsq = distanceSq(p, bb); - if ( mindistsq <= dsq ) continue; - t = nearest_point(p, c[i]); - dsq = distanceSq(p, c[i](t)); - if ( mindistsq > dsq ) - { - nearest = t; - ni = i; - mindistsq = dsq; - } - } - bb = *bounds_fast(c[ei]); - dsq = distanceSq(p, bb); - if ( mindistsq > dsq ) - { - t = nearest_point(p, c[ei], 0, c.segT(to, ei)); - dsq = distanceSq(p, c[ei](t)); - if ( mindistsq > dsq ) - { - nearest = t; - ni = ei; - } - } - return c.mapToDomain(nearest, ni); -} - -std::vector -all_nearest_points( Point const& p, - Piecewise< D2 > const& c, - double from, double to ) -{ - if ( from > to ) std::swap(from, to); - if ( from < c.cuts[0] || to > c.cuts[c.size()] ) - { - THROW_RANGEERROR("[from,to] interval out of bounds"); - } - - unsigned int si = c.segN(from); - unsigned int ei = c.segN(to); - if ( si == ei ) - { - std::vector all_nearest = - all_nearest_points(p, c[si], c.segT(from, si), c.segT(to, si)); - for ( unsigned int i = 0; i < all_nearest.size(); ++i ) - { - all_nearest[i] = c.mapToDomain(all_nearest[i], si); - } - return all_nearest; - } - std::vector all_t; - std::vector< std::vector > all_np; - all_np.push_back( all_nearest_points(p, c[si], c.segT(from, si)) ); - std::vector ni; - ni.push_back(si); - double dsq; - double mindistsq = distanceSq( p, c[si](all_np.front().front()) ); - Rect bb(Geom::Point(0,0),Geom::Point(0,0)); - for ( unsigned int i = si + 1; i < ei; ++i ) - { - bb = *bounds_fast(c[i]); - dsq = distanceSq(p, bb); - if ( mindistsq < dsq ) continue; - all_t = all_nearest_points(p, c[i]); - dsq = distanceSq( p, c[i](all_t.front()) ); - if ( mindistsq > dsq ) - { - all_np.clear(); - all_np.push_back(all_t); - ni.clear(); - ni.push_back(i); - mindistsq = dsq; - } - else if ( mindistsq == dsq ) - { - all_np.push_back(all_t); - ni.push_back(i); - } - } - bb = *bounds_fast(c[ei]); - dsq = distanceSq(p, bb); - if ( mindistsq >= dsq ) - { - all_t = all_nearest_points(p, c[ei], 0, c.segT(to, ei)); - dsq = distanceSq( p, c[ei](all_t.front()) ); - if ( mindistsq > dsq ) - { - for ( unsigned int i = 0; i < all_t.size(); ++i ) - { - all_t[i] = c.mapToDomain(all_t[i], ei); - } - return all_t; - } - else if ( mindistsq == dsq ) - { - all_np.push_back(all_t); - ni.push_back(ei); - } - } - std::vector all_nearest; - for ( unsigned int i = 0; i < all_np.size(); ++i ) - { - for ( unsigned int j = 0; j < all_np[i].size(); ++j ) - { - all_nearest.push_back( c.mapToDomain(all_np[i][j], ni[i]) ); - } - } - all_nearest.erase(std::unique(all_nearest.begin(), all_nearest.end()), - all_nearest.end()); - return all_nearest; -} - -} // end namespace Geom - - diff --git a/src/2geom/nearest-point.h b/src/2geom/nearest-point.h deleted file mode 100644 index 19485242c..000000000 --- a/src/2geom/nearest-point.h +++ /dev/null @@ -1,133 +0,0 @@ -/** - * \file - * \brief nearest point routines for D2 and Piecewise> - * - * Authors: - * - * Marco Cecchetti - * - * Copyright 2007-2008 authors - * - * This library is free software; you can redistribute it and/or - * modify it either under the terms of the GNU Lesser General Public - * License version 2.1 as published by the Free Software Foundation - * (the "LGPL") or, at your option, under the terms of the Mozilla - * Public License Version 1.1 (the "MPL"). If you do not alter this - * notice, a recipient may use your version of this file under either - * the MPL or the LGPL. - * - * You should have received a copy of the LGPL along with this library - * in the file COPYING-LGPL-2.1; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * You should have received a copy of the MPL along with this library - * in the file COPYING-MPL-1.1 - * - * The contents of this file are subject to the Mozilla Public License - * Version 1.1 (the "License"); you may not use this file except in - * compliance with the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY - * OF ANY KIND, either express or implied. See the LGPL or the MPL for - * the specific language governing rights and limitations. - */ - - -#ifndef _NEAREST_POINT_H_ -#define _NEAREST_POINT_H_ - - -#include - -#include <2geom/d2.h> -#include <2geom/piecewise.h> -#include <2geom/exception.h> - - - -namespace Geom -{ - -/* - * Given a line L specified by a point A and direction vector v, - * return the point on L nearest to p. Note that the returned value - * is with respect to the _normalized_ direction of v! - */ -inline double nearest_point(Point const &p, Point const &A, Point const &v) -{ - Point d(p - A); - return d[0] * v[0] + d[1] * v[1]; -} - -//////////////////////////////////////////////////////////////////////////////// -// D2 versions - -/* - * Return the parameter t of a nearest point on the portion of the curve "c", - * related to the interval [from, to], to the point "p". - * The needed curve derivative "dc" is passed as parameter. - * The function return the first nearest point to "p" that is found. - */ -double nearest_point( Point const& p, - D2 const& c, D2 const& dc, - double from = 0, double to = 1 ); - -inline -double nearest_point( Point const& p, - D2 const& c, - double from = 0, double to = 1 ) -{ - return nearest_point(p, c, Geom::derivative(c), from, to); -} - -/* - * Return the parameters t of all the nearest points on the portion of - * the curve "c", related to the interval [from, to], to the point "p". - * The needed curve derivative "dc" is passed as parameter. - */ -std::vector -all_nearest_points( Point const& p, - D2 const& c, D2 const& dc, - double from = 0, double to = 1 ); - -inline -std::vector -all_nearest_points( Point const& p, - D2 const& c, - double from = 0, double to = 1 ) -{ - return all_nearest_points(p, c, Geom::derivative(c), from, to); -} - - -//////////////////////////////////////////////////////////////////////////////// -// Piecewise< D2 > versions - -double nearest_point( Point const& p, - Piecewise< D2 > const& c, - double from, double to ); - -inline -double nearest_point( Point const& p, Piecewise< D2 > const& c ) -{ - return nearest_point(p, c, c.cuts[0], c.cuts[c.size()]); -} - - -std::vector -all_nearest_points( Point const& p, - Piecewise< D2 > const& c, - double from, double to ); - -inline -std::vector -all_nearest_points( Point const& p, Piecewise< D2 > const& c ) -{ - return all_nearest_points(p, c, c.cuts[0], c.cuts[c.size()]); -} - -} // end namespace Geom - - - -#endif /*_NEAREST_POINT_H_*/ diff --git a/src/2geom/nearest-time.cpp b/src/2geom/nearest-time.cpp new file mode 100644 index 000000000..0b21e51a2 --- /dev/null +++ b/src/2geom/nearest-time.cpp @@ -0,0 +1,322 @@ +/** @file + * @brief Nearest time routines for D2 and Piecewise> + *//* + * Authors: + * Marco Cecchetti + * + * Copyright 2007-2008 authors + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + */ + + +#include <2geom/nearest-time.h> +#include + +namespace Geom +{ + +Coord nearest_time(Point const &p, D2 const &input, Coord from, Coord to) +{ + Interval domain(from, to); + bool partial = false; + + if (domain.min() < 0 || domain.max() > 1) { + THROW_RANGEERROR("[from,to] interval out of bounds"); + } + + if (input.isConstant(0)) return from; + + D2 bez; + if (domain.min() != 0 || domain.max() != 1) { + bez = portion(input, domain) - p; + partial = true; + } else { + bez = input - p; + } + + // find extrema of the function x(t)^2 + y(t)^2 + // use the fact that (f^2)' = 2 f f' + // this reduces the order of the distance function by 1 + D2 deriv = derivative(bez); + std::vector ts = (multiply(bez[X], deriv[X]) + multiply(bez[Y], deriv[Y])).roots(); + + Coord t = -1, mind = infinity(); + for (unsigned i = 0; i < ts.size(); ++i) { + Coord droot = L2sq(bez.valueAt(ts[i])); + if (droot < mind) { + mind = droot; + t = ts[i]; + } + } + + // also check endpoints + Coord dinitial = L2sq(bez.at0()); + Coord dfinal = L2sq(bez.at1()); + + if (dinitial < mind) { + mind = dinitial; + t = 0; + } + if (dfinal < mind) { + mind = dfinal; + t = 1; + } + + if (partial) { + t = domain.valueAt(t); + } + return t; +} + +//////////////////////////////////////////////////////////////////////////////// +// D2 versions + +/* + * Return the parameter t of the nearest time value on the portion of the curve "c", + * related to the interval [from, to], to the point "p". + * The needed curve derivative "dc" is passed as parameter. + * The function return the first nearest time value to "p" that is found. + */ + +double nearest_time(Point const& p, + D2 const& c, + D2 const& dc, + double from, double to ) +{ + if ( from > to ) std::swap(from, to); + if ( from < 0 || to > 1 ) + { + THROW_RANGEERROR("[from,to] interval out of bounds"); + } + if (c.isConstant()) return from; + SBasis dd = dot(c - p, dc); + //std::cout << dd << std::endl; + std::vector zeros = Geom::roots(dd); + + double closest = from; + double min_dist_sq = L2sq(c(from) - p); + for ( size_t i = 0; i < zeros.size(); ++i ) + { + double distsq = L2sq(c(zeros[i]) - p); + if ( min_dist_sq > L2sq(c(zeros[i]) - p) ) + { + closest = zeros[i]; + min_dist_sq = distsq; + } + } + if ( min_dist_sq > L2sq( c(to) - p ) ) + closest = to; + return closest; + +} + +/* + * Return the parameters t of all the nearest points on the portion of + * the curve "c", related to the interval [from, to], to the point "p". + * The needed curve derivative "dc" is passed as parameter. + */ + +std::vector +all_nearest_times(Point const &p, + D2 const &c, + D2 const &dc, + double from, double to) +{ + if (from > to) { + std::swap(from, to); + } + if (from < 0 || to > 1) { + THROW_RANGEERROR("[from,to] interval out of bounds"); + } + + std::vector result; + if (c.isConstant()) { + result.push_back(from); + return result; + } + SBasis dd = dot(c - p, dc); + + std::vector zeros = Geom::roots(dd); + std::vector candidates; + candidates.push_back(from); + candidates.insert(candidates.end(), zeros.begin(), zeros.end()); + candidates.push_back(to); + std::vector distsq; + distsq.reserve(candidates.size()); + for (unsigned i = 0; i < candidates.size(); ++i) { + distsq.push_back(L2sq(c(candidates[i]) - p)); + } + unsigned closest = 0; + double dsq = distsq[0]; + for (unsigned i = 1; i < candidates.size(); ++i) { + if (dsq > distsq[i]) { + closest = i; + dsq = distsq[i]; + } + } + for (unsigned i = 0; i < candidates.size(); ++i) { + if (distsq[closest] == distsq[i]) { + result.push_back(candidates[i]); + } + } + return result; +} + + +//////////////////////////////////////////////////////////////////////////////// +// Piecewise< D2 > versions + + +double nearest_time(Point const &p, + Piecewise< D2 > const &c, + double from, double to) +{ + if (from > to) std::swap(from, to); + if (from < c.cuts[0] || to > c.cuts[c.size()]) { + THROW_RANGEERROR("[from,to] interval out of bounds"); + } + + unsigned si = c.segN(from); + unsigned ei = c.segN(to); + if (si == ei) { + double nearest = + nearest_time(p, c[si], c.segT(from, si), c.segT(to, si)); + return c.mapToDomain(nearest, si); + } + + double t; + double nearest = nearest_time(p, c[si], c.segT(from, si)); + unsigned int ni = si; + double dsq; + double mindistsq = distanceSq(p, c[si](nearest)); + Rect bb; + for (unsigned i = si + 1; i < ei; ++i) { + bb = *bounds_fast(c[i]); + dsq = distanceSq(p, bb); + if ( mindistsq <= dsq ) continue; + + t = nearest_time(p, c[i]); + dsq = distanceSq(p, c[i](t)); + if (mindistsq > dsq) { + nearest = t; + ni = i; + mindistsq = dsq; + } + } + bb = *bounds_fast(c[ei]); + dsq = distanceSq(p, bb); + if (mindistsq > dsq) { + t = nearest_time(p, c[ei], 0, c.segT(to, ei)); + dsq = distanceSq(p, c[ei](t)); + if (mindistsq > dsq) { + nearest = t; + ni = ei; + } + } + return c.mapToDomain(nearest, ni); +} + +std::vector +all_nearest_times(Point const &p, + Piecewise< D2 > const &c, + double from, double to) +{ + if (from > to) { + std::swap(from, to); + } + if (from < c.cuts[0] || to > c.cuts[c.size()]) { + THROW_RANGEERROR("[from,to] interval out of bounds"); + } + + unsigned si = c.segN(from); + unsigned ei = c.segN(to); + if ( si == ei ) + { + std::vector all_nearest = + all_nearest_times(p, c[si], c.segT(from, si), c.segT(to, si)); + for ( unsigned int i = 0; i < all_nearest.size(); ++i ) + { + all_nearest[i] = c.mapToDomain(all_nearest[i], si); + } + return all_nearest; + } + std::vector all_t; + std::vector< std::vector > all_np; + all_np.push_back( all_nearest_times(p, c[si], c.segT(from, si)) ); + std::vector ni; + ni.push_back(si); + double dsq; + double mindistsq = distanceSq( p, c[si](all_np.front().front()) ); + Rect bb; + + for (unsigned i = si + 1; i < ei; ++i) { + bb = *bounds_fast(c[i]); + dsq = distanceSq(p, bb); + if ( mindistsq < dsq ) continue; + all_t = all_nearest_times(p, c[i]); + dsq = distanceSq( p, c[i](all_t.front()) ); + if ( mindistsq > dsq ) + { + all_np.clear(); + all_np.push_back(all_t); + ni.clear(); + ni.push_back(i); + mindistsq = dsq; + } + else if ( mindistsq == dsq ) + { + all_np.push_back(all_t); + ni.push_back(i); + } + } + bb = *bounds_fast(c[ei]); + dsq = distanceSq(p, bb); + if (mindistsq >= dsq) { + all_t = all_nearest_times(p, c[ei], 0, c.segT(to, ei)); + dsq = distanceSq( p, c[ei](all_t.front()) ); + if (mindistsq > dsq) { + for (unsigned int i = 0; i < all_t.size(); ++i) { + all_t[i] = c.mapToDomain(all_t[i], ei); + } + return all_t; + } else if (mindistsq == dsq) { + all_np.push_back(all_t); + ni.push_back(ei); + } + } + std::vector all_nearest; + for (unsigned i = 0; i < all_np.size(); ++i) { + for (unsigned int j = 0; j < all_np[i].size(); ++j) { + all_nearest.push_back( c.mapToDomain(all_np[i][j], ni[i]) ); + } + } + all_nearest.erase(std::unique(all_nearest.begin(), all_nearest.end()), + all_nearest.end()); + return all_nearest; +} + +} // end namespace Geom + + diff --git a/src/2geom/nearest-time.h b/src/2geom/nearest-time.h new file mode 100644 index 000000000..007cd27ba --- /dev/null +++ b/src/2geom/nearest-time.h @@ -0,0 +1,141 @@ +/** @file + * @brief Nearest time routines for D2 and Piecewise> + *//* + * Authors: + * Marco Cecchetti + * + * Copyright 2007-2008 authors + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + */ + + +#ifndef LIB2GEOM_SEEN_NEAREST_TIME_H +#define LIB2GEOM_SEEN_NEAREST_TIME_H + + +#include + +#include <2geom/d2.h> +#include <2geom/piecewise.h> +#include <2geom/exception.h> +#include <2geom/bezier.h> + + +namespace Geom +{ + +/* + * Given a line L specified by a point A and direction vector v, + * return the point on L nearest to p. Note that the returned value + * is with respect to the _normalized_ direction of v! + */ +inline double nearest_time(Point const &p, Point const &A, Point const &v) +{ + Point d(p - A); + return d[0] * v[0] + d[1] * v[1]; +} + +Coord nearest_time(Point const &p, D2 const &bez, Coord from = 0, Coord to = 1); + +//////////////////////////////////////////////////////////////////////////////// +// D2 versions + +/* + * Return the parameter t of a nearest point on the portion of the curve "c", + * related to the interval [from, to], to the point "p". + * The needed curve derivative "deriv" is passed as parameter. + * The function return the first nearest point to "p" that is found. + */ +double nearest_time(Point const &p, + D2 const &c, D2 const &deriv, + double from = 0, double to = 1); + +inline +double nearest_time(Point const &p, + D2 const &c, + double from = 0, double to = 1 ) +{ + return nearest_time(p, c, Geom::derivative(c), from, to); +} + +/* + * Return the parameters t of all the nearest times on the portion of + * the curve "c", related to the interval [from, to], to the point "p". + * The needed curve derivative "dc" is passed as parameter. + */ +std::vector +all_nearest_times(Point const& p, + D2 const& c, D2 const& dc, + double from = 0, double to = 1 ); + +inline +std::vector +all_nearest_times(Point const &p, + D2 const &c, + double from = 0, double to = 1) +{ + return all_nearest_times(p, c, Geom::derivative(c), from, to); +} + + +//////////////////////////////////////////////////////////////////////////////// +// Piecewise< D2 > versions + +double nearest_time(Point const &p, + Piecewise< D2 > const &c, + double from, double to); + +inline +double nearest_time(Point const& p, Piecewise< D2 > const &c) +{ + return nearest_time(p, c, c.cuts[0], c.cuts[c.size()]); +} + + +std::vector +all_nearest_times(Point const &p, + Piecewise< D2 > const &c, + double from, double to); + +inline +std::vector +all_nearest_times( Point const& p, Piecewise< D2 > const& c ) +{ + return all_nearest_times(p, c, c.cuts[0], c.cuts[c.size()]); +} + +} // end namespace Geom + +#endif // LIB2GEOM_SEEN_NEAREST_TIME_H +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 : diff --git a/src/2geom/numeric/fitting-model.h b/src/2geom/numeric/fitting-model.h index a44c1ddac..5cc6dde7a 100644 --- a/src/2geom/numeric/fitting-model.h +++ b/src/2geom/numeric/fitting-model.h @@ -298,7 +298,7 @@ class LFMEllipse public: void instance(Ellipse & e, ConstVectorView const& coeff) const { - e.set(1, coeff[0], coeff[1], coeff[2], coeff[3], coeff[4]); + e.setCoefficients(1, coeff[0], coeff[1], coeff[2], coeff[3], coeff[4]); } }; @@ -333,7 +333,7 @@ class LFMCircle public: void instance(Circle & c, ConstVectorView const& coeff) const { - c.set(1, coeff[0], coeff[1], coeff[2]); + c.setCoefficients(1, coeff[0], coeff[1], coeff[2]); } }; diff --git a/src/2geom/numeric/matrix.h b/src/2geom/numeric/matrix.h index a130bd748..ddca35cd6 100644 --- a/src/2geom/numeric/matrix.h +++ b/src/2geom/numeric/matrix.h @@ -432,16 +432,17 @@ class Matrix: public detail::MatrixImpl inline void swap(Matrix & m1, Matrix & m2) { - assert( m1.rows() == m2.rows() && m1.columns() == m2.columns() ); - std::swap(m1.m_matrix, m2.m_matrix); + assert(m1.rows() == m2.rows() && m1.columns() == m2.columns()); + using std::swap; + swap(m1.m_matrix, m2.m_matrix); } -inline -void swap_any(Matrix & m1, Matrix & m2) +inline void swap_any(Matrix &m1, Matrix &m2) { - std::swap(m1.m_matrix, m2.m_matrix); - std::swap(m1.m_rows, m2.m_rows); - std::swap(m1.m_columns, m2.m_columns); + using std::swap; + swap(m1.m_matrix, m2.m_matrix); + swap(m1.m_rows, m2.m_rows); + swap(m1.m_columns, m2.m_columns); } @@ -569,8 +570,9 @@ class MatrixView : public detail::MatrixImpl inline void swap_view(MatrixView & m1, MatrixView & m2) { - assert( m1.rows() == m2.rows() && m1.columns() == m2.columns() ); - std::swap(m1.m_matrix_view, m2.m_matrix_view); + assert(m1.rows() == m2.rows() && m1.columns() == m2.columns()); + using std::swap; + swap(m1.m_matrix_view, m2.m_matrix_view); } Vector operator*( detail::BaseMatrixImpl const& A, diff --git a/src/2geom/numeric/symmetric-matrix-fs-operation.h b/src/2geom/numeric/symmetric-matrix-fs-operation.h index 37ece56ae..c5aaa724b 100644 --- a/src/2geom/numeric/symmetric-matrix-fs-operation.h +++ b/src/2geom/numeric/symmetric-matrix-fs-operation.h @@ -43,12 +43,7 @@ namespace Geom { namespace NL { template -inline -SymmetricMatrix adj(const ConstBaseSymmetricMatrix & /*S*/) -{ - THROW_NOTIMPLEMENTED(); - return SymmetricMatrix(); -} +SymmetricMatrix adj(const ConstBaseSymmetricMatrix & S); template <> inline diff --git a/src/2geom/numeric/symmetric-matrix-fs-trace.h b/src/2geom/numeric/symmetric-matrix-fs-trace.h index dbabecf6e..eff3dd24d 100644 --- a/src/2geom/numeric/symmetric-matrix-fs-trace.h +++ b/src/2geom/numeric/symmetric-matrix-fs-trace.h @@ -73,13 +73,7 @@ bool abs_less (double x, double y) template struct trace { - static - double evaluate (const ConstBaseSymmetricMatrix & /*S*/) - { - THROW_NOTIMPLEMENTED(); - return K; - } - + static double evaluate(const ConstBaseSymmetricMatrix &S); }; template diff --git a/src/2geom/numeric/symmetric-matrix-fs.h b/src/2geom/numeric/symmetric-matrix-fs.h index c1de27afd..2fadd6915 100644 --- a/src/2geom/numeric/symmetric-matrix-fs.h +++ b/src/2geom/numeric/symmetric-matrix-fs.h @@ -339,7 +339,10 @@ class BaseSymmetricMatrix : public ConstBaseSymmetricMatrix { } - using base_type::operator(); + double operator() (size_t i, size_t j) const + { + return m_data[base_type::get_index(i,j)]; + } double& operator() (size_t i, size_t j) { diff --git a/src/2geom/numeric/vector.h b/src/2geom/numeric/vector.h index 6ab898f29..f28289f0f 100644 --- a/src/2geom/numeric/vector.h +++ b/src/2geom/numeric/vector.h @@ -348,15 +348,17 @@ class Vector : public detail::VectorImpl inline void swap(Vector & v1, Vector & v2) { - assert( v1.size() == v2.size() ); - std::swap(v1.m_vector, v2.m_vector); + assert(v1.size() == v2.size()); + using std::swap; + swap(v1.m_vector, v2.m_vector); } inline void swap_any(Vector & v1, Vector & v2) { - std::swap(v1.m_vector, v2.m_vector); - std::swap(v1.m_size, v2.m_size); + using std::swap; + swap(v1.m_vector, v2.m_vector); + swap(v1.m_size, v2.m_size); } @@ -552,7 +554,8 @@ inline void swap_view(VectorView & v1, VectorView & v2) { assert( v1.size() == v2.size() ); - std::swap(v1.m_vector_view, v2.m_vector_view); // not swap m_vector too + using std::swap; + swap(v1.m_vector_view, v2.m_vector_view); // not swap m_vector too } inline diff --git a/src/2geom/ord.h b/src/2geom/ord.h index 0add83da4..e190a4a1e 100644 --- a/src/2geom/ord.h +++ b/src/2geom/ord.h @@ -1,6 +1,5 @@ -/** - * \file - * \brief Comparator template +/** @file + * @brief Comparator template *//* * Authors: * ? @@ -32,8 +31,8 @@ * */ -#ifndef __2GEOM_ORD__ -#define __2GEOM_ORD__ +#ifndef LIB2GEOM_SEEN_ORD_H +#define LIB2GEOM_SEEN_ORD_H namespace { diff --git a/src/2geom/path-intersection.cpp b/src/2geom/path-intersection.cpp index 63a29423d..07e38ba9e 100644 --- a/src/2geom/path-intersection.cpp +++ b/src/2geom/path-intersection.cpp @@ -12,98 +12,9 @@ namespace Geom { -/** - * This function computes the winding of the path, given a reference point. - * Positive values correspond to counter-clockwise in the mathematical coordinate system, - * and clockwise in screen coordinates. This particular implementation casts a ray in - * the positive x direction. It iterates the path, checking for intersection with the - * bounding boxes. If an intersection is found, the initial/final Y value of the curve is - * used to derive a delta on the winding value. If the point is within the bounding box, - * the curve specific winding function is called. - */ -int winding(Path const &path, Point p) { - //start on a segment which is not a horizontal line with y = p[y] - Path::const_iterator start; - for(Path::const_iterator iter = path.begin(); ; ++iter) { - if(iter == path.end_closed()) { return 0; } - if(iter->initialPoint()[Y]!=p[Y]) { start = iter; break; } - if(iter->finalPoint()[Y]!=p[Y]) { start = iter; break; } - if(iter->boundsFast().height()!=0.){ start = iter; break; } - } - int wind = 0; - unsigned cnt = 0; - bool starting = true; - for (Path::const_iterator iter = start; iter != start || starting - ; ++iter, iter = (iter == path.end_closed()) ? path.begin() : iter ) - { - cnt++; - if(cnt > path.size()) return wind; //some bug makes this required - starting = false; - Rect bounds = (iter->boundsFast()); - Coord x = p[X], y = p[Y]; - - if(x > bounds.right() || !bounds[Y].contains(y)) continue; //ray doesn't intersect box - - Point final = iter->finalPoint(); - Point initial = iter->initialPoint(); - Cmp final_to_ray = cmp(final[Y], y); - Cmp initial_to_ray = cmp(initial[Y], y); - - // if y is included, these will have opposite values, giving order. - Cmp c = cmp(final_to_ray, initial_to_ray); - if(x < bounds.left()) { - // ray goes through bbox - // winding delta determined by position of endpoints - if(final_to_ray != EQUAL_TO) { - wind += int(c); // GT = counter-clockwise = 1; LT = clockwise = -1; EQ = not-included = 0 - //std::cout << int(c) << " "; - goto cont; - } - } else { - //inside bbox, use custom per-curve winding thingie - int delt = iter->winding(p); - wind += delt; - //std::cout << "n" << delt << " "; - } - //Handling the special case of an endpoint on the ray: - if(final[Y] == y) { - //Traverse segments until it breaks away from y - //99.9% of the time this will happen the first go - Path::const_iterator next = iter; - ++next; - for(; ; ++next) { - if(next == path.end_closed()) next = path.begin(); - Rect bnds = (next->boundsFast()); - //TODO: X considerations - if(bnds.height() > 0) { - //It has diverged - if(bnds.contains(p)) { - const double fudge = 0.01; - if(cmp(y, next->valueAt(fudge, Y)) == initial_to_ray) { - wind += int(c); - //std::cout << "!!!!!" << int(c) << " "; - } - iter = next; // No increment, as the rest of the thing hasn't been counted. - } else { - Coord ny = next->initialPoint()[Y]; - if(cmp(y, ny) == initial_to_ray) { - //Is a continuation through the ray, so counts windingwise - wind += int(c); - //std::cout << "!!!!!" << int(c) << " "; - } - iter = ++next; - } - goto cont; - } - if(next==start) return wind; - } - //Looks like it looped, which means everything's flat - return 0; - } - - cont:(void)0; - } - return wind; +/// Compute winding number of the path at the specified point +int winding(Path const &path, Point const &p) { + return path.winding(p); } /** @@ -162,7 +73,7 @@ void append(T &a, T const &b) { * indicates if the time values are within their proper range on the line segments. */ bool -linear_intersect(Point A0, Point A1, Point B0, Point B1, +linear_intersect(Point const &A0, Point const &A1, Point const &B0, Point const &B1, double &tA, double &tB, double &det) { bool both_lines_non_zero = (!are_near(A0, A1)) && (!are_near(B0, B1)); @@ -521,7 +432,7 @@ std::vector path_mono_splits(Path const &p) { * Applies path_mono_splits to multiple paths, and returns the results such that * time-set i corresponds to Path i. */ -std::vector > paths_mono_splits(std::vector const &ps) { +std::vector > paths_mono_splits(PathVector const &ps) { std::vector > ret; for(unsigned i = 0; i < ps.size(); i++) ret.push_back(path_mono_splits(ps[i])); @@ -533,7 +444,7 @@ std::vector > paths_mono_splits(std::vector const &ps) * Each entry i corresponds to path i of the input. The number of rects in each entry is guaranteed to be the * number of splits for that path, subtracted by one. */ -std::vector > split_bounds(std::vector const &p, std::vector > splits) { +std::vector > split_bounds(PathVector const &p, std::vector > splits) { std::vector > ret; for(unsigned i = 0; i < p.size(); i++) { std::vector res; @@ -553,7 +464,7 @@ std::vector > split_bounds(std::vector const &p, std::ve * This function does two sweeps, one on the bounds of each path, and after that cull, one on the curves within. * This leads to a certain amount of code complexity, however, most of that is factored into the above functions */ -CrossingSet MonoCrosser::crossings(std::vector const &a, std::vector const &b) { +CrossingSet MonoCrosser::crossings(PathVector const &a, PathVector const &b) { if(b.empty()) return CrossingSet(a.size(), Crossings()); CrossingSet results(a.size() + b.size(), Crossings()); if(a.empty()) return results; @@ -596,7 +507,7 @@ CrossingSet MonoCrosser::crossings(std::vector const &a, std::vector /* This function is similar codewise to the MonoCrosser, the main difference is that it deals with * only one set of paths and includes self intersection -CrossingSet crossings_among(std::vector const &p) { +CrossingSet crossings_among(PathVector const &p) { CrossingSet results(p.size(), Crossings()); if(p.empty()) return results; @@ -780,7 +691,7 @@ void flip_crossings(Crossings &crs) { crs[i] = Crossing(crs[i].tb, crs[i].ta, crs[i].b, crs[i].a, !crs[i].dir); } -CrossingSet crossings_among(std::vector const &p) { +CrossingSet crossings_among(PathVector const &p) { CrossingSet results(p.size(), Crossings()); if(p.empty()) return results; diff --git a/src/2geom/path-intersection.h b/src/2geom/path-intersection.h index 512c31167..e3a8d1de3 100644 --- a/src/2geom/path-intersection.h +++ b/src/2geom/path-intersection.h @@ -32,8 +32,8 @@ * */ -#ifndef __GEOM_PATH_INTERSECTION_H -#define __GEOM_PATH_INTERSECTION_H +#ifndef LIB2GEOM_SEEN_PATH_INTERSECTION_H +#define LIB2GEOM_SEEN_PATH_INTERSECTION_H #include <2geom/path.h> @@ -43,10 +43,10 @@ namespace Geom { -int winding(Path const &path, Point p); +int winding(Path const &path, Point const &p); bool path_direction(Path const &p); -inline bool contains(Path const & p, Point i, bool evenodd = true) { +inline bool contains(Path const & p, Point const &i, bool evenodd = true) { return (evenodd ? winding(p, i) % 2 : winding(p, i)) != 0; } @@ -74,19 +74,19 @@ Crossings mono_intersect(Curve const & A, Interval const &Ad, struct SimpleCrosser : public Crosser { Crossings crossings(Curve const &a, Curve const &b); Crossings crossings(Path const &a, Path const &b) { return curve_sweep(a, b); } - CrossingSet crossings(std::vector const &a, std::vector const &b) { return Crosser::crossings(a, b); } + CrossingSet crossings(PathVector const &a, PathVector const &b) { return Crosser::crossings(a, b); } }; struct MonoCrosser : public Crosser { - Crossings crossings(Path const &a, Path const &b) { return crossings(std::vector(1,a), std::vector(1,b))[0]; } - CrossingSet crossings(std::vector const &a, std::vector const &b); + Crossings crossings(Path const &a, Path const &b) { return crossings(PathVector(a), PathVector(b))[0]; } + CrossingSet crossings(PathVector const &a, PathVector const &b); }; typedef SimpleCrosser DefaultCrosser; std::vector path_mono_splits(Path const &p); -CrossingSet crossings_among(std::vector const & p); +CrossingSet crossings_among(PathVector const & p); Crossings self_crossings(Path const & a); inline Crossings crossings(Curve const & a, Curve const & b) { @@ -99,7 +99,7 @@ inline Crossings crossings(Path const & a, Path const & b) { return c.crossings(a, b); } -inline CrossingSet crossings(std::vector const & a, std::vector const & b) { +inline CrossingSet crossings(PathVector const & a, PathVector const & b) { DefaultCrosser c = DefaultCrosser(); return c.crossings(a, b); } diff --git a/src/2geom/path-sink.cpp b/src/2geom/path-sink.cpp index 6acd9508c..6ccc21e7b 100644 --- a/src/2geom/path-sink.cpp +++ b/src/2geom/path-sink.cpp @@ -34,77 +34,40 @@ namespace Geom { -void output(Curve const &curve, PathSink &sink) { - std::vector pts; - sbasis_to_bezier(pts, curve.toSBasis(), 2); //TODO: use something better! - sink.curveTo(pts[0], pts[1], pts[2]); +void PathSink::feed(Curve const &c, bool moveto_initial) +{ + c.feed(*this, moveto_initial); } -void output(HLineSegment const &curve, PathSink &sink) { - sink.hlineTo(curve.finalPoint()[X]); -} - -void output(VLineSegment const &curve, PathSink &sink) { - sink.vlineTo(curve.finalPoint()[Y]); -} - -void output(LineSegment const &curve, PathSink &sink) { - sink.lineTo(curve[1]); -} - -void output(CubicBezier const &curve, PathSink &sink) { - sink.curveTo(curve[1], curve[2], curve[3]); -} - -void output(QuadraticBezier const &curve, PathSink &sink) { - sink.quadTo(curve[1], curve[2]); -} - -void output(SVGEllipticalArc const &curve, PathSink &sink) { - sink.arcTo( curve.ray(X), curve.ray(Y), curve.rotationAngle(), - curve.largeArc(), curve.sweep(), - curve.finalPoint() ); -} - -template -bool output_as(Curve const &curve, PathSink &sink) { - T const *t = dynamic_cast(&curve); - if (t) { - output(*t, sink); - return true; - } else { - return false; - } -} - -void PathSink::path(Path const &path) { +void PathSink::feed(Path const &path) { flush(); moveTo(path.front().initialPoint()); - Path::const_iterator iter; - for (iter = path.begin(); iter != path.end(); ++iter) { - output_as(*iter, *this) || - output_as(*iter, *this) || - output_as(*iter, *this) || - output_as(*iter, *this) || - output_as(*iter, *this) || - output_as(*iter, *this) || - output_as(*iter, *this); + // never output the closing segment to the sink + Path::const_iterator iter = path.begin(), last = path.end_open(); + for (; iter != last; ++iter) { + iter->feed(*this, false); } - if (path.closed()) { closePath(); } flush(); } -void PathSink::pathvector(PathVector const &pv) { - flush(); +void PathSink::feed(PathVector const &pv) { for (PathVector::const_iterator i = pv.begin(); i != pv.end(); ++i) { - path(*i); + feed(*i); } } +void PathSink::feed(Rect const &r) { + moveTo(r.corner(0)); + lineTo(r.corner(1)); + lineTo(r.corner(2)); + lineTo(r.corner(3)); + closePath(); +} + } /* diff --git a/src/2geom/path-sink.h b/src/2geom/path-sink.h index 949369b80..5913593d2 100644 --- a/src/2geom/path-sink.h +++ b/src/2geom/path-sink.h @@ -29,8 +29,8 @@ * */ -#ifndef SEEN_SVG_PATH_H -#define SEEN_SVG_PATH_H +#ifndef LIB2GEOM_SEEN_PATH_SINK_H +#define LIB2GEOM_SEEN_PATH_SINK_H #include <2geom/pathvector.h> #include <2geom/curves.h> @@ -44,58 +44,69 @@ namespace Geom { * PathSink provides an interface that allows one to easily write * code which processes path data, for instance when converting * between path formats used by different graphics libraries. + * It is also useful for writing algorithms which must do something + * for each curve in the path. * * To store a path in a new format, implement the virtual methods - * for segments in a derived class and call path() or pathvector(). + * for segments in a derived class and call feed(). + * + * @ingroup Paths */ class PathSink { public: - /** Move to a different point without creating a segment. + /** @brief Move to a different point without creating a segment. * Usually starts a new subpath. */ virtual void moveTo(Point const &p) = 0; - /// Output a horizontal line segment. Only the X coordinate of the final point is given. - virtual void hlineTo(Coord v) = 0; - /// Output a vertical line segment. Only the Y coordinate of the final point is given. - virtual void vlineTo(Coord v) = 0; /// Output a line segment. virtual void lineTo(Point const &p) = 0; /// Output a quadratic Bezier segment. virtual void curveTo(Point const &c0, Point const &c1, Point const &p) = 0; /// Output a cubic Bezier segment. virtual void quadTo(Point const &c, Point const &p) = 0; - /** Output an elliptical arc segment. + /** @brief Output an elliptical arc segment. * See the EllipticalArc class for the documentation of parameters. */ - virtual void arcTo(double rx, double ry, double angle, + virtual void arcTo(Coord rx, Coord ry, Coord angle, bool large_arc, bool sweep, Point const &p) = 0; /// Close the current path with a line segment. virtual void closePath() = 0; - /** Flush any internal state of the generator. - * + /** @brief Flush any internal state of the generator. * This call should implicitly finish the current subpath. * Calling this method should be idempotent, because the default - * implementations of path() and pathvector() will be call it + * implementations of path() and pathvector() will call it * multiple times in a row. */ virtual void flush() = 0; + // Get the current point, e.g. where the initial point of the next segment will be. + //virtual Point currentPoint() const = 0; - /** Undo the last segment. + /** @brief Undo the last segment. * This method is optional. * @return true true if a segment was erased, false otherwise. */ virtual bool backspace() { return false; } // these have a default implementation - /** Output a subpath. - * Calls the appropriate segment methods according to the contents - * of the passed subpath. You can override this function. */ - virtual void path(Path const &p); - /** Output a path. + virtual void feed(Curve const &c, bool moveto_initial = true); + /** @brief Output a subpath. * Calls the appropriate segment methods according to the contents - * of the passed path. You can override this function. */ - virtual void pathvector(PathVector const &v); + * of the passed subpath. You can override this function. + * NOTE: if you override only some of the feed() functions, + * always write this in the derived class: + * @code + using PathSink::feed; + @endcode + * Otherwise the remaining methods will be hidden. */ + virtual void feed(Path const &p); + /** @brief Output a path. + * Calls feed() on each path in the vector. You can override this function. */ + virtual void feed(PathVector const &v); + /// Output an axis-aligned rectangle, using moveTo, lineTo and closePath. + virtual void feed(Rect const &); virtual ~PathSink() {} }; +/** @brief Store paths to an output iterator + * @ingroup Paths */ template class PathIteratorSink : public PathSink { public: @@ -110,22 +121,6 @@ public: } //TODO: what if _in_path = false? - void hlineTo(Coord v) { - // check for implicit moveto, like in: "M 1,1 L 2,2 z l 2,2 z" - if (!_in_path) { - moveTo(_start_p); - } - _path.template appendNew(Point(v, _path.finalPoint()[Y])); - } - - void vlineTo(Coord v) { - // check for implicit moveto, like in: "M 1,1 L 2,2 z l 2,2 z" - if (!_in_path) { - moveTo(_start_p); - } - _path.template appendNew(Point(_path.finalPoint()[X], v)); - } - void lineTo(Point const &p) { // check for implicit moveto, like in: "M 1,1 L 2,2 z l 2,2 z" if (!_in_path) { @@ -150,7 +145,7 @@ public: _path.template appendNew(c0, c1, p); } - void arcTo(double rx, double ry, double angle, + void arcTo(Coord rx, Coord ry, Coord angle, bool large_arc, bool sweep, Point const &p) { // check for implicit moveto, like in: "M 1,1 L 2,2 z l 2,2 z" @@ -170,12 +165,12 @@ public: return false; } - void append(Path const &other, Path::Stitching stitching = Path::NO_STITCHING) + void append(Path const &other) { if (!_in_path) { moveTo(other.initialPoint()); } - _path.append(other, stitching); + _path.append(other); } void closePath() { @@ -188,11 +183,15 @@ public: _in_path = false; *_out++ = _path; _path.clear(); - _path.close(false); } } + + void setStitching(bool s) { + _path.setStitching(s); + } - void path(Path const &other) + using PathSink::feed; + void feed(Path const &other) { flush(); *_out++ = other; @@ -205,14 +204,19 @@ protected: Point _start_p; }; -typedef std::back_insert_iterator > iter; +typedef std::back_insert_iterator SubpathInserter; -class PathBuilder : public PathIteratorSink { +/** @brief Store paths to a PathVector + * @ingroup Paths */ +class PathBuilder : public PathIteratorSink { private: - std::vector _pathset; + PathVector _pathset; public: - PathBuilder() : PathIteratorSink(iter(_pathset)) {} - std::vector const &peek() const {return _pathset;} + PathBuilder() : PathIteratorSink(SubpathInserter(_pathset)) {} + /// Retrieve the path + PathVector const &peek() const {return _pathset;} + /// Clear the stored path vector + void clear() { _pathset.clear(); } }; } diff --git a/src/2geom/path.cpp b/src/2geom/path.cpp index 3558af3b3..cf8b15d60 100644 --- a/src/2geom/path.cpp +++ b/src/2geom/path.cpp @@ -1,11 +1,12 @@ -/* - * Path - Series of continuous curves - * +/** @file + * @brief Path - a sequence of contiguous curves (implementation file) + *//* * Authors: - * MenTaLguY - * Marco Cecchetti + * MenTaLguY + * Marco Cecchetti + * Krzysztof Kosiński * - * Copyright 2007-2008 authors + * Copyright 2007-2014 authors * * This library is free software; you can redistribute it and/or * modify it either under the terms of the GNU Lesser General Public @@ -31,414 +32,861 @@ * the specific language governing rights and limitations. */ - - - #include <2geom/path.h> +#include <2geom/pathvector.h> #include <2geom/transforms.h> +#include <2geom/convex-hull.h> #include +#include using std::swap; using namespace Geom::PathInternal; -namespace Geom +namespace Geom { + +// this represents an empty interval +PathInterval::PathInterval() + : _from(0, 0.0) + , _to(0, 0.0) + , _path_size(1) + , _cross_start(false) + , _reverse(false) +{} + +PathInterval::PathInterval(Position const &from, Position const &to, bool cross_start, size_type path_size) + : _from(from) + , _to(to) + , _path_size(path_size) + , _cross_start(cross_start) + , _reverse(cross_start ? to >= from : to < from) +{ + if (_reverse) { + _to.normalizeForward(_path_size); + if (_from != _to) { + _from.normalizeBackward(_path_size); + } + } else { + _from.normalizeForward(_path_size); + if (_from != _to) { + _to.normalizeBackward(_path_size); + } + } + + if (_from == _to) { + _reverse = false; + _cross_start = false; + } +} + +bool PathInterval::contains(Position const &pos) const { + if (_cross_start) { + if (_reverse) { + return pos >= _to || _from >= pos; + } else { + return pos >= _from || _to >= pos; + } + } else { + if (_reverse) { + return _to <= pos && pos <= _from; + } else { + return _from <= pos && pos <= _to; + } + } +} + +PathPosition PathInterval::inside(Coord min_dist) const +{ + // If there is some node further than min_dist (in time coord) from the ends, + // return that node. Otherwise, return the middle. + PathPosition result(0, 0.0); + + if (!_cross_start && _from.curve_index == _to.curve_index) { + PathPosition result(_from.curve_index, lerp(0.5, _from.t, _to.t)); + return result; + } + // If _cross_start, then we can be sure that at least one node is in the domain. + // If dcurve == 0, it actually means that all curves are included in the domain + + if (_reverse) { + size_type dcurve = (_path_size + _from.curve_index - _to.curve_index) % _path_size; + bool from_close = _from.t < min_dist; + bool to_close = _to.t > 1 - min_dist; + + if (dcurve == 0) { + dcurve = _path_size; + } + + if (dcurve == 1) { + if (from_close || to_close) { + result.curve_index = _from.curve_index; + Coord tmid = _from.t - ((1 - _to.t) + _from.t) * 0.5; + if (tmid < 0) { + result.curve_index = (_path_size + result.curve_index - 1) % _path_size; + tmid += 1; + } + result.t = tmid; + return result; + } + + result.curve_index = _from.curve_index; + return result; + } + + result.curve_index = (_to.curve_index + 1) % _path_size; + if (to_close) { + if (dcurve == 2) { + result.t = 0.5; + } else { + result.curve_index = (result.curve_index + 1) % _path_size; + } + } + return result; + } else { + size_type dcurve = (_path_size + _to.curve_index - _from.curve_index) % _path_size; + bool from_close = _from.t > 1 - min_dist; + bool to_close = _to.t < min_dist; + + if (dcurve == 0) { + dcurve = _path_size; + } + + if (dcurve == 1) { + if (from_close || to_close) { + result.curve_index = _from.curve_index; + Coord tmid = ((1 - _from.t) + _to.t) * 0.5 + _from.t; + if (tmid >= 1) { + result.curve_index = (result.curve_index + 1) % _path_size; + tmid -= 1; + } + result.t = tmid; + return result; + } + + result.curve_index = _to.curve_index; + return result; + } + + result.curve_index = (_from.curve_index + 1) % _path_size; + if (from_close) { + if (dcurve == 2) { + result.t = 0.5; + } else { + result.curve_index = (result.curve_index + 1) % _path_size; + } + } + return result; + } + + result.curve_index = _reverse ? _from.curve_index : _to.curve_index; + return result; +} + +PathInterval PathInterval::from_direction(Position const &from, Position const &to, bool reversed, size_type path_size) +{ + PathInterval result; + result._from = from; + result._to = to; + result._path_size = path_size; + + if (reversed) { + result._to.normalizeForward(path_size); + if (result._from != result._to) { + result._from.normalizeBackward(path_size); + } + } else { + result._from.normalizeForward(path_size); + if (result._from != result._to) { + result._to.normalizeBackward(path_size); + } + } + + if (result._from == result._to) { + result._reverse = false; + result._cross_start = false; + } else { + result._reverse = reversed; + if (reversed) { + result._cross_start = from < to; + } else { + result._cross_start = to < from; + } + } + return result; +} + + +Path::Path(ConvexHull const &ch) + : _curves(new Sequence()) + , _closing_seg(new ClosingSegment(Point(), Point())) + , _closed(false) + , _exception_on_stitch(true) +{ + if (ch.empty()) { + _curves->push_back(_closing_seg); + return; + } + + _closing_seg->setInitial(ch.back()); + _closing_seg->setFinal(ch.front()); + + Point last = ch.front(); + + for (std::size_t i = 1; i < ch.size(); ++i) { + _curves->push_back(new LineSegment(last, ch[i])); + last = ch[i]; + } + + _curves->push_back(_closing_seg); + _closed = true; +} + +void Path::clear() +{ + _unshare(); + _curves->pop_back().release(); + _curves->clear(); + _closing_seg->setInitial(Point(0, 0)); + _closing_seg->setFinal(Point(0, 0)); + _curves->push_back(_closing_seg); + _closed = false; +} + +OptRect Path::boundsFast() const { + OptRect bounds; + if (empty()) + return bounds; + bounds = front().boundsFast(); + const_iterator iter = begin(); + // the closing path segment can be ignored, because it will always lie within the bbox of the rest of the path + if (iter != end()) { + for (++iter; iter != end(); ++iter) { + bounds.unionWith(iter->boundsFast()); + } + } + return bounds; +} -OptRect Path::boundsFast() const { - OptRect bounds; - if (empty()) return bounds; - bounds = front().boundsFast(); - const_iterator iter = begin(); - // the closing path segment can be ignored, because it will always lie within the bbox of the rest of the path - if ( iter != end() ) { - for ( ++iter; iter != end() ; ++iter ) { - bounds.unionWith(iter->boundsFast()); +OptRect Path::boundsExact() const +{ + OptRect bounds; + if (empty()) + return bounds; + bounds = front().boundsExact(); + const_iterator iter = begin(); + // the closing path segment can be ignored, because it will always lie within the bbox of the rest of the path + if (iter != end()) { + for (++iter; iter != end(); ++iter) { + bounds.unionWith(iter->boundsExact()); + } } - } - return bounds; + return bounds; } -OptRect Path::boundsExact() const { - OptRect bounds; - if (empty()) return bounds; - bounds = front().boundsExact(); - const_iterator iter = begin(); - // the closing path segment can be ignored, because it will always lie within the bbox of the rest of the path - if ( iter != end() ) { - for ( ++iter; iter != end() ; ++iter ) { - bounds.unionWith(iter->boundsExact()); +Piecewise > Path::toPwSb() const +{ + Piecewise > ret; + ret.push_cut(0); + unsigned i = 1; + bool degenerate = true; + // pw> is always open. so if path is closed, add closing segment as well to pwd2. + for (const_iterator it = begin(); it != end_default(); ++it) { + if (!it->isDegenerate()) { + ret.push(it->toSBasis(), i++); + degenerate = false; + } } - } - return bounds; + if (degenerate) { + // if path only contains degenerate curves, no second cut is added + // so we need to create at least one segment manually + ret = Piecewise >(initialPoint()); + } + return ret; } -template +template iter inc(iter const &x, unsigned n) { - iter ret = x; - for(unsigned i = 0; i < n; i++) - ret++; - return ret; -} - -Path &Path::operator*=(Affine const &m) { - unshare(); - Sequence::iterator last = get_curves().end() - 1; - Sequence::iterator it; - Point prev; - for (it = get_curves().begin() ; it != last ; ++it) { - *it = boost::shared_ptr((*it)->transformed(m)); - if ( it != get_curves().begin() && (*it)->initialPoint() != prev ) { - THROW_CONTINUITYERROR(); - } - prev = (*it)->finalPoint(); - } - for ( int i = 0 ; i < 2 ; ++i ) { - final_->setPoint(i, (*final_)[i] * m); - } - if (get_curves().size() > 1) { - if ( front().initialPoint() != initialPoint() || back().finalPoint() != finalPoint() ) { - THROW_CONTINUITYERROR(); - } - } - return *this; -} - -Path &Path::operator*=(Translate const &m) { -/* Somehow there is something wrong here, LPE Construct grid fails with this code - unshare(); - Sequence::iterator last = get_curves().end() - 1; - Sequence::iterator it; - Point prev; - for (it = get_curves().begin() ; it != last ; ++it) { - // *(const_cast(&**it)) *= m; - const_cast(it->get())->operator*=(m); - if ( it != get_curves().begin() && (*it)->initialPoint() != prev ) { - THROW_CONTINUITYERROR(); - } - prev = (*it)->finalPoint(); - } - for ( int i = 0 ; i < 2 ; ++i ) { - final_->setPoint(i, (*final_)[i] + m.vector()); - } - if (get_curves().size() > 1) { - if ( front().initialPoint() != initialPoint() || back().finalPoint() != finalPoint() ) { - THROW_CONTINUITYERROR(); - } - } - return *this; -*/ - return this->operator*=(static_cast(m)); -} - -std::vector -Path::allNearestPoints(Point const& _point, double from, double to) const -{ - using std::swap; - - if ( from > to ) swap(from, to); - const Path& _path = *this; - unsigned int sz = _path.size(); - if ( _path.closed() ) ++sz; - if ( from < 0 || to > sz ) - { - THROW_RANGEERROR("[from,to] interval out of bounds"); - } - double sif, st = modf(from, &sif); - double eif, et = modf(to, &eif); - unsigned int si = static_cast(sif); - unsigned int ei = static_cast(eif); - if ( si == sz ) - { - --si; - st = 1; - } - if ( ei == sz ) - { - --ei; - et = 1; - } - if ( si == ei ) - { - std::vector all_nearest = - _path[si].allNearestPoints(_point, st, et); - for ( unsigned int i = 0; i < all_nearest.size(); ++i ) - { - all_nearest[i] = si + all_nearest[i]; - } - return all_nearest; - } - std::vector all_t; - std::vector< std::vector > all_np; - all_np.push_back( _path[si].allNearestPoints(_point, st) ); - std::vector ni; - ni.push_back(si); - double dsq; - double mindistsq - = distanceSq( _point, _path[si].pointAt( all_np.front().front() ) ); - Rect bb(Geom::Point(0,0),Geom::Point(0,0)); - for ( unsigned int i = si + 1; i < ei; ++i ) - { - bb = (_path[i].boundsFast()); - dsq = distanceSq(_point, bb); - if ( mindistsq < dsq ) continue; - all_t = _path[i].allNearestPoints(_point); - dsq = distanceSq( _point, _path[i].pointAt( all_t.front() ) ); - if ( mindistsq > dsq ) - { - all_np.clear(); - all_np.push_back(all_t); - ni.clear(); - ni.push_back(i); - mindistsq = dsq; - } - else if ( mindistsq == dsq ) - { - all_np.push_back(all_t); - ni.push_back(i); - } - } - bb = (_path[ei].boundsFast()); - dsq = distanceSq(_point, bb); - if ( mindistsq >= dsq ) - { - all_t = _path[ei].allNearestPoints(_point, 0, et); - dsq = distanceSq( _point, _path[ei].pointAt( all_t.front() ) ); - if ( mindistsq > dsq ) - { - for ( unsigned int i = 0; i < all_t.size(); ++i ) - { - all_t[i] = ei + all_t[i]; - } - return all_t; - } - else if ( mindistsq == dsq ) - { - all_np.push_back(all_t); - ni.push_back(ei); - } - } - std::vector all_nearest; - for ( unsigned int i = 0; i < all_np.size(); ++i ) - { - for ( unsigned int j = 0; j < all_np[i].size(); ++j ) - { - all_nearest.push_back( ni[i] + all_np[i][j] ); - } - } - all_nearest.erase(std::unique(all_nearest.begin(), all_nearest.end()), - all_nearest.end()); - return all_nearest; -} - -std::vector -Path::nearestPointPerCurve(Point const& _point) const -{ - //return a single nearest point for each curve in this path - std::vector np; - for (const_iterator it = begin() ; it != end_default() ; ++it) - //for (std::vector::const_iterator it = _path.begin(); it != _path.end(), ++it){ - { - np.push_back(it->nearestPoint(_point)); - } - return np; -} - -double Path::nearestPoint(Point const &_point, double from, double to, double *distance_squared) const -{ - using std::swap; - - if ( from > to ) swap(from, to); - const Path& _path = *this; - unsigned int sz = _path.size(); - if ( _path.closed() ) ++sz; - if ( from < 0 || to > sz ) - { - THROW_RANGEERROR("[from,to] interval out of bounds"); - } - double sif, st = modf(from, &sif); - double eif, et = modf(to, &eif); - unsigned int si = static_cast(sif); - unsigned int ei = static_cast(eif); - if(sz == 0) {// naked moveto - if (distance_squared != NULL) - *distance_squared = distanceSq(_point, _path.initialPoint()); - return 0; - } - if ( si == sz ) - { - --si; - st = 1; - } - if ( ei == sz ) - { - --ei; - et = 1; - } - if ( si == ei ) - { - double nearest = _path[si].nearestPoint(_point, st, et); - if (distance_squared != NULL) - *distance_squared = distanceSq(_point, _path[si].pointAt(nearest)); - return si + nearest; - } - - double t; - double nearest = _path[si].nearestPoint(_point, st); - unsigned int ni = si; - double dsq; - double mindistsq = distanceSq(_point, _path[si].pointAt(nearest)); - for ( unsigned int i = si + 1; i < ei; ++i ) - { - Rect bb = (_path[i].boundsFast()); - dsq = distanceSq(_point, bb); - if ( mindistsq <= dsq ) continue; - t = _path[i].nearestPoint(_point); - dsq = distanceSq(_point, _path[i].pointAt(t)); - if ( mindistsq > dsq ) - { - nearest = t; - ni = i; - mindistsq = dsq; - } - } - Rect bb = (_path[ei].boundsFast()); - dsq = distanceSq(_point, bb); - if ( mindistsq > dsq ) - { - t = _path[ei].nearestPoint(_point, 0, et); - dsq = distanceSq(_point, _path[ei].pointAt(t)); - if ( mindistsq > dsq ) - { - nearest = t; - ni = ei; - mindistsq = dsq; - } - } - - if (distance_squared != NULL) - *distance_squared = mindistsq; - - return ni + nearest; -} - -void Path::appendPortionTo(Path &ret, double from, double to) const { - if (!(from >= 0 && to >= 0)) { - THROW_RANGEERROR("from and to must be >=0 in Path::appendPortionTo"); - } - if(to == 0) to = size()+0.999999; - if(from == to) { return; } - double fi, ti; - double ff = modf(from, &fi), tf = modf(to, &ti); - if(tf == 0) { ti--; tf = 1; } - const_iterator fromi = inc(begin(), (unsigned)fi); - if(fi == ti && from < to) { - Curve *v = fromi->portion(ff, tf); - ret.append(*v, STITCH_DISCONTINUOUS); - delete v; - return; - } - const_iterator toi = inc(begin(), (unsigned)ti); - if(ff != 1.) { - Curve *fromv = fromi->portion(ff, 1.); - //fromv->setInitial(ret.finalPoint()); - ret.append(*fromv, STITCH_DISCONTINUOUS); - delete fromv; - } - if(from >= to) { - const_iterator ender = end(); - if(ender->initialPoint() == ender->finalPoint()) ++ender; - ret.insert(ret.end(), ++fromi, ender, STITCH_DISCONTINUOUS); - ret.insert(ret.end(), begin(), toi, STITCH_DISCONTINUOUS); - } else { - ret.insert(ret.end(), ++fromi, toi, STITCH_DISCONTINUOUS); - } - Curve *tov = toi->portion(0., tf); - ret.append(*tov, STITCH_DISCONTINUOUS); - delete tov; -} - -void Path::do_update(Sequence::iterator first_replaced, - Sequence::iterator last_replaced, - Sequence::iterator first, - Sequence::iterator last) -{ - // note: modifies the contents of [first,last) - check_continuity(first_replaced, last_replaced, first, last); - if ( ( last - first ) == ( last_replaced - first_replaced ) ) { - std::copy(first, last, first_replaced); - } else { - // this approach depends on std::vector's behavior WRT iterator stability - get_curves().erase(first_replaced, last_replaced); - get_curves().insert(first_replaced, first, last); - } - - if ( get_curves().front().get() != final_ ) { - final_->setPoint(0, back().finalPoint()); - final_->setPoint(1, front().initialPoint()); - } -} - -void Path::do_append(Curve *c) { - if ( get_curves().front().get() == final_ ) { - final_->setPoint(1, c->initialPoint()); - } else { - if (c->initialPoint() != finalPoint()) { - THROW_CONTINUITYERROR(); - } - } - get_curves().insert(get_curves().end()-1, boost::shared_ptr(c)); - final_->setPoint(0, c->finalPoint()); -} - -void Path::stitch(Sequence::iterator first_replaced, - Sequence::iterator last_replaced, - Sequence &source) -{ - if (!source.empty()) { - if ( first_replaced != get_curves().begin() ) { - if ( (*first_replaced)->initialPoint() != source.front()->initialPoint() ) { - Curve *stitch = new StitchSegment((*first_replaced)->initialPoint(), - source.front()->initialPoint()); - source.insert(source.begin(), boost::shared_ptr(stitch)); - } - } - if ( last_replaced != (get_curves().end()-1) ) { - if ( (*last_replaced)->finalPoint() != source.back()->finalPoint() ) { - Curve *stitch = new StitchSegment(source.back()->finalPoint(), - (*last_replaced)->finalPoint()); - source.insert(source.end(), boost::shared_ptr(stitch)); - } - } - } else if ( first_replaced != last_replaced && first_replaced != get_curves().begin() && last_replaced != get_curves().end()-1) { - if ( (*first_replaced)->initialPoint() != (*(last_replaced-1))->finalPoint() ) { - Curve *stitch = new StitchSegment((*(last_replaced-1))->finalPoint(), - (*first_replaced)->initialPoint()); - source.insert(source.begin(), boost::shared_ptr(stitch)); - } - } -} - -void Path::check_continuity(Sequence::iterator first_replaced, - Sequence::iterator last_replaced, - Sequence::iterator first, - Sequence::iterator last) -{ - if ( first != last ) { - if ( first_replaced != get_curves().begin() ) { - if ( (*first_replaced)->initialPoint() != (*first)->initialPoint() ) { - THROW_CONTINUITYERROR(); - } + iter ret = x; + for (unsigned i = 0; i < n; i++) + ret++; + return ret; +} + +bool Path::operator==(Path const &other) const +{ + if (this == &other) + return true; + if (_closed != other._closed) + return false; + return *_curves == *other._curves; +} + +Path &Path::operator*=(Affine const &m) +{ + _unshare(); + Sequence::iterator last = _curves->end() - 1; + Sequence::iterator it; + + for (it = _curves->begin(); it != last; ++it) { + it->transform(m); + } + _closing_seg->transform(m); + checkContinuity(); + return *this; +} + +void Path::start(Point const &p) { + if (_curves->size() > 1) { + clear(); + } + _closing_seg->setInitial(p); + _closing_seg->setFinal(p); +} + +Interval Path::timeRange() const +{ + Interval ret(0, size_default()); + return ret; +} + +Curve const &Path::curveAt(Coord t, Coord *rest) const +{ + Position pos = _getPosition(t); + if (rest) { + *rest = pos.t; + } + return at(pos.curve_index); +} + +Point Path::pointAt(Coord t) const +{ + return pointAt(_getPosition(t)); +} + +Coord Path::valueAt(Coord t, Dim2 d) const +{ + return valueAt(_getPosition(t), d); +} + +Curve const &Path::curveAt(Position const &pos) const +{ + return at(pos.curve_index); +} +Point Path::pointAt(Position const &pos) const +{ + return at(pos.curve_index).pointAt(pos.t); +} +Coord Path::valueAt(Position const &pos, Dim2 d) const +{ + return at(pos.curve_index).valueAt(pos.t, d); +} + +std::vector Path::roots(Coord v, Dim2 d) const +{ + std::vector res; + for (unsigned i = 0; i <= size(); i++) { + std::vector temp = (*this)[i].roots(v, d); + for (unsigned j = 0; j < temp.size(); j++) + res.push_back(PathPosition(i, temp[j])); + } + return res; +} + +std::vector Path::intersect(Path const &other, Coord precision) const +{ + std::vector result; + + // TODO: sweepline optimization + // TODO: remove multiple intersections within precision of each other? + for (size_type i = 0; i < size(); ++i) { + for (size_type j = 0; j < other.size(); ++j) { + std::vector cx = (*this)[i].intersect(other[j], precision); + for (std::size_t ci = 0; ci < cx.size(); ++ci) { + PathPosition a(i, cx[ci].first), b(j, cx[ci].second); + PathIntersection px(a, b, cx[ci].point()); + result.push_back(px); + } + } + } + + return result; +} + +int Path::winding(Point const &p) const { + int wind = 0; + + /* To handle all the edge cases, we consider the maximum Y edge of the bounding box + * as not included in box. This way paths that contain linear horizontal + * segments will be treated correctly. */ + for (const_iterator i = begin(); i != end_closed(); ++i) { + Rect bounds = i->boundsFast(); + + if (bounds.height() == 0) continue; + if (p[X] > bounds.right() || !bounds[Y].lowerContains(p[Y])) { + // Ray doesn't intersect bbox, so we ignore this segment + continue; + } + + if (p[X] < bounds.left()) { + /* Ray intersects the curve's bbox, but the point is outside it. + * The winding contribution is exactly the same as that + * of a linear segment with the same initial and final points. */ + Point ip = i->initialPoint(); + Point fp = i->finalPoint(); + Rect eqbox(ip, fp); + + if (eqbox[Y].lowerContains(p[Y])) { + /* The ray intersects the equivalent linear segment. + * Determine winding contribution based on its derivative. */ + if (ip[Y] < fp[Y]) { + wind += 1; + } else if (ip[Y] > fp[Y]) { + wind -= 1; + } else { + // should never happen, because bounds.height() was not zero + assert(false); + } + } + } else { + // point is inside bbox + wind += i->winding(p); + } } - if ( last_replaced != (get_curves().end()-1) ) { - if ( (*(last_replaced-1))->finalPoint() != (*(last-1))->finalPoint() ) { + return wind; +} + +std::vector Path::allNearestTimes(Point const &_point, double from, double to) const +{ + // TODO from and to are not used anywhere. + // rewrite this to simplify. + using std::swap; + + if (from > to) + swap(from, to); + const Path &_path = *this; + unsigned int sz = _path.size(); + if (_path.closed()) + ++sz; + if (from < 0 || to > sz) { + THROW_RANGEERROR("[from,to] interval out of bounds"); + } + double sif, st = modf(from, &sif); + double eif, et = modf(to, &eif); + unsigned int si = static_cast(sif); + unsigned int ei = static_cast(eif); + if (si == sz) { + --si; + st = 1; + } + if (ei == sz) { + --ei; + et = 1; + } + if (si == ei) { + std::vector all_nearest = _path[si].allNearestTimes(_point, st, et); + for (unsigned int i = 0; i < all_nearest.size(); ++i) { + all_nearest[i] = si + all_nearest[i]; + } + return all_nearest; + } + std::vector all_t; + std::vector > all_np; + all_np.push_back(_path[si].allNearestTimes(_point, st)); + std::vector ni; + ni.push_back(si); + double dsq; + double mindistsq = distanceSq(_point, _path[si].pointAt(all_np.front().front())); + Rect bb(Geom::Point(0, 0), Geom::Point(0, 0)); + for (unsigned int i = si + 1; i < ei; ++i) { + bb = (_path[i].boundsFast()); + dsq = distanceSq(_point, bb); + if (mindistsq < dsq) + continue; + all_t = _path[i].allNearestTimes(_point); + dsq = distanceSq(_point, _path[i].pointAt(all_t.front())); + if (mindistsq > dsq) { + all_np.clear(); + all_np.push_back(all_t); + ni.clear(); + ni.push_back(i); + mindistsq = dsq; + } else if (mindistsq == dsq) { + all_np.push_back(all_t); + ni.push_back(i); + } + } + bb = (_path[ei].boundsFast()); + dsq = distanceSq(_point, bb); + if (mindistsq >= dsq) { + all_t = _path[ei].allNearestTimes(_point, 0, et); + dsq = distanceSq(_point, _path[ei].pointAt(all_t.front())); + if (mindistsq > dsq) { + for (unsigned int i = 0; i < all_t.size(); ++i) { + all_t[i] = ei + all_t[i]; + } + return all_t; + } else if (mindistsq == dsq) { + all_np.push_back(all_t); + ni.push_back(ei); + } + } + std::vector all_nearest; + for (unsigned int i = 0; i < all_np.size(); ++i) { + for (unsigned int j = 0; j < all_np[i].size(); ++j) { + all_nearest.push_back(ni[i] + all_np[i][j]); + } + } + all_nearest.erase(std::unique(all_nearest.begin(), all_nearest.end()), all_nearest.end()); + return all_nearest; +} + +std::vector Path::nearestTimePerCurve(Point const &p) const +{ + // return a single nearest time for each curve in this path + std::vector np; + for (const_iterator it = begin(); it != end_default(); ++it) { + np.push_back(it->nearestTime(p)); + } + return np; +} + +Coord Path::nearestTime(Point const &p, Coord *dist) const +{ + Position pos = nearestPosition(p, dist); + return pos.curve_index + pos.t; +} + +PathPosition Path::nearestPosition(Point const &p, Coord *dist) const +{ + Coord mindist = std::numeric_limits::max(); + Position ret; + + if (_curves->size() == 1) { + // naked moveto + ret.curve_index = 0; + ret.t = 0; + if (dist) { + *dist = distance(_closing_seg->initialPoint(), p); + } + return ret; + } + + for (size_type i = 0; i < size_default(); ++i) { + Curve const &c = at(i); + if (distance(p, c.boundsFast()) >= mindist) continue; + + Coord t = c.nearestTime(p); + Coord d = distance(c.pointAt(t), p); + if (d < mindist) { + mindist = d; + ret.curve_index = i; + ret.t = t; + } + } + if (dist) { + *dist = mindist; + } + + return ret; +} + +void Path::appendPortionTo(Path &ret, double from, double to) const +{ + if (!(from >= 0 && to >= 0)) { + THROW_RANGEERROR("from and to must be >=0 in Path::appendPortionTo"); + } + if (to == 0) + to = size() + 0.999999; + if (from == to) { + return; + } + double fi, ti; + double ff = modf(from, &fi), tf = modf(to, &ti); + if (tf == 0) { + ti--; + tf = 1; + } + const_iterator fromi = inc(begin(), (unsigned)fi); + if (fi == ti && from < to) { + ret.append(fromi->portion(ff, tf)); + return; + } + const_iterator toi = inc(begin(), (unsigned)ti); + if (ff != 1.) { + // fromv->setInitial(ret.finalPoint()); + ret.append(fromi->portion(ff, 1.)); + } + if (from >= to) { + const_iterator ender = end(); + if (ender->initialPoint() == ender->finalPoint()) + ++ender; + ret.insert(ret.end(), ++fromi, ender); + ret.insert(ret.end(), begin(), toi); + } else { + ret.insert(ret.end(), ++fromi, toi); + } + ret.append(toi->portion(0., tf)); +} + +void Path::appendPortionTo(Path &target, PathInterval const &ival, + boost::optional const &p_from, boost::optional const &p_to) const +{ + assert(ival.pathSize() == size_closed()); + + if (ival.isDegenerate()) { + Point stitch_to = p_from ? *p_from : pointAt(ival.from()); + target.stitchTo(stitch_to); + return; + } + + Position const &from = ival.from(), &to = ival.to(); + + bool reverse = ival.reverse(); + int di = reverse ? -1 : 1; + size_type s = size_closed(); + + if (!ival.crossesStart() && from.curve_index == to.curve_index) { + Curve *c = (*this)[from.curve_index].portion(from.t, to.t); + if (p_from) { + c->setInitial(*p_from); + } + if (p_to) { + c->setFinal(*p_to); + } + target.append(c); + } else { + Curve *c_first = (*this)[from.curve_index].portion(from.t, reverse ? 0 : 1); + if (p_from) { + c_first->setInitial(*p_from); + } + target.append(c_first); + + for (size_type i = (from.curve_index + s + di) % s; i != to.curve_index; + i = (i + s + di) % s) + { + if (reverse) { + target.append((*this)[i].reverse()); + } else { + target.append((*this)[i].duplicate()); + } + } + + Curve *c_last = (*this)[to.curve_index].portion(reverse ? 1 : 0, to.t); + if (p_to) { + c_last->setFinal(*p_to); + } + target.append(c_last); + } +} + +Path Path::reversed() const +{ + typedef std::reverse_iterator RIter; + + Path ret; + ret._curves->pop_back(); + RIter iter(_curves->end()), rend(_curves->begin()); + for (; iter != rend; ++iter) { + ret._curves->push_back(iter->reverse()); + } + ret._closing_seg = static_cast(ret._closing_seg->reverse()); + ret._curves->push_back(ret._closing_seg); + return ret; +} + + +void Path::insert(iterator pos, Curve const &curve) +{ + _unshare(); + Sequence::iterator seq_pos(seq_iter(pos)); + Sequence source; + source.push_back(curve.duplicate()); + do_update(seq_pos, seq_pos, source); +} + +void Path::erase(iterator pos) +{ + _unshare(); + Sequence::iterator seq_pos(seq_iter(pos)); + + Sequence stitched; + do_update(seq_pos, seq_pos + 1, stitched); +} + +void Path::erase(iterator first, iterator last) +{ + _unshare(); + Sequence::iterator seq_first = seq_iter(first); + Sequence::iterator seq_last = seq_iter(last); + + Sequence stitched; + do_update(seq_first, seq_last, stitched); +} + +void Path::stitchTo(Point const &p) +{ + if (!empty() && _closing_seg->initialPoint() != p) { + if (_exception_on_stitch) { + THROW_CONTINUITYERROR(); + } + _unshare(); + do_append(new StitchSegment(_closing_seg->initialPoint(), p)); + } +} + +void Path::replace(iterator replaced, Curve const &curve) +{ + replace(replaced, replaced + 1, curve); +} + +void Path::replace(iterator first_replaced, iterator last_replaced, Curve const &curve) +{ + _unshare(); + Sequence::iterator seq_first_replaced(seq_iter(first_replaced)); + Sequence::iterator seq_last_replaced(seq_iter(last_replaced)); + Sequence source(1); + source.push_back(curve.duplicate()); + + do_update(seq_first_replaced, seq_last_replaced, source); +} + +void Path::replace(iterator replaced, Path const &path) +{ + replace(replaced, path.begin(), path.end()); +} + +void Path::replace(iterator first, iterator last, Path const &path) +{ + replace(first, last, path.begin(), path.end()); +} + +// replace curves between first and last with contents of source, +// +void Path::do_update(Sequence::iterator first, Sequence::iterator last, Sequence &source) +{ + // TODO: handle cases where first > last in closed paths? + bool last_beyond_closing_segment = (last == _curves->end()); + + // special case: + // if do_update replaces the closing segment, we have to regenerate it + if (source.empty()) { + if (first == last) return; // nothing to do + + // only removing some segments + if ((!_closed && first == _curves->begin()) || (!_closed && last == _curves->end() - 1) || last_beyond_closing_segment) { + // just adjust the closing segment + // do nothing + } else if (first->initialPoint() != (last - 1)->finalPoint()) { + if (_exception_on_stitch) { + THROW_CONTINUITYERROR(); + } + source.push_back(new StitchSegment(first->initialPoint(), (last - 1)->finalPoint())); + } + } else { + // replacing + if (first == _curves->begin() && last == _curves->end()) { + // special case: replacing everything should work the same in open and closed curves + _curves->erase(_curves->begin(), _curves->end() - 1); + _closing_seg->setFinal(source.front().initialPoint()); + _closing_seg->setInitial(source.back().finalPoint()); + _curves->transfer(_curves->begin(), source.begin(), source.end(), source); + return; + } + + // stitch in front + if (!_closed && first == _curves->begin()) { + // not necessary to stitch in front + } else if (first->initialPoint() != source.front().initialPoint()) { + if (_exception_on_stitch) { + THROW_CONTINUITYERROR(); + } + source.insert(source.begin(), new StitchSegment(first->initialPoint(), source.front().initialPoint())); + } + + // stitch at the end + if ((!_closed && last == _curves->end() - 1) || last_beyond_closing_segment) { + // repurpose the closing segment as the stitch segment + // do nothing + } else if (source.back().finalPoint() != (last - 1)->finalPoint()) { + if (_exception_on_stitch) { + THROW_CONTINUITYERROR(); + } + source.push_back(new StitchSegment(source.back().finalPoint(), (last - 1)->finalPoint())); + } + } + + // do not erase the closing segment, adjust it instead + if (last_beyond_closing_segment) { + --last; + } + _curves->erase(first, last); + _curves->transfer(first, source.begin(), source.end(), source); + + // adjust closing segment + if (size_open() == 0) { + _closing_seg->setFinal(_closing_seg->initialPoint()); + } else { + _closing_seg->setInitial(back_open().finalPoint()); + _closing_seg->setFinal(front().initialPoint()); + } + + checkContinuity(); +} + +void Path::do_append(Curve *c) +{ + if (&_curves->front() == _closing_seg) { + _closing_seg->setFinal(c->initialPoint()); + } else { + // if we can't freely move the closing segment, we check whether + // the new curve connects with the last non-closing curve + if (c->initialPoint() != _closing_seg->initialPoint()) { + THROW_CONTINUITYERROR(); + } + } + _curves->insert(_curves->end() - 1, c); + _closing_seg->setInitial(c->finalPoint()); +} + +void Path::checkContinuity() const +{ + Sequence::const_iterator i = _curves->begin(), j = _curves->begin(); + ++j; + for (; j != _curves->end(); ++i, ++j) { + if (i->finalPoint() != j->initialPoint()) { + THROW_CONTINUITYERROR(); + } + } + if (_curves->front().initialPoint() != _curves->back().finalPoint()) { THROW_CONTINUITYERROR(); - } } - } else if ( first_replaced != last_replaced && first_replaced != get_curves().begin() && last_replaced != get_curves().end()-1) { - if ( (*first_replaced)->initialPoint() != (*(last_replaced-1))->finalPoint() ) { - THROW_CONTINUITYERROR(); +} + +PathPosition Path::_getPosition(Coord t) const +{ + size_type sz = size_default(); + if (t < 0 || t > sz) { + THROW_RANGEERROR("parameter t out of bounds"); + } + + Position ret; + Coord k; + ret.t = modf(t, &k); + ret.curve_index = k; + if (ret.curve_index == sz) { + --ret.curve_index; + ret.t = 1; + } + return ret; +} + +Piecewise > paths_to_pw(PathVector const &paths) +{ + Piecewise > ret = paths[0].toPwSb(); + for (unsigned i = 1; i < paths.size(); i++) { + ret.concat(paths[i].toPwSb()); } - } + return ret; } } // end namespace Geom diff --git a/src/2geom/path.h b/src/2geom/path.h index 28d2a25e4..1940aa580 100644 --- a/src/2geom/path.h +++ b/src/2geom/path.h @@ -1,43 +1,47 @@ -/** - * \file - * \brief Path - Series of continuous curves +/** @file + * @brief Path - a sequence of contiguous curves *//* - * Authors: - * MenTaLguY - * Marco Cecchetti - * - * Copyright 2007-2008 Authors - * - * This library is free software; you can redistribute it and/or - * modify it either under the terms of the GNU Lesser General Public - * License version 2.1 as published by the Free Software Foundation - * (the "LGPL") or, at your option, under the terms of the Mozilla - * Public License Version 1.1 (the "MPL"). If you do not alter this - * notice, a recipient may use your version of this file under either - * the MPL or the LGPL. - * - * You should have received a copy of the LGPL along with this library - * in the file COPYING-LGPL-2.1; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * You should have received a copy of the MPL along with this library - * in the file COPYING-MPL-1.1 - * - * The contents of this file are subject to the Mozilla Public License - * Version 1.1 (the "License"); you may not use this file except in - * compliance with the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY - * OF ANY KIND, either express or implied. See the LGPL or the MPL for - * the specific language governing rights and limitations. - */ + * Authors: + * MenTaLguY + * Marco Cecchetti + * Krzysztof Kosiński + * + * Copyright 2007-2014 Authors + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + */ #ifndef LIB2GEOM_SEEN_PATH_H #define LIB2GEOM_SEEN_PATH_H #include #include +#include +#include +#include #include +#include <2geom/intersection.h> #include <2geom/curve.h> #include <2geom/bezier-curve.h> #include <2geom/transforms.h> @@ -45,656 +49,757 @@ namespace Geom { class Path; +class ConvexHull; namespace PathInternal { -typedef std::vector > Sequence; +typedef boost::ptr_vector Sequence; + +template +class BaseIterator + : public boost::random_access_iterator_helper + < BaseIterator

+ , Curve const + , std::ptrdiff_t + , Curve const * + , Curve const & + > +{ + protected: + BaseIterator(P &p, unsigned i) : path(&p), index(i) {} + // default copy, default assign + typedef BaseIterator

Self; -template -class BaseIterator { -protected: - BaseIterator() : path(NULL), index(0) {} - BaseIterator(P *p, unsigned i) : path(p), index(i) {} - // default copy, default assign + public: + BaseIterator() : path(NULL), index(0) {} -public: - bool operator==(BaseIterator const &other) { - return path == other.path && index == other.index; - } - bool operator!=(BaseIterator const &other) { - return path != other.path || index != other.index; - } - - Curve const &operator*() const { return (*path)[index]; } - Curve const *operator->() const { return &(*path)[index]; } - boost::shared_ptr get_ref() const { - return path->get_ref_at_index(index); - } - - C &operator++() { - ++index; - return static_cast(*this); - } - C operator++(int) { - C old(static_cast(*this)); - ++(*this); - return old; - } - - C &operator--() { - --index; - return static_cast(*this); - } - C operator--(int) { - C old(static_cast(*this)); - --(*this); - return old; - } + bool operator<(BaseIterator const &other) const { + return path == other.path && index < other.index; + } + bool operator==(BaseIterator const &other) const { + return path == other.path && index == other.index; + } + Curve const &operator*() const { + return (*path)[index]; + } -private: - P *path; - unsigned index; + Self &operator++() { + ++index; + return *this; + } + Self &operator--() { + --index; + return *this; + } + Self &operator+=(std::ptrdiff_t d) { + index += d; + return *this; + } + Self &operator-=(std::ptrdiff_t d) { + index -= d; + return *this; + } - friend class ::Geom::Path; + private: + P *path; + unsigned index; + + friend class ::Geom::Path; }; -class ConstIterator : public BaseIterator { -public: - typedef BaseIterator Base; +} - ConstIterator() : Base() {} - // default copy, default assign +/** @brief Position (generalized time value) in the path. + * + * This class exists because when mapping the range of multiple curves onto the same interval + * as the curve index, we lose some precision. For instance, a path with 16 curves will + * have 4 bits less precision than a path with 1 curve. If you need high precision results + * in long paths, either use this class and related methods instead of the standard methods + * pointAt(), nearestTime() and so on, or use curveAt() to first obtain the curve, then + * call the method again to obtain a high precision result. + * + * @ingroup Paths */ +struct PathPosition + : boost::totally_ordered +{ + typedef PathInternal::Sequence::size_type size_type; -private: - ConstIterator(Path const &p, unsigned i) : Base(&p, i) {} - friend class ::Geom::Path; + Coord t; ///< Time value in the curve + size_type curve_index; ///< Index of the curve in the path + + PathPosition() : t(0), curve_index(0) {} + PathPosition(size_type idx, Coord tval) : t(tval), curve_index(idx) {} + + bool operator<(PathPosition const &other) const { + if (curve_index < other.curve_index) return true; + if (curve_index == other.curve_index) { + return t < other.t; + } + return false; + } + bool operator==(PathPosition const &other) const { + return curve_index == other.curve_index && t == other.t; + } + /// Convert positions at or beyond 1 to 0 on the next curve. + void normalizeForward(size_type path_size) { + if (t >= 1) { + curve_index = (curve_index + 1) % path_size; + t = 0; + } + } + /// Convert positions at or before 0 to 1 on the previous curve. + void normalizeBackward(size_type path_size) { + if (t <= 0) { + curve_index = (curve_index - 1) % path_size; + t = 1; + } + } }; -class Iterator : public BaseIterator { -public: - typedef BaseIterator Base; +inline std::ostream &operator<<(std::ostream &os, PathPosition const &pos) { + os << pos.curve_index << ": " << pos.t; + return os; +} - Iterator() : Base() {} - // default copy, default assign - operator ConstIterator const &() const { - return reinterpret_cast(*this); - } +/** @brief Contiguous subset of the path's parameter domain. + * This is a directed interval, which allows one to specify any contiguous subset + * of the path's domain, including subsets that wrap around the initial point + * of the path. + * @ingroup Paths */ +class PathInterval { +public: + typedef PathPosition Position; + typedef PathInternal::Sequence::size_type size_type; + + /** @brief Default interval. + * Default-constructed PathInterval includes only the initial point of the initial segment. */ + PathInterval(); + + /** @brief Construct an interval in the path's parameter domain. + * @param from Initial position + * @param to Final position + * @param cross_start If true, the interval will proceed from the initial to final + * position through the initial point of the path, wrapping around the closing segment; + * otherwise it will not wrap around the closing segment. + * @param path_size Size of the path to which this interval applies, required + * to clean up degenerate cases */ + PathInterval(Position const &from, Position const &to, bool cross_start, size_type path_size); + + /// Get the position of the initial point. + Position const &initialPosition() const { return _from; } + /// Get the position of the final point. + Position const &finalPosition() const { return _to; } + + Position const &from() const { return _from; } + Position const &to() const { return _to; } + + /// Check whether the interval has only one point. + bool isDegenerate() const { return _from == _to; } + /// True if the interval goes in the direction of decreasing time values. + bool reverse() const { return _reverse; } + /// True if the interior of the interval contains the initial point of the path. + bool crossesStart() const { return _cross_start; } + + /// Test a path position for inclusion. + bool contains(Position const &pos) const; + + /// Get a position at least @a min_dist away in parameter space from the ends. + /// If no such position exists, the middle point between these positions is returned. + Position inside(Coord min_dist = EPSILON) const; + + /// Select one of two intervals with given endpoints by parameter direction. + static PathInterval from_direction(Position const &from, Position const &to, + bool reversed, size_type path_size); + + /// Select one of two intervals with given endpoints by whether it includes the initial point. + static PathInterval from_start_crossing(Position const &from, Position const &to, + bool cross_start, size_type path_size) { + PathInterval result(from, to, cross_start, path_size); + return result; + } + + size_type pathSize() const { return _path_size; } private: - Iterator(Path &p, unsigned i) : Base(&p, i) {} - friend class ::Geom::Path; + Position _from, _to; + size_type _path_size; + bool _cross_start, _reverse; }; +/// Create an interval in the direction of increasing time value. +/// @relates PathInterval +inline PathInterval forward_interval(PathPosition const &from, PathPosition const &to, + PathInterval::size_type path_size) +{ + PathInterval result = PathInterval::from_direction(from, to, false, path_size); + return result; +} + +/// Create an interval in the direction of decreasing time value. +/// @relates PathInterval +inline PathInterval backward_interval(PathPosition const &from, PathPosition const &to, + PathInterval::size_type path_size) +{ + PathInterval result = PathInterval::from_direction(from, to, true, path_size); + return result; } -/* - * Open and closed paths: all paths, whether open or closed, store a final - * segment which connects the initial and final endpoints of the "real" - * path data. While similar to the "z" in an SVG path, it exists for - * both open and closed paths, and is not considered part of the "normal" - * path data, which is always covered by the range [begin(), end_open()). - * Conversely, the range [begin(), end_closed()) always contains the "extra" - * closing segment. +/// Output an interval in the path's domain. +/// @relates PathInterval +inline std::ostream &operator<<(std::ostream &os, PathInterval const &ival) { + os << "PathInterval["; + if (ival.crossesStart()) { + os << ival.from() << " -> 0: 0.0 -> " << ival.to(); + } else { + os << ival.from() << " -> " << ival.to(); + } + os << "]"; + return os; +} + +typedef Intersection PathIntersection; + +template <> +struct ShapeTraits { + typedef PathPosition TimeType; + typedef PathInterval IntervalType; + typedef Path AffineClosureType; + typedef PathIntersection IntersectionType; +}; + +/** @brief Sequence of contiguous curves, aka spline. + * + * Path represents a sequence of contiguous curves, also known as a spline. + * It corresponds to a "subpath" in SVG terminology. It can represent both + * open and closed subpaths. The final point of each curve is exactly + * equal to the initial point of the next curve. + * + * The path always contains a linear closing segment that connects + * the final point of the last "real" curve to the initial point of the + * first curve. This way the curves form a closed loop even for open paths. + * If the closing segment has nonzero length and the path is closed, it is + * considered a normal part of the path data. There are three distinct sets + * of end iterators one can use to iterate over the segments: + * + * - Iterating between @a begin() and @a end() will iterate over segments + * which are part of the path. + * - Iterating between @a begin() and @a end_closed() + * will always iterate over a closed loop of segments. + * - Iterating between @a begin() and @a end_open() will always skip + * the closing segment. * - * The only difference between a closed and an open path is whether - * end_default() returns end_closed() or end_open(). The idea behind this - * is to let any path be stroked using [begin(), end_default()), and filled - * using [begin(), end_closed()), without requiring a separate "filled" version - * of the path to use for filling. + * Normally, an exception will be thrown when you try to insert a curve + * that makes the path non-continuous. If you are working with unsanitized + * curve data, you can call setStitching(true), which will insert line segments + * to make the path continuous. * - * \invariant : curves_ always contains at least one segment. The last segment - * is always of type ClosingSegment. All constructors take care of this. - (curves_.size() > 0) && dynamic_cast(curves_.back()) - */ -class Path { + * Internally, Path uses copy-on-write data. This is done for two reasons: first, + * copying a Curve requires calling a virtual function, so it's a little more expensive + * that normal copying; and second, it reduces the memory cost of copying the path. + * Therefore you can return Path and PathVector from functions without worrying + * about temporary copies. + * + * Note that this class cannot represent arbitrary shapes, which may contain holes. + * To do that, use PathVector, which is more generic. + * + * It's not very convenient to create a Path directly. To construct paths more easily, + * use PathBuilder. + * + * @ingroup Paths */ +class Path + : boost::equality_comparable1< Path + , MultipliableNoncommutative< Path, Affine + > > +{ public: - typedef PathInternal::Sequence Sequence; - typedef PathInternal::Iterator iterator; - typedef PathInternal::ConstIterator const_iterator; - typedef Sequence::size_type size_type; - typedef Sequence::difference_type difference_type; + typedef PathPosition Position; + typedef PathInternal::Sequence Sequence; + typedef PathInternal::BaseIterator iterator; + typedef PathInternal::BaseIterator const_iterator; + typedef Sequence::size_type size_type; + typedef Sequence::difference_type difference_type; + + class ClosingSegment : public LineSegment { + public: + ClosingSegment() : LineSegment() {} + ClosingSegment(Point const &p1, Point const &p2) : LineSegment(p1, p2) {} + virtual Curve *duplicate() const { return new ClosingSegment(*this); } + virtual Curve *reverse() const { return new ClosingSegment((*this)[1], (*this)[0]); } + }; + + class StitchSegment : public LineSegment { + public: + StitchSegment() : LineSegment() {} + StitchSegment(Point const &p1, Point const &p2) : LineSegment(p1, p2) {} + virtual Curve *duplicate() const { return new StitchSegment(*this); } + virtual Curve *reverse() const { return new StitchSegment((*this)[1], (*this)[0]); } + }; + + // Path(Path const &other) - use default copy constructor + + /// Construct an empty path starting at the specified point. + explicit Path(Point const &p = Point()) + : _curves(new Sequence()) + , _closing_seg(new ClosingSegment(p, p)) + , _closed(false) + , _exception_on_stitch(true) + { + _curves->push_back(_closing_seg); + } - class ClosingSegment : public LineSegment { - public: - ClosingSegment() : LineSegment() {} - ClosingSegment(Point const &p1, Point const &p2) : LineSegment(p1, p2) {} - virtual Curve *duplicate() const { return new ClosingSegment(*this); } - virtual Curve *reverse() const { return new ClosingSegment((*this)[1], (*this)[0]); } - }; - - enum Stitching { - NO_STITCHING=0, - STITCH_DISCONTINUOUS - }; - - class StitchSegment : public LineSegment { - public: - StitchSegment() : LineSegment() {} - StitchSegment(Point const &p1, Point const &p2) : LineSegment(p1, p2) {} - virtual Curve *duplicate() const { return new StitchSegment(*this); } - virtual Curve *reverse() const { return new StitchSegment((*this)[1], (*this)[0]); } - }; - - // Path(Path const &other) - use default copy constructor - - explicit Path(Point p=Point()) - : curves_(boost::shared_ptr(new Sequence(1, boost::shared_ptr()))), - final_(new ClosingSegment(p, p)), - closed_(false) - { - get_curves().back() = boost::shared_ptr(final_); - } - - Path(const_iterator const &first, - const_iterator const &last, - bool closed=false) - : curves_(boost::shared_ptr(new Sequence(seq_iter(first), - seq_iter(last)))), - closed_(closed) - { - if (!get_curves().empty()) { - final_ = new ClosingSegment(get_curves().back()->finalPoint(), - get_curves().front()->initialPoint()); - } else { - final_ = new ClosingSegment(); - } - get_curves().push_back(boost::shared_ptr(final_)); - } - - virtual ~Path() {} - - // Path &operator=(Path const &other) - use default assignment operator - - /// \todo Add noexcept specifiers for C++11 - void swap(Path &other) { - using std::swap; - swap(other.curves_, curves_); - swap(other.final_, final_); - swap(other.closed_, closed_); - } - friend inline void swap(Path &a, Path &b) { a.swap(b); } - - Curve const &operator[](unsigned i) const { return *get_curves()[i]; } - Curve const &at_index(unsigned i) const { return *get_curves()[i]; } - boost::shared_ptr get_ref_at_index(unsigned i) { - return get_curves()[i]; - } - - Curve const &front() const { return *get_curves()[0]; } - Curve const &back() const { return back_open(); } - Curve const &back_open() const { - if (empty()) { THROW_RANGEERROR("Path contains not enough segments"); } - return *get_curves()[get_curves().size()-2]; - } - Curve const &back_closed() const { return *get_curves()[get_curves().size()-1]; } - Curve const &back_default() const { - return ( closed_ ? back_closed() : back_open() ); - } - - const_iterator begin() const { return const_iterator(*this, 0); } - const_iterator end() const { return const_iterator(*this, size()); } - iterator begin() { return iterator(*this, 0); } - iterator end() { return iterator(*this, size()); } - - const_iterator end_open() const { return const_iterator(*this, size()); } - const_iterator end_closed() const { return const_iterator(*this, size()+1); } - const_iterator end_default() const { - return ( closed_ ? end_closed() : end_open() ); - } - - size_type size_open() const { return get_curves().size()-1; } - size_type size_closed() const { return get_curves().size(); } - size_type size_default() const { - return ( closed_ ? size_closed() : size_open() ); - } - size_type size() const { return size_open(); } - - size_type max_size() const { return get_curves().max_size()-1; } - - bool empty() const { return (get_curves().size() == 1); } - bool closed() const { return closed_; } - void close(bool closed=true) { closed_ = closed; } - - OptRect boundsFast() const; - OptRect boundsExact() const; - - Piecewise > toPwSb() const { - Piecewise > ret; - ret.push_cut(0); - unsigned i = 1; - bool degenerate = true; - // pw> is always open. so if path is closed, add closing segment as well to pwd2. - for(const_iterator it = begin(); it != end_default(); ++it) { - if (!it->isDegenerate()) { - ret.push(it->toSBasis(), i++); - degenerate = false; - } - } - if (degenerate) { - // if path only contains degenerate curves, no second cut is added - // so we need to create at least one segment manually - ret = Piecewise >(initialPoint()); - } - return ret; - } - - bool operator==(Path const &other) const { - if (this == &other) return true; - if (closed_ != other.closed_) return false; - return get_curves() == other.get_curves(); - } - bool operator!=(Path const &other) const { - return !( *this == other ); - } - - Path operator*(Affine const &m) const { - Path ret(*this); - ret *= m; - return ret; - } - Path operator*(Translate const &m) const { // specialization over Affine, for faster computation - Path ret(*this); - ret *= m; - return ret; - } - - Path &operator*=(Affine const &m); - Path &operator*=(Translate const &m); // specialization over Affine, for faster computation - - Point pointAt(double t) const - { - unsigned int sz = size(); - if ( closed() ) ++sz; - if ( t < 0 || t > sz ) - { - THROW_RANGEERROR("parameter t out of bounds"); - } - if ( empty() ) return initialPoint(); // naked moveto - double k, lt = modf(t, &k); - unsigned int i = static_cast(k); - if ( i == sz ) - { - --i; - lt = 1; - } - return (*this)[i].pointAt(lt); - } - - double valueAt(double t, Dim2 d) const - { - unsigned int sz = size(); - if ( closed() ) ++sz; - if ( t < 0 || t > sz ) - { - THROW_RANGEERROR("parameter t out of bounds"); - } - if ( empty() ) return initialPoint()[d]; // naked moveto - double k, lt = modf(t, &k); - unsigned int i = static_cast(k); - if ( i == sz ) - { - --i; - lt = 1; - } - return (*this)[i].valueAt(lt, d); - } - - - Point operator() (double t) const - { - return pointAt(t); - } - - std::vector roots(double v, Dim2 d) const { - std::vector res; - for(unsigned i = 0; i <= size(); i++) { - std::vector temp = (*this)[i].roots(v, d); - for(unsigned j = 0; j < temp.size(); j++) - res.push_back(temp[j] + i); - } - return res; - } - - std::vector - allNearestPoints(Point const& _point, double from, double to) const; - - std::vector - allNearestPoints(Point const& _point) const - { - unsigned int sz = size(); - if ( closed() ) ++sz; - return allNearestPoints(_point, 0, sz); - } - - std::vector - nearestPointPerCurve(Point const& _point) const; - - double nearestPoint(Point const& _point, double from, double to, double *distance_squared = NULL) const; - - double nearestPoint(Point const& _point, double *distance_squared = NULL) const - { - unsigned int sz = size(); - if ( closed() ) ++sz; - return nearestPoint(_point, 0, sz, distance_squared); - } - - void appendPortionTo(Path &p, double f, double t) const; - - Path portion(double f, double t) const { - Path ret; - ret.close(false); - appendPortionTo(ret, f, t); - return ret; - } - Path portion(Interval i) const { return portion(i.min(), i.max()); } - - Path reverse() const { - Path ret(*this); - ret.unshare(); - for ( Sequence::iterator iter = ret.get_curves().begin() ; - iter != ret.get_curves().end()-1 ; ++iter ) + /// Construct a path containing a range of curves. + template + Path(Iter first, Iter last, bool closed = false, bool stitch = false) + : _curves(new Sequence()) + , _closed(closed) + , _exception_on_stitch(!stitch) { - *iter = boost::shared_ptr((*iter)->reverse()); - } - std::reverse(ret.get_curves().begin(), ret.get_curves().end()-1); - ret.final_ = static_cast(ret.final_->reverse()); - ret.get_curves().back() = boost::shared_ptr(ret.final_); - return ret; - } - - void insert(iterator const &pos, - Curve const &curve, Stitching stitching=NO_STITCHING) - { - unshare(); - Sequence::iterator seq_pos(seq_iter(pos)); - Sequence source(1, boost::shared_ptr(curve.duplicate())); - if (stitching) stitch(seq_pos, seq_pos, source); - do_update(seq_pos, seq_pos, source.begin(), source.end()); - } - - void insert(iterator const &pos, - const_iterator const &first, - const_iterator const &last, - Stitching stitching=NO_STITCHING) - { - unshare(); - Sequence::iterator seq_pos(seq_iter(pos)); - Sequence source(seq_iter(first), seq_iter(last)); - if (stitching) stitch(seq_pos, seq_pos, source); - do_update(seq_pos, seq_pos, source.begin(), source.end()); - } - - void clear() { - unshare(); - do_update(get_curves().begin(), get_curves().end()-1, - get_curves().begin(), get_curves().begin()); - } - - void erase(iterator const &pos, Stitching stitching=NO_STITCHING) { - unshare(); - Sequence::iterator seq_pos(seq_iter(pos)); - if (stitching) { - Sequence stitched; - stitch(seq_pos, seq_pos+1, stitched); - do_update(seq_pos, seq_pos+1, stitched.begin(), stitched.end()); - } else { - do_update(seq_pos, seq_pos+1, get_curves().begin(), get_curves().begin()); - } - } - - void erase(iterator const &first, - iterator const &last, - Stitching stitching=NO_STITCHING) - { - unshare(); - Sequence::iterator seq_first=seq_iter(first); - Sequence::iterator seq_last=seq_iter(last); - if (stitching) { - Sequence stitched; - stitch(seq_first, seq_last, stitched); - do_update(seq_first, seq_last, stitched.begin(), stitched.end()); - } else { - do_update(seq_first, seq_last, - get_curves().begin(), get_curves().begin()); - } - } - - // erase last segment of path - void erase_last() { - erase(iterator(*this, size()-1)); - } - - void replace(iterator const &replaced, - Curve const &curve, - Stitching stitching=NO_STITCHING) - { - unshare(); - Sequence::iterator seq_replaced(seq_iter(replaced)); - Sequence source(1, boost::shared_ptr(curve.duplicate())); - if (stitching) stitch(seq_replaced, seq_replaced+1, source); - do_update(seq_replaced, seq_replaced+1, source.begin(), source.end()); - } - - void replace(iterator const &first_replaced, - iterator const &last_replaced, - Curve const &curve, Stitching stitching=NO_STITCHING) - { - unshare(); - Sequence::iterator seq_first_replaced(seq_iter(first_replaced)); - Sequence::iterator seq_last_replaced(seq_iter(last_replaced)); - Sequence source(1, boost::shared_ptr(curve.duplicate())); - if (stitching) stitch(seq_first_replaced, seq_last_replaced, source); - do_update(seq_first_replaced, seq_last_replaced, - source.begin(), source.end()); - } - - void replace(iterator const &replaced, - const_iterator const &first, - const_iterator const &last, - Stitching stitching=NO_STITCHING) - { - unshare(); - Sequence::iterator seq_replaced(seq_iter(replaced)); - Sequence source(seq_iter(first), seq_iter(last)); - if (stitching) stitch(seq_replaced, seq_replaced+1, source); - do_update(seq_replaced, seq_replaced+1, source.begin(), source.end()); - } - - void replace(iterator const &first_replaced, - iterator const &last_replaced, - const_iterator const &first, - const_iterator const &last, - Stitching stitching=NO_STITCHING) - { - unshare(); - Sequence::iterator seq_first_replaced(seq_iter(first_replaced)); - Sequence::iterator seq_last_replaced(seq_iter(last_replaced)); - Sequence source(seq_iter(first), seq_iter(last)); - if (stitching) stitch(seq_first_replaced, seq_last_replaced, source); - do_update(seq_first_replaced, seq_last_replaced, - source.begin(), source.end()); - } - - void start(Point p) { - clear(); - final_->setPoint(0, p); - final_->setPoint(1, p); - } - - Point initialPoint() const { return (*final_)[1]; } - Point finalPoint() const { return (*final_)[0]; } - - void setInitial(Point const& p) - { - if ( empty() ) return; - unshare(); - boost::shared_ptr head(front().duplicate()); - head->setInitial(p); - Sequence::iterator replaced = get_curves().begin(); - Sequence source(1, head); - do_update(replaced, replaced + 1, source.begin(), source.end()); - } - - void setFinal(Point const& p) - { - if ( empty() ) return; - unshare(); - boost::shared_ptr tail(back().duplicate()); - tail->setFinal(p); - Sequence::iterator replaced = get_curves().end() - 2; - Sequence source(1, tail); - do_update(replaced, replaced + 1, source.begin(), source.end()); - } - - void append(Curve const &curve, Stitching stitching=NO_STITCHING) { - unshare(); - if (stitching) stitchTo(curve.initialPoint()); - do_append(curve.duplicate()); - } - void append(D2 const &curve, Stitching stitching=NO_STITCHING) { - unshare(); - if (stitching) stitchTo(Point(curve[X][0][0], curve[Y][0][0])); - do_append(new SBasisCurve(curve)); - } - void append(Path const &other, Stitching stitching=NO_STITCHING) { - insert(end(), other.begin(), other.end(), stitching); - } - - void stitchTo(Point const &p) { - if (!empty() && finalPoint() != p) { - unshare(); - do_append(new StitchSegment(finalPoint(), p)); - } - } - - - /** - * It is important to note that the coordinates passed to appendNew should be finite! - * If one of the coordinates is infinite, 2geom will throw a ContinuityError exception. - */ - - template - void appendNew(A a) { - unshare(); - do_append(new CurveType(finalPoint(), a)); - } - - template - void appendNew(A a, B b) { - unshare(); - do_append(new CurveType(finalPoint(), a, b)); - } - - template - void appendNew(A a, B b, C c) { - unshare(); - do_append(new CurveType(finalPoint(), a, b, c)); - } - - template - void appendNew(A a, B b, C c, D d) { - unshare(); - do_append(new CurveType(finalPoint(), a, b, c, d)); - } - - template - void appendNew(A a, B b, C c, D d, E e) { - unshare(); - do_append(new CurveType(finalPoint(), a, b, c, d, e)); - } - - template - void appendNew(A a, B b, C c, D d, E e, F f) { - unshare(); - do_append(new CurveType(finalPoint(), a, b, c, d, e, f)); - } - - template - void appendNew(A a, B b, C c, D d, E e, F f, G g) { - unshare(); - do_append(new CurveType(finalPoint(), a, b, c, d, e, f, g)); - } - - template - void appendNew(A a, B b, C c, D d, E e, F f, G g, H h) { - unshare(); - do_append(new CurveType(finalPoint(), a, b, c, d, e, f, g, h)); - } - - template - void appendNew(A a, B b, C c, D d, E e, F f, G g, H h, I i) { - unshare(); - do_append(new CurveType(finalPoint(), a, b, c, d, e, f, g, h, i)); - } + for (Iter i = first; i != last; ++i) { + _curves->push_back(i->duplicate()); + } + if (!_curves->empty()) { + _closing_seg = new ClosingSegment(_curves->back().finalPoint(), + _curves->front().initialPoint()); + } else { + _closing_seg = new ClosingSegment(); + } + _curves->push_back(_closing_seg); + } + + /// Construct a path from a convex hull. + Path(ConvexHull const &); + + virtual ~Path() {} + + // Path &operator=(Path const &other) - use default assignment operator + + /** @brief Swap contents with another path + * @todo Add noexcept specifiers for C++11 */ + void swap(Path &other) throw() { + using std::swap; + swap(other._curves, _curves); + swap(other._closing_seg, _closing_seg); + swap(other._closed, _closed); + } + /** @brief Swap contents of two paths. + * @relates Path */ + friend inline void swap(Path &a, Path &b) throw() { a.swap(b); } + + /** @brief Access a curve by index */ + Curve const &operator[](size_type i) const { return (*_curves)[i]; } + /** @brief Access a curve by index */ + Curve const &at(size_type i) const { return _curves->at(i); } + + /** @brief Access the first curve in the path. + * Since the curve always contains at least a degenerate closing segment, + * it is always safe to use this method. */ + Curve const &front() const { return _curves->front(); } + /** @brief Access the last curve in the path. */ + Curve const &back() const { return back_default(); } + Curve const &back_open() const { + if (empty()) return _curves->back(); + return (*_curves)[_curves->size() - 2]; + } + Curve const &back_closed() const { + return _closing_seg->isDegenerate() + ? (*_curves)[_curves->size() - 2] + : (*_curves)[_curves->size() - 1]; + } + Curve const &back_default() const { return (_closed ? back_closed() : back_open()); } + + const_iterator begin() const { return const_iterator(*this, 0); } + const_iterator end() const { return end_default(); } + const_iterator end_default() const { return const_iterator(*this, size_default()); } + const_iterator end_open() const { return const_iterator(*this, size_open()); } + const_iterator end_closed() const { return const_iterator(*this, size_closed()); } + iterator begin() { return iterator(*this, 0); } + iterator end() { return end_default(); } + iterator end_default() { return iterator(*this, size_default()); } + iterator end_open() { return iterator(*this, size_open()); } + iterator end_closed() { return iterator(*this, size_closed()); } + + /// Size without the closing segment, even if the path is closed. + size_type size_open() const { return _curves->size() - 1; } + + /** @brief Size with the closing segment, if it makes a difference. + * If the closing segment is degenerate, i.e. its initial and final points + * are exactly equal, then it is not included in this size. */ + size_type size_closed() const { + return _closing_seg->isDegenerate() ? _curves->size() - 1 : _curves->size(); + } + + /// Natural size of the path. + size_type size_default() const { + return _includesClosingSegment() ? size_closed() : size_open(); + } + /// Natural size of the path. + size_type size() const { return size_default(); } + + size_type max_size() const { return _curves->max_size() - 1; } + + /** @brief Check whether path is empty. + * The path is empty if it contains only the closing segment, which according + * to the continuity invariant must be degenerate. Note that unlike standard + * containers, two empty paths are not necessarily identical, because the + * degenerate closing segment may be at a different point, affecting the operation + * of methods such as appendNew(). */ + bool empty() const { return (_curves->size() == 1); } + + /// Check whether the path is closed. + bool closed() const { return _closed; } + + /// Set whether the path is closed. + void close(bool closed = true) { _closed = closed; } + + /** @brief Remove all curves from the path. + * The initial and final points of the closing segment are set to (0,0). + * The stitching flag remains unchanged. */ + void clear(); + + /** @brief Get the approximate bounding box. + * The rectangle returned by this method will contain all the curves, but it's not + * guaranteed to be the smallest possible one */ + OptRect boundsFast() const; + + /** @brief Get a tight-fitting bounding box. + * This will return the smallest possible axis-aligned rectangle containing + * all the curves in the path. */ + OptRect boundsExact() const; + + Piecewise > toPwSb() const; + + /// Test paths for exact equality. + bool operator==(Path const &other) const; + + /// Apply an affine transform. + Path &operator*=(Affine const &m); + + /** @brief Get the allowed range of time values. + * @return Values for which pointAt() and valueAt() yield valid results. */ + Interval timeRange() const; + + /** Get the curve at the specified time value. + * @param t Time value + * @param rest Optional storage for the corresponding time value in the curve */ + Curve const &curveAt(Coord t, Coord *rest = NULL) const; + + /// Get the closing segment of the path. + LineSegment const &closingSegment() const { return *_closing_seg; } + + /** @brief Get the point at the specified time value. + * Note that this method has reduced precision with respect to calling pointAt() + * directly on the curve. If you want high precision results, use the version + * that takes a Position parameter. + * + * Allowed time values range from zero to the number of curves; you can retrieve + * the allowed range of values with timeRange(). */ + Point pointAt(Coord t) const; + + /// Get one coordinate (X or Y) at the specified time value. + Coord valueAt(Coord t, Dim2 d) const; + + /// Get the curve at the specified position. + Curve const &curveAt(Position const &pos) const; + /// Get the point at the specified position. + Point pointAt(Position const &pos) const; + /// Get one coordinate at the specified position. + Coord valueAt(Position const &pos, Dim2 d) const; + + Point operator()(Coord t) const { return pointAt(t); } + + /// Compute intersections with axis-aligned line. + std::vector roots(Coord v, Dim2 d) const; + + /// Compute intersections with another path. + std::vector intersect(Path const &other, Coord precision = EPSILON) const; + + /** @brief Determine the winding number at the specified point. + * + * The winding number is the number of full turns made by a ray that connects the passed + * point and the path's value (i.e. the result of the pointAt() method) as the time increases + * from 0 to the maximum valid value. Positive numbers indicate turns in the direction + * of increasing angles. + * + * Winding numbers are often used as the definition of what is considered "inside" + * the shape. Typically points with either nonzero winding or odd winding are + * considered to be inside the path. */ + int winding(Point const &p) const; + + std::vector allNearestTimes(Point const &p, Coord from, Coord to) const; + std::vector allNearestTimes(Point const &p) const { + return allNearestTimes(p, 0, size_default()); + } + + Coord nearestTime(Point const &p, Coord *dist = NULL) const; + std::vector nearestTimePerCurve(Point const &p) const; + Position nearestPosition(Point const &p, Coord *dist = NULL) const; + + void appendPortionTo(Path &p, Coord f, Coord t) const; + + /** @brief Append a subset of this path to another path. + * An extra stitching segment will be inserted if the start point of the portion + * and the final point of the target path do not match exactly. + * The closing segment of the target path will be modified. */ + void appendPortionTo(Path &p, Position const &from, Position const &to, bool cross_start = false) const { + PathInterval ival(from, to, cross_start, size_closed()); + appendPortionTo(p, ival, boost::none, boost::none); + } + + /** @brief Append a subset of this path to another path. + * This version allows you to explicitly pass a PathInterval. */ + void appendPortionTo(Path &p, PathInterval const &ival) const { + appendPortionTo(p, ival, boost::none, boost::none); + } + + /** @brief Append a subset of this path to another path, specifying endpoints. + * This method is for use in situations where endpoints of the portion segments + * have to be set exactly, for instance when computing Boolean operations. */ + void appendPortionTo(Path &p, PathInterval const &ival, + boost::optional const &p_from, boost::optional const &p_to) const; + + Path portion(Coord f, Coord t) const { + Path ret; + ret.close(false); + appendPortionTo(ret, f, t); + return ret; + } + + Path portion(Interval const &i) const { return portion(i.min(), i.max()); } + + /** @brief Get a subset of the current path with full precision. + * When @a from is larger (later in the path) than @a to, the returned portion + * will be reversed. If @a cross_start is true, the portion will be reversed + * and will cross the initial point of the path. Therefore, when @a from is larger + * than @a to and @a cross_start is true, the returned portion will not be reversed, + * but will "wrap around" the end of the path. */ + Path portion(Position const &from, Position const &to, bool cross_start = false) const { + Path ret; + ret.close(false); + appendPortionTo(ret, from, to, cross_start); + return ret; + } + + /** @brief Get a subset of the current path with full precision. + * This version allows you to explicitly pass a PathInterval. */ + Path portion(PathInterval const &ival) const { + Path ret; + ret.close(false); + appendPortionTo(ret, ival); + return ret; + } + + /** @brief Obtain a reversed version of the current path. + * The final point of the current path will become the initial point + * of the reversed path, unless it is closed and has a non-degenerate + * closing segment. In that case, the new initial point will be the final point + * of the last "real" segment. */ + Path reversed() const; + + void insert(iterator pos, Curve const &curve); + + template + void insert(iterator pos, Iter first, Iter last) { + _unshare(); + Sequence::iterator seq_pos(seq_iter(pos)); + Sequence source; + for (; first != last; ++first) { + source.push_back(first->duplicate()); + } + do_update(seq_pos, seq_pos, source); + } + + void erase(iterator pos); + void erase(iterator first, iterator last); + + // erase last segment of path + void erase_last() { erase(iterator(*this, size() - 1)); } + + void start(Point const &p); + + /** @brief Get the first point in the path. */ + Point initialPoint() const { return (*_closing_seg)[1]; } + + /** @brief Get the last point in the path. + * If the path is closed, this is always the same as the initial point. */ + Point finalPoint() const { return (*_closing_seg)[_closed ? 1 : 0]; } + + void setInitial(Point const &p) { + _unshare(); + _closed = false; + _curves->front().setInitial(p); + _closing_seg->setFinal(p); + } + void setFinal(Point const &p) { + _unshare(); + _closed = false; + (*_curves)[size_open() - 1].setFinal(p); + _closing_seg->setInitial(p); + } + + /** @brief Add a new curve to the end of the path. + * This inserts the new curve right before the closing segment. + * The path takes ownership of the passed pointer, which should not be freed. */ + void append(Curve *curve) { + _unshare(); + stitchTo(curve->initialPoint()); + do_append(curve); + } + + void append(Curve const &curve) { + _unshare(); + stitchTo(curve.initialPoint()); + do_append(curve.duplicate()); + } + void append(D2 const &curve) { + _unshare(); + stitchTo(Point(curve[X][0][0], curve[Y][0][0])); + do_append(new SBasisCurve(curve)); + } + void append(Path const &other) { + replace(end_open(), other.begin(), other.end()); + } + + void replace(iterator replaced, Curve const &curve); + void replace(iterator first, iterator last, Curve const &curve); + void replace(iterator replaced, Path const &path); + void replace(iterator first, iterator last, Path const &path); + + template + void replace(iterator replaced, Iter first, Iter last) { + replace(replaced, replaced + 1, first, last); + } + + template + void replace(iterator first_replaced, iterator last_replaced, Iter first, Iter last) { + _unshare(); + Sequence::iterator seq_first_replaced(seq_iter(first_replaced)); + Sequence::iterator seq_last_replaced(seq_iter(last_replaced)); + Sequence source; + for (; first != last; ++first) { + source.push_back(first->duplicate()); + } + do_update(seq_first_replaced, seq_last_replaced, source); + } + + /** @brief Append a new curve to the path. + * + * This family of methods will automaticaly use the current final point of the path + * as the first argument of the new curve's constructor. To call this method, + * you'll need to write e.g.: + * @code + path.template appendNew(control1, control2, end_point); + @endcode + * It is important to note that the coordinates passed to appendNew should be finite! + * If one of the coordinates is infinite, 2geom will throw a ContinuityError exception. + */ + template + void appendNew(A a) { + _unshare(); + do_append(new CurveType(finalPoint(), a)); + } + + template + void appendNew(A a, B b) { + _unshare(); + do_append(new CurveType(finalPoint(), a, b)); + } + + template + void appendNew(A a, B b, C c) { + _unshare(); + do_append(new CurveType(finalPoint(), a, b, c)); + } + + template + void appendNew(A a, B b, C c, D d) { + _unshare(); + do_append(new CurveType(finalPoint(), a, b, c, d)); + } + + template + void appendNew(A a, B b, C c, D d, E e) { + _unshare(); + do_append(new CurveType(finalPoint(), a, b, c, d, e)); + } + + template + void appendNew(A a, B b, C c, D d, E e, F f) { + _unshare(); + do_append(new CurveType(finalPoint(), a, b, c, d, e, f)); + } + + template + void appendNew(A a, B b, C c, D d, E e, F f, G g) { + _unshare(); + do_append(new CurveType(finalPoint(), a, b, c, d, e, f, g)); + } + + template + void appendNew(A a, B b, C c, D d, E e, F f, G g, H h) { + _unshare(); + do_append(new CurveType(finalPoint(), a, b, c, d, e, f, g, h)); + } + + template + void appendNew(A a, B b, C c, D d, E e, F f, G g, H h, I i) { + _unshare(); + do_append(new CurveType(finalPoint(), a, b, c, d, e, f, g, h, i)); + } + + /// Append a stitching segment ending at the specified point. + void stitchTo(Point const &p); + + /** @brief Verify the continuity invariant. + * If the path is not contiguous, this will throw a CountinuityError. */ + void checkContinuity() const; + + /** @brief Enable or disable the throwing of exceptions when stitching discontinuities. + * Normally stitching will cause exceptions, but when you are working with unsanitized + * curve data, you can disable these exceptions. */ + void setStitching(bool x) { + _exception_on_stitch = !x; + } private: - static Sequence::iterator seq_iter(iterator const &iter) { - return iter.path->get_curves().begin() + iter.index; - } - static Sequence::const_iterator seq_iter(const_iterator const &iter) { - return iter.path->get_curves().begin() + iter.index; - } - - Sequence &get_curves() { return *curves_; } - Sequence const &get_curves() const { return *curves_; } - - void unshare() { - if (!curves_.unique()) { - curves_ = boost::shared_ptr(new Sequence(*curves_)); - } - if (!get_curves().back().unique()) { - final_ = static_cast(final_->duplicate()); - get_curves().back() = boost::shared_ptr(final_); - } - } - - void stitch(Sequence::iterator first_replaced, - Sequence::iterator last_replaced, - Sequence &sequence); - - void do_update(Sequence::iterator first_replaced, - Sequence::iterator last_replaced, - Sequence::iterator first, - Sequence::iterator last); - - // n.b. takes ownership of curve object - void do_append(Curve *curve); - - void check_continuity(Sequence::iterator first_replaced, - Sequence::iterator last_replaced, - Sequence::iterator first, - Sequence::iterator last); - - boost::shared_ptr curves_; - ClosingSegment *final_; - bool closed_; -}; // end class Path - -inline static Piecewise > paths_to_pw(std::vector paths) { - Piecewise > ret = paths[0].toPwSb(); - for(unsigned i = 1; i < paths.size(); i++) { - ret.concat(paths[i].toPwSb()); - } - return ret; -} + static Sequence::iterator seq_iter(iterator const &iter) { + return iter.path->_curves->begin() + iter.index; + } + static Sequence::const_iterator seq_iter(const_iterator const &iter) { + return iter.path->_curves->begin() + iter.index; + } -inline -Coord nearest_point(Point const& p, Path const& c) -{ - return c.nearestPoint(p); -} + // whether the closing segment is part of the path + bool _includesClosingSegment() const { + return _closed && !_closing_seg->isDegenerate(); + } + void _unshare() { + if (!_curves.unique()) { + _curves.reset(new Sequence(*_curves)); + _closing_seg = static_cast(&_curves->back()); + } + } + Position _getPosition(Coord t) const; + + void stitch(Sequence::iterator first_replaced, Sequence::iterator last_replaced, Sequence &sequence); + void do_update(Sequence::iterator first, Sequence::iterator last, Sequence &source); + + // n.b. takes ownership of curve object + void do_append(Curve *curve); + + boost::shared_ptr _curves; + ClosingSegment *_closing_seg; + bool _closed; + bool _exception_on_stitch; +}; // end class Path + +Piecewise > paths_to_pw(PathVector const &paths); + +inline Coord nearest_time(Point const &p, Path const &c) { return c.nearestTime(p); } -} // end namespace Geom +} // end namespace Geom #endif // LIB2GEOM_SEEN_PATH_H diff --git a/src/2geom/pathvector.cpp b/src/2geom/pathvector.cpp index fc0ad75c4..36364de9b 100644 --- a/src/2geom/pathvector.cpp +++ b/src/2geom/pathvector.cpp @@ -1,12 +1,11 @@ -/* - * PathVector - std::vector containing Geom::Path - * This file provides a set of operations that can be performed on PathVector, - * e.g. an affine transform. - * +/** @file + * @brief PathVector - a sequence of subpaths + *//* * Authors: - * Johan Engelen + * Johan Engelen + * Krzysztof Kosiński * - * Copyright 2008 authors + * Copyright 2008-2014 Authors * * This library is free software; you can redistribute it and/or * modify it either under the terms of the GNU Lesser General Public @@ -32,9 +31,6 @@ * the specific language governing rights and limitations. */ -#ifndef SEEN_GEOM_PATHVECTOR_CPP -#define SEEN_GEOM_PATHVECTOR_CPP - #include <2geom/pathvector.h> #include <2geom/path.h> @@ -42,104 +38,184 @@ namespace Geom { -// TODO: see which of these functions can be inlined for optimization +//PathVector &PathVector::operator+=(PathVector const &other); + +PathVector::size_type PathVector::curveCount() const +{ + size_type n = 0; + for (const_iterator it = begin(); it != end(); ++it) { + n += it->size_default(); + } + return n; +} + +void PathVector::reverse(bool reverse_paths) +{ + if (reverse_paths) { + std::reverse(begin(), end()); + } + for (iterator i = begin(); i != end(); ++i) { + *i = i->reversed(); + } +} -/** - * Reverses all Paths and the order of paths in the vector as well - **/ -PathVector reverse_paths_and_order (PathVector const & path_in) +PathVector PathVector::reversed(bool reverse_paths) const { - PathVector path_out; - for (PathVector::const_reverse_iterator it = path_in.rbegin(); it != path_in.rend(); ++it) { - path_out.push_back( (*it).reverse() ); + PathVector ret; + for (const_iterator i = begin(); i != end(); ++i) { + ret.push_back(i->reversed()); + } + if (reverse_paths) { + std::reverse(ret.begin(), ret.end()); } - return path_out; + return ret; } -OptRect bounds_fast( PathVector const& pv ) +Path &PathVector::pathAt(Coord t, Coord *rest) +{ + return const_cast(static_cast(this)->pathAt(t, rest)); +} +Path const &PathVector::pathAt(Coord t, Coord *rest) const +{ + Position pos = _getPosition(t); + if (rest) { + *rest = Coord(pos.curve_index) + pos.t; + } + return at(pos.path_index); +} +Curve const &PathVector::curveAt(Coord t, Coord *rest) const +{ + Position pos = _getPosition(t); + if (rest) { + *rest = pos.t; + } + return at(pos.path_index).at(pos.curve_index); +} +Coord PathVector::valueAt(Coord t, Dim2 d) const +{ + Position pos = _getPosition(t); + return at(pos.path_index).at(pos.curve_index).valueAt(pos.t, d); +} +Point PathVector::pointAt(Coord t) const +{ + Position pos = _getPosition(t); + return at(pos.path_index).at(pos.curve_index).pointAt(pos.t); +} + +OptRect PathVector::boundsFast() const { - typedef PathVector::const_iterator const_iterator; - OptRect bound; - if (pv.empty()) return bound; - - bound = (pv.begin())->boundsFast(); - for (const_iterator it = ++(pv.begin()); it != pv.end(); ++it) - { + if (empty()) return bound; + + bound = front().boundsFast(); + for (const_iterator it = ++begin(); it != end(); ++it) { bound.unionWith(it->boundsFast()); } return bound; } -OptRect bounds_exact( PathVector const& pv ) +OptRect PathVector::boundsExact() const { - typedef PathVector::const_iterator const_iterator; - OptRect bound; - if (pv.empty()) return bound; - - bound = (pv.begin())->boundsExact(); - for (const_iterator it = ++(pv.begin()); it != pv.end(); ++it) - { + if (empty()) return bound; + + bound = front().boundsExact(); + for (const_iterator it = ++begin(); it != end(); ++it) { bound.unionWith(it->boundsExact()); } return bound; } -/* Note: undefined for empty pathvectors or pathvectors with empty paths. - * */ -boost::optional nearestPoint(PathVector const & path_in, Point const& _point, double *distance_squared) +std::vector PathVector::intersect(PathVector const &other, Coord precision) const { - boost::optional retval; - - double mindsq = infinity(); - unsigned int i = 0; - for (Geom::PathVector::const_iterator pit = path_in.begin(); pit != path_in.end(); ++pit) { - double dsq; - double t = pit->nearestPoint(_point, &dsq); - //std::cout << t << "," << dsq << std::endl; - if (dsq < mindsq) { - mindsq = dsq; - retval = PathVectorPosition(i, t); + typedef PathVectorPosition PVPos; + std::vector result; + for (std::size_t i = 0; i < size(); ++i) { + for (std::size_t j = 0; j < other.size(); ++j) { + std::vector xs = (*this)[i].intersect(other[j]); + for (std::size_t k = 0; k < xs.size(); ++k) { + PVIntersection pvx(PVPos(i, xs[k].first), PVPos(j, xs[k].second), xs[k].point()); + result.push_back(pvx); + } } + } + return result; +} - ++i; +int PathVector::winding(Point const &p) const +{ + int wind = 0; + for (const_iterator i = begin(); i != end(); ++i) { + wind += i->winding(p); } + return wind; +} - if (distance_squared) { - *distance_squared = mindsq; +boost::optional PathVector::nearestPosition(Point const &p, Coord *dist) const +{ + boost::optional retval; + + Coord mindist = infinity(); + for (size_type i = 0; i < size(); ++i) { + Coord d; + PathPosition pos = (*this)[i].nearestPosition(p, &d); + if (d < mindist) { + mindist = d; + retval = Position(i, pos.curve_index, pos.t); + } + } + + if (dist) { + *dist = mindist; } return retval; } -std::vector allNearestPoints(PathVector const & path_in, Point const& _point, double *distance_squared) +std::vector PathVector::allNearestPositions(Point const &p, Coord *dist) const { - std::vector retval; - - double mindsq = infinity(); - unsigned int i = 0; - for (Geom::PathVector::const_iterator pit = path_in.begin(); pit != path_in.end(); ++pit) { - double dsq; - double t = pit->nearestPoint(_point, &dsq); - if (dsq < mindsq) { - mindsq = dsq; - retval.push_back(PathVectorPosition(i, t)); + std::vector retval; + + Coord mindist = infinity(); + for (size_type i = 0; i < size(); ++i) { + Coord d; + PathPosition pos = (*this)[i].nearestPosition(p, &d); + if (d < mindist) { + mindist = d; + retval.clear(); + } + if (d <= mindist) { + retval.push_back(Position(i, pos.curve_index, pos.t)); } - - ++i; } - if (distance_squared) { - *distance_squared = mindsq; + if (dist) { + *dist = mindist; } return retval; +} +PathVectorPosition PathVector::_getPosition(Coord t) const +{ + Position ret; + Coord rest = 0; + ret.t = modf(t, &rest); + ret.curve_index = rest; + for (; ret.path_index < size(); ++ret.path_index) { + unsigned s = _data.at(ret.path_index).size_default(); + if (s > ret.curve_index) break; + // special case for the last point + if (s == ret.curve_index && ret.path_index + 1 == size()) { + --ret.curve_index; + ret.t = 1; + break; + } + ret.curve_index -= s; + } + return ret; } } // namespace Geom -#endif // SEEN_GEOM_PATHVECTOR_CPP - /* Local Variables: mode:c++ diff --git a/src/2geom/pathvector.h b/src/2geom/pathvector.h index e875e915f..6765d6bc0 100644 --- a/src/2geom/pathvector.h +++ b/src/2geom/pathvector.h @@ -1,13 +1,11 @@ -/** - * \file - * \brief PathVector - std::vector containing Geom::Path. - * This file provides a set of operations that can be performed on PathVector, - * e.g. an affine transform. +/** @file + * @brief PathVector - a sequence of subpaths *//* * Authors: - * Johan Engelen + * Johan Engelen + * Krzysztof Kosiński * - * Copyright 2008 authors + * Copyright 2008-2014 authors * * This library is free software; you can redistribute it and/or * modify it either under the terms of the GNU Lesser General Public @@ -36,93 +34,247 @@ #ifndef LIB2GEOM_SEEN_PATHVECTOR_H #define LIB2GEOM_SEEN_PATHVECTOR_H +#include +#include +#include #include <2geom/forward.h> #include <2geom/path.h> #include <2geom/transforms.h> namespace Geom { -typedef std::vector PathVector; - -/* general path transformation: */ -inline -void operator*= (PathVector & path_in, Affine const &m) { - for(PathVector::iterator it = path_in.begin(); it != path_in.end(); ++it) { - (*it) *= m; - } -} -inline -PathVector operator*(PathVector const & path_in, Affine const &m) { - PathVector ret(path_in); - ret *= m; - return ret; -} - -/* specific path transformations: Translation: - * This makes it possible to make optimized implementations for Translate transforms */ -inline -void operator*= (PathVector & path_in, Translate const &m) { - for(PathVector::iterator it = path_in.begin(); it != path_in.end(); ++it) { - (*it) *= m; - } -} -inline -PathVector operator*(PathVector const & path_in, Translate const &m) { - PathVector ret(path_in); - ret *= m; - return ret; -} - -/* user friendly approach to Translate transforms: just add an offset Point to the whole path */ -inline -void operator+=(PathVector &path_in, Point const &p) { - for(PathVector::iterator it = path_in.begin(); it != path_in.end(); ++it) { - (*it) *= Translate(p); - } -} -inline -PathVector operator+(PathVector const &path_in, Point const &p) { - PathVector ret(path_in); - ret *= Translate(p); - return ret; -} - -inline -Geom::Point initialPoint(PathVector const &path_in) +/** @brief Position (generalized time value) in the path vector. + * + * This class exists because mapping the range of multiple curves onto the same interval + * as the curve index, we lose some precision. For instance, a path with 16 curves will + * have 4 bits less precision than a path with 1 curve. If you need high precision results + * in long paths, use this class and related methods instead of the standard methods + * pointAt(), nearestTime() and so on. + * + * @ingroup Paths */ +struct PathVectorPosition + : public PathPosition + , boost::totally_ordered { - return path_in.front().initialPoint(); -} + size_type path_index; ///< Index of the path in the vector -inline -Geom::Point finalPoint(PathVector const &path_in) -{ - return path_in.back().finalPoint(); -} - -PathVector reverse_paths_and_order (PathVector const & path_in); - -OptRect bounds_fast( PathVector const & pv ); -OptRect bounds_exact( PathVector const & pv ); - -struct PathVectorPosition { - // pathvector[path_nr].pointAt(t) is the position - unsigned int path_nr; - double t; - PathVectorPosition() : - path_nr(0), - t(0) - {} - PathVectorPosition(unsigned int path_nr, - double t) : path_nr(path_nr), t(t) {} + PathVectorPosition() : PathPosition(0, 0), path_index(0) {} + PathVectorPosition(size_type _i, size_type _c, Coord _t) + : PathPosition(_c, _t), path_index(_i) {} + PathVectorPosition(size_type _i, PathPosition const &pos) + : PathPosition(pos), path_index(_i) {} + + bool operator<(PathVectorPosition const &other) const { + if (path_index < other.path_index) return true; + if (path_index == other.path_index) { + return static_cast(*this) < static_cast(other); + } + return false; + } + bool operator==(PathVectorPosition const &other) const { + return path_index == other.path_index + && static_cast(*this) == static_cast(other); + } + + PathPosition const &asPathPosition() const { + return *static_cast(this); + } +}; + +typedef Intersection PathVectorIntersection; +typedef PathVectorIntersection PVIntersection; ///< Alias to save typing + +template <> +struct ShapeTraits { + typedef PathVectorPosition TimeType; + //typedef PathVectorInterval IntervalType; + typedef PathVector AffineClosureType; + typedef PathVectorIntersection IntersectionType; }; -boost::optional nearestPoint(PathVector const & path_in, Point const& _point, double *distance_squared = NULL); -std::vector allNearestPoints(PathVector const & path_in, Point const& _point, double *distance_squared = NULL); +/** @brief Sequence of subpaths. + * + * This class corresponds to the SVG notion of a path: + * a sequence of any number of open or closed contiguous subpaths. + * Unlike Path, this class is closed under boolean operations. + * + * If you want to represent an arbitrary shape, this is the best class to use. + * Shapes with a boundary that is composed of only a single contiguous + * component can be represented with Path instead. + * + * @ingroup Paths + */ +class PathVector + : MultipliableNoncommutative< PathVector, Affine + , MultipliableNoncommutative< PathVector, Translate + , MultipliableNoncommutative< PathVector, Scale + , MultipliableNoncommutative< PathVector, Rotate + , MultipliableNoncommutative< PathVector, HShear + , MultipliableNoncommutative< PathVector, VShear + , MultipliableNoncommutative< PathVector, Zoom + , boost::addable< PathVector + , boost::equality_comparable< PathVector + > > > > > > > > > +{ + typedef std::vector Sequence; +public: + typedef PathVectorPosition Position; + typedef Sequence::iterator iterator; + typedef Sequence::const_iterator const_iterator; + typedef Sequence::size_type size_type; + typedef Path value_type; + typedef Path &reference; + typedef Path const &const_reference; + typedef Path *pointer; + typedef std::ptrdiff_t difference_type; + + PathVector() {} + PathVector(Path const &p) + : _data(1, p) + {} + template + PathVector(InputIter first, InputIter last) + : _data(first, last) + {} + + /// Check whether the vector contains any paths. + bool empty() const { return _data.empty(); } + /// Get the number of paths in the vector. + size_type size() const { return _data.size(); } + /// Get the total number of curves in the vector. + size_type curveCount() const; + + iterator begin() { return _data.begin(); } + iterator end() { return _data.end(); } + const_iterator begin() const { return _data.begin(); } + const_iterator end() const { return _data.end(); } + Path &operator[](size_type index) { + return _data[index]; + } + Path const &operator[](size_type index) const { + return _data[index]; + } + Path &at(size_type index) { + return _data.at(index); + } + Path const &at(size_type index) const { + return _data.at(index); + } + Path &front() { return _data.front(); } + Path const &front() const { return _data.front(); } + Path &back() { return _data.back(); } + Path const &back() const { return _data.back(); } + /// Append a path at the end. + void push_back(Path const &path) { + _data.push_back(path); + } + /// Remove the last path. + void pop_back() { + _data.pop_back(); + } + iterator insert(iterator pos, Path const &p) { + return _data.insert(pos, p); + } + template + void insert(iterator out, InputIter first, InputIter last) { + _data.insert(out, first, last); + } + /// Remove a path from the vector. + iterator erase(iterator i) { + return _data.erase(i); + } + /// Remove a range of paths from the vector. + iterator erase(iterator first, iterator last) { + return _data.erase(first, last); + } + /// Remove all paths from the vector. + void clear() { _data.clear(); } + /** @brief Change the number of paths. + * If the vector size increases, it is passed with paths that contain only + * a degenerate closing segment at (0,0). */ + void resize(size_type n) { _data.resize(n); } + /** @brief Reverse the direction of paths in the vector. + * @param reverse_paths If this is true, the order of paths is reversed as well; + * otherwise each path is reversed, but their order in the + * PathVector stays the same */ + void reverse(bool reverse_paths = true); + /** @brief Get a new vector with reversed direction of paths. + * @param reverse_paths If this is true, the order of paths is reversed as well; + * otherwise each path is reversed, but their order in the + * PathVector stays the same */ + PathVector reversed(bool reverse_paths = true) const; + + /// Get the range of allowed time values. + Interval timeRange() const { + Interval ret(0, curveCount()); return ret; + } + /** @brief Get the first point in the first path of the vector. + * This method will throw an exception if the vector doesn't contain any paths. */ + Point initialPoint() const { + return _data.front().initialPoint(); + } + /** @brief Get the last point in the last path of the vector. + * This method will throw an exception if the vector doesn't contain any paths. */ + Point finalPoint() const { + return _data.back().finalPoint(); + } + Path &pathAt(Coord t, Coord *rest = NULL); + Path const &pathAt(Coord t, Coord *rest = NULL) const; + Curve const &curveAt(Coord t, Coord *rest = NULL) const; + Coord valueAt(Coord t, Dim2 d) const; + Point pointAt(Coord t) const; + + Path &pathAt(Position const &pos) { + return const_cast(static_cast(this)->pathAt(pos)); + } + Path const &pathAt(Position const &pos) const { + return at(pos.path_index); + } + Curve const &curveAt(Position const &pos) const { + return at(pos.path_index).at(pos.curve_index); + } + Point pointAt(Position const &pos) const { + return at(pos.path_index).at(pos.curve_index).pointAt(pos.t); + } + Coord valueAt(Position const &pos, Dim2 d) const { + return at(pos.path_index).at(pos.curve_index).valueAt(pos.t, d); + } + + OptRect boundsFast() const; + OptRect boundsExact() const; + + template + BOOST_CONCEPT_REQUIRES(((TransformConcept)), (PathVector &)) + operator*=(T const &t) { + if (empty()) return *this; + for (iterator i = begin(); i != end(); ++i) { + *i *= t; + } + return *this; + } + + bool operator==(PathVector const &other) const { + return boost::range::equal(_data, other._data); + } + + std::vector intersect(PathVector const &other, Coord precision = EPSILON) const; + + /** @brief Determine the winding number at the specified point. + * This is simply the sum of winding numbers for constituent paths. */ + int winding(Point const &p) const; + + Coord nearestTime(Point const &p) const; + boost::optional nearestPosition(Point const &p, Coord *dist = NULL) const; + std::vector allNearestPositions(Point const &p, Coord *dist = NULL) const; + +private: + Position _getPosition(Coord t) const; + + Sequence _data; +}; -inline -Point pointAt(PathVector const & path_in, PathVectorPosition const &pvp) { - return path_in[pvp.path_nr].pointAt(pvp.t); -} +inline OptRect bounds_fast(PathVector const &pv) { return pv.boundsFast(); } +inline OptRect bounds_exact(PathVector const &pv) { return pv.boundsExact(); } } // end namespace Geom diff --git a/src/2geom/piecewise.h b/src/2geom/piecewise.h index ab8417254..981d67144 100644 --- a/src/2geom/piecewise.h +++ b/src/2geom/piecewise.h @@ -1,7 +1,6 @@ -/** - * \file - * \brief Piecewise function class - * +/** @file + * @brief Piecewise function class + *//* * Copyright 2007 Michael Sloan * * This library is free software; you can redistribute it and/or @@ -29,8 +28,8 @@ * */ -#ifndef SEEN_GEOM_PW_SB_H -#define SEEN_GEOM_PW_SB_H +#ifndef LIB2GEOM_SEEN_PIECEWISE_H +#define LIB2GEOM_SEEN_PIECEWISE_H #include #include @@ -933,7 +932,7 @@ Piecewise lerp(double t, Piecewise const &a, Piecewise b) { } } -#endif //SEEN_GEOM_PW_SB_H +#endif //LIB2GEOM_SEEN_PIECEWISE_H /* Local Variables: mode:c++ diff --git a/src/2geom/point.cpp b/src/2geom/point.cpp index b0b00b5da..e2662becd 100644 --- a/src/2geom/point.cpp +++ b/src/2geom/point.cpp @@ -146,8 +146,8 @@ bool is_zero(Point const &p) { /** @brief True if the point has a length near 1. The are_near() function is used. * @relates Point */ -bool is_unit_vector(Point const &p) { - return are_near(L2(p), 1.0); +bool is_unit_vector(Point const &p, Coord eps) { + return are_near(L2(p), 1.0, eps); } /** @brief Return the angle between the point and the +X axis. * @return Angle in \f$(-\pi, \pi]\f$. @@ -161,7 +161,7 @@ Coord atan2(Point const &p) { * @return Angle in \f$(-\pi, \pi]\f$. * @relates Point */ Coord angle_between(Point const &a, Point const &b) { - return std::atan2(cross(b,a), dot(b,a)); + return std::atan2(cross(a,b), dot(a,b)); } /** @brief Create a normalized version of a point. diff --git a/src/2geom/point.h b/src/2geom/point.h index 23dcfd54f..3e56ae358 100644 --- a/src/2geom/point.h +++ b/src/2geom/point.h @@ -1,6 +1,5 @@ -/** - * \file - * \brief Cartesian point / 2D vector and related operations +/** @file + * @brief Cartesian point / 2D vector and related operations *//* * Authors: * Michael G. Sloan @@ -33,8 +32,8 @@ * the specific language governing rights and limitations. */ -#ifndef SEEN_Geom_POINT_H -#define SEEN_Geom_POINT_H +#ifndef LIB2GEOM_SEEN_POINT_H +#define LIB2GEOM_SEEN_POINT_H #include "config.h" #include @@ -59,10 +58,14 @@ class Point , MultipliableNoncommutative< Point, HShear , MultipliableNoncommutative< Point, VShear , MultipliableNoncommutative< Point, Zoom - > > > > > > > > > > // this uses chaining so it looks weird, but works + > > > > > > > > > > // base class chaining, see documentation for Boost.Operator { Coord _pt[2]; public: + typedef Coord D1Value; + typedef Coord &D1Reference; + typedef Coord const &D1ConstReference; + /// @name Create points /// @{ /** Construct a point on the origin. */ @@ -116,6 +119,11 @@ public: * @return Length of the vector from origin to this point */ Coord length() const { return hypot(_pt[0], _pt[1]); } void normalize(); + Point normalized() const { + Point ret(*this); + ret.normalize(); + return ret; + } /** @brief Return a point like this point but rotated -90 degrees. * If the y axis grows downwards and the x axis grows to the @@ -223,16 +231,25 @@ public: } /// @} - /** @brief Lexicographical ordering functor. */ - template struct LexOrder; + /** @brief Lexicographical ordering functor. + * @param d The dimension with higher significance */ + template struct LexLess; + template struct LexGreater; + //template , typename Second = std::less > LexOrder; /** @brief Lexicographical ordering functor with runtime dimension. */ - class LexOrderRt { - public: - LexOrderRt(Dim2 d) : dim(d) {} - inline bool operator()(Point const &a, Point const &b); + struct LexLessRt { + LexLessRt(Dim2 d) : dim(d) {} + inline bool operator()(Point const &a, Point const &b) const; + private: + Dim2 dim; + }; + struct LexGreaterRt { + LexGreaterRt(Dim2 d) : dim(d) {} + inline bool operator()(Point const &a, Point const &b) const; private: Dim2 dim; }; + //template , typename Second = std::less > LexOrder friend inline std::ostream &operator<< (std::ostream &out_file, const Geom::Point &in_pnt); }; @@ -245,18 +262,47 @@ inline std::ostream &operator<< (std::ostream &out_file, const Geom::Point &in_p return out_file; } -template<> struct Point::LexOrder { - bool operator()(Point const &a, Point const &b) { +template<> struct Point::LexLess { + typedef std::less Primary; + typedef std::less Secondary; + typedef std::less XOrder; + typedef std::less YOrder; + bool operator()(Point const &a, Point const &b) const { return a[X] < b[X] || (a[X] == b[X] && a[Y] < b[Y]); } }; -template<> struct Point::LexOrder { - bool operator()(Point const &a, Point const &b) { +template<> struct Point::LexLess { + typedef std::less Primary; + typedef std::less Secondary; + typedef std::less XOrder; + typedef std::less YOrder; + bool operator()(Point const &a, Point const &b) const { return a[Y] < b[Y] || (a[Y] == b[Y] && a[X] < b[X]); } }; -inline bool Point::LexOrderRt::operator()(Point const &a, Point const &b) { - return dim ? Point::LexOrder()(a, b) : Point::LexOrder()(a, b); +template<> struct Point::LexGreater { + typedef std::greater Primary; + typedef std::greater Secondary; + typedef std::greater XOrder; + typedef std::greater YOrder; + bool operator()(Point const &a, Point const &b) const { + return a[X] > b[X] || (a[X] == b[X] && a[Y] > b[Y]); + } +}; +template<> struct Point::LexGreater { + typedef std::greater Primary; + typedef std::greater Secondary; + typedef std::greater XOrder; + typedef std::greater YOrder; + bool operator()(Point const &a, Point const &b) const { + return a[Y] > b[Y] || (a[Y] == b[Y] && a[X] > b[X]); + } +}; +inline bool Point::LexLessRt::operator()(Point const &a, Point const &b) const { + return dim ? Point::LexLess()(a, b) : Point::LexLess()(a, b); +} +inline bool Point::LexGreaterRt::operator()(Point const &a, Point const &b) const { + return dim ? Point::LexGreater()(a, b) : Point::LexGreater()(a, b); } /** @brief Compute the second (Euclidean) norm of @a p. @@ -265,8 +311,7 @@ inline bool Point::LexOrderRt::operator()(Point const &a, Point const &b) { * in a double. * @return \f$\sqrt{p_X^2 + p_Y^2}\f$ * @relates Point */ -inline Coord L2(Point const &p) -{ +inline Coord L2(Point const &p) { return p.length(); } @@ -274,28 +319,10 @@ inline Coord L2(Point const &p) * Warning: this can overflow where L2 won't. * @return \f$p_X^2 + p_Y^2\f$ * @relates Point */ -inline Coord L2sq(Point const &p) -{ +inline Coord L2sq(Point const &p) { return p[0]*p[0] + p[1]*p[1]; } -//IMPL: NearConcept -/** @brief Nearness predicate for points. - * True if neither coordinate of @a a is further than @a eps from the corresponding - * coordinate of @a b. - * @relates Point */ -inline bool are_near(Point const &a, Point const &b, double const eps=EPSILON) -{ - return ( are_near(a[X],b[X],eps) && are_near(a[Y],b[Y],eps) ); -} - -/** @brief Return a point halfway between the specified ones. - * @relates Point */ -inline Point middle_point(Point const& P1, Point const& P2) -{ - return (P1 + P2) / 2; -} - /** @brief Returns p * Geom::rotate_degrees(90), but more efficient. * * Angle direction in 2Geom: If you use the traditional mathematics convention that y @@ -305,8 +332,7 @@ inline Point middle_point(Point const& P1, Point const& P2) * * There is no function to rotate by -90 degrees: use -rot90(p) instead. * @relates Point */ -inline Point rot90(Point const &p) -{ +inline Point rot90(Point const &p) { return Point(-p[Y], p[X]); } @@ -317,9 +343,14 @@ inline Point rot90(Point const &p) * @return Point on a line between a and b. The ratio of its distance from a * and the distance between a and b will be equal to t. * @relates Point */ -inline Point lerp(double const t, Point const &a, Point const &b) -{ - return (a * (1 - t) + b * t); +inline Point lerp(Coord t, Point const &a, Point const &b) { + return (1 - t) * a + t * b; +} + +/** @brief Return a point halfway between the specified ones. + * @relates Point */ +inline Point middle_point(Point const &p1, Point const &p2) { + return lerp(0.5, p1, p2); } /** @brief Compute the dot product of a and b. @@ -328,45 +359,60 @@ inline Point lerp(double const t, Point const &a, Point const &b) * and the sign depends on whether they point in the same direction (+) or opposite ones (-). * @return \f$a \cdot b = a_X b_X + a_Y b_Y\f$. * @relates Point */ -inline Coord dot(Point const &a, Point const &b) -{ - return a[0] * b[0] + a[1] * b[1]; +inline Coord dot(Point const &a, Point const &b) { + return a[X] * b[X] + a[Y] * b[Y]; } /** @brief Compute the 2D cross product. - * Defined as dot(a, b.cw()). This means it will be zero for parallel vectors, - * and its absolute value highest for perpendicular vectors. + * This is also known as "perp dot product". It will be zero for parallel vectors, + * and the absolute value will be highest for perpendicular vectors. + * @return \f$a \times b = a_X b_Y - a_Y b_X\f$. * @relates Point*/ inline Coord cross(Point const &a, Point const &b) { - return dot(a, b.cw()); + // equivalent implementation: + // return dot(a, b.ccw()); + return a[X] * b[Y] - a[Y] * b[X]; } -/** @brief Compute the (Euclidean) distance between points. - * @relates Point */ -inline Coord distance (Point const &a, Point const &b) -{ - return L2(a - b); +/// Compute the (Euclidean) distance between points. +/// @relates Point +inline Coord distance (Point const &a, Point const &b) { + return (a - b).length(); } -/** @brief Compute the square of the distance between points. - * @relates Point */ -inline Coord distanceSq (Point const &a, Point const &b) -{ +/// Compute the square of the distance between points. +/// @relates Point +inline Coord distanceSq (Point const &a, Point const &b) { return L2sq(a - b); } +//IMPL: NearConcept +/// Test whether two points are no further apart than some threshold. +/// @relates Point +inline bool are_near(Point const &a, Point const &b, double eps = EPSILON) { + return are_near(distance(a, b), 0, eps); +} + +/// Test whether three points lie approximately on the same line. +/// @relates Point +inline bool are_collinear(Point const& p1, Point const& p2, Point const& p3, + double eps = EPSILON) +{ + return are_near( cross(p3, p2) - cross(p3, p1) + cross(p2, p1), 0, eps); +} + Point unit_vector(Point const &a); Coord L1(Point const &p); Coord LInfty(Point const &p); bool is_zero(Point const &p); -bool is_unit_vector(Point const &p); +bool is_unit_vector(Point const &p, Coord eps = EPSILON); double atan2(Point const &p); double angle_between(Point const &a, Point const &b); Point abs(Point const &b); Point constrain_angle(Point const &A, Point const &B, unsigned int n = 4, Geom::Point const &dir = Geom::Point(1,0)); -} /* namespace Geom */ +} // end namespace Geom // This is required to fix a bug in GCC 4.3.3 (and probably others) that causes the compiler // to try to instantiate the iterator_traits template and fail. Probably it thinks that Point @@ -375,7 +421,7 @@ namespace std { template <> class iterator_traits {}; } -#endif /* !SEEN_Geom_POINT_H */ +#endif // LIB2GEOM_SEEN_POINT_H /* Local Variables: diff --git a/src/2geom/quadtree.cpp b/src/2geom/quadtree.cpp index 98030c424..76dc68774 100644 --- a/src/2geom/quadtree.cpp +++ b/src/2geom/quadtree.cpp @@ -211,10 +211,6 @@ void QuadTree::insert(double x0, double y0, double x1, double y1, int shape) { // check if rect's bounding box has size 1x1. This means that rect is defined by 2 points // that are in the same place. if( ( fabs(bxx0 - bxx1) < 1.0 ) && ( fabs(byy0 - byy1) < 1.0 )){ - bxx0 = floor(bxx0); - bxx1 = floor(bxx1); - byy0 = floor(byy0); - byy1 = floor(byy1); break; } diff --git a/src/2geom/quadtree.h b/src/2geom/quadtree.h index 949a9b898..62f2b8321 100644 --- a/src/2geom/quadtree.h +++ b/src/2geom/quadtree.h @@ -32,6 +32,9 @@ * */ +#ifndef LIB2GEOM_SEEN_QUADTREE_H +#define LIB2GEOM_SEEN_QUADTREE_H + #include #include @@ -64,6 +67,8 @@ public: * this case should be never reached */ assert(false); } + assert(false); + return Rect(); } }; @@ -87,6 +92,7 @@ private: }; +#endif /* Local Variables: mode:c++ diff --git a/src/2geom/ray.h b/src/2geom/ray.h index 2fda06ff5..a336e3132 100644 --- a/src/2geom/ray.h +++ b/src/2geom/ray.h @@ -98,7 +98,7 @@ public: } return result; } - Coord nearestPoint(Point const& point) const { + Coord nearestTime(Point const& point) const { if ( isDegenerate() ) return 0; double t = dot(point - _origin, _versor); if (t < 0) t = 0; @@ -123,7 +123,7 @@ public: inline double distance(Point const& _point, Ray const& _ray) { - double t = _ray.nearestPoint(_point); + double t = _ray.nearestTime(_point); return ::Geom::distance(_point, _ray.pointAt(t)); } diff --git a/src/2geom/rect.cpp b/src/2geom/rect.cpp index 0cb842d29..383e72c8e 100644 --- a/src/2geom/rect.cpp +++ b/src/2geom/rect.cpp @@ -84,6 +84,17 @@ Coord distance(Point const &p, Rect const &rect) return hypot(dx, dy); } +Coord distanceSq(Point const &p, OptRect const &rect) +{ + if (!rect) return std::numeric_limits::max(); + return distanceSq(p, *rect); +} +Coord distance(Point const &p, OptRect const &rect) +{ + if (!rect) return std::numeric_limits::max(); + return distance(p, *rect); +} + } // namespace Geom /* diff --git a/src/2geom/rect.h b/src/2geom/rect.h index 2516bcfa6..51daf6b5a 100644 --- a/src/2geom/rect.h +++ b/src/2geom/rect.h @@ -75,6 +75,10 @@ public: * @param eps Maximum value of the area to consider empty * @return True if rectangle has an area smaller than tolerance, false otherwise */ bool hasZeroArea(Coord eps = EPSILON) const { return (area() <= eps); } + /// Check whether the rectangle has finite area + bool isFinite() const { return (*this)[X].isFinite() && (*this)[Y].isFinite(); } + /// Calculate the diameter of the smallest circle that would contain the rectangle. + Coord diameter() const { return distance(corner(0), corner(2)); } /// @} /// @name Test other rectangles and points for inclusion. @@ -153,6 +157,10 @@ public: Coord distanceSq(Point const &p, Rect const &rect); Coord distance(Point const &p, Rect const &rect); +/// Minimum square of distance to rectangle, or infinity if empty. +Coord distanceSq(Point const &p, OptRect const &rect); +/// Minimum distance to rectangle, or infinity if empty. +Coord distance(Point const &p, OptRect const &rect); inline bool Rect::interiorContains(OptRect const &r) const { return !r || interiorContains(static_cast(*r)); diff --git a/src/2geom/recursive-bezier-intersection.cpp b/src/2geom/recursive-bezier-intersection.cpp index 548065196..e86192f54 100644 --- a/src/2geom/recursive-bezier-intersection.cpp +++ b/src/2geom/recursive-bezier-intersection.cpp @@ -13,7 +13,6 @@ unsigned intersect_steps = 0; using std::vector; -using std::swap; namespace Geom { @@ -33,7 +32,7 @@ public: minax = p[0][X]; // These are the most likely to be extremal maxax = p.back()[X]; if( minax > maxax ) - swap(minax, maxax); + std::swap(minax, maxax); for(unsigned i = 1; i < p.size()-1; i++) { if( p[i][X] < minax ) minax = p[i][X]; @@ -44,7 +43,7 @@ public: minay = p[0][Y]; // These are the most likely to be extremal maxay = p.back()[Y]; if( minay > maxay ) - swap(minay, maxay); + std::swap(minay, maxay); for(unsigned i = 1; i < p.size()-1; i++) { if( p[i][Y] < minay ) minay = p[i][Y]; diff --git a/src/2geom/region.cpp b/src/2geom/region.cpp deleted file mode 100644 index 8cfb1c68c..000000000 --- a/src/2geom/region.cpp +++ /dev/null @@ -1,45 +0,0 @@ -#include <2geom/region.h> -#include <2geom/utils.h> - -#include <2geom/shape.h> - -namespace Geom { - -Region Region::operator*(Affine const &m) const { - Region r((m.flips() ? boundary.reverse() : boundary) * m, fill); - if(box && m.isZoom()) r.box = (*box) * m; - return r; -} - -bool Region::invariants() const { - return self_crossings(boundary).empty(); -} - -unsigned outer_index(Regions const &ps) { - if(ps.size() <= 1 || ps[0].contains(ps[1])) { - return 0; - } else { - /* Since we've already shown that chunks[0] is not outside - it can be used as an exemplar inner. */ - Point exemplar = Path(ps[0]).initialPoint(); - for(unsigned i = 1; i < ps.size(); i++) { - if(ps[i].contains(exemplar)) { - return i; - } - } - } - return ps.size(); -} - -} - -/* - Local Variables: - mode:c++ - c-file-style:"stroustrup" - c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) - indent-tabs-mode:nil - fill-column:99 - End: -*/ -// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 : diff --git a/src/2geom/region.h b/src/2geom/region.h deleted file mode 100644 index 06a4f63e9..000000000 --- a/src/2geom/region.h +++ /dev/null @@ -1,130 +0,0 @@ -/** - * \file - * \brief Uncrossed path for boolean algorithms - *//* - * Authors: - * ? - * - * Copyright ?-? authors - * - * This library is free software; you can redistribute it and/or - * modify it either under the terms of the GNU Lesser General Public - * License version 2.1 as published by the Free Software Foundation - * (the "LGPL") or, at your option, under the terms of the Mozilla - * Public License Version 1.1 (the "MPL"). If you do not alter this - * notice, a recipient may use your version of this file under either - * the MPL or the LGPL. - * - * You should have received a copy of the LGPL along with this library - * in the file COPYING-LGPL-2.1; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * You should have received a copy of the MPL along with this library - * in the file COPYING-MPL-1.1 - * - * The contents of this file are subject to the Mozilla Public License - * Version 1.1 (the "License"); you may not use this file except in - * compliance with the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY - * OF ANY KIND, either express or implied. See the LGPL or the MPL for - * the specific language governing rights and limitations. - * - */ - -#ifndef __2GEOM_REGION_H -#define __2GEOM_REGION_H - -#include <2geom/path.h> -#include <2geom/path-intersection.h> - -namespace Geom { - -class Shape; - -class Region { - friend Crossings crossings(Region const &a, Region const &b); - friend class Shape; - friend Shape shape_boolean(bool rev, Shape const & a, Shape const & b, CrossingSet const & crs); - - Path boundary; - mutable OptRect box; - bool fill; - public: - Region() : fill(true) {} - explicit Region(Path const &p) : boundary(p) { fill = path_direction(p); } - Region(Path const &p, bool dir) : boundary(p), fill(dir) {} - Region(Path const &p, OptRect const &b) : boundary(p), box(b) { fill = path_direction(p); } - Region(Path const &p, OptRect const &b, bool dir) : boundary(p), box(b), fill(dir) {} - - unsigned size() const { return boundary.size(); } - - bool isFill() const { return fill; } - Region asFill() const { if(fill) return Region(*this); else return inverse(); } - Region asHole() const { if(fill) return inverse(); else return Region(*this); } - - operator Path() const { return boundary; } - Rect boundsFast() const { - if(!box) box = boundary.boundsFast(); /// \todo this doesn't look right at all... - return *box; - } - - bool contains(Point const &p) const { - if(box && !box->contains(p)) return false; - return Geom::contains(boundary, p); - } - bool contains(Region const &other) const { return contains(other.boundary.initialPoint()); } - - bool includes(Point const &p) const { - return logical_xor(!fill, contains(p)); - } - - Region inverse() const { return Region(boundary.reverse(), box, !fill); } - - Region operator*(Affine const &m) const; - - bool invariants() const; -}; - -typedef std::vector Regions; - -unsigned outer_index(Regions const &ps); - -//assumes they're already sanitized somewhat -inline Regions regions_from_paths(std::vector const &ps) { - Regions res; - for(unsigned i = 0; i < ps.size(); i++) - res.push_back(Region(ps[i])); - return res; -} - -inline std::vector paths_from_regions(Regions const &rs) { - std::vector res; - for(unsigned i = 0; i < rs.size(); i++) - res.push_back(rs[i]); - return res; -} - -Regions sanitize_path(Path const &p); - -Regions region_boolean(bool rev, Region const & a, Region const & b, Crossings const &cr); -Regions region_boolean(bool rev, Region const & a, Region const & b, Crossings const & cr_a, Crossings const & cr_b); - -inline Regions region_boolean(bool rev, Region const & a, Region const & b) { - return region_boolean(rev, a, b, crossings(a, b)); -} - -} - -#endif - -/* - Local Variables: - mode:c++ - c-file-style:"stroustrup" - c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) - indent-tabs-mode:nil - fill-column:99 - End: -*/ -// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 : diff --git a/src/2geom/sbasis-2d.cpp b/src/2geom/sbasis-2d.cpp index aa5018e9e..53b09cd35 100644 --- a/src/2geom/sbasis-2d.cpp +++ b/src/2geom/sbasis-2d.cpp @@ -169,7 +169,7 @@ sb2d_cubic_solve(SBasis2d const &f, Geom::Point const &A, Geom::Point const &B){ std::vector > candidates = cubics_fitting_curvature(A,B,V0,V1,D2fVV0,D2fVV1); if (candidates.empty()) { - return D2(Linear(A[X],B[X]),Linear(A[Y],B[Y])); + return D2(SBasis(Linear(A[X],B[X])), SBasis(Linear(A[Y],B[Y]))); } //TODO: I'm sure std algorithm could do that for me... double error = -1; diff --git a/src/2geom/sbasis-2d.h b/src/2geom/sbasis-2d.h index 00429e259..c7d9b000a 100644 --- a/src/2geom/sbasis-2d.h +++ b/src/2geom/sbasis-2d.h @@ -33,8 +33,8 @@ * */ -#ifndef SEEN_SBASIS_2D_H -#define SEEN_SBASIS_2D_H +#ifndef LIB2GEOM_SEEN_SBASIS_2D_H +#define LIB2GEOM_SEEN_SBASIS_2D_H #include #include #include @@ -356,8 +356,9 @@ sb2dsolve(SBasis2d const &f, Geom::Point const &A, Geom::Point const &B, unsigne D2 sb2d_cubic_solve(SBasis2d const &f, Geom::Point const &A, Geom::Point const &B); -}; +} // end namespace Geom +#endif /* Local Variables: mode:c++ @@ -368,4 +369,3 @@ sb2d_cubic_solve(SBasis2d const &f, Geom::Point const &A, Geom::Point const &B); End: */ // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 : -#endif diff --git a/src/2geom/sbasis-curve.h b/src/2geom/sbasis-curve.h index a5c3f2ca7..a7b74dcee 100644 --- a/src/2geom/sbasis-curve.h +++ b/src/2geom/sbasis-curve.h @@ -37,7 +37,7 @@ #define LIB2GEOM_SEEN_SBASIS_CURVE_H #include <2geom/curve.h> -#include <2geom/nearest-point.h> +#include <2geom/nearest-time.h> #include <2geom/sbasis-geometric.h> #include <2geom/transforms.h> @@ -84,11 +84,10 @@ public: explicit SBasisCurve(D2 const &sb) : inner(sb) {} explicit SBasisCurve(Curve const &other) : inner(other.toSBasis()) {} -#ifndef DOXYGEN_SHOULD_SKIP_THIS virtual Curve *duplicate() const { return new SBasisCurve(*this); } virtual Point initialPoint() const { return inner.at0(); } virtual Point finalPoint() const { return inner.at1(); } - virtual bool isDegenerate() const { return inner.isConstant(); } + virtual bool isDegenerate() const { return inner.isConstant(0); } virtual Point pointAt(Coord t) const { return inner.valueAt(t); } virtual std::vector pointAndDerivatives(Coord t, unsigned n) const { return inner.valueAndDerivatives(t, n); @@ -106,33 +105,33 @@ public: return bounds_local(inner, i, deg); } virtual std::vector roots(Coord v, Dim2 d) const { return Geom::roots(inner[d] - v); } - virtual Coord nearestPoint( Point const& p, Coord from = 0, Coord to = 1 ) const { - return nearest_point(p, inner, from, to); + virtual Coord nearestTime( Point const& p, Coord from = 0, Coord to = 1 ) const { + return nearest_time(p, inner, from, to); } - virtual std::vector allNearestPoints( Point const& p, Coord from = 0, + virtual std::vector allNearestTimes( Point const& p, Coord from = 0, Coord to = 1 ) const { - return all_nearest_points(p, inner, from, to); + return all_nearest_times(p, inner, from, to); } virtual Coord length(Coord tolerance) const { return ::Geom::length(inner, tolerance); } virtual Curve *portion(Coord f, Coord t) const { return new SBasisCurve(Geom::portion(inner, f, t)); } - virtual Curve *transformed(Affine const &m) const { return new SBasisCurve(inner * m); } - virtual Curve &operator*=(Translate const &m) { - inner += m.vector(); - return *this; - }; + virtual void transform(Affine const &m) { inner = inner * m; } virtual Curve *derivative() const { return new SBasisCurve(Geom::derivative(inner)); } virtual D2 toSBasis() const { return inner; } + virtual bool operator==(Curve const &c) const { + SBasisCurve const *other = dynamic_cast(&c); + if (!other) return false; + return inner == other->inner; + } virtual int degreesOfFreedom() const { return inner[0].degreesOfFreedom() + inner[1].degreesOfFreedom(); } -#endif }; } // end namespace Geom diff --git a/src/2geom/sbasis-geometric.h b/src/2geom/sbasis-geometric.h index 43c624fb4..7f1e8aaba 100644 --- a/src/2geom/sbasis-geometric.h +++ b/src/2geom/sbasis-geometric.h @@ -1,15 +1,6 @@ -#ifndef _SBASIS_GEOMETRIC -#define _SBASIS_GEOMETRIC -#include <2geom/d2.h> -#include <2geom/piecewise.h> -#include - /** * \file * \brief two-dimensional geometric operators. - * - * Copyright 2007, JFBarraud - * Copyright 2007, njh * * These operators are built on a more 'polynomially robust' * transformation to map a function that takes a [0,1] parameter to a @@ -21,9 +12,42 @@ * from the various tangent directions at each end (angular jet). As * a result, the final path has a convergence behaviour derived from * that of the sin and cos series. -- njh + *//* + * Copyright 2007, JFBarraud + * Copyright 2007, njh + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. */ -namespace Geom{ +#ifndef LIB2GEOM_SEEN_SBASIS_GEOMETRIC_H +#define LIB2GEOM_SEEN_SBASIS_GEOMETRIC_H + +#include <2geom/d2.h> +#include <2geom/piecewise.h> +#include + +namespace Geom { Piecewise > cutAtRoots(Piecewise > const &M, double tol=1e-4); diff --git a/src/2geom/sbasis-math.h b/src/2geom/sbasis-math.h index e6d40a3de..e191dae62 100644 --- a/src/2geom/sbasis-math.h +++ b/src/2geom/sbasis-math.h @@ -1,7 +1,6 @@ -/** - * \file - * \brief some std functions to work with (pw)s-basis - * +/** @file + * @brief some std functions to work with (pw)s-basis + *//* * Authors: * Jean-Francois Barraud * @@ -36,8 +35,8 @@ //TODO: in all these functions, compute 'order' according to 'tol'. //TODO: use template to define the pw version automatically from the sb version? -#ifndef SEEN_GEOM_SB_CALCULS_H -#define SEEN_GEOM_SB_CALCULS_H +#ifndef LIB2GEOM_SEEN_SBASIS_MATH_H +#define LIB2GEOM_SEEN_SBASIS_MATH_H #include <2geom/sbasis.h> diff --git a/src/2geom/sbasis-poly.h b/src/2geom/sbasis-poly.h index e0bef9333..81eeca72c 100644 --- a/src/2geom/sbasis-poly.h +++ b/src/2geom/sbasis-poly.h @@ -1,13 +1,6 @@ -#ifndef _SBASIS_TO_POLY -#define _SBASIS_TO_POLY - -#include <2geom/poly.h> -#include <2geom/sbasis.h> - -/** - * \file - * \brief Conversion between SBasis and Poly. Not recommended for general use due to instability. - * +/** @file + * @brief Conversion between SBasis and Poly. Not recommended for general use due to instability. + *//* * Authors: * ? * @@ -35,9 +28,14 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY * OF ANY KIND, either express or implied. See the LGPL or the MPL for * the specific language governing rights and limitations. - * */ +#ifndef LIB2GEOM_SEEN_SBASIS_POLY_H +#define LIB2GEOM_SEEN_SBASIS_POLY_H + +#include <2geom/poly.h> +#include <2geom/sbasis.h> + namespace Geom{ SBasis poly_to_sbasis(Poly const & p); @@ -45,6 +43,7 @@ Poly sbasis_to_poly(SBasis const & s); }; +#endif /* Local Variables: mode:c++ @@ -55,5 +54,3 @@ Poly sbasis_to_poly(SBasis const & s); End: */ // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 : - -#endif diff --git a/src/2geom/sbasis-roots.cpp b/src/2geom/sbasis-roots.cpp index acf4e1abc..57bef4c0f 100644 --- a/src/2geom/sbasis-roots.cpp +++ b/src/2geom/sbasis-roots.cpp @@ -1,7 +1,38 @@ -/** root finding for sbasis functions. - * Copyright 2006 N Hurst - * Copyright 2007 JF Barraud +/** + * @file + * @brief Root finding for sbasis functions. + *//* + * Authors: + * Nathan Hurst + * JF Barraud + * Copyright 2006-2007 Authors + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + */ + + /* * It is more efficient to find roots of f(t) = c_0, c_1, ... all at once, rather than iterating. * * Todo/think about: @@ -98,20 +129,20 @@ OptInterval bounds_fast(const SBasis &sb, int order) { double b=sb[j][1]; double v, t = 0; - v = res[0]; + v = res.min(); if (v<0) t = ((b-a)/v+1)*0.5; if (v>=0 || t<0 || t>1) { - res[0] = std::min(a,b); - }else{ - res[0]=lerp(t, a+v*t, b); + res.setMin(std::min(a,b)); + } else { + res.setMin(lerp(t, a+v*t, b)); } - v = res[1]; + v = res.max(); if (v>0) t = ((b-a)/v+1)*0.5; if (v<=0 || t<0 || t>1) { - res[1] = std::max(a,b); + res.setMax(std::max(a,b)); }else{ - res[1]=lerp(t, a+v*t, b); + res.setMax(lerp(t, a+v*t, b)); } } if (order>0) res*=std::pow(.25,order); @@ -576,6 +607,7 @@ std::vector roots1(SBasis const & s, Interval const ivl) { /** Find all t s.t s(t) = 0 \param a sbasis function + \see Bezier::roots \returns vector of zeros (roots) */ diff --git a/src/2geom/sbasis-to-bezier.cpp b/src/2geom/sbasis-to-bezier.cpp index a2e4253d2..fe7bbc91c 100644 --- a/src/2geom/sbasis-to-bezier.cpp +++ b/src/2geom/sbasis-to-bezier.cpp @@ -37,7 +37,7 @@ #include <2geom/choose.h> #include <2geom/path-sink.h> #include <2geom/exception.h> -#include <2geom/convex-cover.h> +#include <2geom/convex-hull.h> #include @@ -153,6 +153,15 @@ void sbasis_to_bezier (Bezier & bz, SBasis const& sb, size_t sz) bz[n] = sb[0][1]; } +void sbasis_to_bezier(D2 &bz, D2 const &sb, size_t sz) +{ + if (sz == 0) { + sz = std::max(sb[X].size(), sb[Y].size())*2; + } + sbasis_to_bezier(bz[X], sb[X], sz); + sbasis_to_bezier(bz[Y], sb[Y], sz); +} + /** Changes the basis of p to be Bernstein. \param p the D2 Symmetric basis polynomial \returns the D2 Bernstein basis polynomial @@ -161,24 +170,9 @@ void sbasis_to_bezier (Bezier & bz, SBasis const& sb, size_t sz) */ void sbasis_to_bezier (std::vector & bz, D2 const& sb, size_t sz) { - Bezier bzx, bzy; - if(sz == 0) { - sz = std::max(sb[X].size(), sb[Y].size())*2; - } - sbasis_to_bezier(bzx, sb[X], sz); - sbasis_to_bezier(bzy, sb[Y], sz); - assert(bzx.size() == bzy.size()); - size_t n = (bzx.size() >= bzy.size()) ? bzx.size() : bzy.size(); - - bz.resize(n, Point(0,0)); - for (size_t i = 0; i < bzx.size(); ++i) - { - bz[i][X] = bzx[i]; - } - for (size_t i = 0; i < bzy.size(); ++i) - { - bz[i][Y] = bzy[i]; - } + D2 bez; + sbasis_to_bezier(bez, sb, sz); + bz = bezier_points(bez); } /** Changes the basis of p to be Bernstein. @@ -238,7 +232,7 @@ void sbasis_to_cubic_bezier (std::vector & bz, D2 const& sb) // is midpoint in hull: if not, the solution will be ill-conditioned, LP Bug 1428683 - if (!bezhull.contains_point(Geom::Point(midx, midy))) + if (!bezhull.contains(Geom::Point(midx, midy))) return; // calculate Bezier control arms @@ -264,11 +258,11 @@ void sbasis_to_cubic_bezier (std::vector & bz, D2 const& sb) dely[1] = 0; } else if (std::abs(xprime[1]*yprime[0] - yprime[1]*xprime[0]) > // general case : fit mid fxn value 0.002 * std::abs(xprime[1]*xprime[0] + yprime[1]*yprime[0])) { // approx. 0.1 degree of angle - denom = xprime[1]*yprime[0] - yprime[1]*xprime[0]; + denom = 3.0*(xprime[1]*yprime[0] - yprime[1]*xprime[0]); for (int i = 0; i < 2; ++i) { numer = xprime[1 - i]*midy - yprime[1 - i]*midx; - delx[i] = xprime[i]*numer/denom/3; - dely[i] = yprime[i]*numer/denom/3; + delx[i] = xprime[i]*numer/denom; + dely[i] = yprime[i]*numer/denom; } } else if ((xprime[0]*xprime[1] < 0) || (yprime[0]*yprime[1] < 0)) { // symmetric case : use distance of closest approach numer = midx*xprime[0] + midy*yprime[0]; @@ -514,7 +508,7 @@ path_from_sbasis(D2 const &B, double tol, bool only_cubicbeziers) { If only_cubicbeziers is true, the resulting path may only contain CubicBezier curves. TODO: some of this logic should be lifted into svg-path */ -std::vector +PathVector path_from_piecewise(Geom::Piecewise > const &B, double tol, bool only_cubicbeziers) { Geom::PathBuilder pb; if(B.size() == 0) return pb.peek(); diff --git a/src/2geom/sbasis-to-bezier.h b/src/2geom/sbasis-to-bezier.h index 07511f4a4..eadb47bff 100644 --- a/src/2geom/sbasis-to-bezier.h +++ b/src/2geom/sbasis-to-bezier.h @@ -32,11 +32,11 @@ * */ -#ifndef _SBASIS_TO_BEZIER -#define _SBASIS_TO_BEZIER +#ifndef LIB2GEOM_SEEN_SBASIS_TO_BEZIER_H +#define LIB2GEOM_SEEN_SBASIS_TO_BEZIER_H #include <2geom/d2.h> -#include <2geom/path.h> +#include <2geom/pathvector.h> #include @@ -44,7 +44,8 @@ namespace Geom { class PathBuilder; -void sbasis_to_bezier (Bezier & bz, SBasis const& sb, size_t sz = 0); +void sbasis_to_bezier (Bezier &bz, SBasis const &sb, size_t sz = 0); +void sbasis_to_bezier (D2 &bz, D2 const &sb, size_t sz = 0); void sbasis_to_bezier (std::vector & bz, D2 const& sb, size_t sz = 0); void sbasis_to_cubic_bezier (std::vector & bz, D2 const& sb); void bezier_to_sbasis (SBasis & sb, Bezier const& bz); @@ -65,7 +66,7 @@ sbasis_to_bezier(D2 const &B, unsigned q = 0); #endif -std::vector path_from_piecewise(Piecewise > const &B, double tol, bool only_cubicbeziers = false); +PathVector path_from_piecewise(Piecewise > const &B, double tol, bool only_cubicbeziers = false); Path path_from_sbasis(D2 const &B, double tol, bool only_cubicbeziers = false); inline Path cubicbezierpath_from_sbasis(D2 const &B, double tol) @@ -73,10 +74,7 @@ inline Path cubicbezierpath_from_sbasis(D2 const &B, double tol) } // end namespace Geom - - #endif - /* Local Variables: mode:c++ diff --git a/src/2geom/sbasis.cpp b/src/2geom/sbasis.cpp index b56e03c74..4f1df621e 100644 --- a/src/2geom/sbasis.cpp +++ b/src/2geom/sbasis.cpp @@ -466,6 +466,15 @@ SBasis compose(SBasis const &a, SBasis const &b, unsigned k) { return r; } +SBasis portion(const SBasis &t, double from, double to) { + double fv = t.valueAt(from); + double tv = t.valueAt(to); + SBasis ret = compose(t, Linear(from, to)); + ret.at0() = fv; + ret.at1() = tv; + return ret; +} + /* Inversion algorithm. The notation is certainly very misleading. The pseudocode should say: @@ -632,7 +641,6 @@ SBasis compose_inverse(SBasis const &f, SBasis const &g, unsigned order, double //TODO: handle det~0!! if (fabs(det) * Michael Sloan @@ -32,8 +31,8 @@ * the specific language governing rights and limitations. */ -#ifndef SEEN_SBASIS_H -#define SEEN_SBASIS_H +#ifndef LIB2GEOM_SEEN_SBASIS_H +#define LIB2GEOM_SEEN_SBASIS_H #include #include #include @@ -61,13 +60,13 @@ class SBasis : public SBasisN<1>; }; #else -namespace Geom{ +namespace Geom { /** -* \brief S-power basis function class -* -* An empty SBasis is identically 0. */ -class SBasis{ + * @brief Polynomial in symmetric power basis + * @ingroup Fragments + */ +class SBasis { std::vector d; void push_back(Linear const&l) { d.push_back(l); } @@ -101,11 +100,17 @@ public: SBasis() {} - explicit SBasis(double a) { - push_back(Linear(a,a)); + explicit SBasis(double a) + : d(1) + { + d[0][0] = a; + d[0][1] = a; } - explicit SBasis(double a, double b) { - push_back(Linear(a,b)); + explicit SBasis(double a, double b) + : d(1) + { + d[0][0] = a; + d[0][1] = b; } SBasis(SBasis const & a) : d(a.d) @@ -117,10 +122,69 @@ public: push_back(bo); } SBasis(Linear* bo) { - push_back(*bo); + if (bo) { + push_back(*bo); + } } explicit SBasis(size_t n, Linear const&l) : d(n, l) {} + SBasis(Coord c0, Coord c1, Coord c2, Coord c3) + : d(2) + { + d[0][0] = c0; + d[1][0] = c1; + d[1][1] = c2; + d[0][1] = c3; + } + SBasis(Coord c0, Coord c1, Coord c2, Coord c3, Coord c4, Coord c5) + : d(3) + { + d[0][0] = c0; + d[1][0] = c1; + d[2][0] = c2; + d[2][1] = c3; + d[1][1] = c4; + d[0][1] = c5; + } + SBasis(Coord c0, Coord c1, Coord c2, Coord c3, Coord c4, Coord c5, + Coord c6, Coord c7) + : d(4) + { + d[0][0] = c0; + d[1][0] = c1; + d[2][0] = c2; + d[3][0] = c3; + d[3][1] = c4; + d[2][1] = c5; + d[1][1] = c6; + d[0][1] = c7; + } + SBasis(Coord c0, Coord c1, Coord c2, Coord c3, Coord c4, Coord c5, + Coord c6, Coord c7, Coord c8, Coord c9) + : d(5) + { + d[0][0] = c0; + d[1][0] = c1; + d[2][0] = c2; + d[3][0] = c3; + d[4][0] = c4; + d[4][1] = c5; + d[3][1] = c6; + d[2][1] = c7; + d[1][1] = c8; + d[0][1] = c9; + } + + // construct from a sequence of coefficients + template + SBasis(Iter first, Iter last) { + assert(std::distance(first, last) % 2 == 0); + for (; first != last; ++first) { + --last; + push_back(Linear(*first, *last)); + } + } + //IMPL: FragmentConcept typedef double output_type; inline bool isZero(double eps=EPSILON) const { @@ -140,12 +204,10 @@ public: } bool isFinite() const; - inline double at0() const { - if(empty()) return 0; else return (*this)[0][0]; - } - inline double at1() const{ - if(empty()) return 0; else return (*this)[0][1]; - } + inline Coord at0() const { return (*this)[0][0]; } + inline Coord &at0() { return (*this)[0][0]; } + inline Coord at1() const { return (*this)[0][1]; } + inline Coord &at1() { return (*this)[0][1]; } int degreesOfFreedom() const { return size()*2;} @@ -348,8 +410,8 @@ SBasis compose_inverse(SBasis const &f, SBasis const &g, unsigned order=2, doubl \return sbasis \relates SBasis */ -inline SBasis portion(const SBasis &t, double from, double to) { return compose(t, Linear(from, to)); } -inline SBasis portion(const SBasis &t, Interval ivl) { return compose(t, Linear(ivl.min(), ivl.max())); } +SBasis portion(const SBasis &t, double from, double to); +inline SBasis portion(const SBasis &t, Interval const &ivl) { return portion(t, ivl.min(), ivl.max()); } // compute f(g) inline SBasis @@ -364,7 +426,10 @@ inline std::ostream &operator<< (std::ostream &out_file, const Linear &bo) { inline std::ostream &operator<< (std::ostream &out_file, const SBasis & p) { for(unsigned i = 0; i < p.size(); i++) { - out_file << p[i] << "s^" << i << " + "; + if (i != 0) { + out_file << " + "; + } + out_file << p[i] << "s^" << i; } return out_file; } diff --git a/src/2geom/shape.cpp b/src/2geom/shape.cpp deleted file mode 100644 index e9f5e55dc..000000000 --- a/src/2geom/shape.cpp +++ /dev/null @@ -1,689 +0,0 @@ -/** - * \brief Shapes are special paths on which boolops can be performed - * - * Authors: - * Michael G. Sloan - * Nathan Hurst - * MenTaLguY - * - * Copyright 2007-2009 Authors - * - * This library is free software; you can redistribute it and/or - * modify it either under the terms of the GNU Lesser General Public - * License version 2.1 as published by the Free Software Foundation - * (the "LGPL") or, at your option, under the terms of the Mozilla - * Public License Version 1.1 (the "MPL"). If you do not alter this - * notice, a recipient may use your version of this file under either - * the MPL or the LGPL. - * - * You should have received a copy of the LGPL along with this library - * in the file COPYING-LGPL-2.1; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * You should have received a copy of the MPL along with this library - * in the file COPYING-MPL-1.1 - * - * The contents of this file are subject to the Mozilla Public License - * Version 1.1 (the "License"); you may not use this file except in - * compliance with the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY - * OF ANY KIND, either express or implied. See the LGPL or the MPL for - * the specific language governing rights and limitations. - * - */ - -#include <2geom/shape.h> - -#include <2geom/utils.h> -#include <2geom/sweep.h> -#include <2geom/ord.h> - -#include -#include -#include - -//#define SHAPE_DEBUG // turns on debug outputting to cout. - -namespace Geom { - -// A little sugar for appending a list to another -template -void append(T &a, T const &b) { - a.insert(a.end(), b.begin(), b.end()); -} - -//Orders a list of indices according to their containment within eachother. -struct ContainmentOrder { - std::vector const *rs; - explicit ContainmentOrder(std::vector const *r) : rs(r) {} - bool operator()(unsigned a, unsigned b) const { return (*rs)[b].contains((*rs)[a]); } -}; - -//Returns the list of regions containing a particular point. Useful in tandem with ContainmentOrder -std::vector Shape::containment_list(Point p) const { - std::vector pnt; - pnt.push_back(Rect(p, p)); - std::vector > cull = sweep_bounds(pnt, bounds(*this)); - std::vector containers; - if(cull[0].size() == 0) return containers; - for(unsigned i = 0; i < cull[0].size(); i++) - if(content[cull[0][i]].contains(p)) containers.push_back(cull[0][i]); - return containers; -} - -/* Used within shape_boolean and related functions, as the name describes, finds the - * first false within the list of lists of booleans. - */ -void first_false(std::vector > visited, unsigned &i, unsigned &j) { - for(i = 0, j = 0; i < visited.size(); i++) { - std::vector::iterator unvisited = std::find(visited[i].begin(), visited[i].end(), false); - if(unvisited != visited[i].end()) { - j = unvisited - visited[i].begin(); - break; - } - } -} - -// Finds a crossing in a list of them, given the sorting index. -unsigned find_crossing(Crossings const &cr, Crossing x, unsigned i) { - return std::lower_bound(cr.begin(), cr.end(), x, CrossingOrder(i)) - cr.begin(); -} - -/* This function handles boolean ops on shapes. The first parameter is a bool - * which determines its behavior in each combination of cases. For proper - * fill information and noncrossing behavior, the fill data of the regions - * must be correct. The boolean parameter determines whether the operation - * is a union or a subtraction. Reversed paths represent inverse regions, - * where everything is included in the fill except for the insides. - * - * Here is a chart of the behavior under various circumstances: - * - * rev = false (union) - * A - * F H - * F A+B -> F A-B -> H - *B - * H B-A -> H AxB -> H - * - * rev = true (intersect) - * A - * F H - * F AxB -> F B-A -> F - *B - * H A-B -> F A+B -> H - * - * F/H = Fill outer / Hole outer - * A/B specify operands - * + = union, - = subtraction, x = intersection - * -> read as "produces" - * - * This is the main function of boolops, yet its operation isn't very complicated. - * It traverses the crossings, and uses the crossing direction to decide whether - * the next segment should be taken from A or from B. The second half of the - * function deals with figuring out what to do with bits that have no intersection. - */ -Shape shape_boolean(bool rev, Shape const & a, Shape const & b, CrossingSet const & crs) { - const Regions ac = a.content, bc = b.content; - - //Keep track of which crossings we've hit. - std::vector > visited; - for(unsigned i = 0; i < crs.size(); i++) - visited.push_back(std::vector(crs[i].size(), false)); - - //Traverse the crossings, creating chunks - Regions chunks; - while(true) { - unsigned i, j; - first_false(visited, i, j); - if(i == visited.size()) break; - - Path res; - do { - Crossing cur = crs[i][j]; - visited[i][j] = true; - - //get indices of the dual: - unsigned io = cur.getOther(i), jo = find_crossing(crs[io], cur, io); - if(jo < visited[io].size()) visited[io][jo] = true; - - //main driving logic - if(logical_xor(cur.dir, rev)) { - if(i >= ac.size()) { i = io; j = jo; } - j++; - if(j >= crs[i].size()) j = 0; - Crossing next = crs[i][j]; - ac[next.a].boundary.appendPortionTo(res, cur.ta, next.ta); - } else { - if(i < ac.size()) { i = io; j = jo; } - j++; - if(j >= crs[i].size()) j = 0; - Crossing next = crs[i][j]; - bc[next.b - ac.size()].boundary.appendPortionTo(res, cur.tb, next.tb); - } - } while (!visited[i][j]); - if(res.size() > 0) chunks.push_back(Region(res)); - } - - //If true, then we are on the 'subtraction diagonal' - bool const on_sub = logical_xor(a.fill, b.fill); - //If true, outer paths are filled - bool const res_fill = rev ? (on_sub || (a.fill && b.fill)) : (a.fill && b.fill); - - //Handle unintersecting portions - for(unsigned i = 0; i < crs.size(); i++) { - if(crs[i].size() == 0) { - bool env; - bool on_a = i < ac.size(); - Region const & r(on_a ? ac[i] : bc[i - ac.size()]); - Shape const & other(on_a ? b : a); - - std::vector containers = other.containment_list(r.boundary.initialPoint()); - if(containers.empty()) { - //not included in any container, the environment fill is the opposite of the outer fill - env = !res_fill; - if(on_sub && logical_xor(other.fill, res_fill)) env = !env; //If on the subtractor, invert the environment fill - } else { - //environment fill is the same as the inner-most container - std::vector::iterator cit = std::min_element(containers.begin(), containers.end(), ContainmentOrder(&other.content)); - env = other[*cit].isFill(); - } - if(!logical_xor(rev, env)) chunks.push_back(r); //When unioning, environment must be hole for inclusion, when intersecting, it must be filled - } - } - - return Shape(chunks, res_fill); -} - -// Just a convenience wrapper for shape_boolean, which handles the crossings -Shape shape_boolean(bool rev, Shape const & a, Shape const & b) { - CrossingSet crs = crossings_between(a, b); - - return shape_boolean(rev, a, b, crs); -} - - -// Some utility functions for boolop: - -std::vector region_sizes(Shape const &a) { - std::vector ret; - for(unsigned i = 0; i < a.size(); i++) { - ret.push_back(double(a[i].size())); - } - return ret; -} - -Shape shape_boolean_ra(bool rev, Shape const &a, Shape const &b, CrossingSet const &crs) { - return shape_boolean(rev, a.inverse(), b, reverse_ta(crs, a.size(), region_sizes(a))); -} - -Shape shape_boolean_rb(bool rev, Shape const &a, Shape const &b, CrossingSet const &crs) { - return shape_boolean(rev, a, b.inverse(), reverse_tb(crs, a.size(), region_sizes(b))); -} - -/* This is a function based on shape_boolean which allows boolean operations - * to be specified as a logic table. This logic table is 4 bit-flags, which - * correspond to the elements of the 'truth table' for a particular operation. - * These flags are defined with the enums starting with BOOLOP_ . - * - * NOTE: currently doesn't work, as the CrossingSet reversal functions crash - */ -Shape boolop(Shape const &a, Shape const &b, unsigned flags, CrossingSet const &crs) { - THROW_NOTIMPLEMENTED(); - flags &= 15; - if(flags <= BOOLOP_UNION) { - switch(flags) { - case BOOLOP_INTERSECT: return shape_boolean(true, a, b, crs); - case BOOLOP_SUBTRACT_A_B: return shape_boolean_rb(true, a, b, crs); - case BOOLOP_IDENTITY_A: return a; - case BOOLOP_SUBTRACT_B_A: return shape_boolean_ra(true, a, b, crs); - case BOOLOP_IDENTITY_B: return b; - case BOOLOP_EXCLUSION: { - Shape res = shape_boolean_rb(true, a, b, crs); - append(res.content, shape_boolean_ra(true, a, b, crs).content); - return res; - } - case BOOLOP_UNION: return shape_boolean(false, a, b); - } - } else { - flags = ~flags & 15; - switch(flags - BOOLOP_NEITHER) { - case BOOLOP_SUBTRACT_A_B: return shape_boolean_ra(false, a, b, crs); - case BOOLOP_SUBTRACT_B_A: return shape_boolean_rb(false, a, b, crs); - case BOOLOP_EXCLUSION: { - Shape res = shape_boolean_ra(false, a, b, CrossingSet(crs)); - append(res.content, shape_boolean_rb(false, a, b, CrossingSet(crs)).content); - return res; - } - } - return boolop(a, b, flags, crs).inverse(); - } - return Shape(); -} - -/* This version of the boolop function doesn't require a set of crossings, as - * it computes them for you. This is more efficient in some cases, as the - * shape can be inverted before finding crossings. In the special case of - * exclusion it uses the other version of boolop. - */ -Shape boolop(Shape const &a, Shape const &b, unsigned flags) { - flags &= 15; - if(flags <= BOOLOP_UNION) { - switch(flags) { - case BOOLOP_INTERSECT: return shape_boolean(true, a, b); - case BOOLOP_SUBTRACT_A_B: return shape_boolean(true, a, b.inverse()); - case BOOLOP_IDENTITY_A: return a; - case BOOLOP_SUBTRACT_B_A: return shape_boolean(true, b, a.inverse()); - case BOOLOP_IDENTITY_B: return b; - case BOOLOP_EXCLUSION: { - Shape res = shape_boolean(true, a, b.inverse()); - append(res.content, shape_boolean(true, b, a.inverse()).content); - return res; - } //return boolop(a, b, flags, crossings_between(a, b)); - case BOOLOP_UNION: return shape_boolean(false, a, b); - } - } else { - flags = ~flags & 15; - switch(flags) { - case BOOLOP_SUBTRACT_A_B: return shape_boolean(false, b, a.inverse()); - case BOOLOP_SUBTRACT_B_A: return shape_boolean(false, a, b.inverse()); - case BOOLOP_EXCLUSION: { - Shape res = shape_boolean(false, a, b.inverse()); - append(res.content, shape_boolean(false, b, a.inverse()).content); - return res; - } //return boolop(a, b, flags, crossings_between(a, b)); - } - return boolop(a, b, flags).inverse(); - } - return Shape(); -} - -int paths_winding(std::vector const &ps, Point p) { - int ret = 0; - for(unsigned i = 0; i < ps.size(); i++) - ret += winding(ps[i], p); - return ret; -} - -void add_to_shape(Shape &s, Path const &p, bool fill) { - if(fill) - s.content.push_back(Region(p).asFill()); - else - s.content.push_back(Region(p).asHole()); -} - -int inner_winding(Path const & p, std::vector const &ps) { - Point pnt = p.initialPoint(); - return paths_winding(ps, pnt) - winding(p, pnt) + 1; -} - -double fudgerize(double d, bool rev) { - double ret = rev ? d - 0.01 : d + 0.01; - if(ret < 0) ret = 0; - return ret; -} - -unsigned pick_coincident(unsigned ix, unsigned jx, bool &rev, std::vector const &ps, CrossingSet const &crs) { - unsigned ex_jx = jx; - unsigned oix = crs[ix][jx].getOther(ix); - double otime = crs[ix][jx].getTime(oix); - Point cross_point = ps[oix].pointAt(otime), - along = ps[oix].pointAt(fudgerize(otime, rev)) - cross_point, - prev = -along; - bool ex_dir = rev; - for(unsigned k = jx; k < crs[ix].size(); k++) { - unsigned koix = crs[ix][k].getOther(ix); - if(koix == oix) { - if(!are_near(otime, crs[ix][k].getTime(oix))) break; - for(unsigned dir = 0; dir < 2; dir++) { - Point val = ps[ix].pointAt(fudgerize(crs[ix][k].getTime(ix), dir)) - cross_point; - Cmp to_prev = cmp(cross(val, prev), 0); - Cmp from_along = cmp(cross(along, val), 0); - Cmp c = cmp(from_along, to_prev); - if(c == EQUAL_TO && from_along == LESS_THAN) { - ex_jx = k; - prev = val; - ex_dir = dir; - } - } - } - } - rev = ex_dir; - return ex_jx; -} - -unsigned crossing_along(double t, unsigned ix, unsigned jx, bool dir, Crossings const & crs) { - Crossing cur = Crossing(t, t, ix, ix, false); - if(jx < crs.size()) { - double ct = crs[jx].getTime(ix); - if(t == ct) { - cur = crs[jx]; - if(cur.a == cur.b) { - if(jx+1 <= crs.size() && crs[jx+1].getOther(ix) == ix) return jx+1; - if(jx > 0 && crs[jx-1].getOther(ix) == ix) return jx-1; - } - } - } - if(!dir) { - jx = std::upper_bound(crs.begin(), crs.end(), cur, CrossingOrder(ix)) - crs.begin(); - } else { - jx = std::lower_bound(crs.begin(), crs.end(), cur, CrossingOrder(ix)) - crs.begin(); - if(jx == 0) jx = crs.size() - 1; else jx--; - jx = std::lower_bound(crs.begin(), crs.end(), crs[jx], CrossingOrder(ix)) - crs.begin(); - } - if(jx >= crs.size()) jx = 0; - return jx; -} - -void crossing_dual(unsigned &i, unsigned &j, CrossingSet const & crs) { - Crossing cur = crs[i][j]; - i = cur.getOther(i); -#ifdef SHAPE_DEBUG - std::cout << i << "\n"; -#endif - if(crs[i].empty()) - j = 0; - else - j = std::lower_bound(crs[i].begin(), crs[i].end(), cur, CrossingOrder(i)) - crs[i].begin(); -} - -//locate a crossing on the outside, by casting a ray through the middle of the bbox -void outer_crossing(unsigned &ix, unsigned &jx, bool & dir, std::vector const & ps, CrossingSet const & crs) { - Rect bounds = *(ps[ix].boundsFast()); - double ry = bounds[Y].middle(); - double max_val = bounds.left(), max_t = 0; - ix = ps.size(); - for(unsigned i = 0; i < ps.size(); i++) { - if(!crs[i].empty()) { - std::vector rts = ps[i].roots(ry, Y); - for(unsigned j = 0; j < rts.size(); j++) { - double val = ps[i].valueAt(rts[j], X); - if(val > max_val) { - ix = i; - max_val = val; - max_t = rts[j]; - } - } - } - } - if(ix != ps.size()) { - dir = ps[ix].valueAt(max_t + 0.01, Y) > - ps[ix].valueAt(max_t - 0.01, Y); - jx = crossing_along(max_t, ix, jx, dir, crs[ix]); - } -} - -std::vector inner_sanitize(std::vector const & ps) { - CrossingSet crs(crossings_among(ps)); - - Regions chunks; - - std::vector used_path(ps.size(), false); - std::vector > visited; - for(unsigned i = 0; i < crs.size(); i++) - visited.push_back(std::vector(crs[i].size(), false)); - - std::vector result_paths; - - while(true) { - unsigned ix = 0, jx = 0; - bool dir = false; - - //find an outer crossing by trying various paths and checking if the crossings are used - for(; ix < crs.size(); ix++) { - //TODO: optimize so it doesn't unecessarily check stuff - bool cont = true; - for(unsigned j = 0; j < crs[ix].size(); j++) { - if(!visited[ix][j]) { cont = false; break; } - } - if(cont) continue; - unsigned rix = ix, rjx = jx; - outer_crossing(rix, rjx, dir, ps, crs); - if(rix >= crs.size() || visited[rix][rjx]) continue; - ix = rix; jx = rjx; - break; - } - if(ix == crs.size()) break; - crossing_dual(ix, jx, crs); - - dir = !dir; - - Path res; - do { - visited[ix][jx] = true; - //unsigned nix = ix, njx = jx; - //crossing_dual(nix, njx, crs); - //visited[nix][njx] = true; - unsigned fix = ix, fjx = jx; - - bool new_dir = dir; - - jx = crossing_along(crs[ix][jx].getTime(ix), ix, jx, dir, crs[ix]); - if(crs[ix][jx].a != crs[ix][jx].b) crossing_dual(ix, jx, crs); else new_dir = !new_dir; - jx = pick_coincident(ix, jx, new_dir, ps, crs); - - //unsigned nix = ix, njx = jx; - //crossing_dual(nix, njx, crs); - - Crossing from = crs[fix][fjx], - to = crs[ix][jx]; - if(dir) { - // backwards -#ifdef SHAPE_DEBUG - std::cout << "r" << ix << "[" << from.getTime(ix) << ", " << to.getTime(ix) << "]\n"; -#endif - Path p = ps[ix].portion(from.getTime(ix), to.getTime(ix)).reverse(); - for(unsigned i = 0; i < p.size(); i++) - res.append(p[i], Path::STITCH_DISCONTINUOUS); - } else { - // forwards -#ifdef SHAPE_DEBUG - std::cout << "f" << ix << "[" << from.getTime(ix) << ", " << to.getTime(ix) << "]\n"; -#endif - ps[ix].appendPortionTo(res, from.getTime(ix), to.getTime(ix)); - } - dir = new_dir; - } while(!visited[ix][jx]); -#ifdef SHAPE_DEBUG - std::cout << "added " << res.size() << "\n"; -#endif - result_paths.push_back(res); - } - for(unsigned i = 0; i < crs.size(); i++) { - if(crs[i].empty() && !used_path[i]) - result_paths.push_back(ps[i]); - } - return result_paths; -} - -Shape sanitize(std::vector const & ps) { - std::vector res; - for(unsigned i = 0; i < ps.size(); i++) { - append(res, inner_sanitize(std::vector(1, ps[i]))); - } - return stopgap_cleaner(res); -} - -/* WIP sanitizer: -unsigned pick_coincident(unsigned ix, unsigned jx, bool pref, bool &rev, std::vector const &ps, CrossingSet const &crs) { - unsigned ex_jx = jx; - unsigned oix = crs[ix][jx].getOther(ix); - double otime = crs[ix][jx].getTime(oix); - Point cross_point = ps[oix].pointAt(otime), - along = ps[oix].pointAt(otime + (rev ? -0.01 : 0.01)) - cross_point, - prev = -along; - bool ex_dir = rev; - for(unsigned k = jx; k < crs[ix].size(); k++) { - unsigned koix = crs[ix][k].getOther(ix); - if(koix == oix) { - if(!are_near(otime, crs[ix][k].getTime(oix))) break; - for(unsigned dir = 0; dir < 2; dir++) { - Point val = ps[ix].pointAt(crs[ix][k].getTime(ix) + (dir ? -0.01 : 0.01)) - cross_point; - Cmp to_prev = cmp(cross(val, prev), 0); - Cmp from_along = cmp(cross(along, val), 0); - Cmp c = cmp(from_along, to_prev); - if(c == EQUAL_TO && (from_along == LESS_THAN) == pref) { - ex_jx = k; - prev = val; - ex_dir = dir; - } - } - } - } - rev = ex_dir; - return ex_jx; -} - -unsigned corner_index(unsigned &i) { - div_t div_res = div(i, 4); - i = div_res.quot; - return div_res.rem; -} - -bool corner_direction(unsigned ix, unsigned jc, unsigned corner, CrossingSet const &crs) { - if(crs[ix][jc].a == ix) return corner > 1; else return corner %2 == 1; -} - -Shape sanitize(std::vector const & ps) { - CrossingSet crs = crossings_among(ps); - - //Keep track of which CORNERS we've hit. - // FF FR RF RR, first is A dir, second B dir - std::vector > visited; - for(unsigned i = 0; i < crs.size(); i++) - visited.push_back(std::vector(crs[i].size()*4, false)); - - Regions chunks; - while(true) { - unsigned i, j; - first_false(visited, i, j); - unsigned corner = corner_index(j); - - if(i == visited.size()) break; - - bool dir = corner_direction(i, j, corner, crs); - - //Figure out whether we hug the path cw or ccw, based on the orientation of the initial corner: - unsigned oix = crs[i][j].getOther(i); - double otime = crs[i][j].getTime(oix); - bool odir = (oix == crs[i][j].a) ? corner > 1 : corner % 2 == 1; - Point cross_point = ps[oix].pointAt(otime), - along = ps[oix].pointAt(otime + (odir ? -0.01 : 0.01)) - cross_point, - val = ps[i].pointAt(crs[i][j].getTime(i) + (dir ? -0.01 : 0.01)) - cross_point; - - Cmp from_along = cmp(cross(along, val), 0); - bool cw = from_along == LESS_THAN; - std::cout << "cw = " << cw << "\n"; - Path res; - do { - Crossing cur = crs[i][j]; - visited[i][j*4+corner] = true; - - unsigned fix = i, fjx = j; - crossing_dual(i, j, crs); - visited[i][j*4+corner] = true; - i = fix; j = fjx; - - j = crossing_along(crs[i][j].getTime(i), i, j, dir, crs[i]); - - crossing_dual(i, j, crs); - - bool new_dir = dir; - pick_coincident(i, j, cw, new_dir, ps, crs); - - Crossing from = crs[fix][fjx], - to = crs[i][j]; - if(dir) { - // backwards - std::cout << "r" << i << "[" << to.getTime(i) << ", " << from.getTime(i) << "]\n"; - Path p = ps[i].portion(to.getTime(i) + 0.001, from.getTime(i)).reverse(); - for(unsigned k = 0; k < p.size(); k++) - res.append(p[k]); - } else { - // forwards - std::cout << "f" << i << "[" << from.getTime(i) << ", " << to.getTime(i) << "]\n"; - ps[i].appendPortionTo(res, from.getTime(i) + 0.001, to.getTime(i)); - } - if(i == to.a) - corner = (new_dir ? 2 : 0) + (dir ? 1 : 0); - else - corner = (new_dir ? 1 : 0) + (dir ? 2 : 0); - dir = new_dir; - } while(!visited[i][j*4+corner]); - chunks.push_back(Region(res)); -// if(use) { -// chunks.push_back(Region(res, true)); -// } - } - return Shape(chunks); -// return ret; -} */ - -/* This transforms a shape by a matrix. In the case that the matrix flips - * the shape, it reverses the paths in order to preserve the fill. - */ -Shape Shape::operator*(Affine const &m) const { - Shape ret; - for(unsigned i = 0; i < size(); i++) - ret.content.push_back(content[i] * m); - ret.fill = fill; - return ret; -} - -// Inverse is a boolean not, and simply reverses all the paths & fill flags -Shape Shape::inverse() const { - Shape ret; - for(unsigned i = 0; i < size(); i++) - ret.content.push_back(content[i].inverse()); - ret.fill = !fill; - return ret; -} - -bool Shape::contains(Point const &p) const { - std::vector containers = containment_list(p); - if(containers.empty()) return !isFill(); - unsigned ix = *min_element(containers.begin(), containers.end(), ContainmentOrder(&content)); - return content[ix].isFill(); -} - -Shape stopgap_cleaner(std::vector const &ps) { - if(ps.empty()) return Shape(false); - Shape ret; - for(unsigned i = 0; i < ps.size(); i++) - add_to_shape(ret, ps[i], inner_winding(ps[i], ps) % 2 != 0); - return ret; -} - -bool Shape::inside_invariants() const { //semi-slow & easy to violate - for(unsigned i = 0; i < size(); i++) - if( logical_xor(content[i].isFill(), contains(content[i].boundary.initialPoint())) ) return false; - return true; -} -bool Shape::region_invariants() const { //semi-slow - for(unsigned i = 0; i < size(); i++) - if(!content[i].invariants()) return false; - return true; -} -bool Shape::cross_invariants() const { //slow - CrossingSet crs; // = crossings_among(paths_from_regions(content)); - for(unsigned i = 0; i < crs.size(); i++) - if(!crs[i].empty()) return false; - return true; -} - -bool Shape::invariants() const { - return inside_invariants() && region_invariants() && cross_invariants(); -} - -} - -/* - Local Variables: - mode:c++ - c-file-style:"stroustrup" - c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) - indent-tabs-mode:nil - fill-column:99 - End: -*/ -// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 : diff --git a/src/2geom/shape.h b/src/2geom/shape.h deleted file mode 100644 index 0a7ee9709..000000000 --- a/src/2geom/shape.h +++ /dev/null @@ -1,148 +0,0 @@ -/** - * \brief Shapes are special paths on which boolops can be performed - * - * Authors: - * Michael G. Sloan - * Nathan Hurst - * MenTaLguY - * - * Copyright 2007-2009 Authors - * - * This library is free software; you can redistribute it and/or - * modify it either under the terms of the GNU Lesser General Public - * License version 2.1 as published by the Free Software Foundation - * (the "LGPL") or, at your option, under the terms of the Mozilla - * Public License Version 1.1 (the "MPL"). If you do not alter this - * notice, a recipient may use your version of this file under either - * the MPL or the LGPL. - * - * You should have received a copy of the LGPL along with this library - * in the file COPYING-LGPL-2.1; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * You should have received a copy of the MPL along with this library - * in the file COPYING-MPL-1.1 - * - * The contents of this file are subject to the Mozilla Public License - * Version 1.1 (the "License"); you may not use this file except in - * compliance with the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY - * OF ANY KIND, either express or implied. See the LGPL or the MPL for - * the specific language governing rights and limitations. - * - */ - -#ifndef __2GEOM_SHAPE_H -#define __2GEOM_SHAPE_H - -#include -#include - -#include <2geom/region.h> - -//TODO: BBOX optimizations - -namespace Geom { - -enum { - BOOLOP_JUST_A = 1, - BOOLOP_JUST_B = 2, - BOOLOP_BOTH = 4, - BOOLOP_NEITHER = 8 -}; - -enum { - BOOLOP_NULL = 0, - BOOLOP_INTERSECT = BOOLOP_BOTH, - BOOLOP_SUBTRACT_A_B = BOOLOP_JUST_B, - BOOLOP_IDENTITY_A = BOOLOP_JUST_A | BOOLOP_BOTH, - BOOLOP_SUBTRACT_B_A = BOOLOP_JUST_A, - BOOLOP_IDENTITY_B = BOOLOP_JUST_B | BOOLOP_BOTH, - BOOLOP_EXCLUSION = BOOLOP_JUST_A | BOOLOP_JUST_B, - BOOLOP_UNION = BOOLOP_JUST_A | BOOLOP_JUST_B | BOOLOP_BOTH -}; - -class Shape { - Regions content; - mutable bool fill; - //friend Shape shape_region_boolean(bool rev, Shape const & a, Region const & b); - friend CrossingSet crossings_between(Shape const &a, Shape const &b); - friend Shape shape_boolean(bool rev, Shape const &, Shape const &, CrossingSet const &); - friend Shape boolop(Shape const &a, Shape const &b, unsigned); - friend Shape boolop(Shape const &a, Shape const &b, unsigned, CrossingSet const &); - friend void add_to_shape(Shape &s, Path const &p, bool); - public: - Shape() : fill(true) {} - explicit Shape(Region const & r) { - content = Regions(1, r); - fill = r.fill; - } - explicit Shape(Regions const & r) : content(r) { update_fill(); } - explicit Shape(bool f) : fill(f) {} - Shape(Regions const & r, bool f) : content(r), fill(f) {} - - Regions getContent() const { return content; } - bool isFill() const { return fill; } - - unsigned size() const { return content.size(); } - const Region &operator[](unsigned ix) const { return content[ix]; } - - Shape inverse() const; - Shape operator*(Affine const &m) const; - - bool contains(Point const &p) const; - - bool inside_invariants() const; //semi-slow & easy to violate : checks that the insides are inside, the outsides are outside - bool region_invariants() const; //semi-slow : checks for self crossing - bool cross_invariants() const; //slow : checks that everything is disjoint - bool invariants() const; //vera slow (combo, checks the above) - - private: - std::vector containment_list(Point p) const; - void update_fill() const { - unsigned ix = outer_index(content); - if(ix < size()) - fill = content[ix].fill; - else if(size() > 0) - fill = content.front().fill; - else - fill = true; - } -}; - -inline CrossingSet crossings_between(Shape const &a, Shape const &b) { return crossings(paths_from_regions(a.content), paths_from_regions(b.content)); } - -Shape shape_boolean(bool rev, Shape const &, Shape const &, CrossingSet const &); -Shape shape_boolean(bool rev, Shape const &, Shape const &); - -//unsigned pick_coincident(unsigned ix, unsigned jx, bool &rev, std::vector const &ps, CrossingSet const &crs); -//void outer_crossing(unsigned &ix, unsigned &jx, bool & dir, std::vector const & ps, CrossingSet const & crs); -void crossing_dual(unsigned &i, unsigned &j, CrossingSet const & crs); -unsigned crossing_along(double t, unsigned ix, unsigned jx, bool dir, Crossings const & crs); - -Shape boolop(Shape const &, Shape const &, unsigned flags); -Shape boolop(Shape const &, Shape const &, unsigned flags, CrossingSet &); - -Shape sanitize(std::vector const &ps); - -Shape stopgap_cleaner(std::vector const &ps); - -inline std::vector desanitize(Shape const & s) { - return paths_from_regions(s.getContent()); -} - -} - -#endif - -/* - Local Variables: - mode:c++ - c-file-style:"stroustrup" - c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) - indent-tabs-mode:nil - fill-column:99 - End: -*/ -// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 : diff --git a/src/2geom/solve-bezier-one-d.cpp b/src/2geom/solve-bezier-one-d.cpp index 3d87d4926..3a25e9808 100644 --- a/src/2geom/solve-bezier-one-d.cpp +++ b/src/2geom/solve-bezier-one-d.cpp @@ -27,7 +27,7 @@ static int SGN(t x) { return (x > 0 ? 1 : (x < 0 ? -1 : 0)); } **/ class Bernsteins{ public: - static const size_t MAX_DEPTH = 22; + static const size_t MAX_DEPTH = 53; size_t degree, N; std::vector &solutions; //std::vector bc; @@ -38,17 +38,9 @@ public: { } - void subdivide(double const *V, - double t, - double *Left, - double *Right); - unsigned control_poly_flat_enough(double const *V); - double horner(const double *b, double t); - - void find_bernstein_roots(double const *w, /* The control points */ unsigned depth, /* The depth of the recursion */ @@ -134,7 +126,7 @@ void Bernsteins::find_bernstein_roots(double const *w, /* The control points */ r = (fs*t - ft*s) / (fs - ft); if (fabs(t-s) < e * fabs(t+s)) break; - double fr = horner(w, r); + double fr = bernstein_value_at(r, w, degree); if (fr * ft > 0) { @@ -191,24 +183,6 @@ void Bernsteins::find_bernstein_roots(double const *w, /* The control points */ delete[] LR; } - -// suggested by Sederberg. -double Bernsteins::horner(const double *b, double t) -{ - double u, tn, tmp; - u = 1.0 - t; - tn = 1.0; - tmp = b[0] * u; - for(size_t i = 1; i < degree; ++i) - { - tn *= t; - tmp = (tmp + tn*bc[i]*b[i]) * u; - } - return (tmp + tn*t*b[degree]); -} - - - #if 0 /* * control_poly_flat_enough : diff --git a/src/2geom/solve-bezier-parametric.cpp b/src/2geom/solve-bezier-parametric.cpp index 9b0feaee4..2fb3f41da 100644 --- a/src/2geom/solve-bezier-parametric.cpp +++ b/src/2geom/solve-bezier-parametric.cpp @@ -1,8 +1,9 @@ -#include <2geom/solver.h> +#include <2geom/bezier.h> #include <2geom/point.h> +#include <2geom/solver.h> #include -namespace Geom{ +namespace Geom { /*** Find the zeros of the parametric function in 2d defined by two beziers X(t), Y(t). The code subdivides until it happy with the linearity of the bezier. This requires an n^2 subdivision for each step, even when there is only one solution. * @@ -14,13 +15,6 @@ namespace Geom{ /* * Forward declarations */ -static Geom::Point -Bezier(Geom::Point const *V, - unsigned degree, - double t, - Geom::Point *Left, - Geom::Point *Right); - unsigned crossing_count(Geom::Point const *V, unsigned degree); static unsigned @@ -74,7 +68,7 @@ find_parametric_bezier_roots(Geom::Point const *w, /* The control points */ // Right[degree+1]; /* control polygons */ std::vector Left( degree+1 ), Right(degree+1); - Bezier(w, degree, 0.5, Left.data(), Right.data()); + casteljau_subdivision(0.5, w, Left.data(), Right.data(), degree); total_subs ++; find_parametric_bezier_roots(Left.data(), degree, solutions, depth+1); find_parametric_bezier_roots(Right.data(), degree, solutions, depth+1); @@ -181,43 +175,6 @@ compute_x_intercept(Geom::Point const *V, /* Control points */ return (A[Geom::X]*V[0][Geom::Y] - A[Geom::Y]*V[0][Geom::X]) / -A[Geom::Y]; } - -/* - * Bezier : - * Evaluate a Bezier curve at a particular parameter value - * Fill in control points for resulting sub-curves. - * - */ -static Geom::Point -Bezier(Geom::Point const *V, /* Control pts */ - unsigned degree, /* Degree of bezier curve */ - double t, /* Parameter value */ - Geom::Point *Left, /* RETURN left half ctl pts */ - Geom::Point *Right) /* RETURN right half ctl pts */ -{ - //Geom::Point Vtemp[degree+1][degree+1]; - std::vector > Vtemp(degree+1); - for ( size_t i = 0; i < degree + 1; ++i ) - Vtemp.reserve(degree+1); - - /* Copy control points */ - std::copy(V, V+degree+1, Vtemp[0].begin()); - - /* Triangle computation */ - for (unsigned i = 1; i <= degree; i++) { - for (unsigned j = 0; j <= degree - i; j++) { - Vtemp[i][j] = lerp(t, Vtemp[i-1][j], Vtemp[i-1][j+1]); - } - } - - for (unsigned j = 0; j <= degree; j++) - Left[j] = Vtemp[j][0]; - for (unsigned j = 0; j <= degree; j++) - Right[j] = Vtemp[degree-j][j]; - - return (Vtemp[degree][0]); -} - }; /* diff --git a/src/2geom/solve-bezier.cpp b/src/2geom/solve-bezier.cpp index adf3c9ac0..4732169cb 100644 --- a/src/2geom/solve-bezier.cpp +++ b/src/2geom/solve-bezier.cpp @@ -37,12 +37,10 @@ public: double *Left, double *Right); - double secant(Bezier bz); + double secant(Bezier const &bz); - double horner(Bezier bz, double t); - - void find_bernstein_roots(Bezier bz, unsigned depth, + void find_bernstein_roots(Bezier const &bz, unsigned depth, double left_t, double right_t); }; @@ -55,27 +53,7 @@ inline std::ostream &operator<< (std::ostream &out_file, const std::vector & return out_file << "]"; } -Bezier subRight(Bezier bz, double t) { - unsigned order = bz.order(); - unsigned N = order+1; - std::valarray row(N); - for (unsigned i = 0; i < N; i++) - row[i] = bz[i]; - - // Triangle computation - const double omt = (1-t); - Bezier Right = bz; - Right[order] = row[order]; - for (unsigned i = 1; i < N; i++) { - for (unsigned j = 0; j < N - i; j++) { - row[j] = omt*row[j] + t*row[j+1]; - } - Right[order-i] = row[order-i]; - } - return Right; -} - -void convex_hull_marching(Bezier src_bz, Bezier bz, +void convex_hull_marching(Bezier const &src_bz, Bezier bz, std::vector &solutions, double left_t, double right_t) @@ -111,7 +89,7 @@ void convex_hull_marching(Bezier src_bz, Bezier bz, << " = " << bz(left_bound) << std::endl; double new_left_t = left_bound * (right_t - left_t) + left_t; std::cout << "new_left_t = " << new_left_t << std::endl; - Bezier bzr = subRight(src_bz, new_left_t); + Bezier bzr = portion(src_bz, new_left_t, 1); while(bzr.order() > 0 && bzr[0] == 0) { std::cout << "deflate\n"; bzr = bzr.deflate(); @@ -171,7 +149,7 @@ Bezier::find_bezier_roots(std::vector &solutions, //std::cout << solutions << std::endl; } -void Bernsteins::find_bernstein_roots(Bezier bz, +void Bernsteins::find_bernstein_roots(Bezier const &bz, unsigned depth, double left_t, double right_t) @@ -194,6 +172,11 @@ void Bernsteins::find_bernstein_roots(Bezier bz, old_sign = sign; } } + // if last control point is zero, that counts as crossing too + if (SGN(bz[bz.size()-1]) == 0) { + ++n_crossings; + } + //std::cout << "n_crossings = " << n_crossings << std::endl; if (n_crossings == 0) return; // no solutions here @@ -271,23 +254,7 @@ void Bernsteins::find_bernstein_roots(Bezier bz, } } - -// suggested by Sederberg. -double Bernsteins::horner(Bezier bz, double t) -{ - double u, tn, tmp; - u = 1.0 - t; - tn = 1.0; - tmp = bz.at0() * u; - for(size_t i = 1; i < bz.degree(); ++i) - { - tn *= t; - tmp = (tmp + tn*choose(bz.order(), (unsigned)i)*bz[i]) * u; - } - return (tmp + tn*t*bz.at1()); -} - -double Bernsteins::secant(Bezier bz) { +double Bernsteins::secant(Bezier const &bz) { double s = 0, t = 1; double e = 1e-14; int side = 0; @@ -303,7 +270,7 @@ double Bernsteins::secant(Bezier bz) { return r; } - double fr = horner(bz, r); + double fr = bz.valueAt(r); if (fr * ft > 0) { diff --git a/src/2geom/solver.h b/src/2geom/solver.h index 793939b2a..5b082cb83 100644 --- a/src/2geom/solver.h +++ b/src/2geom/solver.h @@ -32,16 +32,14 @@ * */ -#ifndef _SOLVE_SBASIS_H -#define _SOLVE_SBASIS_H +#ifndef LIB2GEOM_SEEN_SOLVER_H +#define LIB2GEOM_SEEN_SOLVER_H + #include <2geom/point.h> #include <2geom/sbasis.h> - - #include - -namespace Geom{ +namespace Geom { class Point; class Bezier; @@ -78,7 +76,6 @@ find_bernstein_roots(std::vector &solutions, /* RETURN candidate t-value double left_t, double right_t); #endif - /* Local Variables: mode:c++ diff --git a/src/2geom/svg-elliptical-arc.cpp b/src/2geom/svg-elliptical-arc.cpp index 96a4f99d8..3a5154d08 100644 --- a/src/2geom/svg-elliptical-arc.cpp +++ b/src/2geom/svg-elliptical-arc.cpp @@ -207,7 +207,7 @@ bool make_elliptical_arc::make_elliptiarc() Ellipse e; try { - e.set(1, coeff[0], coeff[1], coeff[2], coeff[3], coeff[4]); + e.setCoefficients(1, coeff[0], coeff[1], coeff[2], coeff[3], coeff[4]); } catch(LogicalError const &exc) { diff --git a/src/2geom/svg-elliptical-arc.h b/src/2geom/svg-elliptical-arc.h index ba0a18257..90e16a999 100644 --- a/src/2geom/svg-elliptical-arc.h +++ b/src/2geom/svg-elliptical-arc.h @@ -70,59 +70,57 @@ public: _updateCenterAndAngles(true); } -#ifndef DOXYGEN_SHOULD_SKIP_THIS virtual Curve *duplicate() const { return new SVGEllipticalArc(*this); } virtual Coord valueAt(Coord t, Dim2 d) const { - if (isDegenerate()) return chord().valueAt(t, d); + if (isChord()) return chord().valueAt(t, d); return EllipticalArc::valueAt(t, d); } virtual Point pointAt(Coord t) const { - if (isDegenerate()) return chord().pointAt(t); + if (isChord()) return chord().pointAt(t); return EllipticalArc::pointAt(t); } virtual std::vector pointAndDerivatives(Coord t, unsigned int n) const { - if (isDegenerate()) return chord().pointAndDerivatives(t, n); + if (isChord()) return chord().pointAndDerivatives(t, n); return EllipticalArc::pointAndDerivatives(t, n); } virtual Rect boundsExact() const { - if (isDegenerate()) return chord().boundsExact(); + if (isChord()) return chord().boundsExact(); return EllipticalArc::boundsExact(); } virtual OptRect boundsLocal(OptInterval const &i, unsigned int deg) const { - if (isDegenerate()) return chord().boundsLocal(i, deg); + if (isChord()) return chord().boundsLocal(i, deg); return EllipticalArc::boundsLocal(i, deg); } virtual Curve *derivative() const { - if (isDegenerate()) return chord().derivative(); + if (isChord()) return chord().derivative(); return EllipticalArc::derivative(); } virtual std::vector roots(Coord v, Dim2 d) const { - if (isDegenerate()) return chord().roots(v, d); + if (isChord()) return chord().roots(v, d); return EllipticalArc::roots(v, d); } #ifdef HAVE_GSL - virtual std::vector allNearestPoints( Point const& p, double from = 0, double to = 1 ) const { - if (isDegenerate()) { + virtual std::vector allNearestTimes( Point const& p, double from = 0, double to = 1 ) const { + if (isChord()) { std::vector result; - result.push_back(chord().nearestPoint(p, from, to)); + result.push_back(chord().nearestTime(p, from, to)); return result; } - return EllipticalArc::allNearestPoints(p, from, to); + return EllipticalArc::allNearestTimes(p, from, to); } #endif virtual D2 toSBasis() const { - if (isDegenerate()) return chord().toSBasis(); + if (isChord()) return chord().toSBasis(); return EllipticalArc::toSBasis(); } virtual bool isSVGCompliant() const { return true; } // TODO move SVG-specific behavior here. //protected: //virtual void _updateCenterAndAngles(); -#endif }; // end class SVGEllipticalArc /* diff --git a/src/2geom/svg-path-parser.cpp b/src/2geom/svg-path-parser.cpp index 932f95829..89a912695 100644 --- a/src/2geom/svg-path-parser.cpp +++ b/src/2geom/svg-path-parser.cpp @@ -1,3 +1,5 @@ + +#line 1 "D:/lib2geom/trunk/src/2geom/svg-path-parser.rl" /** * \file * \brief parse SVG path specifications @@ -30,7 +32,7 @@ * */ - +#include #include #include #include @@ -41,229 +43,108 @@ namespace Geom { -namespace { - -class Parser { -public: - Parser(PathSink &sink) : _absolute(false), _sink(sink) {} - - void parse(char const *str) throw(SVGPathParseError); - -private: - bool _absolute; - Point _current; - Point _initial; - Point _cubic_tangent; - Point _quad_tangent; - std::vector _params; - PathSink &_sink; - - void _reset() { - _absolute = false; - _current = _initial = Point(0, 0); - _quad_tangent = _cubic_tangent = Point(0, 0); - _params.clear(); - } - - void _push(double value) { - _params.push_back(value); - } - - double _pop() { - double value = _params.back(); - _params.pop_back(); - return value; - } - - bool _pop_flag() { - return _pop() != 0.0; - } - - double _pop_coord(Geom::Dim2 axis) { - if (_absolute) { - return _pop(); - } else { - return _pop() + _current[axis]; - } - } - - Point _pop_point() { - double y = _pop_coord(Geom::Y); - double x = _pop_coord(Geom::X); - return Point(x, y); - } - - void _moveTo(Point p) { - _quad_tangent = _cubic_tangent = _current = _initial = p; - _sink.moveTo(p); - } - - void _hlineTo(Point p) { - _quad_tangent = _cubic_tangent = _current = p; - _sink.hlineTo(p[Geom::X]); - } - - void _vlineTo(Point p) { - _quad_tangent = _cubic_tangent = _current = p; - _sink.vlineTo(p[Geom::Y]); - } - - void _lineTo(Point p) { - _quad_tangent = _cubic_tangent = _current = p; - _sink.lineTo(p); - } - - void _curveTo(Point c0, Point c1, Point p) { - _quad_tangent = _current = p; - _cubic_tangent = p + ( p - c1 ); - _sink.curveTo(c0, c1, p); - } - - void _quadTo(Point c, Point p) { - _cubic_tangent = _current = p; - _quad_tangent = p + ( p - c ); - _sink.quadTo(c, p); - } - - void _arcTo(double rx, double ry, double angle, - bool large_arc, bool sweep, Point p) - { - if (are_near(_current, p)) { - return; - } - _quad_tangent = _cubic_tangent = _current = p; - _sink.arcTo(rx, ry, angle, large_arc, sweep, p); - } - - void _closePath() { - _quad_tangent = _cubic_tangent = _current = _initial; - _sink.closePath(); - } -}; - +#line 48 "D:/lib2geom/trunk/src/2geom/svg-path-parser.cpp" static const char _svg_path_actions[] = { 0, 1, 0, 1, 1, 1, 2, 1, - 3, 1, 4, 1, 5, 1, 15, 1, - 16, 2, 1, 0, 2, 1, 6, 2, - 1, 7, 2, 1, 8, 2, 1, 9, - 2, 1, 10, 2, 1, 11, 2, 1, - 12, 2, 1, 13, 2, 1, 14, 2, - 4, 0, 2, 5, 0, 2, 15, 16, - 3, 1, 6, 0, 3, 1, 6, 16, - 3, 1, 7, 0, 3, 1, 7, 16, - 3, 1, 8, 0, 3, 1, 8, 16, - 3, 1, 9, 0, 3, 1, 9, 16, - 3, 1, 10, 0, 3, 1, 10, 16, - 3, 1, 11, 0, 3, 1, 11, 16, - 3, 1, 12, 0, 3, 1, 12, 16, - 3, 1, 13, 0, 3, 1, 13, 16, - 3, 1, 14, 0, 3, 1, 14, 16 - + 3, 1, 4, 1, 5, 1, 15, 2, + 1, 0, 2, 1, 6, 2, 1, 7, + 2, 1, 8, 2, 1, 9, 2, 1, + 10, 2, 1, 11, 2, 1, 12, 2, + 1, 13, 2, 1, 14, 2, 2, 0, + 2, 3, 0, 2, 4, 0, 2, 5, + 0, 3, 1, 6, 0, 3, 1, 7, + 0, 3, 1, 8, 0, 3, 1, 9, + 0, 3, 1, 10, 0, 3, 1, 11, + 0, 3, 1, 12, 0, 3, 1, 13, + 0, 3, 1, 14, 0 }; static const short _svg_path_key_offsets[] = { - 0, 0, 7, 16, 25, 28, 30, 42, - 52, 55, 57, 90, 121, 124, 126, 138, - 148, 151, 153, 186, 195, 207, 216, 249, - 256, 263, 265, 275, 283, 290, 292, 304, - 314, 317, 319, 328, 335, 341, 346, 353, - 359, 364, 374, 377, 379, 391, 401, 404, - 406, 437, 466, 476, 480, 482, 490, 499, - 508, 511, 513, 525, 535, 538, 540, 552, - 562, 565, 567, 579, 589, 592, 594, 606, - 616, 619, 621, 633, 643, 646, 648, 681, - 712, 724, 733, 745, 754, 766, 775, 787, - 796, 808, 817, 850, 854, 856, 887, 896, - 905, 908, 910, 943, 974, 1007, 1011, 1013, - 1044, 1053, 1062, 1071, 1074, 1076, 1088, 1098, - 1101, 1103, 1115, 1125, 1128, 1130, 1142, 1152, - 1155, 1157, 1190, 1221, 1233, 1242, 1254, 1263, - 1275, 1284, 1317, 1321, 1323, 1354, 1363, 1372, - 1375, 1377, 1389, 1399, 1402, 1404, 1416, 1426, - 1429, 1431, 1443, 1453, 1456, 1458, 1491, 1522, - 1534, 1543, 1555, 1564, 1576, 1585, 1618, 1622, - 1624, 1655, 1664, 1673, 1676, 1678, 1690, 1700, - 1703, 1705, 1738, 1769, 1781, 1790, 1823, 1827, - 1829, 1860, 1869, 1878, 1881, 1883, 1916, 1947, - 1980, 1984, 1986, 2017, 2042, 2067, 2074, 2083, - 2092, 2101, 2110, 2122, 2131, 2164, 2168, 2170, - 2201, 2210, 2219, 2228, 2237, 2241, 2243, 2253, - 2257, 2259, 2269, 2273, 2275, 2285, 2289, 2291, - 2301, 2305, 2307, 2317, 2321, 2323, 2333, 2337, - 2339, 2349, 2353, 2355, 2365, 2369, 2371, 2381, - 2385, 2387, 2397, 2401, 2403, 2413, 2417, 2419, - 2429, 2433, 2435, 2445, 2449, 2451, 2480, 2511, - 2520, 2524, 2526, 2536, 2548, 2557, 2562, 2567, - 2571, 2573, 2580, 2590, 2599, 2603, 2605, 2615, - 2627, 2631, 2633, 2664, 2668, 2670, 2680 + 0, 0, 9, 18, 21, 23, 35, 45, + 48, 50, 53, 55, 67, 77, 80, 82, + 91, 103, 112, 119, 126, 128, 138, 146, + 153, 155, 167, 177, 180, 182, 191, 198, + 204, 211, 218, 224, 234, 244, 247, 249, + 261, 271, 274, 276, 286, 290, 292, 300, + 309, 318, 321, 323, 335, 345, 348, 350, + 362, 372, 375, 377, 389, 399, 402, 404, + 416, 426, 429, 431, 443, 453, 456, 458, + 470, 479, 491, 500, 512, 521, 533, 542, + 554, 563, 567, 569, 578, 587, 590, 592, + 596, 598, 607, 616, 625, 628, 630, 642, + 652, 655, 657, 669, 679, 682, 684, 696, + 706, 709, 711, 723, 732, 744, 753, 765, + 774, 778, 780, 789, 798, 801, 803, 815, + 825, 828, 830, 842, 852, 855, 857, 869, + 879, 882, 884, 896, 905, 917, 926, 938, + 947, 951, 953, 962, 971, 974, 976, 988, + 998, 1001, 1003, 1015, 1024, 1028, 1030, 1039, + 1048, 1051, 1053, 1057, 1059, 1066, 1075, 1084, + 1093, 1102, 1114, 1123, 1127, 1129, 1138, 1147, + 1156, 1165, 1169, 1171, 1181, 1185, 1187, 1197, + 1201, 1203, 1213, 1217, 1219, 1229, 1233, 1235, + 1245, 1249, 1251, 1261, 1265, 1267, 1277, 1281, + 1283, 1293, 1297, 1299, 1309, 1313, 1315, 1325, + 1329, 1331, 1341, 1345, 1347, 1357, 1361, 1363, + 1373, 1377, 1379, 1388, 1392, 1394, 1404, 1416, + 1425, 1435, 1442, 1446, 1448, 1455, 1465, 1474, + 1478, 1480, 1490, 1502, 1506, 1508, 1512, 1514, + 1524, 1530, 1562, 1592, 1624, 1656, 1686, 1714, + 1746, 1776, 1808, 1838, 1870, 1900, 1932, 1962, + 1994, 2024, 2056, 2086, 2118, 2148, 2180, 2210, + 2242, 2272, 2304, 2334, 2366, 2396, 2428, 2458, + 2482, 2506, 2538, 2568, 2596, 2626 }; static const char _svg_path_trans_keys[] = { - 0, 13, 32, 77, 109, 9, 10, 13, - 32, 43, 45, 46, 9, 10, 48, 57, 13, 32, 43, 45, 46, 9, 10, 48, - 57, 46, 48, 57, 48, 57, 13, 32, - 44, 46, 69, 101, 9, 10, 43, 45, - 48, 57, 13, 32, 44, 46, 9, 10, - 43, 45, 48, 57, 46, 48, 57, 48, - 57, 0, 13, 32, 44, 46, 65, 67, - 69, 72, 76, 77, 81, 83, 84, 86, - 90, 97, 99, 101, 104, 108, 109, 113, - 115, 116, 118, 122, 9, 10, 43, 45, - 48, 57, 0, 13, 32, 44, 46, 65, - 67, 72, 76, 77, 81, 83, 84, 86, - 90, 97, 99, 104, 108, 109, 113, 115, - 116, 118, 122, 9, 10, 43, 45, 48, - 57, 46, 48, 57, 48, 57, 13, 32, - 44, 46, 69, 101, 9, 10, 43, 45, - 48, 57, 13, 32, 44, 46, 9, 10, - 43, 45, 48, 57, 46, 48, 57, 48, - 57, 0, 13, 32, 44, 46, 65, 67, - 69, 72, 76, 77, 81, 83, 84, 86, - 90, 97, 99, 101, 104, 108, 109, 113, - 115, 116, 118, 122, 9, 10, 43, 45, + 57, 13, 32, 43, 45, 46, 9, 10, + 48, 57, 46, 48, 57, 48, 57, 13, + 32, 44, 46, 69, 101, 9, 10, 43, + 45, 48, 57, 13, 32, 44, 46, 9, + 10, 43, 45, 48, 57, 46, 48, 57, + 48, 57, 46, 48, 57, 48, 57, 13, + 32, 44, 46, 69, 101, 9, 10, 43, + 45, 48, 57, 13, 32, 44, 46, 9, + 10, 43, 45, 48, 57, 46, 48, 57, 48, 57, 13, 32, 43, 45, 46, 9, 10, 48, 57, 13, 32, 44, 46, 69, 101, 9, 10, 43, 45, 48, 57, 13, 32, 43, 45, 46, 9, 10, 48, 57, - 0, 13, 32, 44, 46, 65, 67, 69, - 72, 76, 77, 81, 83, 84, 86, 90, - 97, 99, 101, 104, 108, 109, 113, 115, - 116, 118, 122, 9, 10, 43, 45, 48, - 57, 13, 32, 46, 9, 10, 48, 57, - 13, 32, 46, 9, 10, 48, 57, 48, + 13, 32, 46, 9, 10, 48, 57, 13, + 32, 46, 9, 10, 48, 57, 48, 57, + 13, 32, 44, 46, 69, 101, 9, 10, + 48, 57, 13, 32, 44, 46, 9, 10, + 48, 57, 13, 32, 46, 9, 10, 48, + 57, 48, 57, 13, 32, 44, 46, 69, + 101, 9, 10, 43, 45, 48, 57, 13, + 32, 44, 46, 9, 10, 43, 45, 48, + 57, 46, 48, 57, 48, 57, 13, 32, + 44, 69, 101, 9, 10, 48, 57, 13, + 32, 44, 48, 49, 9, 10, 13, 32, + 48, 49, 9, 10, 13, 32, 44, 48, + 49, 9, 10, 13, 32, 44, 48, 49, + 9, 10, 13, 32, 48, 49, 9, 10, + 13, 32, 44, 46, 9, 10, 43, 45, + 48, 57, 13, 32, 44, 46, 9, 10, + 43, 45, 48, 57, 46, 48, 57, 48, 57, 13, 32, 44, 46, 69, 101, 9, - 10, 48, 57, 13, 32, 44, 46, 9, - 10, 48, 57, 13, 32, 46, 9, 10, + 10, 43, 45, 48, 57, 13, 32, 44, + 46, 9, 10, 43, 45, 48, 57, 46, 48, 57, 48, 57, 13, 32, 44, 46, - 69, 101, 9, 10, 43, 45, 48, 57, - 13, 32, 44, 46, 9, 10, 43, 45, - 48, 57, 46, 48, 57, 48, 57, 13, - 32, 44, 69, 101, 9, 10, 48, 57, - 13, 32, 44, 48, 49, 9, 10, 13, - 32, 48, 49, 9, 10, 13, 32, 44, - 9, 10, 13, 32, 44, 48, 49, 9, - 10, 13, 32, 48, 49, 9, 10, 13, - 32, 44, 9, 10, 13, 32, 44, 46, - 9, 10, 43, 45, 48, 57, 46, 48, + 69, 101, 9, 10, 48, 57, 43, 45, + 48, 57, 48, 57, 13, 32, 44, 46, + 9, 10, 48, 57, 13, 32, 43, 45, + 46, 9, 10, 48, 57, 13, 32, 43, + 45, 46, 9, 10, 48, 57, 46, 48, 57, 48, 57, 13, 32, 44, 46, 69, 101, 9, 10, 43, 45, 48, 57, 13, 32, 44, 46, 9, 10, 43, 45, 48, - 57, 46, 48, 57, 48, 57, 0, 13, - 32, 44, 46, 65, 67, 69, 72, 76, - 77, 81, 83, 84, 86, 90, 97, 99, - 101, 104, 108, 109, 113, 115, 116, 118, - 122, 9, 10, 48, 57, 0, 13, 32, - 44, 46, 65, 67, 72, 76, 77, 81, - 83, 84, 86, 90, 97, 99, 104, 108, - 109, 113, 115, 116, 118, 122, 9, 10, - 48, 57, 13, 32, 44, 46, 69, 101, - 9, 10, 48, 57, 43, 45, 48, 57, + 57, 46, 48, 57, 48, 57, 13, 32, + 44, 46, 69, 101, 9, 10, 43, 45, 48, 57, 13, 32, 44, 46, 9, 10, - 48, 57, 13, 32, 43, 45, 46, 9, - 10, 48, 57, 13, 32, 43, 45, 46, - 9, 10, 48, 57, 46, 48, 57, 48, + 43, 45, 48, 57, 46, 48, 57, 48, 57, 13, 32, 44, 46, 69, 101, 9, 10, 43, 45, 48, 57, 13, 32, 44, 46, 9, 10, 43, 45, 48, 57, 46, @@ -276,891 +157,1057 @@ static const char _svg_path_trans_keys[] = { 10, 43, 45, 48, 57, 46, 48, 57, 48, 57, 13, 32, 44, 46, 69, 101, 9, 10, 43, 45, 48, 57, 13, 32, - 44, 46, 9, 10, 43, 45, 48, 57, - 46, 48, 57, 48, 57, 13, 32, 44, - 46, 69, 101, 9, 10, 43, 45, 48, - 57, 13, 32, 44, 46, 9, 10, 43, - 45, 48, 57, 46, 48, 57, 48, 57, - 0, 13, 32, 44, 46, 65, 67, 69, - 72, 76, 77, 81, 83, 84, 86, 90, - 97, 99, 101, 104, 108, 109, 113, 115, - 116, 118, 122, 9, 10, 43, 45, 48, - 57, 0, 13, 32, 44, 46, 65, 67, - 72, 76, 77, 81, 83, 84, 86, 90, - 97, 99, 104, 108, 109, 113, 115, 116, - 118, 122, 9, 10, 43, 45, 48, 57, - 13, 32, 44, 46, 69, 101, 9, 10, - 43, 45, 48, 57, 13, 32, 43, 45, - 46, 9, 10, 48, 57, 13, 32, 44, - 46, 69, 101, 9, 10, 43, 45, 48, - 57, 13, 32, 43, 45, 46, 9, 10, - 48, 57, 13, 32, 44, 46, 69, 101, - 9, 10, 43, 45, 48, 57, 13, 32, 43, 45, 46, 9, 10, 48, 57, 13, 32, 44, 46, 69, 101, 9, 10, 43, 45, 48, 57, 13, 32, 43, 45, 46, 9, 10, 48, 57, 13, 32, 44, 46, 69, 101, 9, 10, 43, 45, 48, 57, 13, 32, 43, 45, 46, 9, 10, 48, - 57, 0, 13, 32, 44, 46, 65, 67, - 69, 72, 76, 77, 81, 83, 84, 86, - 90, 97, 99, 101, 104, 108, 109, 113, - 115, 116, 118, 122, 9, 10, 43, 45, - 48, 57, 43, 45, 48, 57, 48, 57, - 0, 13, 32, 44, 46, 65, 67, 72, - 76, 77, 81, 83, 84, 86, 90, 97, - 99, 104, 108, 109, 113, 115, 116, 118, - 122, 9, 10, 43, 45, 48, 57, 13, + 57, 13, 32, 44, 46, 69, 101, 9, + 10, 43, 45, 48, 57, 13, 32, 43, + 45, 46, 9, 10, 48, 57, 13, 32, + 44, 46, 69, 101, 9, 10, 43, 45, + 48, 57, 13, 32, 43, 45, 46, 9, + 10, 48, 57, 43, 45, 48, 57, 48, + 57, 13, 32, 43, 45, 46, 9, 10, + 48, 57, 13, 32, 43, 45, 46, 9, + 10, 48, 57, 46, 48, 57, 48, 57, + 43, 45, 48, 57, 48, 57, 13, 32, + 43, 45, 46, 9, 10, 48, 57, 13, 32, 43, 45, 46, 9, 10, 48, 57, 13, 32, 43, 45, 46, 9, 10, 48, - 57, 46, 48, 57, 48, 57, 0, 13, - 32, 44, 46, 65, 67, 69, 72, 76, - 77, 81, 83, 84, 86, 90, 97, 99, - 101, 104, 108, 109, 113, 115, 116, 118, - 122, 9, 10, 43, 45, 48, 57, 0, - 13, 32, 44, 46, 65, 67, 72, 76, - 77, 81, 83, 84, 86, 90, 97, 99, - 104, 108, 109, 113, 115, 116, 118, 122, - 9, 10, 43, 45, 48, 57, 0, 13, - 32, 44, 46, 65, 67, 69, 72, 76, - 77, 81, 83, 84, 86, 90, 97, 99, - 101, 104, 108, 109, 113, 115, 116, 118, - 122, 9, 10, 43, 45, 48, 57, 43, - 45, 48, 57, 48, 57, 0, 13, 32, - 44, 46, 65, 67, 72, 76, 77, 81, - 83, 84, 86, 90, 97, 99, 104, 108, - 109, 113, 115, 116, 118, 122, 9, 10, - 43, 45, 48, 57, 13, 32, 43, 45, - 46, 9, 10, 48, 57, 13, 32, 43, - 45, 46, 9, 10, 48, 57, 13, 32, - 43, 45, 46, 9, 10, 48, 57, 46, + 57, 46, 48, 57, 48, 57, 13, 32, + 44, 46, 69, 101, 9, 10, 43, 45, + 48, 57, 13, 32, 44, 46, 9, 10, + 43, 45, 48, 57, 46, 48, 57, 48, + 57, 13, 32, 44, 46, 69, 101, 9, + 10, 43, 45, 48, 57, 13, 32, 44, + 46, 9, 10, 43, 45, 48, 57, 46, 48, 57, 48, 57, 13, 32, 44, 46, 69, 101, 9, 10, 43, 45, 48, 57, 13, 32, 44, 46, 9, 10, 43, 45, 48, 57, 46, 48, 57, 48, 57, 13, 32, 44, 46, 69, 101, 9, 10, 43, - 45, 48, 57, 13, 32, 44, 46, 9, - 10, 43, 45, 48, 57, 46, 48, 57, - 48, 57, 13, 32, 44, 46, 69, 101, - 9, 10, 43, 45, 48, 57, 13, 32, - 44, 46, 9, 10, 43, 45, 48, 57, - 46, 48, 57, 48, 57, 0, 13, 32, - 44, 46, 65, 67, 69, 72, 76, 77, - 81, 83, 84, 86, 90, 97, 99, 101, - 104, 108, 109, 113, 115, 116, 118, 122, - 9, 10, 43, 45, 48, 57, 0, 13, - 32, 44, 46, 65, 67, 72, 76, 77, - 81, 83, 84, 86, 90, 97, 99, 104, - 108, 109, 113, 115, 116, 118, 122, 9, - 10, 43, 45, 48, 57, 13, 32, 44, - 46, 69, 101, 9, 10, 43, 45, 48, - 57, 13, 32, 43, 45, 46, 9, 10, - 48, 57, 13, 32, 44, 46, 69, 101, - 9, 10, 43, 45, 48, 57, 13, 32, - 43, 45, 46, 9, 10, 48, 57, 13, - 32, 44, 46, 69, 101, 9, 10, 43, 45, 48, 57, 13, 32, 43, 45, 46, - 9, 10, 48, 57, 0, 13, 32, 44, - 46, 65, 67, 69, 72, 76, 77, 81, - 83, 84, 86, 90, 97, 99, 101, 104, - 108, 109, 113, 115, 116, 118, 122, 9, - 10, 43, 45, 48, 57, 43, 45, 48, - 57, 48, 57, 0, 13, 32, 44, 46, - 65, 67, 72, 76, 77, 81, 83, 84, - 86, 90, 97, 99, 104, 108, 109, 113, - 115, 116, 118, 122, 9, 10, 43, 45, - 48, 57, 13, 32, 43, 45, 46, 9, - 10, 48, 57, 13, 32, 43, 45, 46, - 9, 10, 48, 57, 46, 48, 57, 48, + 9, 10, 48, 57, 13, 32, 44, 46, + 69, 101, 9, 10, 43, 45, 48, 57, + 13, 32, 43, 45, 46, 9, 10, 48, + 57, 13, 32, 44, 46, 69, 101, 9, + 10, 43, 45, 48, 57, 13, 32, 43, + 45, 46, 9, 10, 48, 57, 43, 45, + 48, 57, 48, 57, 13, 32, 43, 45, + 46, 9, 10, 48, 57, 13, 32, 43, + 45, 46, 9, 10, 48, 57, 46, 48, + 57, 48, 57, 13, 32, 44, 46, 69, + 101, 9, 10, 43, 45, 48, 57, 13, + 32, 44, 46, 9, 10, 43, 45, 48, + 57, 46, 48, 57, 48, 57, 13, 32, + 44, 46, 69, 101, 9, 10, 43, 45, + 48, 57, 13, 32, 44, 46, 9, 10, + 43, 45, 48, 57, 46, 48, 57, 48, 57, 13, 32, 44, 46, 69, 101, 9, 10, 43, 45, 48, 57, 13, 32, 44, 46, 9, 10, 43, 45, 48, 57, 46, 48, 57, 48, 57, 13, 32, 44, 46, 69, 101, 9, 10, 43, 45, 48, 57, + 13, 32, 43, 45, 46, 9, 10, 48, + 57, 13, 32, 44, 46, 69, 101, 9, + 10, 43, 45, 48, 57, 13, 32, 43, + 45, 46, 9, 10, 48, 57, 13, 32, + 44, 46, 69, 101, 9, 10, 43, 45, + 48, 57, 13, 32, 43, 45, 46, 9, + 10, 48, 57, 43, 45, 48, 57, 48, + 57, 13, 32, 43, 45, 46, 9, 10, + 48, 57, 13, 32, 43, 45, 46, 9, + 10, 48, 57, 46, 48, 57, 48, 57, + 13, 32, 44, 46, 69, 101, 9, 10, + 43, 45, 48, 57, 13, 32, 44, 46, + 9, 10, 43, 45, 48, 57, 46, 48, + 57, 48, 57, 13, 32, 44, 46, 69, + 101, 9, 10, 43, 45, 48, 57, 13, + 32, 43, 45, 46, 9, 10, 48, 57, + 43, 45, 48, 57, 48, 57, 13, 32, + 43, 45, 46, 9, 10, 48, 57, 13, + 32, 43, 45, 46, 9, 10, 48, 57, + 46, 48, 57, 48, 57, 43, 45, 48, + 57, 48, 57, 13, 32, 46, 9, 10, + 48, 57, 13, 32, 43, 45, 46, 9, + 10, 48, 57, 13, 32, 43, 45, 46, + 9, 10, 48, 57, 13, 32, 43, 45, + 46, 9, 10, 48, 57, 13, 32, 43, + 45, 46, 9, 10, 48, 57, 13, 32, + 44, 46, 69, 101, 9, 10, 43, 45, + 48, 57, 13, 32, 43, 45, 46, 9, + 10, 48, 57, 43, 45, 48, 57, 48, + 57, 13, 32, 43, 45, 46, 9, 10, + 48, 57, 13, 32, 43, 45, 46, 9, + 10, 48, 57, 13, 32, 43, 45, 46, + 9, 10, 48, 57, 13, 32, 43, 45, + 46, 9, 10, 48, 57, 43, 45, 48, + 57, 48, 57, 13, 32, 44, 46, 9, + 10, 43, 45, 48, 57, 43, 45, 48, + 57, 48, 57, 13, 32, 44, 46, 9, + 10, 43, 45, 48, 57, 43, 45, 48, + 57, 48, 57, 13, 32, 44, 46, 9, + 10, 43, 45, 48, 57, 43, 45, 48, + 57, 48, 57, 13, 32, 44, 46, 9, + 10, 43, 45, 48, 57, 43, 45, 48, + 57, 48, 57, 13, 32, 44, 46, 9, + 10, 43, 45, 48, 57, 43, 45, 48, + 57, 48, 57, 13, 32, 44, 46, 9, + 10, 43, 45, 48, 57, 43, 45, 48, + 57, 48, 57, 13, 32, 44, 46, 9, + 10, 43, 45, 48, 57, 43, 45, 48, + 57, 48, 57, 13, 32, 44, 46, 9, + 10, 43, 45, 48, 57, 43, 45, 48, + 57, 48, 57, 13, 32, 44, 46, 9, + 10, 43, 45, 48, 57, 43, 45, 48, + 57, 48, 57, 13, 32, 44, 46, 9, + 10, 43, 45, 48, 57, 43, 45, 48, + 57, 48, 57, 13, 32, 44, 46, 9, + 10, 43, 45, 48, 57, 43, 45, 48, + 57, 48, 57, 13, 32, 44, 46, 9, + 10, 43, 45, 48, 57, 43, 45, 48, + 57, 48, 57, 13, 32, 44, 46, 9, + 10, 43, 45, 48, 57, 43, 45, 48, + 57, 48, 57, 13, 32, 43, 45, 46, + 9, 10, 48, 57, 43, 45, 48, 57, + 48, 57, 13, 32, 44, 46, 9, 10, + 43, 45, 48, 57, 13, 32, 44, 46, + 69, 101, 9, 10, 43, 45, 48, 57, + 13, 32, 43, 45, 46, 9, 10, 48, + 57, 13, 32, 44, 46, 9, 10, 43, + 45, 48, 57, 13, 32, 44, 48, 49, + 9, 10, 43, 45, 48, 57, 48, 57, + 13, 32, 44, 9, 10, 48, 57, 13, + 32, 44, 46, 69, 101, 9, 10, 48, + 57, 13, 32, 43, 45, 46, 9, 10, + 48, 57, 43, 45, 48, 57, 48, 57, 13, 32, 44, 46, 9, 10, 43, 45, - 48, 57, 46, 48, 57, 48, 57, 13, - 32, 44, 46, 69, 101, 9, 10, 43, - 45, 48, 57, 13, 32, 44, 46, 9, - 10, 43, 45, 48, 57, 46, 48, 57, - 48, 57, 0, 13, 32, 44, 46, 65, - 67, 69, 72, 76, 77, 81, 83, 84, - 86, 90, 97, 99, 101, 104, 108, 109, - 113, 115, 116, 118, 122, 9, 10, 43, - 45, 48, 57, 0, 13, 32, 44, 46, + 48, 57, 13, 32, 44, 46, 69, 101, + 9, 10, 43, 45, 48, 57, 43, 45, + 48, 57, 48, 57, 43, 45, 48, 57, + 48, 57, 13, 32, 44, 46, 9, 10, + 43, 45, 48, 57, 13, 32, 77, 109, + 9, 10, 13, 32, 44, 46, 65, 67, + 69, 72, 76, 77, 81, 83, 84, 86, + 90, 97, 99, 101, 104, 108, 109, 113, + 115, 116, 118, 122, 9, 10, 43, 45, + 48, 57, 13, 32, 44, 46, 65, 67, + 72, 76, 77, 81, 83, 84, 86, 90, + 97, 99, 104, 108, 109, 113, 115, 116, + 118, 122, 9, 10, 43, 45, 48, 57, + 13, 32, 44, 46, 65, 67, 69, 72, + 76, 77, 81, 83, 84, 86, 90, 97, + 99, 101, 104, 108, 109, 113, 115, 116, + 118, 122, 9, 10, 43, 45, 48, 57, + 13, 32, 44, 46, 65, 67, 69, 72, + 76, 77, 81, 83, 84, 86, 90, 97, + 99, 101, 104, 108, 109, 113, 115, 116, + 118, 122, 9, 10, 43, 45, 48, 57, + 13, 32, 44, 46, 65, 67, 69, 72, + 76, 77, 81, 83, 84, 86, 90, 97, + 99, 101, 104, 108, 109, 113, 115, 116, + 118, 122, 9, 10, 48, 57, 13, 32, + 44, 46, 65, 67, 72, 76, 77, 81, + 83, 84, 86, 90, 97, 99, 104, 108, + 109, 113, 115, 116, 118, 122, 9, 10, + 48, 57, 13, 32, 44, 46, 65, 67, + 69, 72, 76, 77, 81, 83, 84, 86, + 90, 97, 99, 101, 104, 108, 109, 113, + 115, 116, 118, 122, 9, 10, 43, 45, + 48, 57, 13, 32, 44, 46, 65, 67, + 72, 76, 77, 81, 83, 84, 86, 90, + 97, 99, 104, 108, 109, 113, 115, 116, + 118, 122, 9, 10, 43, 45, 48, 57, + 13, 32, 44, 46, 65, 67, 69, 72, + 76, 77, 81, 83, 84, 86, 90, 97, + 99, 101, 104, 108, 109, 113, 115, 116, + 118, 122, 9, 10, 43, 45, 48, 57, + 13, 32, 44, 46, 65, 67, 72, 76, + 77, 81, 83, 84, 86, 90, 97, 99, + 104, 108, 109, 113, 115, 116, 118, 122, + 9, 10, 43, 45, 48, 57, 13, 32, + 44, 46, 65, 67, 69, 72, 76, 77, + 81, 83, 84, 86, 90, 97, 99, 101, + 104, 108, 109, 113, 115, 116, 118, 122, + 9, 10, 43, 45, 48, 57, 13, 32, + 44, 46, 65, 67, 72, 76, 77, 81, + 83, 84, 86, 90, 97, 99, 104, 108, + 109, 113, 115, 116, 118, 122, 9, 10, + 43, 45, 48, 57, 13, 32, 44, 46, + 65, 67, 69, 72, 76, 77, 81, 83, + 84, 86, 90, 97, 99, 101, 104, 108, + 109, 113, 115, 116, 118, 122, 9, 10, + 43, 45, 48, 57, 13, 32, 44, 46, 65, 67, 72, 76, 77, 81, 83, 84, 86, 90, 97, 99, 104, 108, 109, 113, 115, 116, 118, 122, 9, 10, 43, 45, - 48, 57, 13, 32, 44, 46, 69, 101, - 9, 10, 43, 45, 48, 57, 13, 32, - 43, 45, 46, 9, 10, 48, 57, 13, - 32, 44, 46, 69, 101, 9, 10, 43, - 45, 48, 57, 13, 32, 43, 45, 46, - 9, 10, 48, 57, 13, 32, 44, 46, - 69, 101, 9, 10, 43, 45, 48, 57, - 13, 32, 43, 45, 46, 9, 10, 48, - 57, 0, 13, 32, 44, 46, 65, 67, + 48, 57, 13, 32, 44, 46, 65, 67, 69, 72, 76, 77, 81, 83, 84, 86, 90, 97, 99, 101, 104, 108, 109, 113, 115, 116, 118, 122, 9, 10, 43, 45, - 48, 57, 43, 45, 48, 57, 48, 57, - 0, 13, 32, 44, 46, 65, 67, 72, + 48, 57, 13, 32, 44, 46, 65, 67, + 72, 76, 77, 81, 83, 84, 86, 90, + 97, 99, 104, 108, 109, 113, 115, 116, + 118, 122, 9, 10, 43, 45, 48, 57, + 13, 32, 44, 46, 65, 67, 69, 72, 76, 77, 81, 83, 84, 86, 90, 97, - 99, 104, 108, 109, 113, 115, 116, 118, - 122, 9, 10, 43, 45, 48, 57, 13, - 32, 43, 45, 46, 9, 10, 48, 57, - 13, 32, 43, 45, 46, 9, 10, 48, - 57, 46, 48, 57, 48, 57, 13, 32, - 44, 46, 69, 101, 9, 10, 43, 45, - 48, 57, 13, 32, 44, 46, 9, 10, - 43, 45, 48, 57, 46, 48, 57, 48, - 57, 0, 13, 32, 44, 46, 65, 67, + 99, 101, 104, 108, 109, 113, 115, 116, + 118, 122, 9, 10, 43, 45, 48, 57, + 13, 32, 44, 46, 65, 67, 72, 76, + 77, 81, 83, 84, 86, 90, 97, 99, + 104, 108, 109, 113, 115, 116, 118, 122, + 9, 10, 43, 45, 48, 57, 13, 32, + 44, 46, 65, 67, 69, 72, 76, 77, + 81, 83, 84, 86, 90, 97, 99, 101, + 104, 108, 109, 113, 115, 116, 118, 122, + 9, 10, 43, 45, 48, 57, 13, 32, + 44, 46, 65, 67, 72, 76, 77, 81, + 83, 84, 86, 90, 97, 99, 104, 108, + 109, 113, 115, 116, 118, 122, 9, 10, + 43, 45, 48, 57, 13, 32, 44, 46, + 65, 67, 69, 72, 76, 77, 81, 83, + 84, 86, 90, 97, 99, 101, 104, 108, + 109, 113, 115, 116, 118, 122, 9, 10, + 43, 45, 48, 57, 13, 32, 44, 46, + 65, 67, 72, 76, 77, 81, 83, 84, + 86, 90, 97, 99, 104, 108, 109, 113, + 115, 116, 118, 122, 9, 10, 43, 45, + 48, 57, 13, 32, 44, 46, 65, 67, 69, 72, 76, 77, 81, 83, 84, 86, 90, 97, 99, 101, 104, 108, 109, 113, 115, 116, 118, 122, 9, 10, 43, 45, - 48, 57, 0, 13, 32, 44, 46, 65, - 67, 72, 76, 77, 81, 83, 84, 86, - 90, 97, 99, 104, 108, 109, 113, 115, - 116, 118, 122, 9, 10, 43, 45, 48, - 57, 13, 32, 44, 46, 69, 101, 9, - 10, 43, 45, 48, 57, 13, 32, 43, - 45, 46, 9, 10, 48, 57, 0, 13, - 32, 44, 46, 65, 67, 69, 72, 76, + 48, 57, 13, 32, 44, 46, 65, 67, + 72, 76, 77, 81, 83, 84, 86, 90, + 97, 99, 104, 108, 109, 113, 115, 116, + 118, 122, 9, 10, 43, 45, 48, 57, + 13, 32, 44, 46, 65, 67, 69, 72, + 76, 77, 81, 83, 84, 86, 90, 97, + 99, 101, 104, 108, 109, 113, 115, 116, + 118, 122, 9, 10, 43, 45, 48, 57, + 13, 32, 44, 46, 65, 67, 72, 76, 77, 81, 83, 84, 86, 90, 97, 99, - 101, 104, 108, 109, 113, 115, 116, 118, - 122, 9, 10, 43, 45, 48, 57, 43, - 45, 48, 57, 48, 57, 0, 13, 32, + 104, 108, 109, 113, 115, 116, 118, 122, + 9, 10, 43, 45, 48, 57, 13, 32, + 44, 46, 65, 67, 69, 72, 76, 77, + 81, 83, 84, 86, 90, 97, 99, 101, + 104, 108, 109, 113, 115, 116, 118, 122, + 9, 10, 43, 45, 48, 57, 13, 32, 44, 46, 65, 67, 72, 76, 77, 81, 83, 84, 86, 90, 97, 99, 104, 108, 109, 113, 115, 116, 118, 122, 9, 10, - 43, 45, 48, 57, 13, 32, 43, 45, - 46, 9, 10, 48, 57, 13, 32, 43, - 45, 46, 9, 10, 48, 57, 46, 48, - 57, 48, 57, 0, 13, 32, 44, 46, - 65, 67, 69, 72, 76, 77, 81, 83, - 84, 86, 90, 97, 99, 101, 104, 108, - 109, 113, 115, 116, 118, 122, 9, 10, - 43, 45, 48, 57, 0, 13, 32, 44, - 46, 65, 67, 72, 76, 77, 81, 83, - 84, 86, 90, 97, 99, 104, 108, 109, - 113, 115, 116, 118, 122, 9, 10, 43, - 45, 48, 57, 0, 13, 32, 44, 46, + 43, 45, 48, 57, 13, 32, 44, 46, 65, 67, 69, 72, 76, 77, 81, 83, 84, 86, 90, 97, 99, 101, 104, 108, 109, 113, 115, 116, 118, 122, 9, 10, - 43, 45, 48, 57, 43, 45, 48, 57, - 48, 57, 0, 13, 32, 44, 46, 65, - 67, 72, 76, 77, 81, 83, 84, 86, - 90, 97, 99, 104, 108, 109, 113, 115, - 116, 118, 122, 9, 10, 43, 45, 48, - 57, 0, 13, 32, 65, 67, 72, 76, + 43, 45, 48, 57, 13, 32, 44, 46, + 65, 67, 72, 76, 77, 81, 83, 84, + 86, 90, 97, 99, 104, 108, 109, 113, + 115, 116, 118, 122, 9, 10, 43, 45, + 48, 57, 13, 32, 65, 67, 72, 76, 77, 81, 83, 84, 86, 90, 97, 99, 104, 108, 109, 113, 115, 116, 118, 122, - 9, 10, 0, 13, 32, 65, 67, 72, - 76, 77, 81, 83, 84, 86, 90, 97, - 99, 104, 108, 109, 113, 115, 116, 118, - 122, 9, 10, 13, 32, 46, 9, 10, - 48, 57, 13, 32, 43, 45, 46, 9, - 10, 48, 57, 13, 32, 43, 45, 46, - 9, 10, 48, 57, 13, 32, 43, 45, - 46, 9, 10, 48, 57, 13, 32, 43, - 45, 46, 9, 10, 48, 57, 13, 32, - 44, 46, 69, 101, 9, 10, 43, 45, - 48, 57, 13, 32, 43, 45, 46, 9, - 10, 48, 57, 0, 13, 32, 44, 46, + 9, 10, 13, 32, 65, 67, 72, 76, + 77, 81, 83, 84, 86, 90, 97, 99, + 104, 108, 109, 113, 115, 116, 118, 122, + 9, 10, 13, 32, 44, 46, 65, 67, + 69, 72, 76, 77, 81, 83, 84, 86, + 90, 97, 99, 101, 104, 108, 109, 113, + 115, 116, 118, 122, 9, 10, 43, 45, + 48, 57, 13, 32, 44, 46, 65, 67, + 72, 76, 77, 81, 83, 84, 86, 90, + 97, 99, 104, 108, 109, 113, 115, 116, + 118, 122, 9, 10, 43, 45, 48, 57, + 13, 32, 44, 46, 65, 67, 72, 76, + 77, 81, 83, 84, 86, 90, 97, 99, + 104, 108, 109, 113, 115, 116, 118, 122, + 9, 10, 48, 57, 13, 32, 44, 46, 65, 67, 69, 72, 76, 77, 81, 83, 84, 86, 90, 97, 99, 101, 104, 108, 109, 113, 115, 116, 118, 122, 9, 10, - 43, 45, 48, 57, 43, 45, 48, 57, - 48, 57, 0, 13, 32, 44, 46, 65, - 67, 72, 76, 77, 81, 83, 84, 86, - 90, 97, 99, 104, 108, 109, 113, 115, - 116, 118, 122, 9, 10, 43, 45, 48, - 57, 13, 32, 43, 45, 46, 9, 10, - 48, 57, 13, 32, 43, 45, 46, 9, - 10, 48, 57, 13, 32, 43, 45, 46, - 9, 10, 48, 57, 13, 32, 43, 45, - 46, 9, 10, 48, 57, 43, 45, 48, - 57, 48, 57, 13, 32, 44, 46, 9, - 10, 43, 45, 48, 57, 43, 45, 48, - 57, 48, 57, 13, 32, 44, 46, 9, - 10, 43, 45, 48, 57, 43, 45, 48, - 57, 48, 57, 13, 32, 44, 46, 9, - 10, 43, 45, 48, 57, 43, 45, 48, - 57, 48, 57, 13, 32, 44, 46, 9, - 10, 43, 45, 48, 57, 43, 45, 48, - 57, 48, 57, 13, 32, 44, 46, 9, - 10, 43, 45, 48, 57, 43, 45, 48, - 57, 48, 57, 13, 32, 44, 46, 9, - 10, 43, 45, 48, 57, 43, 45, 48, - 57, 48, 57, 13, 32, 44, 46, 9, - 10, 43, 45, 48, 57, 43, 45, 48, - 57, 48, 57, 13, 32, 44, 46, 9, - 10, 43, 45, 48, 57, 43, 45, 48, - 57, 48, 57, 13, 32, 44, 46, 9, - 10, 43, 45, 48, 57, 43, 45, 48, - 57, 48, 57, 13, 32, 44, 46, 9, - 10, 43, 45, 48, 57, 43, 45, 48, - 57, 48, 57, 13, 32, 44, 46, 9, - 10, 43, 45, 48, 57, 43, 45, 48, - 57, 48, 57, 13, 32, 44, 46, 9, - 10, 43, 45, 48, 57, 43, 45, 48, - 57, 48, 57, 13, 32, 44, 46, 9, - 10, 43, 45, 48, 57, 43, 45, 48, - 57, 48, 57, 0, 13, 32, 44, 46, - 65, 67, 72, 76, 77, 81, 83, 84, - 86, 90, 97, 99, 104, 108, 109, 113, - 115, 116, 118, 122, 9, 10, 48, 57, - 0, 13, 32, 44, 46, 65, 67, 69, - 72, 76, 77, 81, 83, 84, 86, 90, - 97, 99, 101, 104, 108, 109, 113, 115, - 116, 118, 122, 9, 10, 48, 57, 13, - 32, 43, 45, 46, 9, 10, 48, 57, - 43, 45, 48, 57, 48, 57, 13, 32, - 44, 46, 9, 10, 43, 45, 48, 57, - 13, 32, 44, 46, 69, 101, 9, 10, - 43, 45, 48, 57, 13, 32, 43, 45, - 46, 9, 10, 48, 57, 13, 32, 44, - 9, 10, 13, 32, 44, 9, 10, 43, - 45, 48, 57, 48, 57, 13, 32, 44, - 9, 10, 48, 57, 13, 32, 44, 46, - 69, 101, 9, 10, 48, 57, 13, 32, - 43, 45, 46, 9, 10, 48, 57, 43, - 45, 48, 57, 48, 57, 13, 32, 44, - 46, 9, 10, 43, 45, 48, 57, 13, - 32, 44, 46, 69, 101, 9, 10, 43, - 45, 48, 57, 43, 45, 48, 57, 48, - 57, 0, 13, 32, 44, 46, 65, 67, + 48, 57, 13, 32, 44, 46, 65, 67, 72, 76, 77, 81, 83, 84, 86, 90, 97, 99, 104, 108, 109, 113, 115, 116, 118, 122, 9, 10, 43, 45, 48, 57, - 43, 45, 48, 57, 48, 57, 13, 32, - 44, 46, 9, 10, 43, 45, 48, 57, 0 }; static const char _svg_path_single_lengths[] = { + 0, 5, 5, 1, 0, 6, 4, 1, + 0, 1, 0, 6, 4, 1, 0, 5, + 6, 5, 3, 3, 0, 6, 4, 3, + 0, 6, 4, 1, 0, 5, 5, 4, + 5, 5, 4, 4, 4, 1, 0, 6, + 4, 1, 0, 6, 2, 0, 4, 5, + 5, 1, 0, 6, 4, 1, 0, 6, + 4, 1, 0, 6, 4, 1, 0, 6, + 4, 1, 0, 6, 4, 1, 0, 6, + 5, 6, 5, 6, 5, 6, 5, 6, + 5, 2, 0, 5, 5, 1, 0, 2, 0, 5, 5, 5, 1, 0, 6, 4, - 1, 0, 27, 25, 1, 0, 6, 4, - 1, 0, 27, 5, 6, 5, 27, 3, - 3, 0, 6, 4, 3, 0, 6, 4, - 1, 0, 5, 5, 4, 3, 5, 4, - 3, 4, 1, 0, 6, 4, 1, 0, - 27, 25, 6, 2, 0, 4, 5, 5, 1, 0, 6, 4, 1, 0, 6, 4, + 1, 0, 6, 5, 6, 5, 6, 5, + 2, 0, 5, 5, 1, 0, 6, 4, 1, 0, 6, 4, 1, 0, 6, 4, - 1, 0, 6, 4, 1, 0, 27, 25, - 6, 5, 6, 5, 6, 5, 6, 5, - 6, 5, 27, 2, 0, 25, 5, 5, - 1, 0, 27, 25, 27, 2, 0, 25, - 5, 5, 5, 1, 0, 6, 4, 1, - 0, 6, 4, 1, 0, 6, 4, 1, - 0, 27, 25, 6, 5, 6, 5, 6, - 5, 27, 2, 0, 25, 5, 5, 1, - 0, 6, 4, 1, 0, 6, 4, 1, - 0, 6, 4, 1, 0, 27, 25, 6, - 5, 6, 5, 6, 5, 27, 2, 0, - 25, 5, 5, 1, 0, 6, 4, 1, - 0, 27, 25, 6, 5, 27, 2, 0, - 25, 5, 5, 1, 0, 27, 25, 27, - 2, 0, 25, 23, 23, 3, 5, 5, - 5, 5, 6, 5, 27, 2, 0, 25, - 5, 5, 5, 5, 2, 0, 4, 2, + 1, 0, 6, 5, 6, 5, 6, 5, + 2, 0, 5, 5, 1, 0, 6, 4, + 1, 0, 6, 5, 2, 0, 5, 5, + 1, 0, 2, 0, 3, 5, 5, 5, + 5, 6, 5, 2, 0, 5, 5, 5, + 5, 2, 0, 4, 2, 0, 4, 2, 0, 4, 2, 0, 4, 2, 0, 4, 2, 0, 4, 2, 0, 4, 2, 0, 4, 2, 0, 4, 2, 0, 4, 2, 0, 4, 2, 0, 4, 2, 0, 4, - 2, 0, 4, 2, 0, 25, 27, 5, - 2, 0, 4, 6, 5, 3, 3, 2, - 0, 3, 6, 5, 2, 0, 4, 6, - 2, 0, 25, 2, 0, 4, 0 + 2, 0, 5, 2, 0, 4, 6, 5, + 4, 5, 2, 0, 3, 6, 5, 2, + 0, 4, 6, 2, 0, 2, 0, 4, + 4, 26, 24, 26, 26, 26, 24, 26, + 24, 26, 24, 26, 24, 26, 24, 26, + 24, 26, 24, 26, 24, 26, 24, 26, + 24, 26, 24, 26, 24, 26, 24, 22, + 22, 26, 24, 24, 26, 24 }; static const char _svg_path_range_lengths[] = { - 0, 1, 2, 2, 1, 1, 3, 3, + 0, 2, 2, 1, 1, 3, 3, 1, + 1, 1, 1, 3, 3, 1, 1, 2, + 3, 2, 2, 2, 1, 2, 2, 2, + 1, 3, 3, 1, 1, 2, 1, 1, + 1, 1, 1, 3, 3, 1, 1, 3, + 3, 1, 1, 2, 1, 1, 2, 2, + 2, 1, 1, 3, 3, 1, 1, 3, + 3, 1, 1, 3, 3, 1, 1, 3, + 3, 1, 1, 3, 3, 1, 1, 3, + 2, 3, 2, 3, 2, 3, 2, 3, + 2, 1, 1, 2, 2, 1, 1, 1, + 1, 2, 2, 2, 1, 1, 3, 3, 1, 1, 3, 3, 1, 1, 3, 3, 1, 1, 3, 2, 3, 2, 3, 2, - 2, 1, 2, 2, 2, 1, 3, 3, - 1, 1, 2, 1, 1, 1, 1, 1, - 1, 3, 1, 1, 3, 3, 1, 1, - 2, 2, 2, 1, 1, 2, 2, 2, - 1, 1, 3, 3, 1, 1, 3, 3, - 1, 1, 3, 3, 1, 1, 3, 3, + 1, 1, 2, 2, 1, 1, 3, 3, 1, 1, 3, 3, 1, 1, 3, 3, - 3, 2, 3, 2, 3, 2, 3, 2, - 3, 2, 3, 1, 1, 3, 2, 2, - 1, 1, 3, 3, 3, 1, 1, 3, - 2, 2, 2, 1, 1, 3, 3, 1, - 1, 3, 3, 1, 1, 3, 3, 1, - 1, 3, 3, 3, 2, 3, 2, 3, - 2, 3, 1, 1, 3, 2, 2, 1, - 1, 3, 3, 1, 1, 3, 3, 1, - 1, 3, 3, 1, 1, 3, 3, 3, - 2, 3, 2, 3, 2, 3, 1, 1, - 3, 2, 2, 1, 1, 3, 3, 1, - 1, 3, 3, 3, 2, 3, 1, 1, - 3, 2, 2, 1, 1, 3, 3, 3, - 1, 1, 3, 1, 1, 2, 2, 2, - 2, 2, 3, 2, 3, 1, 1, 3, - 2, 2, 2, 2, 1, 1, 3, 1, + 1, 1, 3, 2, 3, 2, 3, 2, + 1, 1, 2, 2, 1, 1, 3, 3, + 1, 1, 3, 2, 1, 1, 2, 2, + 1, 1, 1, 1, 2, 2, 2, 2, + 2, 3, 2, 1, 1, 2, 2, 2, + 2, 1, 1, 3, 1, 1, 3, 1, 1, 3, 1, 1, 3, 1, 1, 3, 1, 1, 3, 1, 1, 3, 1, 1, 3, 1, 1, 3, 1, 1, 3, 1, 1, 3, 1, 1, 3, 1, 1, 3, - 1, 1, 3, 1, 1, 2, 2, 2, - 1, 1, 3, 3, 2, 1, 1, 1, - 1, 2, 2, 2, 1, 1, 3, 3, - 1, 1, 3, 1, 1, 3, 0 + 1, 1, 2, 1, 1, 3, 3, 2, + 3, 1, 1, 1, 2, 2, 2, 1, + 1, 3, 3, 1, 1, 1, 1, 3, + 1, 3, 3, 3, 3, 2, 2, 3, + 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 1, + 1, 3, 3, 2, 2, 3 }; static const short _svg_path_index_offsets[] = { - 0, 0, 7, 15, 23, 26, 28, 38, - 46, 49, 51, 82, 111, 114, 116, 126, - 134, 137, 139, 170, 178, 188, 196, 227, - 233, 239, 241, 250, 257, 263, 265, 275, - 283, 286, 288, 296, 303, 309, 314, 321, - 327, 332, 340, 343, 345, 355, 363, 366, - 368, 398, 426, 435, 439, 441, 448, 456, - 464, 467, 469, 479, 487, 490, 492, 502, - 510, 513, 515, 525, 533, 536, 538, 548, - 556, 559, 561, 571, 579, 582, 584, 615, - 644, 654, 662, 672, 680, 690, 698, 708, - 716, 726, 734, 765, 769, 771, 800, 808, - 816, 819, 821, 852, 881, 912, 916, 918, - 947, 955, 963, 971, 974, 976, 986, 994, - 997, 999, 1009, 1017, 1020, 1022, 1032, 1040, - 1043, 1045, 1076, 1105, 1115, 1123, 1133, 1141, - 1151, 1159, 1190, 1194, 1196, 1225, 1233, 1241, - 1244, 1246, 1256, 1264, 1267, 1269, 1279, 1287, - 1290, 1292, 1302, 1310, 1313, 1315, 1346, 1375, - 1385, 1393, 1403, 1411, 1421, 1429, 1460, 1464, - 1466, 1495, 1503, 1511, 1514, 1516, 1526, 1534, - 1537, 1539, 1570, 1599, 1609, 1617, 1648, 1652, - 1654, 1683, 1691, 1699, 1702, 1704, 1735, 1764, - 1795, 1799, 1801, 1830, 1855, 1880, 1886, 1894, - 1902, 1910, 1918, 1928, 1936, 1967, 1971, 1973, - 2002, 2010, 2018, 2026, 2034, 2038, 2040, 2048, - 2052, 2054, 2062, 2066, 2068, 2076, 2080, 2082, - 2090, 2094, 2096, 2104, 2108, 2110, 2118, 2122, - 2124, 2132, 2136, 2138, 2146, 2150, 2152, 2160, - 2164, 2166, 2174, 2178, 2180, 2188, 2192, 2194, - 2202, 2206, 2208, 2216, 2220, 2222, 2250, 2280, - 2288, 2292, 2294, 2302, 2312, 2320, 2325, 2330, - 2334, 2336, 2342, 2351, 2359, 2363, 2365, 2373, - 2383, 2387, 2389, 2418, 2422, 2424, 2432 + 0, 0, 8, 16, 19, 21, 31, 39, + 42, 44, 47, 49, 59, 67, 70, 72, + 80, 90, 98, 104, 110, 112, 121, 128, + 134, 136, 146, 154, 157, 159, 167, 174, + 180, 187, 194, 200, 208, 216, 219, 221, + 231, 239, 242, 244, 253, 257, 259, 266, + 274, 282, 285, 287, 297, 305, 308, 310, + 320, 328, 331, 333, 343, 351, 354, 356, + 366, 374, 377, 379, 389, 397, 400, 402, + 412, 420, 430, 438, 448, 456, 466, 474, + 484, 492, 496, 498, 506, 514, 517, 519, + 523, 525, 533, 541, 549, 552, 554, 564, + 572, 575, 577, 587, 595, 598, 600, 610, + 618, 621, 623, 633, 641, 651, 659, 669, + 677, 681, 683, 691, 699, 702, 704, 714, + 722, 725, 727, 737, 745, 748, 750, 760, + 768, 771, 773, 783, 791, 801, 809, 819, + 827, 831, 833, 841, 849, 852, 854, 864, + 872, 875, 877, 887, 895, 899, 901, 909, + 917, 920, 922, 926, 928, 934, 942, 950, + 958, 966, 976, 984, 988, 990, 998, 1006, + 1014, 1022, 1026, 1028, 1036, 1040, 1042, 1050, + 1054, 1056, 1064, 1068, 1070, 1078, 1082, 1084, + 1092, 1096, 1098, 1106, 1110, 1112, 1120, 1124, + 1126, 1134, 1138, 1140, 1148, 1152, 1154, 1162, + 1166, 1168, 1176, 1180, 1182, 1190, 1194, 1196, + 1204, 1208, 1210, 1218, 1222, 1224, 1232, 1242, + 1250, 1258, 1265, 1269, 1271, 1277, 1286, 1294, + 1298, 1300, 1308, 1318, 1322, 1324, 1328, 1330, + 1338, 1344, 1374, 1402, 1432, 1462, 1491, 1518, + 1548, 1576, 1606, 1634, 1664, 1692, 1722, 1750, + 1780, 1808, 1838, 1866, 1896, 1924, 1954, 1982, + 2012, 2040, 2070, 2098, 2128, 2156, 2186, 2214, + 2238, 2262, 2292, 2320, 2347, 2376 }; static const short _svg_path_indicies[] = { - 0, 2, 2, 3, 4, 2, 1, 5, - 5, 6, 6, 7, 5, 8, 1, 9, - 9, 10, 10, 11, 9, 12, 1, 13, - 14, 1, 15, 1, 16, 16, 18, 19, - 20, 20, 16, 17, 15, 1, 21, 21, - 23, 24, 21, 22, 25, 1, 26, 27, - 1, 28, 1, 29, 30, 30, 32, 33, - 34, 35, 36, 37, 38, 39, 40, 41, - 42, 43, 44, 45, 46, 36, 47, 48, - 49, 50, 51, 52, 53, 44, 30, 31, - 28, 1, 0, 54, 54, 56, 57, 59, - 60, 61, 62, 3, 63, 64, 65, 66, - 67, 68, 69, 70, 71, 4, 72, 73, - 74, 75, 67, 54, 55, 58, 1, 76, - 77, 1, 78, 1, 79, 79, 81, 82, - 83, 83, 79, 80, 78, 1, 84, 84, - 86, 87, 84, 85, 88, 1, 89, 90, - 1, 91, 1, 92, 93, 93, 95, 96, - 97, 98, 99, 100, 101, 102, 103, 104, - 105, 106, 107, 108, 109, 99, 110, 111, - 112, 113, 114, 115, 116, 107, 93, 94, - 91, 1, 56, 56, 55, 55, 57, 56, - 58, 1, 79, 79, 81, 78, 83, 83, - 79, 80, 77, 1, 86, 86, 85, 85, - 87, 86, 88, 1, 92, 93, 93, 95, - 91, 97, 98, 99, 100, 101, 102, 103, - 104, 105, 106, 107, 108, 109, 99, 110, - 111, 112, 113, 114, 115, 116, 107, 93, - 94, 90, 1, 117, 117, 118, 117, 119, - 1, 120, 120, 121, 120, 122, 1, 123, - 1, 124, 124, 125, 126, 127, 127, 124, - 123, 1, 128, 128, 129, 130, 128, 131, - 1, 129, 129, 130, 129, 131, 1, 132, - 1, 133, 133, 135, 136, 137, 137, 133, - 134, 132, 1, 138, 138, 140, 141, 138, - 139, 142, 1, 143, 144, 1, 145, 1, - 146, 146, 147, 148, 148, 146, 145, 1, - 149, 149, 150, 151, 152, 149, 1, 150, - 150, 151, 152, 150, 1, 153, 153, 154, - 153, 1, 155, 155, 156, 157, 158, 155, - 1, 156, 156, 157, 158, 156, 1, 159, - 159, 160, 159, 1, 161, 161, 163, 164, - 161, 162, 165, 1, 166, 167, 1, 168, - 1, 169, 169, 171, 172, 173, 173, 169, - 170, 168, 1, 174, 174, 176, 177, 174, - 175, 178, 1, 179, 180, 1, 181, 1, - 182, 183, 183, 184, 185, 186, 187, 188, - 189, 190, 191, 192, 193, 194, 195, 196, - 197, 198, 188, 199, 200, 201, 202, 203, - 204, 205, 196, 183, 181, 1, 0, 206, - 206, 120, 121, 59, 60, 61, 62, 3, - 63, 64, 65, 66, 67, 68, 69, 70, - 71, 4, 72, 73, 74, 75, 67, 206, - 122, 1, 124, 124, 125, 123, 127, 127, - 124, 207, 1, 208, 208, 209, 1, 209, - 1, 124, 124, 125, 126, 124, 209, 1, - 210, 210, 211, 211, 212, 210, 213, 1, - 214, 214, 215, 215, 216, 214, 217, 1, - 218, 219, 1, 220, 1, 221, 221, 223, - 224, 225, 225, 221, 222, 220, 1, 226, - 226, 228, 229, 226, 227, 230, 1, 231, - 232, 1, 233, 1, 234, 234, 236, 237, - 238, 238, 234, 235, 233, 1, 239, 239, - 241, 242, 239, 240, 243, 1, 244, 245, - 1, 246, 1, 247, 247, 249, 250, 251, - 251, 247, 248, 246, 1, 252, 252, 254, - 255, 252, 253, 256, 1, 257, 258, 1, - 259, 1, 260, 260, 262, 263, 264, 264, - 260, 261, 259, 1, 265, 265, 267, 268, - 265, 266, 269, 1, 270, 271, 1, 272, - 1, 273, 273, 275, 276, 277, 277, 273, - 274, 272, 1, 278, 278, 280, 281, 278, - 279, 282, 1, 283, 284, 1, 285, 1, - 286, 287, 287, 289, 290, 291, 292, 293, - 294, 295, 296, 297, 298, 299, 300, 301, - 302, 303, 293, 304, 305, 306, 307, 308, - 309, 310, 301, 287, 288, 285, 1, 0, - 311, 311, 214, 216, 59, 60, 61, 62, - 3, 63, 64, 65, 66, 67, 68, 69, - 70, 71, 4, 72, 73, 74, 75, 67, - 311, 215, 217, 1, 221, 221, 223, 220, - 225, 225, 221, 222, 219, 1, 228, 228, - 227, 227, 229, 228, 230, 1, 234, 234, - 236, 233, 238, 238, 234, 235, 232, 1, - 241, 241, 240, 240, 242, 241, 243, 1, - 247, 247, 249, 246, 251, 251, 247, 248, - 245, 1, 254, 254, 253, 253, 255, 254, - 256, 1, 260, 260, 262, 259, 264, 264, - 260, 261, 258, 1, 267, 267, 266, 266, - 268, 267, 269, 1, 273, 273, 275, 272, - 277, 277, 273, 274, 271, 1, 280, 280, - 279, 279, 281, 280, 282, 1, 286, 287, - 287, 289, 285, 291, 292, 293, 294, 295, - 296, 297, 298, 299, 300, 301, 302, 303, - 293, 304, 305, 306, 307, 308, 309, 310, - 301, 287, 288, 284, 1, 312, 312, 313, - 1, 313, 1, 286, 287, 287, 289, 290, - 291, 292, 294, 295, 296, 297, 298, 299, - 300, 301, 302, 303, 304, 305, 306, 307, - 308, 309, 310, 301, 287, 288, 313, 1, - 314, 314, 315, 315, 316, 314, 317, 1, - 318, 318, 319, 319, 320, 318, 321, 1, - 322, 323, 1, 324, 1, 325, 326, 326, - 328, 329, 330, 331, 332, 333, 334, 335, - 336, 337, 338, 339, 340, 341, 342, 332, - 343, 344, 345, 346, 347, 348, 349, 340, - 326, 327, 324, 1, 0, 350, 350, 318, - 320, 59, 60, 61, 62, 3, 63, 64, - 65, 66, 67, 68, 69, 70, 71, 4, - 72, 73, 74, 75, 67, 350, 319, 321, - 1, 325, 326, 326, 328, 324, 330, 331, - 332, 333, 334, 335, 336, 337, 338, 339, - 340, 341, 342, 332, 343, 344, 345, 346, - 347, 348, 349, 340, 326, 327, 323, 1, - 351, 351, 352, 1, 352, 1, 325, 326, - 326, 328, 329, 330, 331, 333, 334, 335, - 336, 337, 338, 339, 340, 341, 342, 343, - 344, 345, 346, 347, 348, 349, 340, 326, - 327, 352, 1, 353, 353, 354, 354, 355, - 353, 356, 1, 357, 357, 358, 358, 359, - 357, 360, 1, 361, 361, 362, 362, 363, - 361, 364, 1, 365, 366, 1, 367, 1, - 368, 368, 370, 371, 372, 372, 368, 369, - 367, 1, 373, 373, 375, 376, 373, 374, - 377, 1, 378, 379, 1, 380, 1, 381, - 381, 383, 384, 385, 385, 381, 382, 380, - 1, 386, 386, 388, 389, 386, 387, 390, - 1, 391, 392, 1, 393, 1, 394, 394, - 396, 397, 398, 398, 394, 395, 393, 1, - 399, 399, 401, 402, 399, 400, 403, 1, - 404, 405, 1, 406, 1, 407, 408, 408, - 410, 411, 412, 413, 414, 415, 416, 417, - 418, 419, 420, 421, 422, 423, 424, 414, - 425, 426, 427, 428, 429, 430, 431, 422, - 408, 409, 406, 1, 0, 432, 432, 361, - 363, 59, 60, 61, 62, 3, 63, 64, - 65, 66, 67, 68, 69, 70, 71, 4, - 72, 73, 74, 75, 67, 432, 362, 364, - 1, 368, 368, 370, 367, 372, 372, 368, - 369, 366, 1, 375, 375, 374, 374, 376, - 375, 377, 1, 381, 381, 383, 380, 385, - 385, 381, 382, 379, 1, 388, 388, 387, - 387, 389, 388, 390, 1, 394, 394, 396, - 393, 398, 398, 394, 395, 392, 1, 401, - 401, 400, 400, 402, 401, 403, 1, 407, - 408, 408, 410, 406, 412, 413, 414, 415, - 416, 417, 418, 419, 420, 421, 422, 423, - 424, 414, 425, 426, 427, 428, 429, 430, - 431, 422, 408, 409, 405, 1, 433, 433, - 434, 1, 434, 1, 407, 408, 408, 410, - 411, 412, 413, 415, 416, 417, 418, 419, - 420, 421, 422, 423, 424, 425, 426, 427, - 428, 429, 430, 431, 422, 408, 409, 434, - 1, 435, 435, 436, 436, 437, 435, 438, - 1, 439, 439, 440, 440, 441, 439, 442, - 1, 443, 444, 1, 445, 1, 446, 446, - 448, 449, 450, 450, 446, 447, 445, 1, - 451, 451, 453, 454, 451, 452, 455, 1, - 456, 457, 1, 458, 1, 459, 459, 461, - 462, 463, 463, 459, 460, 458, 1, 464, - 464, 466, 467, 464, 465, 468, 1, 469, - 470, 1, 471, 1, 472, 472, 474, 475, - 476, 476, 472, 473, 471, 1, 477, 477, - 479, 480, 477, 478, 481, 1, 482, 483, - 1, 484, 1, 485, 486, 486, 488, 489, - 490, 491, 492, 493, 494, 495, 496, 497, - 498, 499, 500, 501, 502, 492, 503, 504, - 505, 506, 507, 508, 509, 500, 486, 487, - 484, 1, 0, 510, 510, 439, 441, 59, - 60, 61, 62, 3, 63, 64, 65, 66, - 67, 68, 69, 70, 71, 4, 72, 73, - 74, 75, 67, 510, 440, 442, 1, 446, - 446, 448, 445, 450, 450, 446, 447, 444, - 1, 453, 453, 452, 452, 454, 453, 455, - 1, 459, 459, 461, 458, 463, 463, 459, - 460, 457, 1, 466, 466, 465, 465, 467, - 466, 468, 1, 472, 472, 474, 471, 476, - 476, 472, 473, 470, 1, 479, 479, 478, - 478, 480, 479, 481, 1, 485, 486, 486, - 488, 484, 490, 491, 492, 493, 494, 495, - 496, 497, 498, 499, 500, 501, 502, 492, - 503, 504, 505, 506, 507, 508, 509, 500, - 486, 487, 483, 1, 511, 511, 512, 1, - 512, 1, 485, 486, 486, 488, 489, 490, - 491, 493, 494, 495, 496, 497, 498, 499, - 500, 501, 502, 503, 504, 505, 506, 507, - 508, 509, 500, 486, 487, 512, 1, 513, - 513, 514, 514, 515, 513, 516, 1, 517, - 517, 518, 518, 519, 517, 520, 1, 521, - 522, 1, 523, 1, 524, 524, 526, 527, - 528, 528, 524, 525, 523, 1, 529, 529, - 531, 532, 529, 530, 533, 1, 534, 535, - 1, 536, 1, 537, 538, 538, 540, 541, + 0, 0, 2, 2, 3, 0, 4, 1, + 5, 5, 6, 6, 7, 5, 8, 1, + 9, 10, 1, 11, 1, 12, 12, 14, + 15, 16, 16, 12, 13, 11, 1, 17, + 17, 19, 20, 17, 18, 21, 1, 22, + 23, 1, 24, 1, 25, 26, 1, 27, + 1, 28, 28, 30, 31, 32, 32, 28, + 29, 27, 1, 33, 33, 35, 36, 33, + 34, 37, 1, 38, 39, 1, 40, 1, + 41, 41, 42, 42, 43, 41, 44, 1, + 28, 28, 30, 27, 32, 32, 28, 29, + 26, 1, 35, 35, 34, 34, 36, 35, + 37, 1, 45, 45, 46, 45, 47, 1, + 48, 48, 49, 48, 50, 1, 51, 1, + 52, 52, 53, 54, 55, 55, 52, 51, + 1, 56, 56, 57, 58, 56, 59, 1, + 57, 57, 58, 57, 59, 1, 60, 1, + 61, 61, 63, 64, 65, 65, 61, 62, + 60, 1, 66, 66, 68, 69, 66, 67, + 70, 1, 71, 72, 1, 73, 1, 74, + 74, 75, 76, 76, 74, 73, 1, 77, + 77, 78, 79, 80, 77, 1, 78, 78, + 79, 80, 78, 1, 81, 81, 82, 83, + 84, 81, 1, 85, 85, 86, 87, 88, + 85, 1, 86, 86, 87, 88, 86, 1, + 89, 89, 91, 92, 89, 90, 93, 1, + 94, 94, 96, 97, 94, 95, 98, 1, + 99, 100, 1, 101, 1, 102, 102, 104, + 105, 106, 106, 102, 103, 101, 1, 107, + 107, 109, 110, 107, 108, 111, 1, 112, + 113, 1, 114, 1, 52, 52, 53, 51, + 55, 55, 52, 115, 1, 116, 116, 117, + 1, 117, 1, 52, 52, 53, 54, 52, + 117, 1, 118, 118, 119, 119, 120, 118, + 121, 1, 122, 122, 123, 123, 124, 122, + 125, 1, 126, 127, 1, 128, 1, 129, + 129, 131, 132, 133, 133, 129, 130, 128, + 1, 134, 134, 136, 137, 134, 135, 138, + 1, 139, 140, 1, 141, 1, 142, 142, + 144, 145, 146, 146, 142, 143, 141, 1, + 147, 147, 149, 150, 147, 148, 151, 1, + 152, 153, 1, 154, 1, 155, 155, 157, + 158, 159, 159, 155, 156, 154, 1, 160, + 160, 162, 163, 160, 161, 164, 1, 165, + 166, 1, 167, 1, 168, 168, 170, 171, + 172, 172, 168, 169, 167, 1, 173, 173, + 175, 176, 173, 174, 177, 1, 178, 179, + 1, 180, 1, 181, 181, 183, 184, 185, + 185, 181, 182, 180, 1, 186, 186, 188, + 189, 186, 187, 190, 1, 191, 192, 1, + 193, 1, 129, 129, 131, 128, 133, 133, + 129, 130, 127, 1, 136, 136, 135, 135, + 137, 136, 138, 1, 142, 142, 144, 141, + 146, 146, 142, 143, 140, 1, 149, 149, + 148, 148, 150, 149, 151, 1, 155, 155, + 157, 154, 159, 159, 155, 156, 153, 1, + 162, 162, 161, 161, 163, 162, 164, 1, + 168, 168, 170, 167, 172, 172, 168, 169, + 166, 1, 175, 175, 174, 174, 176, 175, + 177, 1, 181, 181, 183, 180, 185, 185, + 181, 182, 179, 1, 188, 188, 187, 187, + 189, 188, 190, 1, 194, 194, 195, 1, + 195, 1, 196, 196, 197, 197, 198, 196, + 199, 1, 200, 200, 201, 201, 202, 200, + 203, 1, 204, 205, 1, 206, 1, 207, + 207, 208, 1, 208, 1, 209, 209, 210, + 210, 211, 209, 212, 1, 213, 213, 214, + 214, 215, 213, 216, 1, 217, 217, 218, + 218, 219, 217, 220, 1, 221, 222, 1, + 223, 1, 224, 224, 226, 227, 228, 228, + 224, 225, 223, 1, 229, 229, 231, 232, + 229, 230, 233, 1, 234, 235, 1, 236, + 1, 237, 237, 239, 240, 241, 241, 237, + 238, 236, 1, 242, 242, 244, 245, 242, + 243, 246, 1, 247, 248, 1, 249, 1, + 250, 250, 252, 253, 254, 254, 250, 251, + 249, 1, 255, 255, 257, 258, 255, 256, + 259, 1, 260, 261, 1, 262, 1, 224, + 224, 226, 223, 228, 228, 224, 225, 222, + 1, 231, 231, 230, 230, 232, 231, 233, + 1, 237, 237, 239, 236, 241, 241, 237, + 238, 235, 1, 244, 244, 243, 243, 245, + 244, 246, 1, 250, 250, 252, 249, 254, + 254, 250, 251, 248, 1, 257, 257, 256, + 256, 258, 257, 259, 1, 263, 263, 264, + 1, 264, 1, 265, 265, 266, 266, 267, + 265, 268, 1, 269, 269, 270, 270, 271, + 269, 272, 1, 273, 274, 1, 275, 1, + 276, 276, 278, 279, 280, 280, 276, 277, + 275, 1, 281, 281, 283, 284, 281, 282, + 285, 1, 286, 287, 1, 288, 1, 289, + 289, 291, 292, 293, 293, 289, 290, 288, + 1, 294, 294, 296, 297, 294, 295, 298, + 1, 299, 300, 1, 301, 1, 302, 302, + 304, 305, 306, 306, 302, 303, 301, 1, + 307, 307, 309, 310, 307, 308, 311, 1, + 312, 313, 1, 314, 1, 276, 276, 278, + 275, 280, 280, 276, 277, 274, 1, 283, + 283, 282, 282, 284, 283, 285, 1, 289, + 289, 291, 288, 293, 293, 289, 290, 287, + 1, 296, 296, 295, 295, 297, 296, 298, + 1, 302, 302, 304, 301, 306, 306, 302, + 303, 300, 1, 309, 309, 308, 308, 310, + 309, 311, 1, 315, 315, 316, 1, 316, + 1, 317, 317, 318, 318, 319, 317, 320, + 1, 321, 321, 322, 322, 323, 321, 324, + 1, 325, 326, 1, 327, 1, 328, 328, + 330, 331, 332, 332, 328, 329, 327, 1, + 333, 333, 335, 336, 333, 334, 337, 1, + 338, 339, 1, 340, 1, 328, 328, 330, + 327, 332, 332, 328, 329, 326, 1, 335, + 335, 334, 334, 336, 335, 337, 1, 341, + 341, 342, 1, 342, 1, 343, 343, 344, + 344, 345, 343, 346, 1, 347, 347, 348, + 348, 349, 347, 350, 1, 351, 352, 1, + 353, 1, 354, 354, 355, 1, 355, 1, + 356, 356, 357, 356, 358, 1, 359, 359, + 360, 360, 361, 359, 362, 1, 363, 363, + 364, 364, 365, 363, 366, 1, 367, 367, + 368, 368, 369, 367, 370, 1, 371, 371, + 372, 372, 373, 371, 374, 1, 12, 12, + 14, 11, 16, 16, 12, 13, 10, 1, + 19, 19, 18, 18, 20, 19, 21, 1, + 375, 375, 376, 1, 376, 1, 377, 377, + 378, 378, 379, 377, 380, 1, 381, 381, + 382, 382, 383, 381, 384, 1, 385, 385, + 386, 386, 387, 385, 388, 1, 389, 389, + 390, 390, 391, 389, 392, 1, 393, 393, + 394, 1, 394, 1, 12, 12, 14, 15, + 12, 13, 394, 1, 395, 395, 396, 1, + 396, 1, 328, 328, 330, 331, 328, 329, + 396, 1, 397, 397, 398, 1, 398, 1, + 302, 302, 304, 305, 302, 303, 398, 1, + 399, 399, 400, 1, 400, 1, 289, 289, + 291, 292, 289, 290, 400, 1, 401, 401, + 402, 1, 402, 1, 276, 276, 278, 279, + 276, 277, 402, 1, 403, 403, 404, 1, + 404, 1, 250, 250, 252, 253, 250, 251, + 404, 1, 405, 405, 406, 1, 406, 1, + 237, 237, 239, 240, 237, 238, 406, 1, + 407, 407, 408, 1, 408, 1, 224, 224, + 226, 227, 224, 225, 408, 1, 409, 409, + 410, 1, 410, 1, 181, 181, 183, 184, + 181, 182, 410, 1, 411, 411, 412, 1, + 412, 1, 168, 168, 170, 171, 168, 169, + 412, 1, 413, 413, 414, 1, 414, 1, + 155, 155, 157, 158, 155, 156, 414, 1, + 415, 415, 416, 1, 416, 1, 142, 142, + 144, 145, 142, 143, 416, 1, 417, 417, + 418, 1, 418, 1, 129, 129, 131, 132, + 129, 130, 418, 1, 419, 419, 420, 1, + 420, 1, 109, 109, 108, 108, 110, 109, + 111, 1, 421, 421, 422, 1, 422, 1, + 102, 102, 104, 105, 102, 103, 422, 1, + 102, 102, 104, 101, 106, 106, 102, 103, + 100, 1, 96, 96, 95, 95, 97, 96, + 98, 1, 423, 423, 425, 426, 423, 424, + 427, 1, 428, 428, 429, 430, 431, 428, + 1, 432, 432, 433, 1, 433, 1, 74, + 74, 75, 74, 433, 1, 74, 74, 75, + 73, 76, 76, 74, 72, 1, 68, 68, + 67, 67, 69, 68, 70, 1, 434, 434, + 435, 1, 435, 1, 61, 61, 63, 64, + 61, 62, 435, 1, 61, 61, 63, 60, + 65, 65, 61, 62, 436, 1, 437, 437, + 438, 1, 438, 1, 439, 439, 440, 1, + 440, 1, 28, 28, 30, 31, 28, 29, + 440, 1, 441, 441, 442, 443, 441, 1, + 444, 444, 446, 447, 448, 449, 450, 451, + 452, 453, 454, 455, 456, 457, 458, 459, + 460, 450, 461, 462, 463, 464, 465, 466, + 467, 458, 444, 445, 24, 1, 468, 468, + 41, 43, 469, 470, 471, 472, 442, 473, + 474, 475, 476, 477, 478, 479, 480, 481, + 443, 482, 483, 484, 485, 477, 468, 42, + 44, 1, 486, 486, 488, 489, 490, 491, + 492, 493, 494, 495, 496, 497, 498, 499, + 500, 501, 502, 492, 503, 504, 505, 506, + 507, 508, 509, 500, 486, 487, 40, 1, + 486, 486, 488, 40, 490, 491, 492, 493, + 494, 495, 496, 497, 498, 499, 500, 501, + 502, 492, 503, 504, 505, 506, 507, 508, + 509, 500, 486, 487, 39, 1, 510, 510, + 511, 512, 513, 514, 515, 516, 517, 518, + 519, 520, 521, 522, 523, 524, 525, 515, + 526, 527, 528, 529, 530, 531, 532, 523, + 510, 114, 1, 533, 533, 48, 49, 469, + 470, 471, 472, 442, 473, 474, 475, 476, + 477, 478, 479, 480, 481, 443, 482, 483, + 484, 485, 477, 533, 50, 1, 534, 534, + 536, 537, 538, 539, 540, 541, 542, 543, + 544, 545, 546, 547, 548, 549, 550, 540, + 551, 552, 553, 554, 555, 556, 557, 548, + 534, 535, 193, 1, 558, 558, 122, 124, + 469, 470, 471, 472, 442, 473, 474, 475, + 476, 477, 478, 479, 480, 481, 443, 482, + 483, 484, 485, 477, 558, 123, 125, 1, + 534, 534, 536, 193, 538, 539, 540, 541, 542, 543, 544, 545, 546, 547, 548, 549, - 550, 551, 552, 553, 554, 544, 555, 556, - 557, 558, 559, 560, 561, 552, 538, 539, - 536, 1, 0, 562, 562, 517, 519, 59, - 60, 61, 62, 3, 63, 64, 65, 66, - 67, 68, 69, 70, 71, 4, 72, 73, - 74, 75, 67, 562, 518, 520, 1, 524, - 524, 526, 523, 528, 528, 524, 525, 522, - 1, 531, 531, 530, 530, 532, 531, 533, - 1, 537, 538, 538, 540, 536, 542, 543, - 544, 545, 546, 547, 548, 549, 550, 551, - 552, 553, 554, 544, 555, 556, 557, 558, - 559, 560, 561, 552, 538, 539, 535, 1, - 563, 563, 564, 1, 564, 1, 537, 538, - 538, 540, 541, 542, 543, 545, 546, 547, - 548, 549, 550, 551, 552, 553, 554, 555, - 556, 557, 558, 559, 560, 561, 552, 538, - 539, 564, 1, 565, 565, 566, 566, 567, - 565, 568, 1, 569, 569, 570, 570, 571, - 569, 572, 1, 573, 574, 1, 575, 1, - 576, 577, 577, 579, 580, 581, 582, 583, - 584, 585, 586, 587, 588, 589, 590, 591, - 592, 593, 583, 594, 595, 596, 597, 598, - 599, 600, 591, 577, 578, 575, 1, 0, - 601, 601, 569, 571, 59, 60, 61, 62, - 3, 63, 64, 65, 66, 67, 68, 69, - 70, 71, 4, 72, 73, 74, 75, 67, - 601, 570, 572, 1, 576, 577, 577, 579, - 575, 581, 582, 583, 584, 585, 586, 587, - 588, 589, 590, 591, 592, 593, 583, 594, - 595, 596, 597, 598, 599, 600, 591, 577, - 578, 574, 1, 602, 602, 603, 1, 603, - 1, 576, 577, 577, 579, 580, 581, 582, - 584, 585, 586, 587, 588, 589, 590, 591, + 550, 540, 551, 552, 553, 554, 555, 556, + 557, 548, 534, 535, 192, 1, 534, 534, + 536, 537, 538, 539, 541, 542, 543, 544, + 545, 546, 547, 548, 549, 550, 551, 552, + 553, 554, 555, 556, 557, 548, 534, 535, + 195, 1, 559, 559, 561, 562, 563, 564, + 565, 566, 567, 568, 569, 570, 571, 572, + 573, 574, 575, 565, 576, 577, 578, 579, + 580, 581, 582, 573, 559, 560, 206, 1, + 583, 583, 200, 202, 469, 470, 471, 472, + 442, 473, 474, 475, 476, 477, 478, 479, + 480, 481, 443, 482, 483, 484, 485, 477, + 583, 201, 203, 1, 559, 559, 561, 206, + 563, 564, 565, 566, 567, 568, 569, 570, + 571, 572, 573, 574, 575, 565, 576, 577, + 578, 579, 580, 581, 582, 573, 559, 560, + 205, 1, 559, 559, 561, 562, 563, 564, + 566, 567, 568, 569, 570, 571, 572, 573, + 574, 575, 576, 577, 578, 579, 580, 581, + 582, 573, 559, 560, 208, 1, 584, 584, + 586, 587, 588, 589, 590, 591, 592, 593, + 594, 595, 596, 597, 598, 599, 600, 590, + 601, 602, 603, 604, 605, 606, 607, 598, + 584, 585, 262, 1, 608, 608, 217, 219, + 469, 470, 471, 472, 442, 473, 474, 475, + 476, 477, 478, 479, 480, 481, 443, 482, + 483, 484, 485, 477, 608, 218, 220, 1, + 584, 584, 586, 262, 588, 589, 590, 591, 592, 593, 594, 595, 596, 597, 598, 599, - 600, 591, 577, 578, 603, 1, 604, 605, - 605, 606, 607, 608, 609, 610, 611, 612, + 600, 590, 601, 602, 603, 604, 605, 606, + 607, 598, 584, 585, 261, 1, 584, 584, + 586, 587, 588, 589, 591, 592, 593, 594, + 595, 596, 597, 598, 599, 600, 601, 602, + 603, 604, 605, 606, 607, 598, 584, 585, + 264, 1, 609, 609, 611, 612, 613, 614, + 615, 616, 617, 618, 619, 620, 621, 622, + 623, 624, 625, 615, 626, 627, 628, 629, + 630, 631, 632, 623, 609, 610, 314, 1, + 633, 633, 269, 271, 469, 470, 471, 472, + 442, 473, 474, 475, 476, 477, 478, 479, + 480, 481, 443, 482, 483, 484, 485, 477, + 633, 270, 272, 1, 609, 609, 611, 314, 613, 614, 615, 616, 617, 618, 619, 620, - 621, 622, 623, 624, 615, 605, 1, 0, - 625, 625, 59, 60, 61, 62, 3, 63, - 64, 65, 66, 67, 68, 69, 70, 71, - 4, 72, 73, 74, 75, 67, 625, 1, - 626, 626, 627, 626, 628, 1, 629, 629, - 630, 630, 631, 629, 632, 1, 633, 633, - 634, 634, 635, 633, 636, 1, 637, 637, - 638, 638, 639, 637, 640, 1, 641, 641, - 642, 642, 643, 641, 644, 1, 16, 16, - 18, 15, 20, 20, 16, 17, 14, 1, - 23, 23, 22, 22, 24, 23, 25, 1, - 29, 30, 30, 32, 28, 34, 35, 36, - 37, 38, 39, 40, 41, 42, 43, 44, - 45, 46, 36, 47, 48, 49, 50, 51, - 52, 53, 44, 30, 31, 27, 1, 645, - 645, 646, 1, 646, 1, 29, 30, 30, - 32, 33, 34, 35, 37, 38, 39, 40, - 41, 42, 43, 44, 45, 46, 47, 48, - 49, 50, 51, 52, 53, 44, 30, 31, - 646, 1, 647, 647, 648, 648, 649, 647, - 650, 1, 651, 651, 652, 652, 653, 651, - 654, 1, 655, 655, 656, 656, 657, 655, - 658, 1, 659, 659, 660, 660, 661, 659, - 662, 1, 663, 663, 664, 1, 664, 1, - 16, 16, 18, 19, 16, 17, 664, 1, - 665, 665, 666, 1, 666, 1, 524, 524, - 526, 527, 524, 525, 666, 1, 667, 667, - 668, 1, 668, 1, 472, 472, 474, 475, - 472, 473, 668, 1, 669, 669, 670, 1, - 670, 1, 459, 459, 461, 462, 459, 460, - 670, 1, 671, 671, 672, 1, 672, 1, - 446, 446, 448, 449, 446, 447, 672, 1, - 673, 673, 674, 1, 674, 1, 394, 394, - 396, 397, 394, 395, 674, 1, 675, 675, - 676, 1, 676, 1, 381, 381, 383, 384, - 381, 382, 676, 1, 677, 677, 678, 1, - 678, 1, 368, 368, 370, 371, 368, 369, - 678, 1, 679, 679, 680, 1, 680, 1, - 273, 273, 275, 276, 273, 274, 680, 1, - 681, 681, 682, 1, 682, 1, 260, 260, - 262, 263, 260, 261, 682, 1, 683, 683, - 684, 1, 684, 1, 247, 247, 249, 250, - 247, 248, 684, 1, 685, 685, 686, 1, - 686, 1, 234, 234, 236, 237, 234, 235, - 686, 1, 687, 687, 688, 1, 688, 1, - 221, 221, 223, 224, 221, 222, 688, 1, - 689, 689, 690, 1, 690, 1, 182, 183, - 183, 184, 185, 186, 187, 189, 190, 191, - 192, 193, 194, 195, 196, 197, 198, 199, - 200, 201, 202, 203, 204, 205, 196, 183, - 690, 1, 182, 183, 183, 184, 181, 186, - 187, 188, 189, 190, 191, 192, 193, 194, - 195, 196, 197, 198, 188, 199, 200, 201, - 202, 203, 204, 205, 196, 183, 180, 1, - 176, 176, 175, 175, 177, 176, 178, 1, - 691, 691, 692, 1, 692, 1, 169, 169, - 171, 172, 169, 170, 692, 1, 169, 169, - 171, 168, 173, 173, 169, 170, 167, 1, - 163, 163, 162, 162, 164, 163, 165, 1, - 693, 693, 694, 693, 1, 695, 695, 696, - 695, 1, 697, 697, 698, 1, 698, 1, - 146, 146, 147, 146, 698, 1, 146, 146, - 147, 145, 148, 148, 146, 144, 1, 140, - 140, 139, 139, 141, 140, 142, 1, 699, - 699, 700, 1, 700, 1, 133, 133, 135, - 136, 133, 134, 700, 1, 133, 133, 135, - 132, 137, 137, 133, 134, 701, 1, 702, - 702, 703, 1, 703, 1, 92, 93, 93, - 95, 96, 97, 98, 100, 101, 102, 103, - 104, 105, 106, 107, 108, 109, 110, 111, - 112, 113, 114, 115, 116, 107, 93, 94, - 703, 1, 704, 704, 705, 1, 705, 1, - 79, 79, 81, 82, 79, 80, 705, 1, - 1, 0 + 621, 622, 623, 624, 625, 615, 626, 627, + 628, 629, 630, 631, 632, 623, 609, 610, + 313, 1, 609, 609, 611, 612, 613, 614, + 616, 617, 618, 619, 620, 621, 622, 623, + 624, 625, 626, 627, 628, 629, 630, 631, + 632, 623, 609, 610, 316, 1, 634, 634, + 636, 637, 638, 639, 640, 641, 642, 643, + 644, 645, 646, 647, 648, 649, 650, 640, + 651, 652, 653, 654, 655, 656, 657, 648, + 634, 635, 340, 1, 658, 658, 321, 323, + 469, 470, 471, 472, 442, 473, 474, 475, + 476, 477, 478, 479, 480, 481, 443, 482, + 483, 484, 485, 477, 658, 322, 324, 1, + 634, 634, 636, 340, 638, 639, 640, 641, + 642, 643, 644, 645, 646, 647, 648, 649, + 650, 640, 651, 652, 653, 654, 655, 656, + 657, 648, 634, 635, 339, 1, 634, 634, + 636, 637, 638, 639, 641, 642, 643, 644, + 645, 646, 647, 648, 649, 650, 651, 652, + 653, 654, 655, 656, 657, 648, 634, 635, + 342, 1, 659, 659, 661, 662, 663, 664, + 665, 666, 667, 668, 669, 670, 671, 672, + 673, 674, 675, 665, 676, 677, 678, 679, + 680, 681, 682, 673, 659, 660, 353, 1, + 683, 683, 347, 349, 469, 470, 471, 472, + 442, 473, 474, 475, 476, 477, 478, 479, + 480, 481, 443, 482, 483, 484, 485, 477, + 683, 348, 350, 1, 659, 659, 661, 353, + 663, 664, 665, 666, 667, 668, 669, 670, + 671, 672, 673, 674, 675, 665, 676, 677, + 678, 679, 680, 681, 682, 673, 659, 660, + 352, 1, 659, 659, 661, 662, 663, 664, + 666, 667, 668, 669, 670, 671, 672, 673, + 674, 675, 676, 677, 678, 679, 680, 681, + 682, 673, 659, 660, 355, 1, 684, 684, + 685, 686, 687, 688, 689, 690, 691, 692, + 693, 694, 695, 696, 697, 698, 699, 700, + 701, 702, 703, 694, 684, 1, 704, 704, + 469, 470, 471, 472, 442, 473, 474, 475, + 476, 477, 478, 479, 480, 481, 443, 482, + 483, 484, 485, 477, 704, 1, 444, 444, + 446, 24, 448, 449, 450, 451, 452, 453, + 454, 455, 456, 457, 458, 459, 460, 450, + 461, 462, 463, 464, 465, 466, 467, 458, + 444, 445, 23, 1, 444, 444, 446, 447, + 448, 449, 451, 452, 453, 454, 455, 456, + 457, 458, 459, 460, 461, 462, 463, 464, + 465, 466, 467, 458, 444, 445, 376, 1, + 510, 510, 511, 512, 513, 514, 516, 517, + 518, 519, 520, 521, 522, 523, 524, 525, + 526, 527, 528, 529, 530, 531, 532, 523, + 510, 420, 1, 510, 510, 511, 114, 513, + 514, 515, 516, 517, 518, 519, 520, 521, + 522, 523, 524, 525, 515, 526, 527, 528, + 529, 530, 531, 532, 523, 510, 113, 1, + 486, 486, 488, 489, 490, 491, 493, 494, + 495, 496, 497, 498, 499, 500, 501, 502, + 503, 504, 505, 506, 507, 508, 509, 500, + 486, 487, 438, 1, 0 }; static const short _svg_path_trans_targs[] = { - 270, 0, 1, 2, 193, 3, 4, 5, - 194, 3, 4, 5, 194, 5, 194, 6, - 7, 8, 195, 9, 204, 7, 8, 195, - 9, 196, 9, 196, 10, 270, 11, 12, - 19, 13, 23, 54, 197, 94, 104, 2, - 105, 133, 161, 177, 187, 189, 190, 191, - 192, 193, 200, 201, 202, 203, 11, 12, - 19, 13, 20, 23, 54, 94, 104, 105, - 133, 161, 177, 187, 189, 190, 191, 192, - 200, 201, 202, 203, 13, 20, 14, 15, - 16, 21, 17, 267, 15, 16, 21, 17, - 22, 17, 22, 18, 270, 11, 12, 19, - 13, 23, 54, 264, 94, 104, 2, 105, - 133, 161, 177, 187, 189, 190, 191, 192, - 193, 200, 201, 202, 203, 24, 25, 50, - 24, 25, 50, 26, 27, 28, 29, 51, - 27, 28, 29, 263, 30, 31, 32, 259, - 33, 260, 31, 32, 259, 33, 258, 33, - 258, 34, 35, 36, 255, 35, 36, 37, - 254, 38, 39, 38, 39, 40, 253, 41, - 252, 41, 42, 252, 43, 251, 43, 251, - 44, 45, 46, 247, 47, 248, 45, 46, - 247, 47, 246, 47, 246, 48, 270, 49, - 24, 25, 23, 54, 243, 94, 104, 2, - 105, 133, 161, 177, 187, 189, 190, 191, - 192, 193, 200, 201, 202, 203, 49, 50, - 52, 53, 55, 56, 57, 80, 55, 56, - 57, 80, 57, 80, 58, 59, 60, 81, - 61, 240, 59, 60, 81, 61, 82, 61, - 82, 62, 63, 64, 83, 65, 237, 63, - 64, 83, 65, 84, 65, 84, 66, 67, - 68, 85, 69, 234, 67, 68, 85, 69, - 86, 69, 86, 70, 71, 72, 87, 73, - 231, 71, 72, 87, 73, 88, 73, 88, - 74, 75, 76, 89, 77, 228, 75, 76, - 89, 77, 90, 77, 90, 78, 270, 79, - 56, 55, 57, 23, 54, 91, 94, 104, - 2, 105, 133, 161, 177, 187, 189, 190, - 191, 192, 193, 200, 201, 202, 203, 79, - 92, 93, 95, 96, 97, 100, 95, 96, - 97, 100, 97, 100, 98, 270, 99, 96, - 95, 97, 23, 54, 101, 94, 104, 2, - 105, 133, 161, 177, 187, 189, 190, 191, - 192, 193, 200, 201, 202, 203, 99, 102, - 103, 19, 12, 13, 20, 106, 107, 108, - 123, 106, 107, 108, 123, 108, 123, 109, - 110, 111, 124, 112, 225, 110, 111, 124, - 112, 125, 112, 125, 113, 114, 115, 126, - 116, 222, 114, 115, 126, 116, 127, 116, - 127, 117, 118, 119, 128, 120, 219, 118, - 119, 128, 120, 129, 120, 129, 121, 270, - 122, 107, 106, 108, 23, 54, 130, 94, - 104, 2, 105, 133, 161, 177, 187, 189, - 190, 191, 192, 193, 200, 201, 202, 203, - 122, 131, 132, 134, 135, 136, 151, 134, - 135, 136, 151, 136, 151, 137, 138, 139, - 152, 140, 216, 138, 139, 152, 140, 153, - 140, 153, 141, 142, 143, 154, 144, 213, - 142, 143, 154, 144, 155, 144, 155, 145, - 146, 147, 156, 148, 210, 146, 147, 156, - 148, 157, 148, 157, 149, 270, 150, 135, - 134, 136, 23, 54, 158, 94, 104, 2, - 105, 133, 161, 177, 187, 189, 190, 191, - 192, 193, 200, 201, 202, 203, 150, 159, - 160, 162, 163, 164, 171, 162, 163, 164, - 171, 164, 171, 165, 166, 167, 172, 168, - 207, 166, 167, 172, 168, 173, 168, 173, - 169, 270, 170, 163, 162, 164, 23, 54, - 174, 94, 104, 2, 105, 133, 161, 177, - 187, 189, 190, 191, 192, 193, 200, 201, - 202, 203, 170, 175, 176, 178, 179, 180, - 183, 178, 179, 180, 183, 180, 183, 181, - 270, 182, 179, 178, 180, 23, 54, 184, - 94, 104, 2, 105, 133, 161, 177, 187, - 189, 190, 191, 192, 193, 200, 201, 202, - 203, 182, 185, 186, 270, 188, 23, 54, - 94, 104, 2, 105, 133, 161, 177, 187, - 189, 190, 191, 192, 193, 200, 201, 202, - 203, 188, 24, 25, 50, 55, 56, 57, - 80, 95, 96, 97, 100, 19, 12, 13, - 20, 3, 4, 5, 194, 198, 199, 106, - 107, 108, 123, 134, 135, 136, 151, 162, - 163, 164, 171, 178, 179, 180, 183, 205, - 206, 208, 209, 211, 212, 214, 215, 217, - 218, 220, 221, 223, 224, 226, 227, 229, - 230, 232, 233, 235, 236, 238, 239, 241, - 242, 244, 245, 249, 250, 41, 252, 38, - 39, 256, 257, 261, 262, 263, 265, 266, - 268, 269 + 2, 0, 3, 4, 161, 2, 3, 4, + 161, 4, 161, 5, 6, 7, 162, 8, + 169, 6, 7, 162, 8, 265, 8, 265, + 233, 10, 16, 11, 12, 13, 17, 14, + 229, 12, 13, 17, 14, 236, 14, 236, + 235, 15, 9, 10, 16, 19, 20, 43, + 19, 20, 43, 21, 22, 23, 24, 44, + 22, 23, 24, 226, 25, 26, 27, 222, + 28, 223, 26, 27, 222, 28, 221, 28, + 221, 29, 30, 31, 218, 30, 31, 32, + 217, 33, 34, 35, 216, 33, 34, 35, + 216, 36, 37, 215, 38, 214, 36, 37, + 215, 38, 214, 38, 214, 39, 40, 41, + 210, 42, 211, 40, 41, 210, 42, 268, + 42, 268, 237, 43, 45, 46, 48, 49, + 50, 71, 48, 49, 50, 71, 50, 71, + 51, 52, 53, 72, 54, 205, 52, 53, + 72, 54, 73, 54, 73, 55, 56, 57, + 74, 58, 202, 56, 57, 74, 58, 75, + 58, 75, 59, 60, 61, 76, 62, 199, + 60, 61, 76, 62, 77, 62, 77, 63, + 64, 65, 78, 66, 196, 64, 65, 78, + 66, 79, 66, 79, 67, 68, 69, 80, + 70, 193, 68, 69, 80, 70, 241, 70, + 241, 239, 82, 242, 84, 85, 86, 245, + 84, 85, 86, 245, 86, 245, 243, 88, + 246, 15, 9, 10, 16, 91, 92, 93, + 106, 91, 92, 93, 106, 93, 106, 94, + 95, 96, 107, 97, 190, 95, 96, 107, + 97, 108, 97, 108, 98, 99, 100, 109, + 101, 187, 99, 100, 109, 101, 110, 101, + 110, 102, 103, 104, 111, 105, 184, 103, + 104, 111, 105, 249, 105, 249, 247, 113, + 250, 115, 116, 117, 130, 115, 116, 117, + 130, 117, 130, 118, 119, 120, 131, 121, + 181, 119, 120, 131, 121, 132, 121, 132, + 122, 123, 124, 133, 125, 178, 123, 124, + 133, 125, 134, 125, 134, 126, 127, 128, + 135, 129, 175, 127, 128, 135, 129, 253, + 129, 253, 251, 137, 254, 139, 140, 141, + 146, 139, 140, 141, 146, 141, 146, 142, + 143, 144, 147, 145, 172, 143, 144, 147, + 145, 257, 145, 257, 255, 149, 258, 151, + 152, 153, 261, 151, 152, 153, 261, 153, + 261, 259, 155, 262, 19, 20, 43, 48, + 49, 50, 71, 84, 85, 86, 245, 15, + 9, 10, 16, 2, 3, 4, 161, 164, + 266, 91, 92, 93, 106, 115, 116, 117, + 130, 139, 140, 141, 146, 151, 152, 153, + 261, 170, 171, 173, 174, 176, 177, 179, + 180, 182, 183, 185, 186, 188, 189, 191, + 192, 194, 195, 197, 198, 200, 201, 203, + 204, 206, 207, 209, 267, 212, 213, 36, + 37, 215, 38, 214, 33, 34, 35, 216, + 219, 220, 224, 225, 226, 228, 269, 230, + 231, 232, 1, 160, 234, 9, 15, 10, + 18, 47, 163, 83, 89, 1, 90, 114, + 138, 150, 263, 156, 157, 158, 159, 160, + 165, 166, 167, 168, 234, 18, 47, 83, + 89, 90, 114, 138, 150, 263, 156, 157, + 158, 159, 165, 166, 167, 168, 234, 9, + 15, 10, 18, 47, 227, 83, 89, 1, + 90, 114, 138, 150, 263, 156, 157, 158, + 159, 160, 165, 166, 167, 168, 238, 19, + 20, 18, 47, 208, 83, 89, 1, 90, + 114, 138, 150, 263, 156, 157, 158, 159, + 160, 165, 166, 167, 168, 238, 240, 49, + 48, 50, 18, 47, 81, 83, 89, 1, + 90, 114, 138, 150, 263, 156, 157, 158, + 159, 160, 165, 166, 167, 168, 240, 244, + 85, 84, 86, 18, 47, 87, 83, 89, + 1, 90, 114, 138, 150, 263, 156, 157, + 158, 159, 160, 165, 166, 167, 168, 244, + 248, 92, 91, 93, 18, 47, 112, 83, + 89, 1, 90, 114, 138, 150, 263, 156, + 157, 158, 159, 160, 165, 166, 167, 168, + 248, 252, 116, 115, 117, 18, 47, 136, + 83, 89, 1, 90, 114, 138, 150, 263, + 156, 157, 158, 159, 160, 165, 166, 167, + 168, 252, 256, 140, 139, 141, 18, 47, + 148, 83, 89, 1, 90, 114, 138, 150, + 263, 156, 157, 158, 159, 160, 165, 166, + 167, 168, 256, 260, 152, 151, 153, 18, + 47, 154, 83, 89, 1, 90, 114, 138, + 150, 263, 156, 157, 158, 159, 160, 165, + 166, 167, 168, 260, 264, 18, 47, 83, + 89, 1, 90, 114, 138, 150, 263, 156, + 157, 158, 159, 160, 165, 166, 167, 168, + 264 }; static const char _svg_path_trans_actions[] = { - 15, 0, 0, 0, 0, 9, 47, 47, - 47, 0, 1, 1, 1, 0, 0, 0, - 3, 17, 3, 17, 0, 0, 1, 0, - 1, 1, 0, 0, 0, 60, 20, 56, - 20, 56, 20, 20, 0, 20, 20, 20, - 20, 20, 20, 20, 20, 20, 20, 20, - 20, 20, 20, 20, 20, 20, 0, 1, - 0, 1, 1, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 3, - 17, 3, 17, 0, 0, 1, 0, 1, - 1, 0, 0, 0, 68, 23, 64, 23, - 64, 23, 23, 0, 23, 23, 23, 23, - 23, 23, 23, 23, 23, 23, 23, 23, - 23, 23, 23, 23, 23, 9, 47, 47, - 0, 1, 1, 0, 3, 3, 17, 0, - 0, 0, 1, 1, 0, 3, 17, 3, - 17, 0, 0, 1, 0, 1, 1, 0, - 0, 0, 3, 3, 0, 0, 0, 0, - 0, 7, 7, 0, 0, 0, 0, 7, - 7, 0, 1, 0, 1, 1, 0, 0, - 0, 3, 17, 3, 17, 0, 0, 1, - 0, 1, 1, 0, 0, 0, 124, 44, - 44, 120, 44, 44, 0, 44, 44, 44, - 44, 44, 44, 44, 44, 44, 44, 44, - 44, 44, 44, 44, 44, 44, 0, 0, - 0, 0, 9, 47, 47, 47, 0, 1, - 1, 1, 0, 0, 0, 3, 17, 3, - 17, 0, 0, 1, 0, 1, 1, 0, - 0, 0, 3, 17, 3, 17, 0, 0, - 1, 0, 1, 1, 0, 0, 0, 3, - 17, 3, 17, 0, 0, 1, 0, 1, - 1, 0, 0, 0, 3, 17, 3, 17, + 9, 0, 51, 51, 51, 0, 1, 1, + 1, 0, 0, 0, 3, 15, 3, 15, 0, 0, 1, 0, 1, 1, 0, 0, - 0, 3, 17, 3, 17, 0, 0, 1, - 0, 1, 1, 0, 0, 0, 92, 32, - 88, 32, 88, 32, 32, 0, 32, 32, - 32, 32, 32, 32, 32, 32, 32, 32, - 32, 32, 32, 32, 32, 32, 32, 0, - 0, 0, 9, 47, 47, 47, 0, 1, - 1, 1, 0, 0, 0, 76, 26, 72, - 26, 72, 26, 26, 0, 26, 26, 26, - 26, 26, 26, 26, 26, 26, 26, 26, - 26, 26, 26, 26, 26, 26, 0, 0, - 0, 9, 47, 47, 47, 9, 47, 47, - 47, 0, 1, 1, 1, 0, 0, 0, - 3, 17, 3, 17, 0, 0, 1, 0, - 1, 1, 0, 0, 0, 3, 17, 3, - 17, 0, 0, 1, 0, 1, 1, 0, - 0, 0, 3, 17, 3, 17, 0, 0, - 1, 0, 1, 1, 0, 0, 0, 108, - 38, 104, 38, 104, 38, 38, 0, 38, - 38, 38, 38, 38, 38, 38, 38, 38, - 38, 38, 38, 38, 38, 38, 38, 38, - 0, 0, 0, 9, 47, 47, 47, 0, - 1, 1, 1, 0, 0, 0, 3, 17, - 3, 17, 0, 0, 1, 0, 1, 1, - 0, 0, 0, 3, 17, 3, 17, 0, + 0, 0, 0, 0, 3, 15, 3, 15, + 0, 0, 1, 0, 1, 1, 0, 0, + 0, 0, 1, 1, 1, 9, 51, 51, + 0, 1, 1, 0, 3, 3, 15, 0, + 0, 0, 1, 1, 0, 3, 15, 3, + 15, 0, 0, 1, 0, 1, 1, 0, + 0, 0, 3, 3, 0, 0, 0, 0, + 0, 7, 7, 7, 7, 0, 0, 0, + 0, 7, 48, 7, 48, 48, 0, 1, + 0, 1, 1, 0, 0, 0, 3, 15, + 3, 15, 0, 0, 1, 0, 1, 1, + 0, 0, 0, 0, 0, 0, 9, 51, + 51, 51, 0, 1, 1, 1, 0, 0, + 0, 3, 15, 3, 15, 0, 0, 1, + 0, 1, 1, 0, 0, 0, 3, 15, + 3, 15, 0, 0, 1, 0, 1, 1, + 0, 0, 0, 3, 15, 3, 15, 0, 0, 1, 0, 1, 1, 0, 0, 0, - 3, 17, 3, 17, 0, 0, 1, 0, - 1, 1, 0, 0, 0, 100, 35, 96, - 35, 96, 35, 35, 0, 35, 35, 35, - 35, 35, 35, 35, 35, 35, 35, 35, - 35, 35, 35, 35, 35, 35, 0, 0, - 0, 9, 47, 47, 47, 0, 1, 1, - 1, 0, 0, 0, 3, 17, 3, 17, + 3, 15, 3, 15, 0, 0, 1, 0, + 1, 1, 0, 0, 0, 3, 15, 3, + 15, 0, 0, 1, 0, 1, 1, 0, + 0, 0, 0, 0, 9, 51, 51, 51, + 0, 1, 1, 1, 0, 0, 0, 0, + 0, 9, 51, 51, 51, 9, 51, 51, + 51, 0, 1, 1, 1, 0, 0, 0, + 3, 15, 3, 15, 0, 0, 1, 0, + 1, 1, 0, 0, 0, 3, 15, 3, + 15, 0, 0, 1, 0, 1, 1, 0, + 0, 0, 3, 15, 3, 15, 0, 0, + 1, 0, 1, 1, 0, 0, 0, 0, + 0, 9, 51, 51, 51, 0, 1, 1, + 1, 0, 0, 0, 3, 15, 3, 15, 0, 0, 1, 0, 1, 1, 0, 0, - 0, 116, 41, 112, 41, 112, 41, 41, - 0, 41, 41, 41, 41, 41, 41, 41, - 41, 41, 41, 41, 41, 41, 41, 41, - 41, 41, 0, 0, 0, 9, 47, 47, - 47, 0, 1, 1, 1, 0, 0, 0, - 84, 29, 80, 29, 80, 29, 29, 0, - 29, 29, 29, 29, 29, 29, 29, 29, - 29, 29, 29, 29, 29, 29, 29, 29, - 29, 0, 0, 0, 53, 13, 13, 13, + 0, 3, 15, 3, 15, 0, 0, 1, + 0, 1, 1, 0, 0, 0, 3, 15, + 3, 15, 0, 0, 1, 0, 1, 1, + 0, 0, 0, 0, 0, 9, 51, 51, + 51, 0, 1, 1, 1, 0, 0, 0, + 3, 15, 3, 15, 0, 0, 1, 0, + 1, 1, 0, 0, 0, 0, 0, 9, + 51, 51, 51, 0, 1, 1, 1, 0, + 0, 0, 0, 0, 11, 54, 54, 11, + 54, 54, 54, 11, 54, 54, 54, 11, + 54, 54, 54, 11, 54, 54, 54, 0, + 0, 11, 54, 54, 54, 11, 54, 54, + 54, 11, 54, 54, 54, 11, 54, 54, + 54, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 5, + 45, 5, 45, 45, 5, 5, 5, 5, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 18, 57, 18, 57, + 18, 18, 0, 18, 18, 18, 18, 18, + 18, 18, 18, 18, 18, 18, 18, 18, + 18, 18, 18, 18, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 21, 61, + 21, 61, 21, 21, 0, 21, 21, 21, + 21, 21, 21, 21, 21, 21, 21, 21, + 21, 21, 21, 21, 21, 21, 42, 42, + 89, 42, 42, 0, 42, 42, 42, 42, + 42, 42, 42, 42, 42, 42, 42, 42, + 42, 42, 42, 42, 42, 0, 30, 73, + 30, 73, 30, 30, 0, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 0, 24, + 65, 24, 65, 24, 24, 0, 24, 24, + 24, 24, 24, 24, 24, 24, 24, 24, + 24, 24, 24, 24, 24, 24, 24, 0, + 36, 81, 36, 81, 36, 36, 0, 36, + 36, 36, 36, 36, 36, 36, 36, 36, + 36, 36, 36, 36, 36, 36, 36, 36, + 0, 33, 77, 33, 77, 33, 33, 0, + 33, 33, 33, 33, 33, 33, 33, 33, + 33, 33, 33, 33, 33, 33, 33, 33, + 33, 0, 39, 85, 39, 85, 39, 39, + 0, 39, 39, 39, 39, 39, 39, 39, + 39, 39, 39, 39, 39, 39, 39, 39, + 39, 39, 0, 27, 69, 27, 69, 27, + 27, 0, 27, 27, 27, 27, 27, 27, + 27, 27, 27, 27, 27, 27, 27, 27, + 27, 27, 27, 0, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, - 13, 0, 11, 50, 50, 11, 50, 50, - 50, 11, 50, 50, 50, 11, 50, 50, - 50, 11, 50, 50, 50, 0, 0, 11, - 50, 50, 50, 11, 50, 50, 50, 11, - 50, 50, 50, 11, 50, 50, 50, 0, + 0 +}; + +static const char _svg_path_eof_actions[] = { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 5, 5, 5, - 5, 0, 0, 0, 0, 0, 0, 0, - 0, 0 + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 18, 0, 21, 21, 42, 0, 30, + 0, 30, 30, 24, 0, 24, 24, 36, + 0, 36, 36, 33, 0, 33, 33, 39, + 0, 39, 39, 27, 0, 27, 27, 13, + 0, 18, 18, 42, 42, 21 }; -static const int svg_path_start = 1; -static const int svg_path_first_final = 270; +static const int svg_path_start = 232; +static const int svg_path_first_final = 232; + +static const int svg_path_en_main = 232; -//static const int svg_path_en_main = 1; +#line 47 "D:/lib2geom/trunk/src/2geom/svg-path-parser.rl" -void Parser::parse(char const *str) -throw(SVGPathParseError) + +SVGPathParser::SVGPathParser(PathSink &sink) + : _absolute(false) + , _sink(sink) { - char const *p = str; - char const *start = NULL; - int cs; + reset(); +} - _reset(); +void SVGPathParser::reset() { + _absolute = false; + _current = _initial = Point(0, 0); + _quad_tangent = _cubic_tangent = Point(0, 0); + _params.clear(); + +#line 1096 "D:/lib2geom/trunk/src/2geom/svg-path-parser.cpp" { cs = svg_path_start; } +#line 64 "D:/lib2geom/trunk/src/2geom/svg-path-parser.rl" + +} + +void SVGPathParser::parse(char const *str, int len) +{ + if (len < 0) { + len = std::strlen(str); + } + _parse(str, str + len, true); +} + +void SVGPathParser::parse(std::string const &s) +{ + _parse(s.c_str(), s.c_str() + s.size(), true); +} + +void SVGPathParser::feed(char const *str, int len) +{ + if (len < 0) { + len = std::strlen(str); + } + _parse(str, str + len, false); +} + +void SVGPathParser::feed(std::string const &s) +{ + _parse(s.c_str(), s.c_str() + s.size(), false); +} + +void SVGPathParser::finish() +{ + char const *empty = ""; + _parse(empty, empty, true); +} + +void SVGPathParser::_push(Coord value) { + _params.push_back(value); +} + +Coord SVGPathParser::_pop() { + Coord value = _params.back(); + _params.pop_back(); + return value; +} + +bool SVGPathParser::_pop_flag() { + return _pop() != 0.0; +} + +Coord SVGPathParser::_pop_coord(Dim2 axis) { + if (_absolute) { + return _pop(); + } else { + return _pop() + _current[axis]; + } +} + +Point SVGPathParser::_pop_point() { + Coord y = _pop_coord(Y); + Coord x = _pop_coord(X); + return Point(x, y); +} + +void SVGPathParser::_moveTo(Point const &p) { + _sink.moveTo(p); + _quad_tangent = _cubic_tangent = _current = _initial = p; +} + +void SVGPathParser::_lineTo(Point const &p) { + _sink.lineTo(p); + _quad_tangent = _cubic_tangent = _current = p; +} + +void SVGPathParser::_curveTo(Point const &c0, Point const &c1, Point const &p) { + _sink.curveTo(c0, c1, p); + _quad_tangent = _current = p; + _cubic_tangent = p + ( p - c1 ); +} + +void SVGPathParser::_quadTo(Point const &c, Point const &p) { + _sink.quadTo(c, p); + _cubic_tangent = _current = p; + _quad_tangent = p + ( p - c ); +} + +void SVGPathParser::_arcTo(Coord rx, Coord ry, Coord angle, + bool large_arc, bool sweep, Point const &p) +{ + if (are_near(_current, p)) { + return; // ignore invalid (ambiguous) arc segments where start and end point are the same (per SVG spec) + } + + _sink.arcTo(rx, ry, angle, large_arc, sweep, p); + _quad_tangent = _cubic_tangent = _current = p; +} + +void SVGPathParser::_closePath() { + _sink.closePath(); + _quad_tangent = _cubic_tangent = _current = _initial; +} + +void SVGPathParser::_parse(char const *str, char const *strend, bool finish) +{ + char const *p = str; + char const *pe = strend; + char const *eof = finish ? pe : NULL; + char const *start = NULL; + +#line 1211 "D:/lib2geom/trunk/src/2geom/svg-path-parser.cpp" { int _klen; unsigned int _trans; @@ -1168,6 +1215,8 @@ throw(SVGPathParseError) unsigned int _nacts; const char *_keys; + if ( p == pe ) + goto _test_eof; if ( cs == 0 ) goto _out; _resume: @@ -1233,63 +1282,75 @@ _match: switch ( *_acts++ ) { case 0: +#line 173 "D:/lib2geom/trunk/src/2geom/svg-path-parser.rl" { start = p; } break; case 1: - +#line 177 "D:/lib2geom/trunk/src/2geom/svg-path-parser.rl" { - char const *end=p; - std::string buf(start, end); - _push(g_ascii_strtod(buf.c_str(), NULL)); - start = NULL; + if (start) { + std::string buf(start, p); + _push(g_ascii_strtod(buf.c_str(), NULL)); + start = NULL; + } else { + std::string buf(str, p); + _push(g_ascii_strtod((_number_part + buf).c_str(), NULL)); + _number_part.clear(); + } } break; case 2: - +#line 189 "D:/lib2geom/trunk/src/2geom/svg-path-parser.rl" { _push(1.0); } break; case 3: - +#line 193 "D:/lib2geom/trunk/src/2geom/svg-path-parser.rl" { _push(0.0); } break; case 4: - +#line 197 "D:/lib2geom/trunk/src/2geom/svg-path-parser.rl" { _absolute = true; } break; case 5: +#line 201 "D:/lib2geom/trunk/src/2geom/svg-path-parser.rl" { _absolute = false; } break; case 6: +#line 205 "D:/lib2geom/trunk/src/2geom/svg-path-parser.rl" { _moveTo(_pop_point()); } break; case 7: +#line 209 "D:/lib2geom/trunk/src/2geom/svg-path-parser.rl" { _lineTo(_pop_point()); } break; case 8: +#line 213 "D:/lib2geom/trunk/src/2geom/svg-path-parser.rl" { - _hlineTo(Point(_pop_coord(X), _current[Y])); + _lineTo(Point(_pop_coord(X), _current[Y])); } break; case 9: +#line 217 "D:/lib2geom/trunk/src/2geom/svg-path-parser.rl" { - _vlineTo(Point(_current[X], _pop_coord(Y))); + _lineTo(Point(_current[X], _pop_coord(Y))); } break; case 10: +#line 221 "D:/lib2geom/trunk/src/2geom/svg-path-parser.rl" { Point p = _pop_point(); Point c1 = _pop_point(); @@ -1298,6 +1359,7 @@ _match: } break; case 11: +#line 228 "D:/lib2geom/trunk/src/2geom/svg-path-parser.rl" { Point p = _pop_point(); Point c1 = _pop_point(); @@ -1305,6 +1367,7 @@ _match: } break; case 12: +#line 234 "D:/lib2geom/trunk/src/2geom/svg-path-parser.rl" { Point p = _pop_point(); Point c = _pop_point(); @@ -1312,12 +1375,14 @@ _match: } break; case 13: +#line 240 "D:/lib2geom/trunk/src/2geom/svg-path-parser.rl" { Point p = _pop_point(); _quadTo(_quad_tangent, p); } break; case 14: +#line 245 "D:/lib2geom/trunk/src/2geom/svg-path-parser.rl" { Point point = _pop_point(); bool sweep = _pop_flag(); @@ -1330,42 +1395,167 @@ _match: } break; case 15: +#line 256 "D:/lib2geom/trunk/src/2geom/svg-path-parser.rl" { _closePath(); } break; - case 16: - {{p++; goto _out; }} - break; +#line 1404 "D:/lib2geom/trunk/src/2geom/svg-path-parser.cpp" } } _again: if ( cs == 0 ) goto _out; - p += 1; - goto _resume; + if ( ++p != pe ) + goto _resume; + _test_eof: {} + if ( p == eof ) + { + const char *__acts = _svg_path_actions + _svg_path_eof_actions[cs]; + unsigned int __nacts = (unsigned int) *__acts++; + while ( __nacts-- > 0 ) { + switch ( *__acts++ ) { + case 1: +#line 177 "D:/lib2geom/trunk/src/2geom/svg-path-parser.rl" + { + if (start) { + std::string buf(start, p); + _push(g_ascii_strtod(buf.c_str(), NULL)); + start = NULL; + } else { + std::string buf(str, p); + _push(g_ascii_strtod((_number_part + buf).c_str(), NULL)); + _number_part.clear(); + } + } + break; + case 6: +#line 205 "D:/lib2geom/trunk/src/2geom/svg-path-parser.rl" + { + _moveTo(_pop_point()); + } + break; + case 7: +#line 209 "D:/lib2geom/trunk/src/2geom/svg-path-parser.rl" + { + _lineTo(_pop_point()); + } + break; + case 8: +#line 213 "D:/lib2geom/trunk/src/2geom/svg-path-parser.rl" + { + _lineTo(Point(_pop_coord(X), _current[Y])); + } + break; + case 9: +#line 217 "D:/lib2geom/trunk/src/2geom/svg-path-parser.rl" + { + _lineTo(Point(_current[X], _pop_coord(Y))); + } + break; + case 10: +#line 221 "D:/lib2geom/trunk/src/2geom/svg-path-parser.rl" + { + Point p = _pop_point(); + Point c1 = _pop_point(); + Point c0 = _pop_point(); + _curveTo(c0, c1, p); + } + break; + case 11: +#line 228 "D:/lib2geom/trunk/src/2geom/svg-path-parser.rl" + { + Point p = _pop_point(); + Point c1 = _pop_point(); + _curveTo(_cubic_tangent, c1, p); + } + break; + case 12: +#line 234 "D:/lib2geom/trunk/src/2geom/svg-path-parser.rl" + { + Point p = _pop_point(); + Point c = _pop_point(); + _quadTo(c, p); + } + break; + case 13: +#line 240 "D:/lib2geom/trunk/src/2geom/svg-path-parser.rl" + { + Point p = _pop_point(); + _quadTo(_quad_tangent, p); + } + break; + case 14: +#line 245 "D:/lib2geom/trunk/src/2geom/svg-path-parser.rl" + { + Point point = _pop_point(); + bool sweep = _pop_flag(); + bool large_arc = _pop_flag(); + double angle = deg_to_rad(_pop()); + double ry = _pop(); + double rx = _pop(); + + _arcTo(rx, ry, angle, large_arc, sweep, point); + } + break; + case 15: +#line 256 "D:/lib2geom/trunk/src/2geom/svg-path-parser.rl" + { + _closePath(); + } + break; +#line 1509 "D:/lib2geom/trunk/src/2geom/svg-path-parser.cpp" + } + } + } + _out: {} } +#line 398 "D:/lib2geom/trunk/src/2geom/svg-path-parser.rl" - if ( cs < svg_path_first_final ) { - throw SVGPathParseError(); + + if (finish) { + if (cs < svg_path_first_final) { + throw SVGPathParseError(); + } + } else if (start != NULL) { + _number_part = std::string(start, pe); } -} + if (finish) { + _sink.flush(); + reset(); + } } void parse_svg_path(char const *str, PathSink &sink) -throw(SVGPathParseError) { - Parser parser(sink); + SVGPathParser parser(sink); parser.parse(str); - sink.flush(); } +void parse_svg_path_file(FILE *fi, PathSink &sink) +{ + static const size_t BUFFER_SIZE = 4096; + char buffer[BUFFER_SIZE]; + size_t bytes_read; + SVGPathParser parser(sink); + + while (true) { + bytes_read = fread(buffer, 1, BUFFER_SIZE, fi); + if (bytes_read < BUFFER_SIZE) { + parser.parse(buffer, bytes_read); + break; + } else { + parser.feed(buffer, bytes_read); + } + } } +} // namespace Geom + /* Local Variables: mode:c++ diff --git a/src/2geom/svg-path-parser.h b/src/2geom/svg-path-parser.h index 163fbe5c4..6478ba468 100644 --- a/src/2geom/svg-path-parser.h +++ b/src/2geom/svg-path-parser.h @@ -30,48 +30,143 @@ * */ -#ifndef SEEN_SVG_PATH_PARSER_H -#define SEEN_SVG_PATH_PARSER_H +#ifndef LIB2GEOM_SEEN_SVG_PATH_PARSER_H +#define LIB2GEOM_SEEN_SVG_PATH_PARSER_H -#include +#include #include #include +#include #include <2geom/exception.h> #include <2geom/point.h> #include <2geom/path-sink.h> namespace Geom { -void parse_svg_path(char const *str, PathSink &sink) throw(SVGPathParseError); +/** @brief Read SVG path data and feed it to a PathSink + * + * This class provides an interface to an SVG path data parser written in Ragel. + * It supports parsing the path data either at once or block-by-block. + * Use the parse() functions to parse complete data and the feed() and finish() + * functions to parse partial data. + * + * The parser will call the appropriate methods on the PathSink supplied + * at construction. To store the path in memory as a PathVector, pass + * a PathBuilder. You can also use one of the freestanding helper functions + * if you don't need to parse data block-by-block. + * + * @ingroup Paths + */ +class SVGPathParser { +public: + SVGPathParser(PathSink &sink); + + /** @brief Reset internal state. + * Discards the internal state associated with partially parsed data, + * letting you start from scratch. Note that any partial data written + * to the path sink is not affected - you need to clear it yourself. */ + void reset(); + + /** @brief Parse a C-style string. + * The path sink is flushed and the internal state is reset after this call. + * Note that the state is not reset before this method, so you can use it to + * process the last block of partial data. + * @param str String to parse + * @param len Length of string or -1 if null-terminated */ + void parse(char const *str, int len = -1); + /** @brief Parse an STL string. */ + void parse(std::string const &s); + + /** @brief Parse a part of path data stored in a C-style string. + * This method does not reset internal state, so it can be called multiple + * times to parse successive blocks of a longer SVG path data string. + * To finish parsing, call finish() after the final block or call parse() + * with the last block of data. + * @param str String to parse + * @param len Length of string or -1 if null-terminated */ + void feed(char const *str, int len = -1); + /** @brief Parse a part of path data stored in an STL string. */ + void feed(std::string const &s); -inline std::vector parse_svg_path(char const *str) throw(SVGPathParseError) { - typedef std::vector Subpaths; - typedef std::back_insert_iterator Inserter; - - Subpaths subpaths; - Inserter iter(subpaths); - PathIteratorSink generator(iter); + /** @brief Finalize parsing. + * After the last block of data was submitted with feed(), call this method + * to finalize parsing, flush the path sink and reset internal state. + * You should not call this after parse(). */ + void finish(); + +private: + bool _absolute; + Point _current; + Point _initial; + Point _cubic_tangent; + Point _quad_tangent; + std::vector _params; + PathSink &_sink; + + int cs; + std::string _number_part; + + void _push(Coord value); + Coord _pop(); + bool _pop_flag(); + Coord _pop_coord(Geom::Dim2 axis); + Point _pop_point(); + void _moveTo(Point const &p); + void _lineTo(Point const &p); + void _curveTo(Point const &c0, Point const &c1, Point const &p); + void _quadTo(Point const &c, Point const &p); + void _arcTo(double rx, double ry, double angle, + bool large_arc, bool sweep, Point const &p); + void _closePath(); + + void _parse(char const *str, char const *strend, bool finish); +}; + +/** @brief Feed SVG path data to the specified sink + * @ingroup Paths */ +void parse_svg_path(char const *str, PathSink &sink); +/** @brief Feed SVG path data to the specified sink + * @ingroup Paths */ +inline void parse_svg_path(std::string const &str, PathSink &sink) { + parse_svg_path(str.c_str(), sink); +} +/** Feed SVG path data from a C stream to the specified sink + * @ingroup Paths */ +void parse_svg_path_file(FILE *fi, PathSink &sink); + +/** @brief Create path vector from SVG path data stored in a C string + * @ingroup Paths */ +inline PathVector parse_svg_path(char const *str) { + PathVector ret; + SubpathInserter iter(ret); + PathIteratorSink generator(iter); parse_svg_path(str, generator); - return subpaths; + return ret; } -inline std::vector read_svgd_f(FILE * fi) throw(SVGPathParseError) { - /// @bug The 10kB length limit should be removed - char input[1024 * 10]; - fgets(input, 1024 * 10, fi); - return parse_svg_path(input); +/** @brief Create path vector from a C stream with SVG path data + * @ingroup Paths */ +inline PathVector read_svgd_f(FILE * fi) { + PathVector ret; + SubpathInserter iter(ret); + PathIteratorSink generator(iter); + + parse_svg_path_file(fi, generator); + return ret; } -inline std::vector read_svgd(char const * name) throw(SVGPathParseError) { - FILE* fi = fopen(name, "r"); +/** @brief Create path vector from SVG path data stored in a file + * @ingroup Paths */ +inline PathVector read_svgd(char const *filename) { + FILE* fi = fopen(filename, "r"); if(fi == NULL) throw(std::runtime_error("Error opening file")); - std::vector out = read_svgd_f(fi); + PathVector out = read_svgd_f(fi); fclose(fi); return out; } -} +} // end namespace Geom #endif /* diff --git a/src/2geom/svg-path-writer.cpp b/src/2geom/svg-path-writer.cpp new file mode 100644 index 000000000..e8083a8d1 --- /dev/null +++ b/src/2geom/svg-path-writer.cpp @@ -0,0 +1,296 @@ +/** @file + * @brief Path sink which writes an SVG-compatible command string + *//* + * Authors: + * Krzysztof Kosiński + * + * Copyright 2014 Authors + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + */ + +#include +#include +#include <2geom/coord.h> +#include <2geom/svg-path-writer.h> +#include + +namespace Geom { + +static inline bool is_digit(char c) { + return c >= '0' && c <= '9'; +} + +SVGPathWriter::SVGPathWriter() + : _epsilon(0) + , _precision(-1) + , _optimize(false) + , _use_shorthands(true) + , _command(0) +{ + // always use C locale for number formatting + _ns.imbue(std::locale::classic()); + _ns.unsetf(std::ios::floatfield); +} + +void SVGPathWriter::moveTo(Point const &p) +{ + _setCommand('M'); + _current_pars.push_back(p[X]); + _current_pars.push_back(p[Y]); + + _current = _subpath_start = _quad_tangent = _cubic_tangent = p; + if (!_optimize) { + flush(); + } +} + +void SVGPathWriter::lineTo(Point const &p) +{ + // The weird setting of _current is to avoid drift with many almost-aligned segments + // The additional conditions ensure that the smaller dimension is rounded to zero + bool written = false; + if (_use_shorthands) { + Point r = _current - p; + if (are_near(p[X], _current[X], _epsilon) && std::abs(r[X]) < std::abs(r[Y])) { + // emit vlineto + _setCommand('V'); + _current_pars.push_back(p[Y]); + _current[Y] = p[Y]; + written = true; + } else if (are_near(p[Y], _current[Y], _epsilon) && std::abs(r[Y]) < std::abs(r[X])) { + // emit hlineto + _setCommand('H'); + _current_pars.push_back(p[X]); + _current[X] = p[X]; + written = true; + } + } + + if (!written) { + // emit normal lineto + if (_command != 'M' && _command != 'L') { + _setCommand('L'); + } + _current_pars.push_back(p[X]); + _current_pars.push_back(p[Y]); + _current = p; + } + + _cubic_tangent = _quad_tangent = _current; + if (!_optimize) { + flush(); + } +} + +void SVGPathWriter::quadTo(Point const &c, Point const &p) +{ + bool shorthand = _use_shorthands && are_near(c, _quad_tangent, _epsilon); + + _setCommand(shorthand ? 'T' : 'Q'); + if (!shorthand) { + _current_pars.push_back(c[X]); + _current_pars.push_back(c[Y]); + } + _current_pars.push_back(p[X]); + _current_pars.push_back(p[Y]); + + _current = _cubic_tangent = p; + _quad_tangent = p + (p - c); + if (!_optimize) { + flush(); + } +} + +void SVGPathWriter::curveTo(Point const &p1, Point const &p2, Point const &p3) +{ + bool shorthand = _use_shorthands && are_near(p1, _cubic_tangent, _epsilon); + + _setCommand(shorthand ? 'S' : 'C'); + if (!shorthand) { + _current_pars.push_back(p1[X]); + _current_pars.push_back(p1[Y]); + } + _current_pars.push_back(p2[X]); + _current_pars.push_back(p2[Y]); + _current_pars.push_back(p3[X]); + _current_pars.push_back(p3[Y]); + + _current = _quad_tangent = p3; + _cubic_tangent = p3 + (p3 - p2); + if (!_optimize) { + flush(); + } +} + +void SVGPathWriter::arcTo(double rx, double ry, double angle, + bool large_arc, bool sweep, Point const &p) +{ + _setCommand('A'); + _current_pars.push_back(rx); + _current_pars.push_back(ry); + _current_pars.push_back(angle); + _current_pars.push_back(large_arc ? 1. : 0.); + _current_pars.push_back(sweep ? 1. : 0.); + _current_pars.push_back(p[X]); + _current_pars.push_back(p[Y]); + + _current = _quad_tangent = _cubic_tangent = p; + if (!_optimize) { + flush(); + } +} + +void SVGPathWriter::closePath() +{ + flush(); + if (_optimize) { + _s << "z"; + } else { + _s << " z"; + } + _current = _quad_tangent = _cubic_tangent = _subpath_start; +} + +void SVGPathWriter::flush() +{ + if (_command == 0 || _current_pars.empty()) return; + + if (_optimize) { + _s << _command; + } else { + if (_s.tellp() != 0) { + _s << ' '; + } + _s << _command; + } + + char lastchar = _command; + bool contained_dot = false; + + for (unsigned i = 0; i < _current_pars.size(); ++i) { + // TODO: optimize the use of absolute / relative coords + std::string cs = _formatCoord(_current_pars[i]); + + // Separator handling logic. + // Floating point values can end with a digit or dot + // and start with a digit, a plus or minus sign, or a dot. + // The following cases require a separator: + // * digit-digit + // * digit-dot (only if the previous number didn't contain a dot) + // * dot-digit + if (_optimize) { + // C++11: change to front() + char firstchar = cs[0]; + if (is_digit(lastchar)) { + if (is_digit(firstchar)) { + _s << " "; + } else if (firstchar == '.' && !contained_dot) { + _s << " "; + } + } else if (lastchar == '.' && is_digit(firstchar)) { + _s << " "; + } + _s << cs; + + // C++11: change to back() + lastchar = cs[cs.length()-1]; + contained_dot = cs.find('.') != std::string::npos; + } else { + _s << " " << cs; + } + } + _current_pars.clear(); + _command = 0; +} + +void SVGPathWriter::clear() +{ + _s.clear(); + _s.str(""); + _ns.clear(); + _ns.str(""); + _command = 0; + _current_pars.clear(); + _current = Point(0,0); + _subpath_start = Point(0,0); +} + +void SVGPathWriter::setPrecision(int prec) +{ + _precision = prec; + if (prec < 0) { + _epsilon = 0; + } else { + _epsilon = std::pow(10., -prec); + _ns << std::setprecision(_precision); + } +} + +void SVGPathWriter::_setCommand(char cmd) +{ + if (_command != 0 && _command != cmd) { + flush(); + } + _command = cmd; +} + +std::string SVGPathWriter::_formatCoord(Coord par) +{ + std::string ret; + if (_precision < 0) { + ret = format_coord_shortest(par); + } else { + _ns << par; + ret = _ns.str(); + _ns.clear(); + _ns.str(""); + } + return ret; +} + + +std::string write_svg_path(PathVector const &pv, int prec, bool optimize, bool shorthands) +{ + SVGPathWriter writer; + writer.setPrecision(prec); + writer.setOptimize(optimize); + writer.setUseShorthands(shorthands); + + writer.feed(pv); + return writer.str(); +} + +} // namespace Geom + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 : diff --git a/src/2geom/svg-path-writer.h b/src/2geom/svg-path-writer.h new file mode 100644 index 000000000..e639541ab --- /dev/null +++ b/src/2geom/svg-path-writer.h @@ -0,0 +1,122 @@ +/** @file + * @brief Path sink which writes an SVG-compatible command string + *//* + * Authors: + * Krzysztof Kosiński + * + * Copyright 2014 Authors + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + */ + +#ifndef LIB2GEOM_SEEN_SVG_PATH_WRITER_H +#define LIB2GEOM_SEEN_SVG_PATH_WRITER_H + +#include <2geom/path-sink.h> +#include + +namespace Geom { + +/** @brief Serialize paths to SVG path data strings. + * You can access the generated string by calling the str() method. + * @ingroup Paths + */ +class SVGPathWriter + : public PathSink +{ +public: + SVGPathWriter(); + ~SVGPathWriter() {} + + void moveTo(Point const &p); + void lineTo(Point const &p); + void quadTo(Point const &c, Point const &p); + void curveTo(Point const &c0, Point const &c1, Point const &p); + void arcTo(double rx, double ry, double angle, + bool large_arc, bool sweep, Point const &p); + void closePath(); + void flush(); + + /// Clear any path data written so far. + void clear(); + + /** @brief Set output precision. + * When the parameter is negative, the path writer enters a verbatim mode + * which preserves all values exactly. */ + void setPrecision(int prec); + + /** @brief Enable or disable length optimization. + * + * When set to true, the path writer will optimize the generated path data + * for minimum length. However, this will make the data less readable, + * because spaces between commands and coordinates will be omitted where + * unnecessary for correct parsing. + * + * When set to false, the string will be a straightforward, partially redundant + * representation of the passed commands, optimized for readability. + * Commands and coordinates will always be separated by spaces and the command + * symbol will not be omitted for multiple consecutive commands of the same type. + * + * Length optimization is turned off by default. */ + void setOptimize(bool opt) { _optimize = opt; } + + /** @brief Enable or disable the use of V, H, T and S commands where possible. + * Shorthands are turned on by default. */ + void setUseShorthands(bool use) { _use_shorthands = use; } + + /// Retrieve the generated path data string. + std::string str() const { return _s.str(); } + +private: + void _setCommand(char cmd); + std::string _formatCoord(Coord par); + + std::ostringstream _s, _ns; + std::vector _current_pars; + Point _subpath_start; + Point _current; + Point _quad_tangent; + Point _cubic_tangent; + Coord _epsilon; + int _precision; + bool _optimize; + bool _use_shorthands; + char _command; +}; + +std::string write_svg_path(PathVector const &pv, int prec = -1, bool optimize = false, bool shorthands = true); + +} // namespace Geom + +#endif // LIB2GEOM_SEEN_SVG_PATH_WRITER_H +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 : diff --git a/src/2geom/sweep.cpp b/src/2geom/sweep.cpp index f25894282..6910d5d02 100644 --- a/src/2geom/sweep.cpp +++ b/src/2geom/sweep.cpp @@ -19,8 +19,8 @@ std::vector > sweep_bounds(std::vector rs, Dim2 d) { std::vector > pairs(rs.size()); for(unsigned i = 0; i < rs.size(); i++) { - events.push_back(Event(rs[i][d][0], i, false)); - events.push_back(Event(rs[i][d][1], i, true)); + events.push_back(Event(rs[i][d].min(), i, false)); + events.push_back(Event(rs[i][d].max(), i, true)); } std::sort(events.begin(), events.end()); @@ -66,8 +66,8 @@ std::vector > sweep_bounds(std::vector a, std::vecto events[n].reserve(sz*2); for(unsigned i = 0; i < sz; i++) { Rect r = n ? b[i] : a[i]; - events[n].push_back(Event(r[d][0], i, false)); - events[n].push_back(Event(r[d][1], i, true)); + events[n].push_back(Event(r[d].min(), i, false)); + events[n].push_back(Event(r[d].max(), i, true)); } std::sort(events[n].begin(), events[n].end()); } diff --git a/src/2geom/sweep.h b/src/2geom/sweep.h index 91371e6fb..9c012958b 100644 --- a/src/2geom/sweep.h +++ b/src/2geom/sweep.h @@ -32,8 +32,8 @@ * */ -#ifndef __2GEOM_SWEEP_H__ -#define __2GEOM_SWEEP_H__ +#ifndef LIB2GEOM_SEEN_SWEEP_H +#define LIB2GEOM_SEEN_SWEEP_H #include #include <2geom/d2.h> diff --git a/src/2geom/toposweep.cpp b/src/2geom/toposweep.cpp index 4da3f6922..3cb231142 100644 --- a/src/2geom/toposweep.cpp +++ b/src/2geom/toposweep.cpp @@ -189,7 +189,7 @@ bool SectionSorter::operator()(Section const &a, Section const &b) const { } } - return Point::LexOrderRt(dim)(a.fp, b.fp); + return Point::LexLessRt(dim)(a.fp, b.fp); } // splits a section into pieces, as specified by an array of doubles, mutating the section to @@ -203,7 +203,7 @@ std::vector > split_section(boost::shared_ptr

t = cuts[1]; s->tp = s->curve.get(ps)(cuts[1]); - assert(Point::LexOrderRt(d)(s->fp, s->tp)); + assert(Point::LexLessRt(d)(s->fp, s->tp)); ret.reserve(cuts.size() - 2); for(int i = cuts.size() - 1; i > 1; i--) ret.push_back(boost::shared_ptr
(new Section(s->curve, cuts[i-1], cuts[i], ps, d))); @@ -380,7 +380,7 @@ TopoGraph::TopoGraph(PathVector const &ps, Dim2 d, double t) : dim(d), tol(t) { //find all sections to remove for(int i = context.size() - 1; i >= 0; i--) { boost::shared_ptr
sec = context[i].section; - if(Point::LexOrderRt(d)(lim, sec->tp)) { + if(Point::LexLessRt(d)(lim, sec->tp)) { //sec->tp is less than or equal to lim if(context[i].to_vert == -1) { //we need to create a new vertex; add everything that enters it @@ -639,6 +639,7 @@ void remove_area_whiskers(Areas &areas) { Path area_to_path(PathVector const &ps, Area const &area) { Path ret; + ret.setStitching(true); if(area.size() == 0) return ret; Point prev = area[0]->fp; for(unsigned i = 0; i < area.size(); i++) { @@ -646,17 +647,18 @@ Path area_to_path(PathVector const &ps, Area const &area) { Curve *curv = area[i]->curve.get(ps).portion( forward ? area[i]->f : area[i]->t, forward ? area[i]->t : area[i]->f); - ret.append(*curv, Path::STITCH_DISCONTINUOUS); + ret.append(*curv); delete curv; prev = forward ? area[i]->tp : area[i]->fp; } + ret.setStitching(false); return ret; } PathVector areas_to_paths(PathVector const &ps, Areas const &areas) { - std::vector ret; - ret.reserve(areas.size()); - for(unsigned i = 0; i < areas.size(); i++) + PathVector ret; + //ret.reserve(areas.size()); + for(unsigned i = 0; i < areas.size(); ++i) ret.push_back(area_to_path(ps, areas[i])); return ret; } diff --git a/src/2geom/toposweep.h b/src/2geom/toposweep.h index b6a55b154..7faf890e1 100644 --- a/src/2geom/toposweep.h +++ b/src/2geom/toposweep.h @@ -1,8 +1,7 @@ - /** * \file * \brief TopoSweep - topology / graph representation of a PathVector, for boolean operations and related tasks - * + *//* * Authors: * Michael Sloan * Nathan Hurst @@ -33,8 +32,8 @@ * the specific language governing rights and limitations. */ -#ifndef SEEN_GEOM_TOPOSWEEP_H -#define SEEN_GEOM_TOPOSWEEP_H +#ifndef LIB2GEOM_SEEN_TOPOSWEEP_H +#define LIB2GEOM_SEEN_TOPOSWEEP_H #include <2geom/coord.h> #include <2geom/point.h> @@ -69,10 +68,11 @@ struct Section { Section(CurveIx cix, double fd, double td, Point fdp, Point tdp) : curve(cix), f(fd), t(td), fp(fdp), tp(tdp) { } Section(CurveIx cix, double fd, double td, PathVector ps, Dim2 d) : curve(cix), f(fd), t(td) { fp = curve.get(ps).pointAt(f), tp = curve.get(ps).pointAt(t); - if (Point::LexOrderRt(d)(tp, fp)) { + if (Point::LexLessRt(d)(tp, fp)) { //swap from and to, since tp is left or above fp - std::swap(f, t); - std::swap(fp, tp); + using std::swap; + swap(f, t); + swap(fp, tp); } } Rect bbox() const { return Rect(fp, tp); } @@ -167,7 +167,7 @@ struct SweepSorter { Dim2 dim; SweepSorter(Dim2 d) : dim(d) {} bool operator()(const Section &a, const Section &b) const { - return Point::LexOrderRt(dim)(a.fp, b.fp); + return Point::LexLessRt(dim)(a.fp, b.fp); } }; @@ -208,7 +208,7 @@ Areas filter_areas(PathVector const &ps, Areas const & areas, Z const &z) { } // end namespace Geom -#endif // SEEN_GEOM_TOPOSWEEP_H +#endif // LIB2GEOM_SEEN_TOPOSWEEP_H /* Local Variables: diff --git a/src/2geom/transforms.h b/src/2geom/transforms.h index 7f5635747..2e805786d 100644 --- a/src/2geom/transforms.h +++ b/src/2geom/transforms.h @@ -199,6 +199,7 @@ public: /** @brief Get the characteristic vector of the rotation. * @return A vector that would be obtained by applying this transform to the X versor. */ Point vector() const { return vec; } + Coord angle() const { return atan2(vec); } Coord operator[](Dim2 dim) const { return vec[dim]; } Coord operator[](unsigned dim) const { return vec[dim]; } Rotate &operator*=(Rotate const &o) { vec *= o; return *this; } @@ -343,6 +344,8 @@ inline Translate pow(Translate const &t, int n) { /** @brief Reflects objects about line. * The line, defined by a vector along the line and a point on it, acts as a mirror. + * @ingroup Transforms + * @see Line::reflection() */ Affine reflection(Point const & vector, Point const & origin); diff --git a/src/2geom/utils.h b/src/2geom/utils.h index fe955dd41..bc0ad74b8 100644 --- a/src/2geom/utils.h +++ b/src/2geom/utils.h @@ -30,11 +30,12 @@ * */ -#ifndef SEEN_LIB2GEOM_UTILS_H -#define SEEN_LIB2GEOM_UTILS_H +#ifndef LIB2GEOM_SEEN_UTILS_H +#define LIB2GEOM_SEEN_UTILS_H #include #include +#include namespace Geom { @@ -59,9 +60,20 @@ struct MultipliableNoncommutative : B } }; +/** @brief Null output iterator + * Use this if you want to discard a result returned through an output iterator. */ +struct NullIterator + : public boost::output_iterator_helper +{ + NullIterator() {} + + template + void operator=(T const &v) {} +}; + } // end namespace Geom -#endif // SEEN_LIB2GEOM_UTILS_H +#endif // LIB2GEOM_SEEN_UTILS_H /* Local Variables: diff --git a/src/2geom/viewbox.cpp b/src/2geom/viewbox.cpp new file mode 100644 index 000000000..69bd0c487 --- /dev/null +++ b/src/2geom/viewbox.cpp @@ -0,0 +1,133 @@ +/** + * \file + * \brief Convenience class for SVG viewBox handling + *//* + * Authors: + * Krzysztof Kosiński + * + * Copyright (C) 2013 Authors + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + */ + +#include <2geom/transforms.h> +#include <2geom/viewbox.h> + +namespace Geom { + +/** Convert an align specification to coordinate fractions. */ +Point align_factors(Align g) { + Point p; + switch (g) { + case ALIGN_XMIN_YMIN: + p[X] = 0.0; + p[Y] = 0.0; + break; + case ALIGN_XMID_YMIN: + p[X] = 0.5; + p[Y] = 0.0; + break; + case ALIGN_XMAX_YMIN: + p[X] = 1.0; + p[Y] = 0.0; + break; + case ALIGN_XMIN_YMID: + p[X] = 0.0; + p[Y] = 0.5; + break; + case ALIGN_XMID_YMID: + p[X] = 0.5; + p[Y] = 0.5; + break; + case ALIGN_XMAX_YMID: + p[X] = 1.0; + p[Y] = 0.5; + break; + case ALIGN_XMIN_YMAX: + p[X] = 0.0; + p[Y] = 1.0; + break; + case ALIGN_XMID_YMAX: + p[X] = 0.5; + p[Y] = 1.0; + break; + case ALIGN_XMAX_YMAX: + p[X] = 1.0; + p[Y] = 1.0; + break; + default: + break; + } + return p; +} + +/** Obtain transformation from the viewbox to the specified viewport. */ +Affine ViewBox::transformTo(Geom::Rect const &viewport) const +{ + if (!_box) { + return Geom::Affine::identity(); + } + + // 1. translate viewbox to origin + Geom::Affine total = Translate(-_box->min()); + + // 2. compute scale + Geom::Point vdims = viewport.dimensions(); + Geom::Point bdims = _box->dimensions(); + Geom::Scale scale(vdims[X] / bdims[X], vdims[Y] / bdims[Y]); + + if (_align == ALIGN_NONE) { + // apply non-uniform scale + // = Scale(_box->dimensions()).inverse() * Scale(viewport.dimensions()) + total *= scale * Translate(viewport.min()); + } else { + double uscale = 0; + if (_expansion == EXPANSION_MEET) { + uscale = std::min(scale[X], scale[Y]); + } else { + uscale = std::max(scale[X], scale[Y]); + } + scale = Scale(uscale); + + // compute offset for align + Geom::Point offset = bdims * scale - vdims; + offset *= Scale(align_factors(_align)); + total *= Translate(-offset); + } + + return total; +} + +} // namespace Geom + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 : diff --git a/src/2geom/viewbox.h b/src/2geom/viewbox.h new file mode 100644 index 000000000..81f59ee36 --- /dev/null +++ b/src/2geom/viewbox.h @@ -0,0 +1,102 @@ +/** + * \file + * \brief Convenience class for SVG viewBox handling + *//* + * Authors: + * Krzysztof Kosiński + * + * Copyright (C) 2013 Authors + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + */ + +#ifndef LIB2GEOM_SEEN_VIEWBOX_H +#define LIB2GEOM_SEEN_VIEWBOX_H + +#include <2geom/affine.h> +#include <2geom/rect.h> + +namespace Geom { + +/** Values for the parameter of preserveAspectRatio. + * See: http://www.w3.org/TR/SVG/coords.html#PreserveAspectRatioAttribute */ +enum Align { + ALIGN_NONE, + ALIGN_XMIN_YMIN, + ALIGN_XMID_YMIN, + ALIGN_XMAX_YMIN, + ALIGN_XMIN_YMID, + ALIGN_XMID_YMID, + ALIGN_XMAX_YMID, + ALIGN_XMIN_YMAX, + ALIGN_XMID_YMAX, + ALIGN_XMAX_YMAX +}; + +/** Values for the parameter of preserveAspectRatio. + * See: http://www.w3.org/TR/SVG/coords.html#PreserveAspectRatioAttribute */ +enum Expansion { + EXPANSION_MEET, + EXPANSION_SLICE +}; + +Point align_factors(Align align); + +class ViewBox { + OptRect _box; + Align _align; + Expansion _expansion; + +public: + explicit ViewBox(OptRect const &r = OptRect(), Align a = ALIGN_XMID_YMID, Expansion ex = EXPANSION_MEET) + : _box(r) + , _align(a) + , _expansion(ex) + {} + + void setBox(OptRect const &r) { _box = r; } + void setAlign(Align a) { _align = a; } + void setExpansion(Expansion ex) { _expansion = ex; } + OptRect const &box() const { return _box; } + Align align() const { return _align; } + Expansion expansion() const { return _expansion; } + + /** Obtain transformation from the viewbox to the specified viewport. */ + Affine transformTo(Geom::Rect const &viewport) const; +}; + +} // namespace Geom + +#endif // !LIB2GEOM_SEEN_VIEWBOX_H + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 : diff --git a/src/conn-avoid-ref.cpp b/src/conn-avoid-ref.cpp index c13b9a5d3..4a49bf645 100644 --- a/src/conn-avoid-ref.cpp +++ b/src/conn-avoid-ref.cpp @@ -19,7 +19,7 @@ #include "display/curve.h" #include "2geom/line.h" #include "2geom/crossing.h" -#include "2geom/convex-cover.h" +#include "2geom/convex-hull.h" #include "helper/geom-curves.h" #include "svg/stringstream.h" #include "conn-avoid-ref.h" @@ -296,7 +296,7 @@ static Avoid::Polygon avoid_item_poly(SPItem const *item) Geom::Line prev_parallel_hull_edge; prev_parallel_hull_edge.setOrigin(hull_edge.origin()+hull_edge.versor().ccw()*spacing); prev_parallel_hull_edge.setVersor(hull_edge.versor()); - int hull_size = hull.boundary.size(); + int hull_size = hull.size(); for (int i = 0; i < hull_size; ++i) { hull_edge.setPoints(hull[i], hull[i+1]); diff --git a/src/desktop-events.cpp b/src/desktop-events.cpp index e80e5f6c1..b685dacbf 100644 --- a/src/desktop-events.cpp +++ b/src/desktop-events.cpp @@ -354,7 +354,7 @@ gint sp_dt_guide_event(SPCanvasItem *item, GdkEvent *event, gpointer data) // the origin should still be constrained to the guide. So let's do // that explicitly first: Geom::Line line(guide->getPoint(), guide->angle()); - Geom::Coord t = line.nearestPoint(motion_dt); + Geom::Coord t = line.nearestTime(motion_dt); motion_dt = line.pointAt(t); if (!(event->motion.state & GDK_SHIFT_MASK)) { m.guideConstrainedSnap(motion_dt, *guide); @@ -435,7 +435,7 @@ gint sp_dt_guide_event(SPCanvasItem *item, GdkEvent *event, gpointer data) // the origin should still be constrained to the guide. So let's // do that explicitly first: Geom::Line line(guide->getPoint(), guide->angle()); - Geom::Coord t = line.nearestPoint(event_dt); + Geom::Coord t = line.nearestTime(event_dt); event_dt = line.pointAt(t); if (!(event->button.state & GDK_SHIFT_MASK)) { m.guideConstrainedSnap(event_dt, *guide); diff --git a/src/display/cairo-utils.cpp b/src/display/cairo-utils.cpp index e1f12b04b..59e190676 100644 --- a/src/display/cairo-utils.cpp +++ b/src/display/cairo-utils.cpp @@ -18,9 +18,7 @@ #include #include #include <2geom/pathvector.h> -#include <2geom/bezier-curve.h> -#include <2geom/elliptical-arc.h> -#include <2geom/hvlinesegment.h> +#include <2geom/curves.h> #include <2geom/affine.h> #include <2geom/point.h> #include <2geom/path.h> @@ -531,7 +529,7 @@ feed_curve_to_cairo(cairo_t *cr, Geom::Curve const &c, Geom::Affine const & tran case 2: { Geom::QuadraticBezier const *quadratic_bezier = static_cast(&c); - std::vector points = quadratic_bezier->points(); + std::vector points = quadratic_bezier->controlPoints(); points[0] *= trans; points[1] *= trans; points[2] *= trans; @@ -554,7 +552,7 @@ feed_curve_to_cairo(cairo_t *cr, Geom::Curve const &c, Geom::Affine const & tran case 3: { Geom::CubicBezier const *cubic_bezier = static_cast(&c); - std::vector points = cubic_bezier->points(); + std::vector points = cubic_bezier->controlPoints(); //points[0] *= trans; // don't do this one here for fun: it is only needed for optimized strokes points[1] *= trans; points[2] *= trans; diff --git a/src/display/curve-test.h b/src/display/curve-test.h index 3d698ca07..34137f3c8 100644 --- a/src/display/curve-test.h +++ b/src/display/curve-test.h @@ -25,8 +25,8 @@ public: path2.close(); // Open path path3.append(Geom::SVGEllipticalArc(Geom::Point(4,0),1,2,M_PI,false,false,Geom::Point(5,1))); - path3.append(Geom::VLineSegment(Geom::Point(5,1),2), Geom::Path::STITCH_DISCONTINUOUS); - path3.append(Geom::HLineSegment(Geom::Point(6,4),2), Geom::Path::STITCH_DISCONTINUOUS); + path3.append(Geom::LineSegment(Geom::Point(5,1),Geom::Point(5,2))); + path3.append(Geom::LineSegment(Geom::Point(6,4),Geom::Point(2,4))); } virtual ~CurveTest() {} diff --git a/src/display/curve.cpp b/src/display/curve.cpp index 54a62939d..6cc7121dc 100644 --- a/src/display/curve.cpp +++ b/src/display/curve.cpp @@ -476,7 +476,7 @@ SPCurve::last_point() const SPCurve * SPCurve::create_reverse() const { - SPCurve *new_curve = new SPCurve(Geom::reverse_paths_and_order(_pathv)); + SPCurve *new_curve = new SPCurve(_pathv.reversed()); return new_curve; } diff --git a/src/display/curve.h b/src/display/curve.h index 5fad75b18..42b899210 100644 --- a/src/display/curve.h +++ b/src/display/curve.h @@ -13,7 +13,7 @@ #ifndef SEEN_DISPLAY_CURVE_H #define SEEN_DISPLAY_CURVE_H -#include <2geom/forward.h> +#include <2geom/pathvector.h> #include #include diff --git a/src/display/drawing-image.cpp b/src/display/drawing-image.cpp index 8fe337959..1594614ac 100644 --- a/src/display/drawing-image.cpp +++ b/src/display/drawing-image.cpp @@ -172,7 +172,7 @@ static double distance_to_segment (Geom::Point const &p, Geom::Point const &a1, Geom::Point const &a2) { Geom::LineSegment l(a1, a2); - Geom::Point np = l.pointAt(l.nearestPoint(p)); + Geom::Point np = l.pointAt(l.nearestTime(p)); return Geom::distance(np, p); } diff --git a/src/extension/implementation/implementation.h b/src/extension/implementation/implementation.h index fb323cd78..f6f933aaf 100644 --- a/src/extension/implementation/implementation.h +++ b/src/extension/implementation/implementation.h @@ -15,14 +15,7 @@ #include #include #include - -namespace Geom { - class Affine; - class OptRect; - class Path; - typedef std::vector PathVector; - class Point; -} +#include <2geom/forward.h> namespace Gtk { class Widget; diff --git a/src/extension/internal/emf-print.cpp b/src/extension/internal/emf-print.cpp index 67a9242bc..7815c51c7 100644 --- a/src/extension/internal/emf-print.cpp +++ b/src/extension/internal/emf-print.cpp @@ -862,7 +862,7 @@ Geom::Path PrintEmf::pathv_to_rect(Geom::PathVector const &pathv, bool *is_rect, /* Get the ends of the LAST line segment. Find minimum rotation to align rectangle with X,Y axes. (Very degenerate if it is rotated 45 degrees.) */ *angle = 10.0; /* must be > than the actual angle in radians. */ - for(Geom::Path::const_iterator cit = pR.begin(); cit != pR.end_open(); ++cit){ + for(Geom::Path::iterator cit = pR.begin(); cit != pR.end_open(); ++cit){ P1_trail = cit->initialPoint(); P1 = cit->finalPoint(); v1 = unit_vector(P1 - P1_trail); @@ -876,7 +876,7 @@ Geom::Path PrintEmf::pathv_to_rect(Geom::PathVector const &pathv, bool *is_rect, double convert = 36000.0/ (2.0 * M_PI); *angle = round(*angle * convert)/convert; - for(Geom::Path::const_iterator cit = pR.begin(); cit != pR.end_open();++cit) { + for(Geom::Path::iterator cit = pR.begin(); cit != pR.end_open();++cit) { P1_lead = cit->finalPoint(); v1 = unit_vector(P1 - P1_trail); v2 = unit_vector(P1_lead - P1 ); @@ -926,7 +926,7 @@ int PrintEmf::vector_rect_alignment(double angle, Geom::Point vtest){ */ Geom::Point PrintEmf::get_pathrect_corner(Geom::Path pathRect, double angle, int corner){ Geom::Point center(0,0); - for(Geom::Path::const_iterator cit = pathRect.begin(); cit != pathRect.end_open(); ++cit) { + for(Geom::Path::iterator cit = pathRect.begin(); cit != pathRect.end_open(); ++cit) { center += cit->initialPoint()/4.0; } @@ -954,7 +954,7 @@ Geom::Point PrintEmf::get_pathrect_corner(Geom::Path pathRect, double angle, int Geom::Point v1 = Geom::Point(1,0) * Geom::Rotate(-angle); // unit horizontal side (sign change because Y increases DOWN) Geom::Point v2 = Geom::Point(0,1) * Geom::Rotate(-angle); // unit vertical side (sign change because Y increases DOWN) Geom::Point P1; - for(Geom::Path::const_iterator cit = pathRect.begin(); cit != pathRect.end_open(); ++cit) { + for(Geom::Path::iterator cit = pathRect.begin(); cit != pathRect.end_open(); ++cit) { P1 = cit->initialPoint(); if ( ( LR == (dot(P1 - center,v1) > 0 ? 0 : 1) ) @@ -1496,11 +1496,11 @@ bool PrintEmf::print_simple_shape(Geom::PathVector const &pathv, const Geom::Aff int curves = 0; char *rec = NULL; - for (Geom::PathVector::const_iterator pit = pv.begin(); pit != pv.end(); ++pit) { + for (Geom::PathVector::iterator pit = pv.begin(); pit != pv.end(); ++pit) { moves++; nodes++; - for (Geom::Path::const_iterator cit = pit->begin(); cit != pit->end_open(); ++cit) { + for (Geom::Path::iterator cit = pit->begin(); cit != pit->end_open(); ++cit) { nodes++; if (is_straight_curve(*cit)) { @@ -1521,7 +1521,7 @@ bool PrintEmf::print_simple_shape(Geom::PathVector const &pathv, const Geom::Aff /** * For all Subpaths in the */ - for (Geom::PathVector::const_iterator pit = pv.begin(); pit != pv.end(); ++pit) { + for (Geom::PathVector::iterator pit = pv.begin(); pit != pv.end(); ++pit) { using Geom::X; using Geom::Y; @@ -1540,7 +1540,7 @@ bool PrintEmf::print_simple_shape(Geom::PathVector const &pathv, const Geom::Aff /** * For all segments in the subpath */ - for (Geom::Path::const_iterator cit = pit->begin(); cit != pit->end_open(); ++cit) { + for (Geom::Path::iterator cit = pit->begin(); cit != pit->end_open(); ++cit) { if (is_straight_curve(*cit)) { //Geom::Point p0 = cit->initialPoint(); Geom::Point p1 = cit->finalPoint(); @@ -1559,7 +1559,7 @@ bool PrintEmf::print_simple_shape(Geom::PathVector const &pathv, const Geom::Aff lpPoints[i].y = y1; i = i + 1; } else if (Geom::CubicBezier const *cubic = dynamic_cast(&*cit)) { - std::vector points = cubic->points(); + std::vector points = cubic->controlPoints(); //Geom::Point p0 = points[0]; Geom::Point p1 = points[1]; Geom::Point p2 = points[2]; @@ -1848,7 +1848,7 @@ unsigned int PrintEmf::draw_pathv_to_EMF(Geom::PathVector const &pathv, const Ge g_error("Fatal programming error in PrintEmf::print_pathv at U_EMRLINETO_set"); } } else if (Geom::CubicBezier const *cubic = dynamic_cast(&*cit)) { - std::vector points = cubic->points(); + std::vector points = cubic->controlPoints(); //Geom::Point p0 = points[0]; Geom::Point p1 = points[1]; Geom::Point p2 = points[2]; diff --git a/src/extension/internal/javafx-out.cpp b/src/extension/internal/javafx-out.cpp index 19946022c..386bde1d6 100644 --- a/src/extension/internal/javafx-out.cpp +++ b/src/extension/internal/javafx-out.cpp @@ -35,8 +35,7 @@ #include #include <2geom/pathvector.h> #include <2geom/rect.h> -#include <2geom/bezier-curve.h> -#include <2geom/hvlinesegment.h> +#include <2geom/curves.h> #include "helper/geom.h" #include "helper/geom-curves.h" #include @@ -531,9 +530,7 @@ bool JavaFXOutput::doCurve(SPItem *item, const String &id) for (Geom::Path::const_iterator cit = pit->begin(); cit != pit->end_closed(); ++cit) { //### LINE - if ( dynamic_cast (&*cit) || - dynamic_cast (&*cit) || - dynamic_cast (&*cit) ) + if ( dynamic_cast (&*cit) ) { Geom::Point p = cit->finalPoint(); out(" LineTo {\n"); @@ -545,7 +542,7 @@ bool JavaFXOutput::doCurve(SPItem *item, const String &id) //### BEZIER else if (Geom::CubicBezier const *cubic = dynamic_cast(&*cit)) { - std::vector points = cubic->points(); + std::vector points = cubic->controlPoints(); Geom::Point p1 = points[1]; Geom::Point p2 = points[2]; Geom::Point p3 = points[3]; diff --git a/src/extension/internal/latex-pstricks.cpp b/src/extension/internal/latex-pstricks.cpp index 6aaa1bca4..ae8f30a5c 100644 --- a/src/extension/internal/latex-pstricks.cpp +++ b/src/extension/internal/latex-pstricks.cpp @@ -17,8 +17,7 @@ #include <2geom/pathvector.h> #include <2geom/sbasis-to-bezier.h> -#include <2geom/bezier-curve.h> -#include <2geom/hvlinesegment.h> +#include <2geom/curves.h> #include #include #include "util/units.h" @@ -300,7 +299,7 @@ PrintLatex::print_2geomcurve(SVGOStringStream &os, Geom::Curve const &c) os << "\\lineto(" << c.finalPoint()[X] << "," << c.finalPoint()[Y] << ")\n"; } else if(Geom::CubicBezier const *cubic_bezier = dynamic_cast(&c)) { - std::vector points = cubic_bezier->points(); + std::vector points = cubic_bezier->controlPoints(); os << "\\curveto(" << points[1][X] << "," << points[1][Y] << ")(" << points[2][X] << "," << points[2][Y] << ")(" << points[3][X] << "," << points[3][Y] << ")\n"; diff --git a/src/extension/internal/metafile-print.cpp b/src/extension/internal/metafile-print.cpp index 73d63f27d..2fb36be85 100644 --- a/src/extension/internal/metafile-print.cpp +++ b/src/extension/internal/metafile-print.cpp @@ -389,7 +389,7 @@ Geom::PathVector PrintMetafile::center_ellipse_as_SVG_PathV(Geom::Point ctr, dou char text[256]; sprintf(text, " M %f,%f A %f %f %f 0 0 %f %f A %f %f %f 0 0 %f %f z", x1, y1, rx, ry, F * 360. / (2.*M_PI), x2, y2, rx, ry, F * 360. / (2.*M_PI), x1, y1); - std::vector outres = Geom::parse_svg_path(text); + Geom::PathVector outres = Geom::parse_svg_path(text); return outres; } @@ -419,7 +419,7 @@ Geom::PathVector PrintMetafile::center_elliptical_ring_as_SVG_PathV(Geom::Point sprintf(text, " M %f,%f A %f %f %f 0 1 %f %f A %f %f %f 0 1 %f %f z M %f,%f A %f %f %f 0 0 %f %f A %f %f %f 0 0 %f %f z", x11, y11, rx1, ry1, degrot, x12, y12, rx1, ry1, degrot, x11, y11, x21, y21, rx2, ry2, degrot, x22, y22, rx2, ry2, degrot, x21, y21); - std::vector outres = Geom::parse_svg_path(text); + Geom::PathVector outres = Geom::parse_svg_path(text); return outres; } @@ -440,7 +440,7 @@ Geom::PathVector PrintMetafile::center_elliptical_hole_as_SVG_PathV(Geom::Point char text[256]; sprintf(text, " M %f,%f A %f %f %f 0 0 %f %f A %f %f %f 0 0 %f %f z M 50000,50000 50000,-50000 -50000,-50000 -50000,50000 z", x1, y1, rx, ry, F * 360. / (2.*M_PI), x2, y2, rx, ry, F * 360. / (2.*M_PI), x1, y1); - std::vector outres = Geom::parse_svg_path(text); + Geom::PathVector outres = Geom::parse_svg_path(text); return outres; } @@ -452,7 +452,7 @@ width vector to side edge */ Geom::PathVector PrintMetafile::rect_cutter(Geom::Point ctr, Geom::Point pos, Geom::Point neg, Geom::Point width) { - std::vector outres; + Geom::PathVector outres; Geom::Path cutter; cutter.start(ctr + pos - width); cutter.appendNew(ctr + pos + width); diff --git a/src/extension/internal/odf.cpp b/src/extension/internal/odf.cpp index 52fabcf3c..6904eb2fd 100644 --- a/src/extension/internal/odf.cpp +++ b/src/extension/internal/odf.cpp @@ -55,8 +55,7 @@ #include #include "display/curve.h" #include <2geom/pathvector.h> -#include <2geom/bezier-curve.h> -#include <2geom/hvlinesegment.h> +#include <2geom/curves.h> #include <2geom/transforms.h> #include #include "helper/geom-curves.h" @@ -1299,7 +1298,7 @@ writePath(Writer &outs, Geom::PathVector const &pathv, outs.printf("L %.3f %.3f ", destx, desty); } else if(Geom::CubicBezier const *cubic = dynamic_cast(&*cit)) { - std::vector points = cubic->points(); + std::vector points = cubic->controlPoints(); for (unsigned i = 1; i <= 3; i++) { if (fabs(points[i][X])<1.0) points[i][X] = 0.0; // Why is this needed? Shouldn't we just round all numbers then? if (fabs(points[i][Y])<1.0) points[i][Y] = 0.0; diff --git a/src/extension/internal/pov-out.cpp b/src/extension/internal/pov-out.cpp index 3d149928f..bd2168b68 100644 --- a/src/extension/internal/pov-out.cpp +++ b/src/extension/internal/pov-out.cpp @@ -30,8 +30,7 @@ #include #include <2geom/pathvector.h> #include <2geom/rect.h> -#include <2geom/bezier-curve.h> -#include <2geom/hvlinesegment.h> +#include <2geom/curves.h> #include "helper/geom.h" #include "helper/geom-curves.h" #include @@ -388,7 +387,7 @@ bool PovOutput::doCurve(SPItem *item, const String &id) } else if(Geom::CubicBezier const *cubic = dynamic_cast(&*cit)) { - std::vector points = cubic->points(); + std::vector points = cubic->controlPoints(); Geom::Point p0 = points[0]; Geom::Point p1 = points[1]; Geom::Point p2 = points[2]; diff --git a/src/extension/internal/wmf-print.cpp b/src/extension/internal/wmf-print.cpp index 567f9f366..f750044eb 100644 --- a/src/extension/internal/wmf-print.cpp +++ b/src/extension/internal/wmf-print.cpp @@ -29,14 +29,13 @@ #endif -#include "2geom/sbasis-to-bezier.h" -#include "2geom/svg-elliptical-arc.h" - -#include "2geom/path.h" -#include "2geom/pathvector.h" -#include "2geom/rect.h" -#include "2geom/bezier-curve.h" -#include "2geom/hvlinesegment.h" +#include <2geom/sbasis-to-bezier.h> +#include <2geom/svg-elliptical-arc.h> + +#include <2geom/path.h> +#include <2geom/pathvector.h> +#include <2geom/rect.h> +#include <2geom/curves.h> #include "helper/geom.h" #include "helper/geom-curves.h" #include "sp-item.h" @@ -59,7 +58,7 @@ #include "display/cairo-utils.h" #include "splivarot.h" // pieces for union on shapes -#include "2geom/svg-path-parser.h" // to get from SVG text to Geom::Path +#include <2geom/svg-path-parser.h> // to get from SVG text to Geom::Path #include "display/canvas-bpath.h" // for SPWindRule #include "wmf-print.h" @@ -984,7 +983,7 @@ bool PrintWmf::print_simple_shape(Geom::PathVector const &pathv, const Geom::Aff lpPoints[i].y = y1; i = i + 1; } else if (Geom::CubicBezier const *cubic = dynamic_cast(&*cit)) { - std::vector points = cubic->points(); + std::vector points = cubic->controlPoints(); //Geom::Point p0 = points[0]; Geom::Point p1 = points[1]; Geom::Point p2 = points[2]; diff --git a/src/gradient-chemistry.cpp b/src/gradient-chemistry.cpp index aecf1aa35..02513379d 100644 --- a/src/gradient-chemistry.cpp +++ b/src/gradient-chemistry.cpp @@ -1068,7 +1068,7 @@ void sp_item_gradient_set_coords(SPItem *item, GrPointType point_type, guint poi // using X-coordinates only to determine the offset, assuming p has been snapped to the vector from begin to end. Geom::Point begin(lg->x1.computed, lg->y1.computed); Geom::Point end(lg->x2.computed, lg->y2.computed); - double offset = Geom::LineSegment(begin, end).nearestPoint(p); + double offset = Geom::LineSegment(begin, end).nearestTime(p); SPGradient *vector = sp_gradient_get_forked_vector_if_necessary (lg, false); lg->ensureVector(); lg->vector.stops.at(point_i).offset = offset; @@ -1163,7 +1163,7 @@ void sp_item_gradient_set_coords(SPItem *item, GrPointType point_type, guint poi { Geom::Point start = Geom::Point (rg->cx.computed, rg->cy.computed); Geom::Point end = Geom::Point (rg->cx.computed + rg->r.computed, rg->cy.computed); - double offset = Geom::LineSegment(start, end).nearestPoint(p); + double offset = Geom::LineSegment(start, end).nearestTime(p); SPGradient *vector = sp_gradient_get_forked_vector_if_necessary (rg, false); rg->ensureVector(); rg->vector.stops.at(point_i).offset = offset; @@ -1180,7 +1180,7 @@ void sp_item_gradient_set_coords(SPItem *item, GrPointType point_type, guint poi { Geom::Point start = Geom::Point (rg->cx.computed, rg->cy.computed); Geom::Point end = Geom::Point (rg->cx.computed, rg->cy.computed - rg->r.computed); - double offset = Geom::LineSegment(start, end).nearestPoint(p); + double offset = Geom::LineSegment(start, end).nearestTime(p); SPGradient *vector = sp_gradient_get_forked_vector_if_necessary(rg, false); rg->ensureVector(); rg->vector.stops.at(point_i).offset = offset; diff --git a/src/gradient-drag.cpp b/src/gradient-drag.cpp index cb2bd737f..7af7b11b2 100644 --- a/src/gradient-drag.cpp +++ b/src/gradient-drag.cpp @@ -378,7 +378,7 @@ SPStop *GrDrag::addStopNearPoint(SPItem *item, Geom::Point mouse_p, double toler Geom::Point begin = getGradientCoords(item, POINT_LG_BEGIN, 0, fill_or_stroke); Geom::Point end = getGradientCoords(item, POINT_LG_END, 0, fill_or_stroke); Geom::LineSegment ls(begin, end); - double offset = ls.nearestPoint(mouse_p); + double offset = ls.nearestTime(mouse_p); Geom::Point nearest = ls.pointAt(offset); double dist_screen = Geom::distance(mouse_p, nearest); if ( dist_screen < tolerance ) { @@ -391,7 +391,7 @@ SPStop *GrDrag::addStopNearPoint(SPItem *item, Geom::Point mouse_p, double toler Geom::Point begin = getGradientCoords(item, POINT_RG_CENTER, 0, fill_or_stroke); Geom::Point end = getGradientCoords(item, POINT_RG_R1, 0, fill_or_stroke); Geom::LineSegment ls(begin, end); - double offset = ls.nearestPoint(mouse_p); + double offset = ls.nearestTime(mouse_p); Geom::Point nearest = ls.pointAt(offset); double dist_screen = Geom::distance(mouse_p, nearest); if ( dist_screen < tolerance ) { @@ -403,7 +403,7 @@ SPStop *GrDrag::addStopNearPoint(SPItem *item, Geom::Point mouse_p, double toler } else { end = getGradientCoords(item, POINT_RG_R2, 0, fill_or_stroke); ls = Geom::LineSegment(begin, end); - offset = ls.nearestPoint(mouse_p); + offset = ls.nearestTime(mouse_p); nearest = ls.pointAt(offset); dist_screen = Geom::distance(mouse_p, nearest); if ( dist_screen < tolerance ) { @@ -442,7 +442,7 @@ SPStop *GrDrag::addStopNearPoint(SPItem *item, Geom::Point mouse_p, double toler p[2] = patch.getPoint( 0, 2 ) * transform; p[3] = patch.getPoint( 0, 3 ) * transform; Geom::BezierCurveN<3> b( p[0], p[1], p[2], p[3] ); - Geom::Coord coord = b.nearestPoint( mouse_p ); + Geom::Coord coord = b.nearestTime( mouse_p ); Geom::Point nearest = b( coord ); double dist_screen = Geom::L2 ( mouse_p - nearest ); if ( dist_screen < closest ) { @@ -460,7 +460,7 @@ SPStop *GrDrag::addStopNearPoint(SPItem *item, Geom::Point mouse_p, double toler p[2] = patch.getPoint( 1, 2 ) * transform; p[3] = patch.getPoint( 1, 3 ) * transform; Geom::BezierCurveN<3> b( p[0], p[1], p[2], p[3] ); - Geom::Coord coord = b.nearestPoint( mouse_p ); + Geom::Coord coord = b.nearestTime( mouse_p ); Geom::Point nearest = b( coord ); double dist_screen = Geom::L2 ( mouse_p - nearest ); if ( dist_screen < closest ) { @@ -478,7 +478,7 @@ SPStop *GrDrag::addStopNearPoint(SPItem *item, Geom::Point mouse_p, double toler p[2] = patch.getPoint( 2, 2 ) * transform; p[3] = patch.getPoint( 2, 3 ) * transform; Geom::BezierCurveN<3> b( p[0], p[1], p[2], p[3] ); - Geom::Coord coord = b.nearestPoint( mouse_p ); + Geom::Coord coord = b.nearestTime( mouse_p ); Geom::Point nearest = b( coord ); double dist_screen = Geom::L2 ( mouse_p - nearest ); if ( dist_screen < closest ) { @@ -496,7 +496,7 @@ SPStop *GrDrag::addStopNearPoint(SPItem *item, Geom::Point mouse_p, double toler p[2] = patch.getPoint( 3, 2 ) * transform; p[3] = patch.getPoint( 3, 3 ) * transform; Geom::BezierCurveN<3> b( p[0], p[1], p[2], p[3] ); - Geom::Coord coord = b.nearestPoint( mouse_p ); + Geom::Coord coord = b.nearestTime( mouse_p ); Geom::Point nearest = b( coord ); double dist_screen = Geom::L2 ( mouse_p - nearest ); if ( dist_screen < closest ) { @@ -603,7 +603,7 @@ bool GrDrag::dropColor(SPItem */*item*/, gchar const *c, Geom::Point p) for (GSList *l = lines; (l != NULL) && (!over_line); l = l->next) { SPCtrlLine *line = (SPCtrlLine*) l->data; Geom::LineSegment ls(line->s, line->e); - Geom::Point nearest = ls.pointAt(ls.nearestPoint(p)); + Geom::Point nearest = ls.pointAt(ls.nearestTime(p)); double dist_screen = Geom::L2(p - nearest) * desktop->current_zoom(); if (line->item && dist_screen < 5) { SPStop *stop = addStopNearPoint(line->item, p, 5/desktop->current_zoom()); @@ -1018,10 +1018,10 @@ static void gr_knot_moved_midpoint_handler(SPKnot */*knot*/, Geom::Point const & if (state & GDK_CONTROL_MASK) { Geom::LineSegment ls(low_lim, high_lim); - p = ls.pointAt(round(ls.nearestPoint(p) / snap_fraction) * snap_fraction); + p = ls.pointAt(round(ls.nearestTime(p) / snap_fraction) * snap_fraction); } else { Geom::LineSegment ls(low_lim, high_lim); - p = ls.pointAt(ls.nearestPoint(p)); + p = ls.pointAt(ls.nearestTime(p)); if (!(state & GDK_SHIFT_MASK)) { Inkscape::Snapper::SnapConstraint cl(low_lim, high_lim - low_lim); SPDesktop *desktop = dragger->parent->desktop; @@ -2393,7 +2393,7 @@ void GrDrag::selected_move(double x, double y, bool write_repr, bool scale_radia gr_midpoint_limits(dragger, server, &begin, &end, &low_lim, &high_lim, &moving); Geom::LineSegment ls(low_lim, high_lim); - Geom::Point p = ls.pointAt(ls.nearestPoint(dragger->point + Geom::Point(x,y))); + Geom::Point p = ls.pointAt(ls.nearestTime(dragger->point + Geom::Point(x,y))); Geom::Point displacement = p - dragger->point; for (GSList const* i = moving; i != NULL; i = i->next) { diff --git a/src/helper/geom-curves.h b/src/helper/geom-curves.h index 4586a346c..7357403f7 100644 --- a/src/helper/geom-curves.h +++ b/src/helper/geom-curves.h @@ -14,15 +14,13 @@ * Released under GNU GPL */ -#include <2geom/hvlinesegment.h> #include <2geom/line.h> #include <2geom/bezier-curve.h> /// \todo un-inline this function -inline bool is_straight_curve(Geom::Curve const & c) { - if( dynamic_cast(&c) || - dynamic_cast(&c) || - dynamic_cast(&c) ) +inline bool is_straight_curve(Geom::Curve const & c) +{ + if( dynamic_cast(&c) ) { return true; } @@ -31,7 +29,7 @@ inline bool is_straight_curve(Geom::Curve const & c) { Geom::BezierCurve const *curve = dynamic_cast(&c); if (curve) { Geom::Line line(curve->initialPoint(), curve->finalPoint()); - std::vector pts = curve->points(); + std::vector pts = curve->controlPoints(); for (unsigned i = 1; i < pts.size() - 1; ++i) { if (!are_near(pts[i], line)) return false; diff --git a/src/helper/geom-pathstroke.cpp b/src/helper/geom-pathstroke.cpp index eb0c432c6..df5e5a82b 100644 --- a/src/helper/geom-pathstroke.cpp +++ b/src/helper/geom-pathstroke.cpp @@ -34,7 +34,7 @@ int circle_circle_intersection(Point X0, double r0, Point X1, double r1, Point & static int circle_line_intersection(Circle C0, Point X0, Point X1, Point &p0, Point &p1) { /* equation of a circle: (x - h)^2 + (y - k)^2 = r^2 */ - Coord r = C0.ray(); + Coord r = C0.radius(); Coord h = C0.center()[X]; Coord k = C0.center()[Y]; @@ -252,8 +252,8 @@ void extrapolate_join(Geom::Path& res, Geom::Curve const& outgoing, double miter if (!inc_ls && !out_ls) { // Two circles - solutions = Geom::circle_circle_intersection(circle1.center(), circle1.ray(), - circle2.center(), circle2.ray(), + solutions = Geom::circle_circle_intersection(circle1.center(), circle1.radius(), + circle2.center(), circle2.radius(), points[0], points[1]); if (solutions == 2) { sol = pick_solution(points, tang2, endPt); @@ -486,7 +486,7 @@ void get_cubic_data(Geom::CubicBezier const& bez, double time, double& len, doub if (Geom::are_near(l, 0)) { return; // this isn't a segment... } - rad = 1e8; + rad = 1e8; } else { rad = -l * (Geom::dot(der2, der2) / Geom::cross(der3, der2)); } @@ -538,7 +538,7 @@ void offset_cubic(Geom::Path& p, Geom::CubicBezier const& bez, double width, dou // reached maximum recursive depth // don't bother with any more correction if (levels == 0) { - p.append(c, Geom::Path::STITCH_DISCONTINUOUS); + p.append(c); return; } @@ -570,7 +570,7 @@ void offset_quadratic(Geom::Path& p, Geom::QuadraticBezier const& bez, double wi // cheat // it's faster // seriously - std::vector points = bez.points(); + std::vector points = bez.controlPoints(); Geom::Point b1 = points[0] + (2./3) * (points[1] - points[0]); Geom::Point b2 = b1 + (1./3) * (points[2] - points[0]); Geom::CubicBezier cub = Geom::CubicBezier(points[0], b1, b2, points[2]); @@ -658,7 +658,7 @@ Geom::PathVector outline(Geom::Path const& input, double width, double miter, Li Geom::PathBuilder res; Geom::Path with_dir = half_outline(input, width/2., miter, join); - Geom::Path against_dir = half_outline(input.reverse(), width/2., miter, join); + Geom::Path against_dir = half_outline(input.reversed(), width/2., miter, join); res.moveTo(with_dir[0].initialPoint()); res.append(with_dir); @@ -706,6 +706,9 @@ Geom::Path half_outline(Geom::Path const& input, double width, double miter, Lin Geom::Point start = input.initialPoint() + tang1 * width; Geom::Path temp; + res.setStitching(true); + temp.setStitching(true); + res.start(start); // Do two curves at a time for efficiency, since the join function needs to know the outgoing curve as well diff --git a/src/helper/geom.cpp b/src/helper/geom.cpp index 91689375f..daaf90ff2 100644 --- a/src/helper/geom.cpp +++ b/src/helper/geom.cpp @@ -15,8 +15,7 @@ #include #include <2geom/pathvector.h> #include <2geom/path.h> -#include <2geom/bezier-curve.h> -#include <2geom/hvlinesegment.h> +#include <2geom/curves.h> #include <2geom/transforms.h> #include <2geom/rect.h> #include <2geom/coord.h> @@ -473,8 +472,8 @@ pathv_to_linear_and_cubic_beziers( Geom::PathVector const &pathv ) for (Geom::PathVector::const_iterator pit = pathv.begin(); pit != pathv.end(); ++pit) { output.push_back( Geom::Path() ); + output.back().setStitching(true); output.back().start( pit->initialPoint() ); - output.back().close( pit->closed() ); for (Geom::Path::const_iterator cit = pit->begin(); cit != pit->end_open(); ++cit) { if (is_straight_curve(*cit)) { @@ -488,10 +487,13 @@ pathv_to_linear_and_cubic_beziers( Geom::PathVector const &pathv ) } else { // convert all other curve types to cubicbeziers Geom::Path cubicbezier_path = Geom::cubicbezierpath_from_sbasis(cit->toSBasis(), 0.1); + cubicbezier_path.close(false); output.back().append(cubicbezier_path); } } } + + output.back().close( pit->closed() ); } return output; @@ -525,8 +527,7 @@ pathv_to_linear( Geom::PathVector const &pathv, double /*maxdisp*/) } else { /* all others must be Bezier curves */ Geom::BezierCurve const *curve = dynamic_cast(&*cit); - Geom::CubicBezier b((*curve)[0], (*curve)[1], (*curve)[2], (*curve)[3]); - std::vector bzrpoints = b.points(); + std::vector bzrpoints = curve->controlPoints(); Geom::Point A = bzrpoints[0]; Geom::Point B = bzrpoints[1]; Geom::Point C = bzrpoints[2]; @@ -584,7 +585,7 @@ pathv_to_cubicbezier( Geom::PathVector const &pathv) pitCubic.appendNew( pitCubic.initialPoint() ); pitCubic.close(true); } - for (Geom::Path::const_iterator cit = pitCubic.begin(); cit != pitCubic.end_open(); ++cit) { + for (Geom::Path::iterator cit = pitCubic.begin(); cit != pitCubic.end_open(); ++cit) { if (is_straight_curve(*cit)) { Geom::CubicBezier b(cit->initialPoint(), cit->pointAt(0.3334) + Geom::Point(cubicGap,cubicGap), cit->finalPoint(), cit->finalPoint()); output.back().append(b); diff --git a/src/libdepixelize/priv/splines-kopf2011.h b/src/libdepixelize/priv/splines-kopf2011.h index c586f74b7..c3da58c05 100644 --- a/src/libdepixelize/priv/splines-kopf2011.h +++ b/src/libdepixelize/priv/splines-kopf2011.h @@ -93,7 +93,7 @@ template void worker(const typename HomogeneousSplines::Polygon &source, Splines::Path &dest, bool optimize) { - dest.pathVector.reserve(source.holes.size() + 1); + //dest.pathVector.reserve(source.holes.size() + 1); for ( int i = 0 ; i != 4 ; ++i ) dest.rgba[i] = source.rgba[i]; diff --git a/src/live_effects/Makefile_insert b/src/live_effects/Makefile_insert index dace45739..c2c2ce93c 100644 --- a/src/live_effects/Makefile_insert +++ b/src/live_effects/Makefile_insert @@ -14,8 +14,6 @@ ink_common_sources += \ live_effects/lpe-patternalongpath.h \ live_effects/lpe-bendpath.cpp \ live_effects/lpe-bendpath.h \ - live_effects/lpe-boolops.cpp \ - live_effects/lpe-boolops.h \ live_effects/lpe-dynastroke.cpp \ live_effects/lpe-dynastroke.h \ live_effects/lpe-extrude.cpp \ diff --git a/src/live_effects/effect.cpp b/src/live_effects/effect.cpp index 1da364580..d3ca781e9 100644 --- a/src/live_effects/effect.cpp +++ b/src/live_effects/effect.cpp @@ -14,54 +14,53 @@ // include effects: #include "live_effects/lpe-patternalongpath.h" #include "live_effects/effect.h" +#include "live_effects/lpe-angle_bisector.h" +#include "live_effects/lpe-attach-path.h" #include "live_effects/lpe-bendpath.h" -#include "live_effects/lpe-sketch.h" -#include "live_effects/lpe-vonkoch.h" -#include "live_effects/lpe-knot.h" -#include "live_effects/lpe-rough-hatches.h" -#include "live_effects/lpe-dynastroke.h" -#include "live_effects/lpe-test-doEffect-stack.h" -#include "live_effects/lpe-gears.h" -#include "live_effects/lpe-curvestitch.h" +#include "live_effects/lpe-bounding-box.h" +#include "live_effects/lpe-bspline.h" +#include "live_effects/lpe-circle_3pts.h" #include "live_effects/lpe-circle_with_radius.h" -#include "live_effects/lpe-perspective_path.h" -#include "live_effects/lpe-perspective-envelope.h" -#include "live_effects/lpe-spiro.h" -#include "live_effects/lpe-lattice.h" -#include "live_effects/lpe-lattice2.h" -#include "live_effects/lpe-roughen.h" -#include "live_effects/lpe-show_handles.h" -#include "live_effects/lpe-simplify.h" -#include "live_effects/lpe-envelope.h" +#include "live_effects/lpe-clone-original.h" #include "live_effects/lpe-constructgrid.h" -#include "live_effects/lpe-perp_bisector.h" -#include "live_effects/lpe-tangent_to_curve.h" -#include "live_effects/lpe-mirror_symmetry.h" -#include "live_effects/lpe-circle_3pts.h" -#include "live_effects/lpe-angle_bisector.h" -#include "live_effects/lpe-parallel.h" #include "live_effects/lpe-copy_rotate.h" -#include "live_effects/lpe-offset.h" -#include "live_effects/lpe-ruler.h" -#include "live_effects/lpe-boolops.h" +#include "live_effects/lpe-curvestitch.h" +#include "live_effects/lpe-dynastroke.h" +#include "live_effects/lpe-ellipse_5pts.h" +#include "live_effects/lpe-envelope.h" +#include "live_effects/lpe-extrude.h" +#include "live_effects/lpe-fill-between-many.h" +#include "live_effects/lpe-fill-between-strokes.h" +#include "live_effects/lpe-fillet-chamfer.h" +#include "live_effects/lpe-gears.h" #include "live_effects/lpe-interpolate.h" #include "live_effects/lpe-interpolate_points.h" -#include "live_effects/lpe-text_label.h" -#include "live_effects/lpe-path_length.h" +#include "live_effects/lpe-jointype.h" +#include "live_effects/lpe-knot.h" +#include "live_effects/lpe-lattice2.h" +#include "live_effects/lpe-lattice.h" #include "live_effects/lpe-line_segment.h" -#include "live_effects/lpe-recursiveskeleton.h" -#include "live_effects/lpe-extrude.h" +#include "live_effects/lpe-mirror_symmetry.h" +#include "live_effects/lpe-offset.h" +#include "live_effects/lpe-parallel.h" +#include "live_effects/lpe-path_length.h" +#include "live_effects/lpe-perp_bisector.h" +#include "live_effects/lpe-perspective-envelope.h" +#include "live_effects/lpe-perspective_path.h" #include "live_effects/lpe-powerstroke.h" -#include "live_effects/lpe-clone-original.h" -#include "live_effects/lpe-bspline.h" -#include "live_effects/lpe-attach-path.h" -#include "live_effects/lpe-fill-between-strokes.h" -#include "live_effects/lpe-fill-between-many.h" -#include "live_effects/lpe-ellipse_5pts.h" -#include "live_effects/lpe-bounding-box.h" -#include "live_effects/lpe-jointype.h" +#include "live_effects/lpe-recursiveskeleton.h" +#include "live_effects/lpe-roughen.h" +#include "live_effects/lpe-rough-hatches.h" +#include "live_effects/lpe-ruler.h" +#include "live_effects/lpe-show_handles.h" +#include "live_effects/lpe-simplify.h" +#include "live_effects/lpe-sketch.h" +#include "live_effects/lpe-spiro.h" +#include "live_effects/lpe-tangent_to_curve.h" #include "live_effects/lpe-taperstroke.h" -#include "live_effects/lpe-fillet-chamfer.h" +#include "live_effects/lpe-test-doEffect-stack.h" +#include "live_effects/lpe-text_label.h" +#include "live_effects/lpe-vonkoch.h" #include "xml/node-event-vector.h" #include "sp-object.h" @@ -98,8 +97,6 @@ const Util::EnumData LPETypeData[] = { #ifdef LPE_ENABLE_TEST_EFFECTS {DOEFFECTSTACK_TEST, N_("doEffect stack test"), "doeffectstacktest"}, {ANGLE_BISECTOR, N_("Angle bisector"), "angle_bisector"}, - // TRANSLATORS: boolean operations - {BOOLOPS, N_("Boolops"), "boolops"}, {CIRCLE_WITH_RADIUS, N_("Circle (by center and radius)"), "circle_with_radius"}, {CIRCLE_3PTS, N_("Circle by 3 points"), "circle_3pts"}, {DYNASTROKE, N_("Dynamic stroke"), "dynastroke"}, @@ -243,9 +240,6 @@ Effect::New(EffectType lpenr, LivePathEffectObject *lpeobj) case RULER: neweffect = static_cast ( new LPERuler(lpeobj) ); break; - case BOOLOPS: - neweffect = static_cast ( new LPEBoolops(lpeobj) ); - break; case INTERPOLATE: neweffect = static_cast ( new LPEInterpolate(lpeobj) ); break; @@ -523,24 +517,24 @@ Effect::acceptParamPath (SPPath const*/*param_path*/) { void Effect::doEffect (SPCurve * curve) { - std::vector orig_pathv = curve->get_pathvector(); + Geom::PathVector orig_pathv = curve->get_pathvector(); - std::vector result_pathv = doEffect_path(orig_pathv); + Geom::PathVector result_pathv = doEffect_path(orig_pathv); curve->set_pathvector(result_pathv); } -std::vector -Effect::doEffect_path (std::vector const & path_in) +Geom::PathVector +Effect::doEffect_path (Geom::PathVector const & path_in) { - std::vector path_out; + Geom::PathVector path_out; if ( !concatenate_before_pwd2 ) { // default behavior for (unsigned int i=0; i < path_in.size(); i++) { Geom::Piecewise > pwd2_in = path_in[i].toPwSb(); Geom::Piecewise > pwd2_out = doEffect_pwd2(pwd2_in); - std::vector path = Geom::path_from_piecewise( pwd2_out, LPE_CONVERSION_TOLERANCE); + Geom::PathVector path = Geom::path_from_piecewise( pwd2_out, LPE_CONVERSION_TOLERANCE); // add the output path vector to the already accumulated vector: for (unsigned int j=0; j < path.size(); j++) { path_out.push_back(path[j]); diff --git a/src/live_effects/effect.h b/src/live_effects/effect.h index ac1f0b8dc..63d357481 100644 --- a/src/live_effects/effect.h +++ b/src/live_effects/effect.h @@ -129,9 +129,9 @@ protected: // of what kind of input/output parameters he desires. // the order in which they appear is the order in which they are // called by this base class. (i.e. doEffect(SPCurve * curve) defaults to calling - // doEffect(std::vector ) - virtual std::vector - doEffect_path (std::vector const & path_in); + // doEffect(Geom::PathVector ) + virtual Geom::PathVector + doEffect_path (Geom::PathVector const & path_in); virtual Geom::Piecewise > doEffect_pwd2 (Geom::Piecewise > const & pwd2_in); @@ -163,7 +163,7 @@ protected: double current_zoom; std::vector selectedNodesPoints; SPCurve * sp_curve; - std::vector pathvector_before_effect; + Geom::PathVector pathvector_before_effect; private: bool provides_own_flash_paths; // if true, the standard flash path is suppressed diff --git a/src/live_effects/lpe-angle_bisector.cpp b/src/live_effects/lpe-angle_bisector.cpp index 1acf9605f..95a81c763 100644 --- a/src/live_effects/lpe-angle_bisector.cpp +++ b/src/live_effects/lpe-angle_bisector.cpp @@ -56,8 +56,8 @@ LPEAngleBisector::~LPEAngleBisector() { } -std::vector -LPEAngleBisector::doEffect_path (std::vector const & path_in) +Geom::PathVector +LPEAngleBisector::doEffect_path (Geom::PathVector const & path_in) { using namespace Geom; @@ -73,7 +73,7 @@ LPEAngleBisector::doEffect_path (std::vector const & path_in) Geom::Point D = ptA - dir * length_left; Geom::Point E = ptA + dir * length_right; - Piecewise > output = Piecewise >(D2(Linear(D[X], E[X]), Linear(D[Y], E[Y]))); + Piecewise > output = Piecewise >(D2(SBasis(D[X], E[X]), SBasis(D[Y], E[Y]))); return path_from_piecewise(output, LPE_CONVERSION_TOLERANCE); } @@ -103,7 +103,7 @@ KnotHolderEntityLeftEnd::knot_set(Geom::Point const &p, Geom::Point const &/*ori Geom::Point const s = snap_knot_position(p, state); - double lambda = Geom::nearest_point(s, lpe->ptA, lpe->dir); + double lambda = Geom::nearest_time(s, lpe->ptA, lpe->dir); lpe->length_left.param_set_value(-lambda); sp_lpe_item_update_patheffect (SP_LPE_ITEM(item), false, true); @@ -116,7 +116,7 @@ KnotHolderEntityRightEnd::knot_set(Geom::Point const &p, Geom::Point const &/*or Geom::Point const s = snap_knot_position(p, state); - double lambda = Geom::nearest_point(s, lpe->ptA, lpe->dir); + double lambda = Geom::nearest_time(s, lpe->ptA, lpe->dir); lpe->length_right.param_set_value(lambda); sp_lpe_item_update_patheffect (SP_LPE_ITEM(item), false, true); diff --git a/src/live_effects/lpe-angle_bisector.h b/src/live_effects/lpe-angle_bisector.h index 95048751e..400cbf6b6 100644 --- a/src/live_effects/lpe-angle_bisector.h +++ b/src/live_effects/lpe-angle_bisector.h @@ -28,7 +28,7 @@ public: LPEAngleBisector(LivePathEffectObject *lpeobject); virtual ~LPEAngleBisector(); - virtual std::vector doEffect_path (std::vector const & path_in); + virtual Geom::PathVector doEffect_path (Geom::PathVector const & path_in); friend class AB::KnotHolderEntityLeftEnd; friend class AB::KnotHolderEntityRightEnd; diff --git a/src/live_effects/lpe-attach-path.cpp b/src/live_effects/lpe-attach-path.cpp index 768c66ee2..0fcd725ce 100644 --- a/src/live_effects/lpe-attach-path.cpp +++ b/src/live_effects/lpe-attach-path.cpp @@ -64,7 +64,7 @@ void LPEAttachPath::resetDefaults(SPItem const * /*item*/) void LPEAttachPath::doEffect (SPCurve * curve) { - std::vector this_pathv = curve->get_pathvector(); + Geom::PathVector this_pathv = curve->get_pathvector(); if (sp_lpe_item && !this_pathv.empty()) { Geom::Path p = Geom::Path(this_pathv.front().initialPoint()); @@ -73,7 +73,7 @@ void LPEAttachPath::doEffect (SPCurve * curve) if (start_path.linksToPath()) { - std::vector linked_pathv = start_path.get_pathvector(); + Geom::PathVector linked_pathv = start_path.get_pathvector(); Geom::Affine linkedtransform = start_path.getObject()->getRelativeTransform(sp_lpe_item); if ( !linked_pathv.empty() ) @@ -87,7 +87,7 @@ void LPEAttachPath::doEffect (SPCurve * curve) Geom::Coord length = derivs[deriv_n].length(); if ( ! Geom::are_near(length, 0) ) { if (set_start_end) { - start_path_position.param_set_value(transformedpath.nearestPoint(start_path_curve_end.getOrigin())); + start_path_position.param_set_value(transformedpath.nearestTime(start_path_curve_end.getOrigin())); } if (start_path_position > transformedpath.size()) { @@ -95,7 +95,8 @@ void LPEAttachPath::doEffect (SPCurve * curve) } else if (start_path_position < 0) { start_path_position.param_set_value(0); } - const Geom::Curve *c = start_path_position >= transformedpath.size() ? &transformedpath.back() : &transformedpath.at_index((int)start_path_position); + Geom::Curve const *c = start_path_position >= transformedpath.size() ? + &transformedpath.back() : &transformedpath.at((int)start_path_position); std::vector derivs_2 = c->pointAndDerivatives(start_path_position >= transformedpath.size() ? 1 : (start_path_position - (int)start_path_position), 3); for (unsigned deriv_n_2 = 1; deriv_n_2 < derivs_2.size(); deriv_n_2++) { @@ -126,7 +127,7 @@ void LPEAttachPath::doEffect (SPCurve * curve) if (end_path.linksToPath()) { - std::vector linked_pathv = end_path.get_pathvector(); + Geom::PathVector linked_pathv = end_path.get_pathvector(); Geom::Affine linkedtransform = end_path.getObject()->getRelativeTransform(sp_lpe_item); if ( !linked_pathv.empty() ) @@ -141,7 +142,7 @@ void LPEAttachPath::doEffect (SPCurve * curve) Geom::Coord length = derivs[deriv_n].length(); if ( ! Geom::are_near(length, 0) ) { if (set_end_end) { - end_path_position.param_set_value(transformedpath.nearestPoint(end_path_curve_end.getOrigin())); + end_path_position.param_set_value(transformedpath.nearestTime(end_path_curve_end.getOrigin())); } if (end_path_position > transformedpath.size()) { @@ -149,7 +150,8 @@ void LPEAttachPath::doEffect (SPCurve * curve) } else if (end_path_position < 0) { end_path_position.param_set_value(0); } - const Geom::Curve *c = end_path_position >= transformedpath.size() ? &transformedpath.back() : &transformedpath.at_index((int)end_path_position); + const Geom::Curve *c = end_path_position >= transformedpath.size() ? + &transformedpath.back() : &transformedpath.at((int)end_path_position); std::vector derivs_2 = c->pointAndDerivatives(end_path_position >= transformedpath.size() ? 1 : (end_path_position - (int)end_path_position), 3); for (unsigned deriv_n_2 = 1; deriv_n_2 < derivs_2.size(); deriv_n_2++) { diff --git a/src/live_effects/lpe-boolops.cpp b/src/live_effects/lpe-boolops.cpp deleted file mode 100644 index 641cf5d50..000000000 --- a/src/live_effects/lpe-boolops.cpp +++ /dev/null @@ -1,79 +0,0 @@ -/** \file - * LPE boolops implementation - */ -/* - * Authors: - * Johan Engelen - * - * Copyright (C) Johan Engelen 2007-2008 - * - * Released under GNU GPL, read the file 'COPYING' for more information - */ - -#include "live_effects/lpe-boolops.h" - -#include <2geom/path.h> -#include <2geom/shape.h> - -namespace Inkscape { -namespace LivePathEffect { - -static const Util::EnumData BoolopTypeData[] = { - {Geom::BOOLOP_NULL , N_("Null"), "null"}, - {Geom::BOOLOP_INTERSECT , N_("Intersect"), "intersect"}, - {Geom::BOOLOP_SUBTRACT_A_B , N_("Subtract A-B"), "subtract_a_b"}, - {Geom::BOOLOP_IDENTITY_A , N_("Identity A"), "identity_a"}, - {Geom::BOOLOP_SUBTRACT_B_A , N_("Subtract B-A"), "subtract_b_a"}, - {Geom::BOOLOP_IDENTITY_B , N_("Identity B"), "identity_b"}, - {Geom::BOOLOP_EXCLUSION , N_("Exclusion"), "Exclusion"}, - {Geom::BOOLOP_UNION , N_("Union"), "Union"} -}; -static const Util::EnumDataConverter BoolopTypeConverter(BoolopTypeData, sizeof(BoolopTypeData)/sizeof(*BoolopTypeData)); - -LPEBoolops::LPEBoolops(LivePathEffectObject *lpeobject) : - Effect(lpeobject), - bool_path(_("2nd path:"), _("Path to which the original path will be boolop'ed."), "path_2nd", &wr, this, "M0,0 L1,0"), - boolop_type(_("Boolop type:"), _("Determines which kind of boolop will be performed."), "boolop_type", BoolopTypeConverter, &wr, this, Geom::BOOLOP_UNION) -{ - show_orig_path = true; - - registerParameter( dynamic_cast(&boolop_type) ); - registerParameter( dynamic_cast(&bool_path) ); -} - -LPEBoolops::~LPEBoolops() -{ - -} - - -Geom::PathVector -LPEBoolops::doEffect_path (Geom::PathVector const & path_in) -{ - std::vector path_out; - - Geom::Shape shape_in = Geom::sanitize(path_in); - - Geom::Shape shape_param = Geom::sanitize(bool_path.get_pathvector()); - - Geom::Shape shape_out = Geom::boolop(shape_in, shape_param, boolop_type.get_value()); - - path_out = Geom::desanitize(shape_out); - - return path_out; -} - - -} //namespace LivePathEffect -} /* namespace Inkscape */ - -/* - Local Variables: - mode:c++ - c-file-style:"stroustrup" - c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) - indent-tabs-mode:nil - fill-column:99 - End: -*/ -// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 : diff --git a/src/live_effects/lpe-boolops.h b/src/live_effects/lpe-boolops.h deleted file mode 100644 index 3c8dc85c4..000000000 --- a/src/live_effects/lpe-boolops.h +++ /dev/null @@ -1,53 +0,0 @@ -#ifndef INKSCAPE_LPE_BOOLOPS_H -#define INKSCAPE_LPE_BOOLOPS_H - -/** \file - * LPE boolops implementation, see lpe-boolops.cpp. - */ - -/* - * Authors: - * Johan Engelen - * - * Copyright (C) Johan Engelen 2007-2008 - * - * Released under GNU GPL, read the file 'COPYING' for more information - */ - -#include "live_effects/parameter/enum.h" -#include "live_effects/effect.h" -#include "live_effects/parameter/path.h" - -namespace Inkscape { -namespace LivePathEffect { - -class LPEBoolops : public Effect { -public: - LPEBoolops(LivePathEffectObject *lpeobject); - virtual ~LPEBoolops(); - - virtual std::vector doEffect_path (std::vector const & path_in); - -private: - PathParam bool_path; - EnumParam boolop_type; - - LPEBoolops(const LPEBoolops&); - LPEBoolops& operator=(const LPEBoolops&); -}; - -} //namespace LivePathEffect -} //namespace Inkscape - -#endif // INKSCAPE_LPE_BOOLOPS_H - -/* - Local Variables: - mode:c++ - c-file-style:"stroustrup" - c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) - indent-tabs-mode:nil - fill-column:99 - End: -*/ -// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 : diff --git a/src/live_effects/lpe-bounding-box.cpp b/src/live_effects/lpe-bounding-box.cpp index bafd5e70e..43a60d482 100644 --- a/src/live_effects/lpe-bounding-box.cpp +++ b/src/live_effects/lpe-bounding-box.cpp @@ -45,7 +45,7 @@ void LPEBoundingBox::doEffect (SPCurve * curve) p.appendNew(Geom::Point(bbox->right(), bbox->bottom())); p.appendNew(Geom::Point(bbox->left(), bbox->bottom())); p.appendNew(Geom::Point(bbox->left(), bbox->top())); - std::vector out; + Geom::PathVector out; out.push_back(p); curve->set_pathvector(out); } diff --git a/src/live_effects/lpe-bspline.cpp b/src/live_effects/lpe-bspline.cpp index ecbfef76a..e5389684a 100644 --- a/src/live_effects/lpe-bspline.cpp +++ b/src/live_effects/lpe-bspline.cpp @@ -121,12 +121,12 @@ void LPEBSpline::doEffect(SPCurve *curve) if(are_near((*cubic)[1],(*cubic)[0]) && !are_near((*cubic)[2],(*cubic)[3])) { point_at1 = sbasis_in.valueAt(DEFAULT_START_POWER); } else { - point_at1 = sbasis_in.valueAt(Geom::nearest_point((*cubic)[1], *in->first_segment())); + point_at1 = sbasis_in.valueAt(Geom::nearest_time((*cubic)[1], *in->first_segment())); } if(are_near((*cubic)[2],(*cubic)[3]) && !are_near((*cubic)[1],(*cubic)[0])) { point_at2 = sbasis_in.valueAt(DEFAULT_END_POWER); } else { - point_at2 = sbasis_in.valueAt(Geom::nearest_point((*cubic)[2], *in->first_segment())); + point_at2 = sbasis_in.valueAt(Geom::nearest_time((*cubic)[2], *in->first_segment())); } } else { point_at1 = in->first_segment()->initialPoint(); @@ -144,7 +144,7 @@ void LPEBSpline::doEffect(SPCurve *curve) if(are_near((*cubic)[1],(*cubic)[0]) && !are_near((*cubic)[2],(*cubic)[3])) { next_point_at1 = sbasis_in.valueAt(DEFAULT_START_POWER); } else { - next_point_at1 = sbasis_out.valueAt(Geom::nearest_point((*cubic)[1], *out->first_segment())); + next_point_at1 = sbasis_out.valueAt(Geom::nearest_time((*cubic)[1], *out->first_segment())); } } else { next_point_at1 = out->first_segment()->initialPoint(); @@ -161,7 +161,7 @@ void LPEBSpline::doEffect(SPCurve *curve) cubic = dynamic_cast(&*path_it->begin()); if (cubic) { line_helper->moveto(sbasis_start.valueAt( - Geom::nearest_point((*cubic)[1], *start->first_segment()))); + Geom::nearest_time((*cubic)[1], *start->first_segment()))); } else { line_helper->moveto(start->first_segment()->initialPoint()); } @@ -175,7 +175,7 @@ void LPEBSpline::doEffect(SPCurve *curve) cubic = dynamic_cast(&*curve_it1); if (cubic) { line_helper->lineto(sbasis_end.valueAt( - Geom::nearest_point((*cubic)[2], *end->first_segment()))); + Geom::nearest_time((*cubic)[2], *end->first_segment()))); } else { line_helper->lineto(end->first_segment()->finalPoint()); } @@ -233,7 +233,7 @@ LPEBSpline::drawHandle(Geom::Point p, double helper_size) Geom::Affine aff = Geom::Affine(); aff *= Geom::Scale(helper_size); pathv *= aff; - pathv += p - Geom::Point(0.5*helper_size, 0.5*helper_size); + pathv *= Geom::Translate(p - Geom::Point(0.5*helper_size, 0.5*helper_size)); hp.push_back(pathv[0]); } diff --git a/src/live_effects/lpe-circle_3pts.cpp b/src/live_effects/lpe-circle_3pts.cpp index fb7496f58..cbabb5a6c 100644 --- a/src/live_effects/lpe-circle_3pts.cpp +++ b/src/live_effects/lpe-circle_3pts.cpp @@ -30,7 +30,7 @@ LPECircle3Pts::~LPECircle3Pts() { } -static void _circle3(Geom::Point const &A, Geom::Point const &B, Geom::Point const &C, std::vector &path_out) { +static void _circle3(Geom::Point const &A, Geom::Point const &B, Geom::Point const &C, Geom::PathVector &path_out) { using namespace Geom; Point D = (A + B)/2; @@ -50,10 +50,10 @@ static void _circle3(Geom::Point const &A, Geom::Point const &B, Geom::Point con c.getPath(path_out); } -std::vector -LPECircle3Pts::doEffect_path (std::vector const & path_in) +Geom::PathVector +LPECircle3Pts::doEffect_path (Geom::PathVector const & path_in) { - std::vector path_out = std::vector(); + Geom::PathVector path_out = Geom::PathVector(); // we assume that the path has >= 3 nodes Geom::Point A = path_in[0].initialPoint(); diff --git a/src/live_effects/lpe-circle_3pts.h b/src/live_effects/lpe-circle_3pts.h index 2533fe251..07c2eddb0 100644 --- a/src/live_effects/lpe-circle_3pts.h +++ b/src/live_effects/lpe-circle_3pts.h @@ -27,7 +27,7 @@ public: LPECircle3Pts(LivePathEffectObject *lpeobject); virtual ~LPECircle3Pts(); - virtual std::vector doEffect_path (std::vector const & path_in); + virtual Geom::PathVector doEffect_path (Geom::PathVector const & path_in); private: LPECircle3Pts(const LPECircle3Pts&); diff --git a/src/live_effects/lpe-circle_with_radius.cpp b/src/live_effects/lpe-circle_with_radius.cpp index 8a32cd230..32d0c0bf5 100644 --- a/src/live_effects/lpe-circle_with_radius.cpp +++ b/src/live_effects/lpe-circle_with_radius.cpp @@ -40,10 +40,10 @@ LPECircleWithRadius::~LPECircleWithRadius() } -std::vector -LPECircleWithRadius::doEffect_path (std::vector const & path_in) +Geom::PathVector +LPECircleWithRadius::doEffect_path (Geom::PathVector const & path_in) { - std::vector path_out = std::vector(); + Geom::PathVector path_out = Geom::PathVector(); Geom::Point center = path_in[0].initialPoint(); Geom::Point pt = path_in[0].finalPoint(); diff --git a/src/live_effects/lpe-circle_with_radius.h b/src/live_effects/lpe-circle_with_radius.h index 10f652771..f5bf0c414 100644 --- a/src/live_effects/lpe-circle_with_radius.h +++ b/src/live_effects/lpe-circle_with_radius.h @@ -26,7 +26,7 @@ public: virtual ~LPECircleWithRadius(); // Choose to implement one of the doEffect functions. You can delete or comment out the others. - virtual std::vector doEffect_path (std::vector const & path_in); + virtual Geom::PathVector doEffect_path (Geom::PathVector const & path_in); private: // add the parameters for your effect here: diff --git a/src/live_effects/lpe-clone-original.cpp b/src/live_effects/lpe-clone-original.cpp index d7cd6e19c..7541c0be2 100644 --- a/src/live_effects/lpe-clone-original.cpp +++ b/src/live_effects/lpe-clone-original.cpp @@ -28,7 +28,7 @@ LPECloneOriginal::~LPECloneOriginal() void LPECloneOriginal::doEffect (SPCurve * curve) { if ( linked_path.linksToPath() ) { - std::vector linked_pathv = linked_path.get_pathvector(); + Geom::PathVector linked_pathv = linked_path.get_pathvector(); if ( !linked_pathv.empty() ) { curve->set_pathvector(linked_pathv); } diff --git a/src/live_effects/lpe-constructgrid.cpp b/src/live_effects/lpe-constructgrid.cpp index fbf9faf56..b1e0edaac 100644 --- a/src/live_effects/lpe-constructgrid.cpp +++ b/src/live_effects/lpe-constructgrid.cpp @@ -41,8 +41,8 @@ LPEConstructGrid::~LPEConstructGrid() } -std::vector -LPEConstructGrid::doEffect_path (std::vector const & path_in) +Geom::PathVector +LPEConstructGrid::doEffect_path (Geom::PathVector const & path_in) { // Check that the path has at least 3 nodes (i.e. 2 segments), more nodes are ignored if (path_in[0].size() >= 2) { @@ -64,7 +64,7 @@ LPEConstructGrid::doEffect_path (std::vector const & path_in) second_path.appendNew( origin + second_p*nr_x ); // use the gridpaths and set them in the correct grid - std::vector path_out; + Geom::PathVector path_out; path_out.push_back(first_path); for (int ix = 0; ix < nr_x; ix++) { path_out.push_back(path_out.back() * second_translation ); diff --git a/src/live_effects/lpe-constructgrid.h b/src/live_effects/lpe-constructgrid.h index c7e695794..49c986742 100644 --- a/src/live_effects/lpe-constructgrid.h +++ b/src/live_effects/lpe-constructgrid.h @@ -25,7 +25,7 @@ public: LPEConstructGrid(LivePathEffectObject *lpeobject); virtual ~LPEConstructGrid(); - virtual std::vector doEffect_path (std::vector const & path_in); + virtual Geom::PathVector doEffect_path (Geom::PathVector const & path_in); private: ScalarParam nr_x; diff --git a/src/live_effects/lpe-curvestitch.cpp b/src/live_effects/lpe-curvestitch.cpp index 854cc0734..609447f26 100644 --- a/src/live_effects/lpe-curvestitch.cpp +++ b/src/live_effects/lpe-curvestitch.cpp @@ -68,8 +68,8 @@ LPECurveStitch::~LPECurveStitch() } -std::vector -LPECurveStitch::doEffect_path (std::vector const & path_in) +Geom::PathVector +LPECurveStitch::doEffect_path (Geom::PathVector const & path_in) { if (path_in.size() >= 2) { startpoint_edge_variation.resetRandomizer(); @@ -86,7 +86,7 @@ LPECurveStitch::doEffect_path (std::vector const & path_in) gdouble scaling = bndsStroke->max() - bndsStroke->min(); Point stroke_origin(bndsStroke->min(), (bndsStrokeY->max()+bndsStrokeY->min())/2); - std::vector path_out; + Geom::PathVector path_out; // do this for all permutations (ii,jj) if there are more than 2 paths? realllly cool! for (unsigned ii = 0 ; ii < path_in.size() - 1; ii++) @@ -127,7 +127,7 @@ LPECurveStitch::doEffect_path (std::vector const & path_in) // add stuff to one big pw > and then outside the loop convert to path? // No: this way, the separate result paths are kept separate which might come in handy some time! - std::vector result = Geom::path_from_piecewise(pwd2_out, LPE_CONVERSION_TOLERANCE); + Geom::PathVector result = Geom::path_from_piecewise(pwd2_out, LPE_CONVERSION_TOLERANCE); path_out.push_back(result[0]); } gdouble svA = startpoint_spacing_variation - startpoint_spacing_variation.get_value()/2; @@ -162,7 +162,7 @@ LPECurveStitch::resetDefaults(SPItem const* item) // calculate bounding box: (isn't there a simpler way?) Piecewise > pwd2; - std::vector temppath = sp_svg_read_pathv( item->getRepr()->attribute("inkscape:original-d")); + Geom::PathVector temppath = sp_svg_read_pathv( item->getRepr()->attribute("inkscape:original-d")); for (unsigned int i=0; i < temppath.size(); i++) { pwd2.concat( temppath[i].toPwSb() ); } diff --git a/src/live_effects/lpe-curvestitch.h b/src/live_effects/lpe-curvestitch.h index 38a11b4af..c6ea66f6c 100644 --- a/src/live_effects/lpe-curvestitch.h +++ b/src/live_effects/lpe-curvestitch.h @@ -28,7 +28,7 @@ public: LPECurveStitch(LivePathEffectObject *lpeobject); virtual ~LPECurveStitch(); - virtual std::vector doEffect_path (std::vector const & path_in); + virtual Geom::PathVector doEffect_path (Geom::PathVector const & path_in); virtual void resetDefaults(SPItem const* item); diff --git a/src/live_effects/lpe-ellipse_5pts.cpp b/src/live_effects/lpe-ellipse_5pts.cpp index b0a5919fe..4c953bcda 100644 --- a/src/live_effects/lpe-ellipse_5pts.cpp +++ b/src/live_effects/lpe-ellipse_5pts.cpp @@ -67,10 +67,10 @@ static double _det5(double (*mat)[5]) return mat[4][4]; } -std::vector -LPEEllipse5Pts::doEffect_path (std::vector const & path_in) +Geom::PathVector +LPEEllipse5Pts::doEffect_path (Geom::PathVector const & path_in) { - std::vector path_out = std::vector(); + Geom::PathVector path_out = Geom::PathVector(); if (path_in[0].size() < 4) { @@ -190,7 +190,7 @@ LPEEllipse5Pts::doEffect_path (std::vector const & path_in) p.appendNew(Geom::Point(x1,y1), Geom::Point(x2,y2), Geom::Point(x3,y3)); } - Geom::Affine aff = Geom::Scale(el.ray(Geom::X), el.ray(Geom::Y)) * Geom::Rotate(el.rot_angle()) * Geom::Translate(el.center()); + Geom::Affine aff = Geom::Scale(el.rays()) * Geom::Rotate(el.rotationAngle()) * Geom::Translate(el.center()); path_out.push_back(p * aff); diff --git a/src/live_effects/lpe-ellipse_5pts.h b/src/live_effects/lpe-ellipse_5pts.h index d3b1fccfa..691a693dc 100644 --- a/src/live_effects/lpe-ellipse_5pts.h +++ b/src/live_effects/lpe-ellipse_5pts.h @@ -26,7 +26,7 @@ public: LPEEllipse5Pts(LivePathEffectObject *lpeobject); virtual ~LPEEllipse5Pts(); - virtual std::vector doEffect_path (std::vector const & path_in); + virtual Geom::PathVector doEffect_path (Geom::PathVector const & path_in); private: LPEEllipse5Pts(const LPEEllipse5Pts&); diff --git a/src/live_effects/lpe-fill-between-many.cpp b/src/live_effects/lpe-fill-between-many.cpp index 7cf354044..3e0810cfc 100644 --- a/src/live_effects/lpe-fill-between-many.cpp +++ b/src/live_effects/lpe-fill-between-many.cpp @@ -35,14 +35,14 @@ LPEFillBetweenMany::~LPEFillBetweenMany() void LPEFillBetweenMany::doEffect (SPCurve * curve) { - std::vector res_pathv; + Geom::PathVector res_pathv; SPItem * firstObj = NULL; for (std::vector::iterator iter = linked_paths._vector.begin(); iter != linked_paths._vector.end(); iter++) { SPObject *obj; if ((*iter)->ref.isAttached() && (obj = (*iter)->ref.getObject()) && SP_IS_ITEM(obj) && !(*iter)->_pathvector.empty()) { Geom::Path linked_path; if ((*iter)->reversed) { - linked_path = (*iter)->_pathvector.front().reverse(); + linked_path = (*iter)->_pathvector.front().reversed(); } else { linked_path = (*iter)->_pathvector.front(); } diff --git a/src/live_effects/lpe-fill-between-strokes.cpp b/src/live_effects/lpe-fill-between-strokes.cpp index e72979ed0..89ea80545 100644 --- a/src/live_effects/lpe-fill-between-strokes.cpp +++ b/src/live_effects/lpe-fill-between-strokes.cpp @@ -39,17 +39,17 @@ void LPEFillBetweenStrokes::doEffect (SPCurve * curve) { if (curve) { if ( linked_path.linksToPath() && second_path.linksToPath() && linked_path.getObject() && second_path.getObject() ) { - std::vector linked_pathv = linked_path.get_pathvector(); - std::vector second_pathv = second_path.get_pathvector(); - std::vector result_linked_pathv; - std::vector result_second_pathv; + Geom::PathVector linked_pathv = linked_path.get_pathvector(); + Geom::PathVector second_pathv = second_path.get_pathvector(); + Geom::PathVector result_linked_pathv; + Geom::PathVector result_second_pathv; Geom::Affine second_transform = second_path.getObject()->getRelativeTransform(linked_path.getObject()); - for (std::vector::iterator iter = linked_pathv.begin(); iter != linked_pathv.end(); ++iter) + for (Geom::PathVector::iterator iter = linked_pathv.begin(); iter != linked_pathv.end(); ++iter) { result_linked_pathv.push_back((*iter)); } - for (std::vector::iterator iter = second_pathv.begin(); iter != second_pathv.end(); ++iter) + for (Geom::PathVector::iterator iter = second_pathv.begin(); iter != second_pathv.end(); ++iter) { result_second_pathv.push_back((*iter) * second_transform); } @@ -58,7 +58,7 @@ void LPEFillBetweenStrokes::doEffect (SPCurve * curve) if (reverse_second.get_value()) { result_linked_pathv.front().appendNew(result_second_pathv.front().finalPoint()); - result_linked_pathv.front().append(result_second_pathv.front().reverse()); + result_linked_pathv.front().append(result_second_pathv.front().reversed()); } else { @@ -75,10 +75,10 @@ void LPEFillBetweenStrokes::doEffect (SPCurve * curve) } } else if ( linked_path.linksToPath() && linked_path.getObject() ) { - std::vector linked_pathv = linked_path.get_pathvector(); - std::vector result_pathv; + Geom::PathVector linked_pathv = linked_path.get_pathvector(); + Geom::PathVector result_pathv; - for (std::vector::iterator iter = linked_pathv.begin(); iter != linked_pathv.end(); ++iter) + for (Geom::PathVector::iterator iter = linked_pathv.begin(); iter != linked_pathv.end(); ++iter) { result_pathv.push_back((*iter)); } @@ -87,10 +87,10 @@ void LPEFillBetweenStrokes::doEffect (SPCurve * curve) } } else if ( second_path.linksToPath() && second_path.getObject() ) { - std::vector second_pathv = second_path.get_pathvector(); - std::vector result_pathv; + Geom::PathVector second_pathv = second_path.get_pathvector(); + Geom::PathVector result_pathv; - for (std::vector::iterator iter = second_pathv.begin(); iter != second_pathv.end(); ++iter) + for (Geom::PathVector::iterator iter = second_pathv.begin(); iter != second_pathv.end(); ++iter) { result_pathv.push_back((*iter)); } diff --git a/src/live_effects/lpe-fillet-chamfer.cpp b/src/live_effects/lpe-fillet-chamfer.cpp index c8458b8cb..c03312ce2 100644 --- a/src/live_effects/lpe-fillet-chamfer.cpp +++ b/src/live_effects/lpe-fillet-chamfer.cpp @@ -275,11 +275,11 @@ void LPEFilletChamfer::refreshKnots() } } -void LPEFilletChamfer::doUpdateFillet(std::vector const& original_pathv, double power) +void LPEFilletChamfer::doUpdateFillet(Geom::PathVector const &original_pathv, double power) { std::vector filletChamferData = fillet_chamfer_values.data(); std::vector result; - std::vector original_pathv_processed = pathv_to_linear_and_cubic_beziers(original_pathv); + Geom::PathVector original_pathv_processed = pathv_to_linear_and_cubic_beziers(original_pathv); int counter = 0; for (PathVector::const_iterator path_it = original_pathv_processed.begin(); path_it != original_pathv_processed.end(); ++path_it) { @@ -323,11 +323,11 @@ void LPEFilletChamfer::doUpdateFillet(std::vector const& original_pa fillet_chamfer_values.param_set_and_write_new_value(result); } -void LPEFilletChamfer::doChangeType(std::vector const& original_pathv, int type) +void LPEFilletChamfer::doChangeType(Geom::PathVector const &original_pathv, int type) { std::vector filletChamferData = fillet_chamfer_values.data(); std::vector result; - std::vector original_pathv_processed = pathv_to_linear_and_cubic_beziers(original_pathv); + Geom::PathVector original_pathv_processed = pathv_to_linear_and_cubic_beziers(original_pathv); int counter = 0; for (PathVector::const_iterator path_it = original_pathv_processed.begin(); path_it != original_pathv_processed.end(); ++path_it) { int pathCounter = 0; @@ -466,7 +466,7 @@ int LPEFilletChamfer::getKnotsNumber(SPCurve const *c) { int nKnots = c->nodes_in_path(); PathVector const pv = pathv_to_linear_and_cubic_beziers(c->get_pathvector()); - for (std::vector::const_iterator path_it = pv.begin(); + for (Geom::PathVector::const_iterator path_it = pv.begin(); path_it != pv.end(); ++path_it) { if (!(*path_it).closed()) { nKnots--; @@ -476,17 +476,17 @@ int LPEFilletChamfer::getKnotsNumber(SPCurve const *c) } void -LPEFilletChamfer::adjustForNewPath(std::vector const &path_in) +LPEFilletChamfer::adjustForNewPath(Geom::PathVector const &path_in) { if (!path_in.empty()) { fillet_chamfer_values.recalculate_controlpoints_for_new_pwd2(pathv_to_linear_and_cubic_beziers(path_in)[0].toPwSb()); } } -std::vector -LPEFilletChamfer::doEffect_path(std::vector const &path_in) +Geom::PathVector +LPEFilletChamfer::doEffect_path(Geom::PathVector const &path_in) { - std::vector pathvector_out; + Geom::PathVector pathvector_out; Piecewise > pwd2_in = paths_to_pw(pathv_to_linear_and_cubic_beziers(path_in)); pwd2_in = remove_short_cuts(pwd2_in, .01); Piecewise > der = derivative(pwd2_in); @@ -495,7 +495,7 @@ LPEFilletChamfer::doEffect_path(std::vector const &path_in) std::vector filletChamferData = fillet_chamfer_values.data(); unsigned int counter = 0; const double K = (4.0 / 3.0) * (sqrt(2.0) - 1.0); - std::vector path_in_processed = pathv_to_linear_and_cubic_beziers(path_in); + Geom::PathVector path_in_processed = pathv_to_linear_and_cubic_beziers(path_in); for (PathVector::const_iterator path_it = path_in_processed.begin(); path_it != path_in_processed.end(); ++path_it) { if (path_it->empty()) diff --git a/src/live_effects/lpe-fillet-chamfer.h b/src/live_effects/lpe-fillet-chamfer.h index 0d6a1ff17..6da12cce7 100644 --- a/src/live_effects/lpe-fillet-chamfer.h +++ b/src/live_effects/lpe-fillet-chamfer.h @@ -45,11 +45,11 @@ public: LPEFilletChamfer(LivePathEffectObject *lpeobject); virtual ~LPEFilletChamfer(); - virtual std::vector doEffect_path(std::vector const &path_in); + virtual Geom::PathVector doEffect_path(Geom::PathVector const &path_in); virtual void doOnApply(SPLPEItem const *lpeItem); virtual void doBeforeEffect(SPLPEItem const *lpeItem); - virtual void adjustForNewPath(std::vector const &path_in); + virtual void adjustForNewPath(Geom::PathVector const &path_in); virtual Gtk::Widget* newWidget(); int getKnotsNumber(SPCurve const *c); @@ -61,8 +61,8 @@ public: void fillet(); void inverseFillet(); void updateFillet(); - void doUpdateFillet(std::vector const& original_pathv, double power); - void doChangeType(std::vector const& original_pathv, int type); + void doUpdateFillet(Geom::PathVector const& original_pathv, double power); + void doChangeType(Geom::PathVector const& original_pathv, int type); void refreshKnots(); FilletChamferPointArrayParam fillet_chamfer_values; diff --git a/src/live_effects/lpe-gears.cpp b/src/live_effects/lpe-gears.cpp index 003e22567..903dfd716 100644 --- a/src/live_effects/lpe-gears.cpp +++ b/src/live_effects/lpe-gears.cpp @@ -232,10 +232,10 @@ LPEGears::~LPEGears() } -std::vector -LPEGears::doEffect_path (std::vector const & path_in) +Geom::PathVector +LPEGears::doEffect_path (Geom::PathVector const &path_in) { - std::vector path_out; + Geom::PathVector path_out; Geom::Path gearpath = path_in[0]; Geom::Path::iterator it(gearpath.begin()); diff --git a/src/live_effects/lpe-gears.h b/src/live_effects/lpe-gears.h index bd5e4c4f9..5dd6dd239 100644 --- a/src/live_effects/lpe-gears.h +++ b/src/live_effects/lpe-gears.h @@ -22,7 +22,7 @@ public: LPEGears(LivePathEffectObject *lpeobject); virtual ~LPEGears(); - virtual std::vector doEffect_path (std::vector const & path_in); + virtual Geom::PathVector doEffect_path(Geom::PathVector const &path_in); private: ScalarParam teeth; diff --git a/src/live_effects/lpe-interpolate.cpp b/src/live_effects/lpe-interpolate.cpp index e41bc6f0e..b1ad07d23 100644 --- a/src/live_effects/lpe-interpolate.cpp +++ b/src/live_effects/lpe-interpolate.cpp @@ -61,7 +61,7 @@ LPEInterpolate::doEffect_path (Geom::PathVector const & path_in) return path_in; } - std::vector path_out; + Geom::PathVector path_out; Geom::Piecewise > pwd2_A = path_in[0].toPwSb(); Geom::Piecewise > pwd2_B = path_in[1].toPwSb(); diff --git a/src/live_effects/lpe-interpolate.h b/src/live_effects/lpe-interpolate.h index 679001a81..ef8043e46 100644 --- a/src/live_effects/lpe-interpolate.h +++ b/src/live_effects/lpe-interpolate.h @@ -27,7 +27,7 @@ public: LPEInterpolate(LivePathEffectObject *lpeobject); virtual ~LPEInterpolate(); - virtual std::vector doEffect_path (std::vector const & path_in); + virtual Geom::PathVector doEffect_path (Geom::PathVector const & path_in); virtual void resetDefaults(SPItem const* item); private: diff --git a/src/live_effects/lpe-interpolate_points.h b/src/live_effects/lpe-interpolate_points.h index 7a3364747..eb706a320 100644 --- a/src/live_effects/lpe-interpolate_points.h +++ b/src/live_effects/lpe-interpolate_points.h @@ -25,7 +25,7 @@ public: LPEInterpolatePoints(LivePathEffectObject *lpeobject); virtual ~LPEInterpolatePoints(); - virtual std::vector doEffect_path (std::vector const & path_in); + virtual Geom::PathVector doEffect_path (Geom::PathVector const & path_in); private: EnumParam interpolator_type; diff --git a/src/live_effects/lpe-jointype.cpp b/src/live_effects/lpe-jointype.cpp index 0111a0f99..893f3ab4e 100644 --- a/src/live_effects/lpe-jointype.cpp +++ b/src/live_effects/lpe-jointype.cpp @@ -150,7 +150,7 @@ void LPEJoinType::doOnRemove(SPLPEItem const* lpeitem) } } -std::vector LPEJoinType::doEffect_path(std::vector const & path_in) +Geom::PathVector LPEJoinType::doEffect_path(Geom::PathVector const & path_in) { Geom::PathVector ret; for (size_t i = 0; i < path_in.size(); ++i) { diff --git a/src/live_effects/lpe-jointype.h b/src/live_effects/lpe-jointype.h index bca0961c9..fddaeb619 100644 --- a/src/live_effects/lpe-jointype.h +++ b/src/live_effects/lpe-jointype.h @@ -24,7 +24,7 @@ public: virtual void doOnApply(SPLPEItem const* lpeitem); virtual void doOnRemove(SPLPEItem const* lpeitem); - virtual std::vector doEffect_path (std::vector const & path_in); + virtual Geom::PathVector doEffect_path (Geom::PathVector const & path_in); private: LPEJoinType(const LPEJoinType&); diff --git a/src/live_effects/lpe-knot.cpp b/src/live_effects/lpe-knot.cpp index 820221abf..84e4deda7 100644 --- a/src/live_effects/lpe-knot.cpp +++ b/src/live_effects/lpe-knot.cpp @@ -155,7 +155,7 @@ findShadowedTime(Geom::Path const &patha, std::vector const &pt_and // -for each component, the time at which this crossing occurs + the order of this crossing along the component (when starting from 0). namespace LPEKnotNS {//just in case... -CrossingPoints::CrossingPoints(std::vector const &paths) : std::vector(){ +CrossingPoints::CrossingPoints(Geom::PathVector const &paths) : std::vector(){ // std::cout<<"\nCrossingPoints creation from path vector\n"; for( unsigned i=0; i -LPEKnot::doEffect_path (std::vector const &path_in) +Geom::PathVector +LPEKnot::doEffect_path (Geom::PathVector const &path_in) { using namespace Geom; - std::vector path_out; + Geom::PathVector path_out; if (gpaths.size()==0){ return path_in; @@ -486,8 +486,9 @@ LPEKnot::doEffect_path (std::vector const &path_in) ++beg_comp; --end_comp; Path first = gpaths[i0].portion(dom.back()); - //FIXME: STITCH_DISCONTINUOUS should not be necessary (?!?) - first.append(gpaths[i0].portion(dom.front()), Path::STITCH_DISCONTINUOUS); + //FIXME: stitching should not be necessary (?!?) + first.setStitching(true); + first.append(gpaths[i0].portion(dom.front())); path_out.push_back(first); } } @@ -503,7 +504,7 @@ LPEKnot::doEffect_path (std::vector const &path_in) //recursively collect gpaths and stroke widths (stolen from "sp-lpe_item.cpp"). static void -collectPathsAndWidths (SPLPEItem const *lpeitem, std::vector &paths, std::vector &stroke_widths){ +collectPathsAndWidths (SPLPEItem const *lpeitem, Geom::PathVector &paths, std::vector &stroke_widths){ if (SP_IS_GROUP(lpeitem)) { GSList const *item_list = sp_item_group_item_list(SP_GROUP(lpeitem)); for ( GSList const *iter = item_list; iter; iter = iter->next ) { @@ -615,8 +616,7 @@ LPEKnot::addCanvasIndicators(SPLPEItem const */*lpeitem*/, std::vector{ public: CrossingPoints() : std::vector() {} - CrossingPoints(Geom::CrossingSet const &cs, std::vector const &path);//for self crossings only! - CrossingPoints(std::vector const &paths); + CrossingPoints(Geom::CrossingSet const &cs, Geom::PathVector const &path);//for self crossings only! + CrossingPoints(Geom::PathVector const &paths); CrossingPoints(std::vector const &input); std::vector to_vector(); CrossingPoint get(unsigned const i, unsigned const ni); @@ -57,7 +57,7 @@ public: virtual ~LPEKnot(); virtual void doBeforeEffect (SPLPEItem const* lpeitem); - virtual std::vector doEffect_path (std::vector const & input_path); + virtual Geom::PathVector doEffect_path (Geom::PathVector const & input_path); /* the knotholder entity classes must be declared friends */ friend class KnotHolderEntityCrossingSwitcher; @@ -65,7 +65,7 @@ public: protected: virtual void addCanvasIndicators(SPLPEItem const *lpeitem, std::vector &hp_vec); - std::vector supplied_path; //for knotholder business + Geom::PathVector supplied_path; //for knotholder business private: void updateSwitcher(); @@ -79,7 +79,7 @@ private: LPEKnotNS::CrossingPoints crossing_points;//topology representation of the knot. - std::vector gpaths;//the collection of all the paths in the object or group. + Geom::PathVector gpaths;//the collection of all the paths in the object or group. std::vector gstroke_widths;//the collection of all the stroke widths in the object or group. //UI: please, someone, help me to improve this!! diff --git a/src/live_effects/lpe-lattice2.cpp b/src/live_effects/lpe-lattice2.cpp index abd6e7786..51453357b 100644 --- a/src/live_effects/lpe-lattice2.cpp +++ b/src/live_effects/lpe-lattice2.cpp @@ -289,7 +289,7 @@ LPELattice2::vertical(PointParam ¶m_one, PointParam ¶m_two, Geom::Line v double Y = (A[Geom::Y] + B[Geom::Y])/2; A[Geom::Y] = Y; B[Geom::Y] = Y; - Geom::Point nearest = vert.pointAt(vert.nearestPoint(A)); + Geom::Point nearest = vert.pointAt(vert.nearestTime(A)); double distance_one = Geom::distance(A,nearest); double distance_two = Geom::distance(B,nearest); double distance_middle = (distance_one + distance_two)/2; @@ -310,7 +310,7 @@ LPELattice2::horizontal(PointParam ¶m_one, PointParam ¶m_two, Geom::Line double X = (A[Geom::X] + B[Geom::X])/2; A[Geom::X] = X; B[Geom::X] = X; - Geom::Point nearest = horiz.pointAt(horiz.nearestPoint(A)); + Geom::Point nearest = horiz.pointAt(horiz.nearestTime(A)); double distance_one = Geom::distance(A,nearest); double distance_two = Geom::distance(B,nearest); double distance_middle = (distance_one + distance_two)/2; diff --git a/src/live_effects/lpe-line_segment.cpp b/src/live_effects/lpe-line_segment.cpp index 78d286143..dfd8aea8f 100644 --- a/src/live_effects/lpe-line_segment.cpp +++ b/src/live_effects/lpe-line_segment.cpp @@ -48,16 +48,16 @@ LPELineSegment::doBeforeEffect (SPLPEItem const* lpeitem) Inkscape::UI::Tools::lpetool_get_limiting_bbox_corners(lpeitem->document, bboxA, bboxB); } -std::vector -LPELineSegment::doEffect_path (std::vector const & path_in) +Geom::PathVector +LPELineSegment::doEffect_path (Geom::PathVector const & path_in) { - std::vector output; + Geom::PathVector output; - A = initialPoint(path_in); - B = finalPoint(path_in); + A = path_in.initialPoint(); + B = path_in.finalPoint(); Geom::Rect dummyRect(bboxA, bboxB); - boost::optional intersection_segment = Geom::rect_line_intersect(dummyRect, Geom::Line(A, B)); + boost::optional intersection_segment = Geom::Line(A, B).clip(dummyRect); if (!intersection_segment) { g_print ("Possible error - no intersection with limiting bounding box.\n"); @@ -65,11 +65,11 @@ LPELineSegment::doEffect_path (std::vector const & path_in) } if (end_type == END_OPEN_INITIAL || end_type == END_OPEN_BOTH) { - A = (*intersection_segment).initialPoint(); + A = intersection_segment->initialPoint(); } if (end_type == END_OPEN_FINAL || end_type == END_OPEN_BOTH) { - B = (*intersection_segment).finalPoint(); + B = intersection_segment->finalPoint(); } Geom::Path path(A); diff --git a/src/live_effects/lpe-line_segment.h b/src/live_effects/lpe-line_segment.h index 1a57688b6..def828fe2 100644 --- a/src/live_effects/lpe-line_segment.h +++ b/src/live_effects/lpe-line_segment.h @@ -34,7 +34,7 @@ public: virtual void doBeforeEffect (SPLPEItem const* lpeitem); - virtual std::vector doEffect_path (std::vector const & path_in); + virtual Geom::PathVector doEffect_path (Geom::PathVector const & path_in); //private: EnumParam end_type; diff --git a/src/live_effects/lpe-mirror_symmetry.cpp b/src/live_effects/lpe-mirror_symmetry.cpp index 0bb67a4a2..783053df2 100644 --- a/src/live_effects/lpe-mirror_symmetry.cpp +++ b/src/live_effects/lpe-mirror_symmetry.cpp @@ -64,24 +64,24 @@ LPEMirrorSymmetry::doOnApply (SPLPEItem const* lpeitem) Point B(bbox.left(), bbox.top()); A *= t; B *= t; - Piecewise > rline = Piecewise >(D2(Linear(A[X], B[X]), Linear(A[Y], B[Y]))); + Piecewise > rline = Piecewise >(D2(SBasis(A[X], B[X]), SBasis(A[Y], B[Y]))); reflection_line.set_new_value(rline, true); } -std::vector -LPEMirrorSymmetry::doEffect_path (std::vector const & path_in) +Geom::PathVector +LPEMirrorSymmetry::doEffect_path (Geom::PathVector const & path_in) { // Don't allow empty path parameter: if ( reflection_line.get_pathvector().empty() ) { return path_in; } - std::vector path_out; + Geom::PathVector path_out; if (!discard_orig_path) { path_out = path_in; } - std::vector mline(reflection_line.get_pathvector()); + Geom::PathVector mline(reflection_line.get_pathvector()); Geom::Point A(mline.front().initialPoint()); Geom::Point B(mline.back().finalPoint()); diff --git a/src/live_effects/lpe-mirror_symmetry.h b/src/live_effects/lpe-mirror_symmetry.h index a4a2b86c0..7a484a473 100644 --- a/src/live_effects/lpe-mirror_symmetry.h +++ b/src/live_effects/lpe-mirror_symmetry.h @@ -32,7 +32,7 @@ public: virtual void doBeforeEffect (SPLPEItem const* lpeitem); - virtual std::vector doEffect_path (std::vector const & path_in); + virtual Geom::PathVector doEffect_path (Geom::PathVector const & path_in); private: BoolParam discard_orig_path; diff --git a/src/live_effects/lpe-offset.cpp b/src/live_effects/lpe-offset.cpp index ba7179476..c841a5442 100644 --- a/src/live_effects/lpe-offset.cpp +++ b/src/live_effects/lpe-offset.cpp @@ -72,7 +72,7 @@ LPEOffset::doEffect_pwd2 (Geom::Piecewise > const & pwd2_ Piecewise > output; - double t = nearest_point(offset_pt, pwd2_in); + double t = nearest_time(offset_pt, pwd2_in); Point A = pwd2_in.valueAt(t); double offset = L2(A - offset_pt); diff --git a/src/live_effects/lpe-parallel.cpp b/src/live_effects/lpe-parallel.cpp index aa7405607..23cd5e2e7 100644 --- a/src/live_effects/lpe-parallel.cpp +++ b/src/live_effects/lpe-parallel.cpp @@ -91,7 +91,7 @@ LPEParallel::doEffect_pwd2 (Geom::Piecewise > const & pwd C = offset_pt - dir * length_left; D = offset_pt + dir * length_right; - output = Piecewise >(D2(Linear(C[X], D[X]), Linear(C[Y], D[Y]))); + output = Piecewise >(D2(SBasis(C[X], D[X]), SBasis(C[Y], D[Y]))); return output + dir; } diff --git a/src/live_effects/lpe-perp_bisector.cpp b/src/live_effects/lpe-perp_bisector.cpp index feed55b26..660318c57 100644 --- a/src/live_effects/lpe-perp_bisector.cpp +++ b/src/live_effects/lpe-perp_bisector.cpp @@ -67,7 +67,7 @@ KnotHolderEntityEnd::bisector_end_set(Geom::Point const &p, guint state, bool le Geom::Point const s = snap_knot_position(p, state); - double lambda = Geom::nearest_point(s, lpe->M, lpe->perp_dir); + double lambda = Geom::nearest_time(s, lpe->M, lpe->perp_dir); if (left) { lpe->C = lpe->M + lpe->perp_dir * lambda; lpe->length_left.param_set_value(lambda); @@ -146,7 +146,7 @@ LPEPerpBisector::doEffect_pwd2 (Geom::Piecewise > const & C = M + perp_dir * length_left; D = M - perp_dir * length_right; - output = Piecewise >(D2(Linear(C[X], D[X]), Linear(C[Y], D[Y]))); + output = Piecewise >(D2(SBasis(C[X], D[X]), SBasis(C[Y], D[Y]))); return output; } diff --git a/src/live_effects/lpe-perspective-envelope.cpp b/src/live_effects/lpe-perspective-envelope.cpp index 08100bb2d..72c1b0e99 100644 --- a/src/live_effects/lpe-perspective-envelope.cpp +++ b/src/live_effects/lpe-perspective-envelope.cpp @@ -323,7 +323,7 @@ LPEPerspectiveEnvelope::vertical(PointParam ¶m_one, PointParam ¶m_two, G double Y = (A[Geom::Y] + B[Geom::Y])/2; A[Geom::Y] = Y; B[Geom::Y] = Y; - Geom::Point nearest = vert.pointAt(vert.nearestPoint(A)); + Geom::Point nearest = vert.pointAt(vert.nearestTime(A)); double distance_one = Geom::distance(A,nearest); double distance_two = Geom::distance(B,nearest); double distance_middle = (distance_one + distance_two)/2; @@ -344,7 +344,7 @@ LPEPerspectiveEnvelope::horizontal(PointParam ¶m_one, PointParam ¶m_two, double X = (A[Geom::X] + B[Geom::X])/2; A[Geom::X] = X; B[Geom::X] = X; - Geom::Point nearest = horiz.pointAt(horiz.nearestPoint(A)); + Geom::Point nearest = horiz.pointAt(horiz.nearestTime(A)); double distance_one = Geom::distance(A,nearest); double distance_two = Geom::distance(B,nearest); double distance_middle = (distance_one + distance_two)/2; diff --git a/src/live_effects/lpe-powerstroke.cpp b/src/live_effects/lpe-powerstroke.cpp index 5d9d224e8..e6644c7e9 100644 --- a/src/live_effects/lpe-powerstroke.cpp +++ b/src/live_effects/lpe-powerstroke.cpp @@ -106,9 +106,9 @@ static int circle_circle_intersection(Circle const &circle0, Circle const &circl Point & p0, Point & p1) { Point X0 = circle0.center(); - double r0 = circle0.ray(); + double r0 = circle0.radius(); Point X1 = circle1.center(); - double r1 = circle1.ray(); + double r1 = circle1.radius(); /* dx and dy are the vertical and horizontal distances between * the circle centers. @@ -313,7 +313,7 @@ LPEPowerStroke::doOnApply(SPLPEItem const* lpeitem) Geom::Path const &path = pathv.front(); Geom::Path::size_type const size = path.size_default(); if (!path.closed()) { - points.push_back( Geom::Point(0.2,width) ); + points.push_back( Geom::Point(0.2,width) ); } points.push_back( Geom::Point(0.5*size,width) ); if (!path.closed()) { @@ -362,7 +362,7 @@ void LPEPowerStroke::doOnRemove(SPLPEItem const* lpeitem) } void -LPEPowerStroke::adjustForNewPath(std::vector const & path_in) +LPEPowerStroke::adjustForNewPath(Geom::PathVector const & path_in) { if (!path_in.empty()) { offset_points.recalculate_controlpoints_for_new_pwd2(path_in[0].toPwSb()); @@ -387,6 +387,8 @@ static Geom::Path path_from_piecewise_fix_cusps( Geom::Piecewise -LPEPowerStroke::doEffect_path (std::vector const & path_in) +Geom::PathVector +LPEPowerStroke::doEffect_path (Geom::PathVector const & path_in) { using namespace Geom; - std::vector path_out; + Geom::PathVector path_out; if (path_in.empty()) { return path_out; } @@ -742,7 +744,7 @@ LPEPowerStroke::doEffect_path (std::vector const & path_in) } } - fixed_path.append(fixed_mirrorpath, Geom::Path::STITCH_DISCONTINUOUS); + fixed_path.append(fixed_mirrorpath); switch (start_linecap) { case LINECAP_ZERO_WIDTH: diff --git a/src/live_effects/lpe-powerstroke.h b/src/live_effects/lpe-powerstroke.h index a773434aa..135d39274 100644 --- a/src/live_effects/lpe-powerstroke.h +++ b/src/live_effects/lpe-powerstroke.h @@ -26,13 +26,13 @@ public: virtual ~LPEPowerStroke(); - virtual std::vector doEffect_path (std::vector const & path_in); + virtual Geom::PathVector doEffect_path (Geom::PathVector const & path_in); virtual void doOnApply(SPLPEItem const* lpeitem); virtual void doOnRemove(SPLPEItem const* lpeitem); // methods called by path-manipulator upon edits - void adjustForNewPath(std::vector const & path_in); + void adjustForNewPath(Geom::PathVector const & path_in); PowerStrokePointArrayParam offset_points; diff --git a/src/live_effects/lpe-rough-hatches.cpp b/src/live_effects/lpe-rough-hatches.cpp index 455653e46..76421e0f0 100644 --- a/src/live_effects/lpe-rough-hatches.cpp +++ b/src/live_effects/lpe-rough-hatches.cpp @@ -529,7 +529,8 @@ LPERoughHatches::smoothSnake(std::vector > const &linearSnake } if ( fat_output.get_value() ){ res_comp = res_comp_bot; - res_comp.append(res_comp_top.reverse(),Geom::Path::STITCH_DISCONTINUOUS); + res_comp.setStitching(true); + res_comp.append(res_comp_top.reversed()); } result.concat(res_comp.toPwSb()); } diff --git a/src/live_effects/lpe-roughen.cpp b/src/live_effects/lpe-roughen.cpp index 9d1c3152b..44ff54554 100644 --- a/src/live_effects/lpe-roughen.cpp +++ b/src/live_effects/lpe-roughen.cpp @@ -287,8 +287,8 @@ SPCurve *LPERoughen::addNodesAndJitter(const Geom::Curve *A, double t) } if (cubic) { std::pair div = cubic->subdivide(t); - std::vector seg1 = div.first.points(), - seg2 = div.second.points(); + std::vector seg1 = div.first.controlPoints(), + seg2 = div.second.controlPoints(); out->moveto(seg1[0]); out->curveto(seg1[1] + point1, seg1[2] + point2, seg1[3] + point3); out->curveto(seg2[1] + point_b1, seg2[2], seg2[3]); diff --git a/src/live_effects/lpe-ruler.cpp b/src/live_effects/lpe-ruler.cpp index fd611c78d..49b5faa2e 100644 --- a/src/live_effects/lpe-ruler.cpp +++ b/src/live_effects/lpe-ruler.cpp @@ -111,7 +111,7 @@ LPERuler::ruler_mark(Geom::Point const &A, Geom::Point const &n, MarkType const break; } - Piecewise > seg(D2(Linear(C[X], D[X]), Linear(C[Y], D[Y]))); + Piecewise > seg(D2(SBasis(C[X], D[X]), SBasis(C[Y], D[Y]))); return seg; } diff --git a/src/live_effects/lpe-show_handles.cpp b/src/live_effects/lpe-show_handles.cpp index 2638f312e..0bc1c4f17 100644 --- a/src/live_effects/lpe-show_handles.cpp +++ b/src/live_effects/lpe-show_handles.cpp @@ -79,9 +79,9 @@ void LPEShowHandles::doBeforeEffect (SPLPEItem const* lpeitem) stroke_width = item->style->stroke_width.computed; } -std::vector LPEShowHandles::doEffect_path (std::vector const & path_in) +Geom::PathVector LPEShowHandles::doEffect_path (Geom::PathVector const & path_in) { - std::vector path_out; + Geom::PathVector path_out; Geom::PathVector const original_pathv = pathv_to_linear_and_cubic_beziers(path_in); if(original_path) { for (unsigned int i=0; i < path_in.size(); i++) { @@ -112,14 +112,14 @@ LPEShowHandles::generateHelperPath(Geom::PathVector result) continue; } //Itreadores - Geom::Path::const_iterator curve_it1 = path_it->begin(); // incoming curve - Geom::Path::const_iterator curve_it2 = ++(path_it->begin()); // outgoing curve - Geom::Path::const_iterator curve_endit = path_it->end_default(); // this determines when the loop has to stop + Geom::Path::iterator curve_it1 = path_it->begin(); // incoming curve + Geom::Path::iterator curve_it2 = ++(path_it->begin()); // outgoing curve + Geom::Path::iterator curve_endit = path_it->end_default(); // this determines when the loop has to stop if (path_it->closed()) { // if the path is closed, maybe we have to stop a bit earlier because the // closing line segment has zerolength. - const Geom::Curve &closingline = path_it->back_closed(); // the closing line segment is always of type + Geom::Curve const &closingline = path_it->back_closed(); // the closing line segment is always of type // Geom::LineSegment. if (are_near(closingline.initialPoint(), closingline.finalPoint())) { // closingline.isDegenerate() did not work, because it only checks for @@ -165,9 +165,7 @@ LPEShowHandles::drawNode(Geom::Point p) char const * svgd; svgd = "M 0.05,0 A 0.05,0.05 0 0 1 0,0.05 0.05,0.05 0 0 1 -0.05,0 0.05,0.05 0 0 1 0,-0.05 0.05,0.05 0 0 1 0.05,0 Z M -0.5,-0.5 0.5,-0.5 0.5,0.5 -0.5,0.5 Z"; Geom::PathVector pathv = sp_svg_read_pathv(svgd); - pathv *= Geom::Rotate::from_degrees(rotate_nodes); - pathv *= Geom::Scale (diameter); - pathv += p; + pathv *= Geom::Rotate::from_degrees(rotate_nodes) * Geom::Scale(diameter) * Geom::Translate(p); outline_path.push_back(pathv[0]); outline_path.push_back(pathv[1]); } @@ -181,8 +179,7 @@ LPEShowHandles::drawHandle(Geom::Point p) char const * svgd; svgd = "M 0.7,0.35 A 0.35,0.35 0 0 1 0.35,0.7 0.35,0.35 0 0 1 0,0.35 0.35,0.35 0 0 1 0.35,0 0.35,0.35 0 0 1 0.7,0.35 Z"; Geom::PathVector pathv = sp_svg_read_pathv(svgd); - pathv *= Geom::Scale (diameter); - pathv += p-Geom::Point(diameter * 0.35,diameter * 0.35); + pathv *= Geom::Scale (diameter) * Geom::Translate(p - Geom::Point(diameter * 0.35,diameter * 0.35)); outline_path.push_back(pathv[0]); } } diff --git a/src/live_effects/lpe-show_handles.h b/src/live_effects/lpe-show_handles.h index 77b28e77a..34390dd32 100644 --- a/src/live_effects/lpe-show_handles.h +++ b/src/live_effects/lpe-show_handles.h @@ -36,7 +36,7 @@ public: protected: - virtual std::vector doEffect_path (std::vector const & path_in); + virtual Geom::PathVector doEffect_path (Geom::PathVector const & path_in); private: diff --git a/src/live_effects/lpe-simplify.cpp b/src/live_effects/lpe-simplify.cpp index 7fc20ede1..265192a17 100644 --- a/src/live_effects/lpe-simplify.cpp +++ b/src/live_effects/lpe-simplify.cpp @@ -164,14 +164,13 @@ LPESimplify::generateHelperPathAndSmooth(Geom::PathVector &result) Geom::PathVector tmp_path; Geom::CubicBezier const *cubic = NULL; for (Geom::PathVector::iterator path_it = result.begin(); path_it != result.end(); ++path_it) { - //Si está vacío... if (path_it->empty()) { continue; } - //Itreadores - Geom::Path::const_iterator curve_it1 = path_it->begin(); // incoming curve - Geom::Path::const_iterator curve_it2 = ++(path_it->begin());// outgoing curve - Geom::Path::const_iterator curve_endit = path_it->end_default(); // this determines when the loop has to stop + + Geom::Path::iterator curve_it1 = path_it->begin(); // incoming curve + Geom::Path::iterator curve_it2 = ++(path_it->begin());// outgoing curve + Geom::Path::iterator curve_endit = path_it->end_default(); // this determines when the loop has to stop SPCurve *nCurve = new SPCurve(); if (path_it->closed()) { // if the path is closed, maybe we have to stop a bit earlier because the @@ -264,8 +263,7 @@ LPESimplify::drawNode(Geom::Point p) char const * svgd; svgd = "M 0.55,0.5 A 0.05,0.05 0 0 1 0.5,0.55 0.05,0.05 0 0 1 0.45,0.5 0.05,0.05 0 0 1 0.5,0.45 0.05,0.05 0 0 1 0.55,0.5 Z M 0,0 1,0 1,1 0,1 Z"; Geom::PathVector pathv = sp_svg_read_pathv(svgd); - pathv *= Geom::Affine(r,0,0,r,0,0); - pathv += p - Geom::Point(0.5*r,0.5*r); + pathv *= Geom::Scale(r) * Geom::Translate(p - Geom::Point(0.5*r,0.5*r)); hp.push_back(pathv[0]); hp.push_back(pathv[1]); } @@ -277,8 +275,7 @@ LPESimplify::drawHandle(Geom::Point p) char const * svgd; svgd = "M 0.7,0.35 A 0.35,0.35 0 0 1 0.35,0.7 0.35,0.35 0 0 1 0,0.35 0.35,0.35 0 0 1 0.35,0 0.35,0.35 0 0 1 0.7,0.35 Z"; Geom::PathVector pathv = sp_svg_read_pathv(svgd); - pathv *= Geom::Affine(r,0,0,r,0,0); - pathv += p - Geom::Point(0.35*r,0.35*r); + pathv *= Geom::Scale(r) * Geom::Translate(p - Geom::Point(0.35*r,0.35*r)); hp.push_back(pathv[0]); } diff --git a/src/live_effects/lpe-skeleton.cpp b/src/live_effects/lpe-skeleton.cpp index c61e9773f..6e4afbe9b 100644 --- a/src/live_effects/lpe-skeleton.cpp +++ b/src/live_effects/lpe-skeleton.cpp @@ -62,10 +62,10 @@ LPESkeleton::doEffect (SPCurve * curve) // spice this up to make the effect actually *do* something! } -std::vector -LPESkeleton::doEffect_path (std::vector const & path_in) +Geom::PathVector +LPESkeleton::doEffect_path (Geom::PathVector const & path_in) { - std::vector path_out; + Geom::PathVector path_out; path_out = path_in; // spice this up to make the effect actually *do* something! diff --git a/src/live_effects/lpe-skeleton.h b/src/live_effects/lpe-skeleton.h index 124d1a4cb..3b45b6978 100644 --- a/src/live_effects/lpe-skeleton.h +++ b/src/live_effects/lpe-skeleton.h @@ -36,8 +36,8 @@ public: // Choose to implement one of the doEffect functions. You can delete or comment out the others. // virtual void doEffect (SPCurve * curve); -// virtual std::vector doEffect_path (std::vector const & path_in); - virtual Geom::Piecewise > doEffect_pwd2 (Geom::Piecewise > const & pwd2_in); +// virtual Geom::PathVector doEffect_path (Geom::PathVector const &path_in); + virtual Geom::Piecewise > doEffect_pwd2 (Geom::Piecewise > const &pwd2_in); /* the knotholder entity classes (if any) can be declared friends */ //friend class Skeleton::KnotHolderEntityMyHandle; diff --git a/src/live_effects/lpe-spiro.cpp b/src/live_effects/lpe-spiro.cpp index 8b4274ab2..eefd25c7d 100644 --- a/src/live_effects/lpe-spiro.cpp +++ b/src/live_effects/lpe-spiro.cpp @@ -10,8 +10,7 @@ #include #include <2geom/pathvector.h> #include <2geom/affine.h> -#include <2geom/bezier-curve.h> -#include <2geom/hvlinesegment.h> +#include <2geom/curves.h> #include "helper/geom-nodetype.h" #include "helper/geom-curves.h" diff --git a/src/live_effects/lpe-tangent_to_curve.cpp b/src/live_effects/lpe-tangent_to_curve.cpp index bce4876af..978ab57fb 100644 --- a/src/live_effects/lpe-tangent_to_curve.cpp +++ b/src/live_effects/lpe-tangent_to_curve.cpp @@ -90,7 +90,7 @@ LPETangentToCurve::doEffect_pwd2 (Geom::Piecewise > const C = ptA - derivA * length_left; D = ptA + derivA * length_right; - output = Piecewise >(D2(Linear(C[X], D[X]), Linear(C[Y], D[Y]))); + output = Piecewise >(D2(SBasis(C[X], D[X]), SBasis(C[Y], D[Y]))); return output; } @@ -135,7 +135,7 @@ KnotHolderEntityAttachPt::knot_set(Geom::Point const &p, Geom::Point const &/*or } Piecewise > pwd2 = paths_to_pw( lpe->pathvector_before_effect ); - double t0 = nearest_point(s, pwd2); + double t0 = nearest_time(s, pwd2); lpe->t_attach.param_set_value(t0); // FIXME: this should not directly ask for updating the item. It should write to SVG, which triggers updating. @@ -149,7 +149,7 @@ KnotHolderEntityLeftEnd::knot_set(Geom::Point const &p, Geom::Point const &/*ori Geom::Point const s = snap_knot_position(p, state); - double lambda = Geom::nearest_point(s, lpe->ptA, lpe->derivA); + double lambda = Geom::nearest_time(s, lpe->ptA, lpe->derivA); lpe->length_left.param_set_value(-lambda); sp_lpe_item_update_patheffect (SP_LPE_ITEM(item), false, true); @@ -162,7 +162,7 @@ KnotHolderEntityRightEnd::knot_set(Geom::Point const &p, Geom::Point const &/*or Geom::Point const s = snap_knot_position(p, state); - double lambda = Geom::nearest_point(s, lpe->ptA, lpe->derivA); + double lambda = Geom::nearest_time(s, lpe->ptA, lpe->derivA); lpe->length_right.param_set_value(lambda); sp_lpe_item_update_patheffect (SP_LPE_ITEM(item), false, true); diff --git a/src/live_effects/lpe-taperstroke.cpp b/src/live_effects/lpe-taperstroke.cpp index 2c74af6d6..a681ad473 100644 --- a/src/live_effects/lpe-taperstroke.cpp +++ b/src/live_effects/lpe-taperstroke.cpp @@ -14,7 +14,6 @@ #include "live_effects/lpe-taperstroke.h" #include <2geom/path.h> -#include <2geom/shape.h> #include <2geom/path.h> #include <2geom/circle.h> #include <2geom/sbasis-to-bezier.h> @@ -193,7 +192,7 @@ Piecewise > stretch_along(Piecewise > pwd2_in, Geom::Path Geom::PathVector LPETaperStroke::doEffect_path(Geom::PathVector const& path_in) { Geom::Path first_cusp = return_at_first_cusp(path_in[0]); - Geom::Path last_cusp = return_at_first_cusp(path_in[0].reverse()); + Geom::Path last_cusp = return_at_first_cusp(path_in[0].reversed()); bool zeroStart = false; // [distance from start taper knot -> start of path] == 0 bool zeroEnd = false; // [distance from end taper knot -> end of path] == 0 @@ -317,7 +316,7 @@ Geom::PathVector LPETaperStroke::doEffect_path(Geom::PathVector const& path_in) if (!metInMiddle) { // append the inside outline of the path (against direction) - throwaway_path = half_outline(pathv_out[1].reverse(), fabs(line_width)/2., miter_limit, static_cast(join_type.get_value())); + throwaway_path = half_outline(pathv_out[1].reversed(), fabs(line_width)/2., miter_limit, static_cast(join_type.get_value())); if (!Geom::are_near(real_path.finalPoint(), throwaway_path.initialPoint()) && real_path.size() >= 1) { real_path.appendNew(throwaway_path.initialPoint()); @@ -486,7 +485,7 @@ void KnotHolderEntityAttachBegin::knot_set(Geom::Point const &p, Geom::Point con Geom::Path p_in = return_at_first_cusp(pathv[0]); pwd2.concat(p_in.toPwSb()); - double t0 = nearest_point(s, pwd2); + double t0 = nearest_time(s, pwd2); lpe->attach_start.param_set_value(t0); // FIXME: this should not directly ask for updating the item. It should write to SVG, which triggers updating. @@ -511,10 +510,10 @@ void KnotHolderEntityAttachEnd::knot_set(Geom::Point const &p, Geom::Point const return; } Geom::PathVector pathv = lpe->pathvector_before_effect; - Geom::Path p_in = return_at_first_cusp(pathv[0].reverse()); + Geom::Path p_in = return_at_first_cusp(pathv[0].reversed()); Piecewise > pwd2 = p_in.toPwSb(); - double t0 = nearest_point(s, pwd2); + double t0 = nearest_time(s, pwd2); lpe->attach_end.param_set_value(t0); sp_lpe_item_update_patheffect (SP_LPE_ITEM(item), false, true); diff --git a/src/live_effects/lpe-test-doEffect-stack.cpp b/src/live_effects/lpe-test-doEffect-stack.cpp index c6787aae1..2bcd4c136 100644 --- a/src/live_effects/lpe-test-doEffect-stack.cpp +++ b/src/live_effects/lpe-test-doEffect-stack.cpp @@ -47,14 +47,14 @@ LPEdoEffectStackTest::doEffect (SPCurve * curve) } } -std::vector -LPEdoEffectStackTest::doEffect_path (std::vector const & path_in) +Geom::PathVector +LPEdoEffectStackTest::doEffect_path (Geom::PathVector const &path_in) { if (step >= 2) { return Effect::doEffect_path(path_in); } else { // return here - std::vector path_out = path_in; + Geom::PathVector path_out = path_in; return path_out; } } diff --git a/src/live_effects/lpe-test-doEffect-stack.h b/src/live_effects/lpe-test-doEffect-stack.h index fa3ee09be..208a345c6 100644 --- a/src/live_effects/lpe-test-doEffect-stack.h +++ b/src/live_effects/lpe-test-doEffect-stack.h @@ -27,7 +27,7 @@ public: virtual ~LPEdoEffectStackTest(); virtual void doEffect (SPCurve * curve); - virtual std::vector doEffect_path (std::vector const & path_in); + virtual Geom::PathVector doEffect_path (Geom::PathVector const & path_in); virtual Geom::Piecewise > doEffect_pwd2 (Geom::Piecewise > const & pwd2_in); private: diff --git a/src/live_effects/lpe-vonkoch.cpp b/src/live_effects/lpe-vonkoch.cpp index b52816c87..7b424e019 100644 --- a/src/live_effects/lpe-vonkoch.cpp +++ b/src/live_effects/lpe-vonkoch.cpp @@ -76,12 +76,12 @@ LPEVonKoch::~LPEVonKoch() } -std::vector -LPEVonKoch::doEffect_path (std::vector const & path_in) +Geom::PathVector +LPEVonKoch::doEffect_path (Geom::PathVector const & path_in) { using namespace Geom; - std::vector generating_path = generator.get_pathvector(); + Geom::PathVector generating_path = generator.get_pathvector(); if (generating_path.empty()) { return path_in; @@ -148,15 +148,15 @@ LPEVonKoch::doEffect_path (std::vector const & path_in) } //Generate path: - std::vector pathi = path_in; - std::vector path_out = path_in; + Geom::PathVector pathi = path_in; + Geom::PathVector path_out = path_in; for (unsigned i = 0; i(); + path_out = Geom::PathVector(); complexity = 0; } for (unsigned j = 0; j const & path_in) hp_vec.push_back(refbox_as_vect); } //Draw the transformed boxes - std::vector generating_path = generator.get_pathvector(); + Geom::PathVector generating_path = generator.get_pathvector(); for (unsigned i=0;i paths = ref_path.get_pathvector(); + Geom::PathVector paths = ref_path.get_pathvector(); Geom::Point A,B; if (paths.empty()||paths.front().size()==0){ //FIXME: a path is used as ref instead of 2 points to work around path/point param incompatibility bug. @@ -258,7 +258,7 @@ LPEVonKoch::doBeforeEffect (SPLPEItem const* lpeitem) if (paths.size()!=1||paths.front().size()!=1){ Geom::Path tmp_path(A); tmp_path.appendNew(B); - std::vector tmp_pathv; + Geom::PathVector tmp_pathv; tmp_pathv.push_back(tmp_path); ref_path.set_new_value(tmp_pathv,true); } @@ -282,7 +282,7 @@ LPEVonKoch::resetDefaults(SPItem const* item) B[Geom::X] = boundingbox_X.max(); B[Geom::Y] = boundingbox_Y.middle(); - std::vector paths,refpaths; + Geom::PathVector paths,refpaths; Geom::Path path = Geom::Path(A); path.appendNew(B); @@ -298,7 +298,7 @@ LPEVonKoch::resetDefaults(SPItem const* item) //refA[Geom::Y] = boundingbox_Y.middle(); //refB[Geom::X] = boundingbox_X.max(); //refB[Geom::Y] = boundingbox_Y.middle(); - //std::vector paths; + //Geom::PathVector paths; //Geom::Path path = Geom::Path( (Point) refA); //path.appendNew( (Point) refB ); //paths.push_back(path * Affine(1./3,0,0,1./3, refA[X]*2./3, refA[Y]*2./3 + boundingbox_Y.extent()/2)); diff --git a/src/live_effects/lpe-vonkoch.h b/src/live_effects/lpe-vonkoch.h index 7dff2be52..bffbebd54 100644 --- a/src/live_effects/lpe-vonkoch.h +++ b/src/live_effects/lpe-vonkoch.h @@ -49,7 +49,7 @@ public: LPEVonKoch(LivePathEffectObject *lpeobject); virtual ~LPEVonKoch(); - virtual std::vector doEffect_path (std::vector const & path_in); + virtual Geom::PathVector doEffect_path (Geom::PathVector const & path_in); virtual void resetDefaults(SPItem const* item); diff --git a/src/live_effects/parameter/filletchamferpointarray.cpp b/src/live_effects/parameter/filletchamferpointarray.cpp index e9d375b93..fb6cb8e07 100644 --- a/src/live_effects/parameter/filletchamferpointarray.cpp +++ b/src/live_effects/parameter/filletchamferpointarray.cpp @@ -205,7 +205,7 @@ void FilletChamferPointArrayParam::recalculate_controlpoints_for_new_pwd2( //delete temp vector std::vector().swap(tmp); if (last_pathv.size() > counterPaths) { - last_pathv[counterPaths] = last_pathv[counterPaths].reverse(); + last_pathv[counterPaths] = last_pathv[counterPaths].reversed(); } } else { if (last_pathv.size() > counterPaths) { @@ -223,7 +223,7 @@ void FilletChamferPointArrayParam::recalculate_controlpoints_for_new_pwd2( } double xPos = 0; if (_vector[1][X] > 0) { - xPos = nearest_point(curve_it1->initialPoint(), pwd2_in); + xPos = nearest_time(curve_it1->initialPoint(), pwd2_in); } if (nodetype == NODE_CUSP) { result.push_back(Point(xPos, 1)); @@ -234,7 +234,7 @@ void FilletChamferPointArrayParam::recalculate_controlpoints_for_new_pwd2( double xPos = _vector[counter - offset][X]; if (_vector.size() <= (unsigned)(counter - offset)) { if (_vector[1][X] > 0) { - xPos = nearest_point(curve_it1->initialPoint(), pwd2_in); + xPos = nearest_time(curve_it1->initialPoint(), pwd2_in); } else { xPos = 0; } @@ -403,8 +403,8 @@ void FilletChamferPointArrayParam::updateCanvasIndicators() Geom::Affine aff = Geom::Affine(); aff *= Geom::Scale(helper_size); aff *= Geom::Rotate(ray1.angle() - deg_to_rad(270)); + aff *= Geom::Translate(last_pwd2[i].valueAt(Xvalue)); pathv *= aff; - pathv += last_pwd2[i].valueAt(Xvalue); hp.push_back(pathv[0]); hp.push_back(pathv[1]); i++; @@ -420,7 +420,7 @@ void FilletChamferPointArrayParam::addCanvasIndicators( double FilletChamferPointArrayParam::rad_to_len(int index, double rad) { double len = 0; - std::vector subpaths = path_from_piecewise(last_pwd2, 0.1); + Geom::PathVector subpaths = path_from_piecewise(last_pwd2, 0.1); std::pair positions = get_positions(index, subpaths); D2 A = last_pwd2[last_index(index, subpaths)]; if(positions.second != 0){ @@ -438,7 +438,7 @@ double FilletChamferPointArrayParam::rad_to_len(int index, double rad) Geom::Crossings cs = Geom::crossings(p0, p1); if(cs.size() > 0){ Point cp =p0(cs[0].ta); - double p0pt = nearest_point(cp, B); + double p0pt = nearest_time(cp, B); len = time_to_len(index,p0pt); } else { if(rad < 0){ @@ -453,7 +453,7 @@ double FilletChamferPointArrayParam::len_to_rad(int index, double len) double rad = 0; double tmp_len = _vector[index][X]; _vector[index] = Geom::Point(len,_vector[index][Y]); - std::vector subpaths = path_from_piecewise(last_pwd2, 0.1); + Geom::PathVector subpaths = path_from_piecewise(last_pwd2, 0.1); std::pair positions = get_positions(index, subpaths); Piecewise > u; u.push_cut(0); @@ -492,7 +492,7 @@ double FilletChamferPointArrayParam::len_to_rad(int index, double len) return rad * -1; } -std::vector FilletChamferPointArrayParam::get_times(int index, std::vector subpaths, bool last) +std::vector FilletChamferPointArrayParam::get_times(int index, Geom::PathVector subpaths, bool last) { const double tolerance = 0.001; const double gapHelper = 0.00001; @@ -541,7 +541,7 @@ std::vector FilletChamferPointArrayParam::get_times(int index, std::vect return out; } -std::pair FilletChamferPointArrayParam::get_positions(int index, std::vector subpaths) +std::pair FilletChamferPointArrayParam::get_positions(int index, Geom::PathVector subpaths) { int counter = -1; std::size_t first = 0; @@ -583,7 +583,7 @@ std::pair FilletChamferPointArrayParam::get_positions( return out; } -int FilletChamferPointArrayParam::last_index(int index, std::vector subpaths) +int FilletChamferPointArrayParam::last_index(int index, Geom::PathVector subpaths) { int counter = -1; bool inSubpath = false; @@ -709,9 +709,9 @@ void FilletChamferPointArrayParamKnotHolderEntity::knot_set(Point const &p, return; } Piecewise > const &pwd2 = _pparam->get_pwd2(); - double t = nearest_point(p, pwd2[_index]); + double t = nearest_time(p, pwd2[_index]); Geom::Point const s = snap_knot_position(pwd2[_index].valueAt(t), state); - t = nearest_point(s, pwd2[_index]); + t = nearest_time(s, pwd2[_index]); if (t == 1) { t = 0.9999; } @@ -803,7 +803,7 @@ void FilletChamferPointArrayParamKnotHolderEntity::knot_click(guint state) if(xModified < 0 && !_pparam->use_distance){ xModified = _pparam->len_to_rad(_index, _pparam->_vector.at(_index).x()); } - std::vector subpaths = path_from_piecewise(_pparam->last_pwd2, 0.1); + Geom::PathVector subpaths = path_from_piecewise(_pparam->last_pwd2, 0.1); std::pair positions = _pparam->get_positions(_index, subpaths); D2 A = _pparam->last_pwd2[_pparam->last_index(_index, subpaths)]; if(positions.second != 0){ diff --git a/src/live_effects/parameter/filletchamferpointarray.h b/src/live_effects/parameter/filletchamferpointarray.h index 7849d5afb..bc05ecfc4 100644 --- a/src/live_effects/parameter/filletchamferpointarray.h +++ b/src/live_effects/parameter/filletchamferpointarray.h @@ -47,9 +47,9 @@ public: virtual double len_to_rad(int index, double len); virtual double len_to_time(int index, double len); virtual double time_to_len(int index, double time); - virtual std::pair get_positions(int index, std::vector subpaths); - virtual int last_index(int index, std::vector subpaths); - std::vector get_times(int index, std::vector subpaths, bool last); + virtual std::pair get_positions(int index, Geom::PathVector subpaths); + virtual int last_index(int index, Geom::PathVector subpaths); + std::vector get_times(int index, Geom::PathVector subpaths, bool last); virtual void set_helper_size(int hs); virtual void set_use_distance(bool use_knot_distance); virtual void set_chamfer_steps(int value_chamfer_steps); diff --git a/src/live_effects/parameter/originalpatharray.h b/src/live_effects/parameter/originalpatharray.h index 6c792613f..296c0f7f7 100644 --- a/src/live_effects/parameter/originalpatharray.h +++ b/src/live_effects/parameter/originalpatharray.h @@ -40,7 +40,7 @@ public: } gchar *href; URIReference ref; - std::vector _pathvector; + Geom::PathVector _pathvector; bool reversed; sigc::connection linked_changed_connection; diff --git a/src/live_effects/parameter/path.cpp b/src/live_effects/parameter/path.cpp index ba95affd9..dd6b54f7c 100644 --- a/src/live_effects/parameter/path.cpp +++ b/src/live_effects/parameter/path.cpp @@ -77,7 +77,7 @@ PathParam::~PathParam() g_free(defvalue); } -std::vector const & +Geom::PathVector const & PathParam::get_pathvector() const { return _pathvector; @@ -255,7 +255,7 @@ PathParam::param_transform_multiply(Geom::Affine const& postmul, bool /*set*/) } /* - * See comments for set_new_value(std::vector). + * See comments for set_new_value(Geom::PathVector). */ void PathParam::set_new_value (Geom::Piecewise > const & newpath, bool write_to_svg) @@ -291,7 +291,7 @@ PathParam::set_new_value (Geom::Piecewise > const & newpa * The new path data is not written to SVG. This method will emit the signal_path_changed signal. */ void -PathParam::set_new_value (std::vector const &newpath, bool write_to_svg) +PathParam::set_new_value (Geom::PathVector const &newpath, bool write_to_svg) { remove_link(); _pathvector = newpath; diff --git a/src/live_effects/parameter/path.h b/src/live_effects/parameter/path.h index 112a1ea13..d2dddbe97 100644 --- a/src/live_effects/parameter/path.h +++ b/src/live_effects/parameter/path.h @@ -31,7 +31,7 @@ public: const gchar * default_value = "M0,0 L1,1"); virtual ~PathParam(); - std::vector const & get_pathvector() const; + Geom::PathVector const & get_pathvector() const; Geom::Piecewise > const & get_pwd2(); virtual Gtk::Widget * param_newWidget(); @@ -41,7 +41,7 @@ public: virtual void param_set_default(); void param_set_and_write_default(); - void set_new_value (std::vector const &newpath, bool write_to_svg); + void set_new_value (Geom::PathVector const &newpath, bool write_to_svg); void set_new_value (Geom::Piecewise > const &newpath, bool write_to_svg); virtual void param_editOncanvas(SPItem * item, SPDesktop * dt); @@ -59,7 +59,7 @@ public: void on_paste_button_click(); protected: - std::vector _pathvector; // this is primary data storage, since it is closest to SVG. + Geom::PathVector _pathvector; // this is primary data storage, since it is closest to SVG. Geom::Piecewise > _pwd2; // secondary, hence the bool must_recalculate_pwd2 bool must_recalculate_pwd2; // set when _pathvector was updated, but _pwd2 not diff --git a/src/live_effects/parameter/powerstrokepointarray.cpp b/src/live_effects/parameter/powerstrokepointarray.cpp index e0c2f4c68..c61e8f9cb 100644 --- a/src/live_effects/parameter/powerstrokepointarray.cpp +++ b/src/live_effects/parameter/powerstrokepointarray.cpp @@ -79,7 +79,7 @@ PowerStrokePointArrayParam::recalculate_controlpoints_for_new_pwd2(Geom::Piecewi Geom::Point pt = _vector[i]; Geom::Point position = last_pwd2.valueAt(pt[Geom::X]) + pt[Geom::Y] * last_pwd2_normal.valueAt(pt[Geom::X]); - double t = nearest_point(position, pwd2_in); + double t = nearest_time(position, pwd2_in); double offset = dot(position - pwd2_in.valueAt(t), normal.valueAt(t)); _vector[i] = Geom::Point(t, offset); } @@ -161,7 +161,7 @@ PowerStrokePointArrayParamKnotHolderEntity::knot_set(Geom::Point const &p, Geom: Piecewise > const & n = _pparam->get_pwd2_normal(); Geom::Point const s = snap_knot_position(p, state); - double t = nearest_point(s, pwd2); + double t = nearest_time(s, pwd2); double offset = dot(s - pwd2.valueAt(t), n.valueAt(t)); _pparam->_vector.at(_index) = Geom::Point(t, offset); sp_lpe_item_update_patheffect(SP_LPE_ITEM(item), false, false); diff --git a/src/object-snapper.cpp b/src/object-snapper.cpp index 338f91463..3f8d4a662 100644 --- a/src/object-snapper.cpp +++ b/src/object-snapper.cpp @@ -516,14 +516,14 @@ void Inkscape::ObjectSnapper::_snapPaths(IntermSnapResults &isr, for(Geom::PathVector::iterator it_pv = (it_p->path_vector)->begin(); it_pv != (it_p->path_vector)->end(); ++it_pv) { // Find a nearest point for each curve within this path // n curves will return n time values with 0 <= t <= 1 - std::vector anp = (*it_pv).nearestPointPerCurve(p_doc); + std::vector anp = (*it_pv).nearestTimePerCurve(p_doc); //std::cout << "#nearest points = " << anp.size() << " | p = " << p.getPoint() << std::endl; // Now we will examine each of the nearest points, and determine whether it's within snapping range and if we should snap to it std::vector::const_iterator np = anp.begin(); unsigned int index = 0; for (; np != anp.end(); ++np, index++) { - Geom::Curve const *curve = &((*it_pv).at_index(index)); + Geom::Curve const *curve = &(it_pv->at(index)); Geom::Point const sp_doc = curve->pointAt(*np); //dt->snapindicator->set_new_debugging_point(sp_doc*dt->doc2dt()); bool c1 = true; @@ -622,7 +622,7 @@ void Inkscape::ObjectSnapper::_snapPathsConstrained(IntermSnapResults &isr, // PS: Because the paths we're about to snap to are all expressed relative to document coordinate system, we will have // to convert the snapper coordinates from the desktop coordinates to document coordinates - std::vector constraint_path; + Geom::PathVector constraint_path; if (c.isCircular()) { Geom::Circle constraint_circle(dt->dt2doc(c.getPoint()), c.getRadius()); constraint_circle.getPath(constraint_path); diff --git a/src/sp-conn-end.cpp b/src/sp-conn-end.cpp index 3e5398ced..7aace1849 100644 --- a/src/sp-conn-end.cpp +++ b/src/sp-conn-end.cpp @@ -109,7 +109,7 @@ static bool try_get_intersect_point_with_item(SPPath* conn, SPItem* item, if (!at_start) { // connectors are actually a single path, so consider the first element from a Geom::PathVector - conn_pv[0] = conn_pv[0].reverse(); + conn_pv[0] = conn_pv[0].reversed(); } // We start with the intersection point at the beginning of the path diff --git a/src/sp-path.cpp b/src/sp-path.cpp index 42883588b..cabed0467 100644 --- a/src/sp-path.cpp +++ b/src/sp-path.cpp @@ -28,8 +28,7 @@ #include "display/curve.h" #include <2geom/pathvector.h> -#include <2geom/bezier-curve.h> -#include <2geom/hvlinesegment.h> +#include <2geom/curves.h> #include "helper/geom-curves.h" #include "svg/svg.h" diff --git a/src/sp-polygon.cpp b/src/sp-polygon.cpp index af71280d5..ced485f12 100644 --- a/src/sp-polygon.cpp +++ b/src/sp-polygon.cpp @@ -16,8 +16,7 @@ #include "display/curve.h" #include #include <2geom/pathvector.h> -#include <2geom/bezier-curve.h> -#include <2geom/hvlinesegment.h> +#include <2geom/curves.h> #include "helper/geom-curves.h" #include "svg/stringstream.h" #include "xml/repr.h" diff --git a/src/splivarot.cpp b/src/splivarot.cpp index 46279cbce..95bd179f9 100644 --- a/src/splivarot.cpp +++ b/src/splivarot.cpp @@ -305,8 +305,7 @@ sp_pathvector_boolop(Geom::PathVector const &pathva, Geom::PathVector const &pat delete originaux[0]; delete originaux[1]; - std::vector outres = Geom::parse_svg_path(res->svg_dump_path()); - + Geom::PathVector outres = Geom::parse_svg_path(res->svg_dump_path()); delete res; return outres; @@ -315,7 +314,7 @@ sp_pathvector_boolop(Geom::PathVector const &pathva, Geom::PathVector const &pat /* Convert from a livarot path to a 2geom PathVector */ Geom::PathVector pathliv_to_pathvector(Path *pathliv){ - std::vector outres = Geom::parse_svg_path(pathliv->svg_dump_path()); + Geom::PathVector outres = Geom::parse_svg_path(pathliv->svg_dump_path()); return outres; } @@ -2273,15 +2272,11 @@ Ancetre(Inkscape::XML::Node *a, Inkscape::XML::Node *who) } // derived from Path_for_item -// there must be some other way to load dest directly from epathv, without going through pathv... Path * Path_for_pathvector(Geom::PathVector const &epathv) { - Geom::PathVector *pathv = new Geom::PathVector; - std::copy(epathv.begin(), epathv.end(), std::back_inserter(*pathv)); - Path *dest = new Path; - dest->LoadPathVector(*pathv); + dest->LoadPathVector(epathv); delete pathv; return dest; diff --git a/src/svg/svg-path.cpp b/src/svg/svg-path.cpp index 9ba3c0ebd..8f839eca5 100644 --- a/src/svg/svg-path.cpp +++ b/src/svg/svg-path.cpp @@ -61,10 +61,17 @@ Geom::PathVector sp_svg_read_pathv(char const * str) } static void sp_svg_write_curve(Inkscape::SVG::PathString & str, Geom::Curve const * c) { + // TODO: this code needs to removed and replaced by appropriate path sink if(Geom::LineSegment const *line_segment = dynamic_cast(c)) { // don't serialize stitch segments if (!dynamic_cast(c)) { - str.lineTo( (*line_segment)[1][0], (*line_segment)[1][1] ); + if (line_segment->initialPoint()[Geom::X] == line_segment->finalPoint()[Geom::X]) { + str.verticalLineTo( line_segment->finalPoint()[Geom::Y] ); + } else if (line_segment->initialPoint()[Geom::Y] == line_segment->finalPoint()[Geom::Y]) { + str.horizontalLineTo( line_segment->finalPoint()[Geom::X] ); + } else { + str.lineTo( (*line_segment)[1][0], (*line_segment)[1][1] ); + } } } else if(Geom::QuadraticBezier const *quadratic_bezier = dynamic_cast(c)) { @@ -81,12 +88,6 @@ static void sp_svg_write_curve(Inkscape::SVG::PathString & str, Geom::Curve cons Geom::rad_to_deg(svg_elliptical_arc->rotationAngle()), svg_elliptical_arc->largeArc(), svg_elliptical_arc->sweep(), svg_elliptical_arc->finalPoint() ); - } - else if(Geom::HLineSegment const *hline_segment = dynamic_cast(c)) { - str.horizontalLineTo( hline_segment->finalPoint()[0] ); - } - else if(Geom::VLineSegment const *vline_segment = dynamic_cast(c)) { - str.verticalLineTo( vline_segment->finalPoint()[1] ); } else { //this case handles sbasis as well as all other curve types Geom::Path sbasis_path = Geom::cubicbezierpath_from_sbasis(c->toSBasis(), 0.1); diff --git a/src/ui/tool/node.cpp b/src/ui/tool/node.cpp index aa5365265..ea8b53991 100644 --- a/src/ui/tool/node.cpp +++ b/src/ui/tool/node.cpp @@ -356,8 +356,8 @@ void Handle::dragged(Geom::Point &new_pos, GdkEventMotion *event) Geom::Line perp_line(parent_pos, parent_pos + Geom::rot90(origin - parent_pos)); Geom::Point snap_pos = parent_pos + Geom::constrain_angle( Geom::Point(0,0), new_pos - parent_pos, snaps, Geom::Point(1,0)); - Geom::Point orig_pos = original_line.pointAt(original_line.nearestPoint(new_pos)); - Geom::Point perp_pos = perp_line.pointAt(perp_line.nearestPoint(new_pos)); + Geom::Point orig_pos = original_line.pointAt(original_line.nearestTime(new_pos)); + Geom::Point perp_pos = perp_line.pointAt(perp_line.nearestTime(new_pos)); Geom::Point result = snap_pos; ctrl_constraint = Inkscape::Snapper::SnapConstraint(parent_pos, parent_pos - snap_pos); @@ -1567,6 +1567,13 @@ NodeList::iterator NodeList::before(double t, double *fracpart) return ret; } +NodeList::iterator NodeList::before(Geom::PathPosition const &pvp) +{ + iterator ret = begin(); + std::advance(ret, pvp.curve_index); + return ret; +} + NodeList::iterator NodeList::insert(iterator pos, Node *x) { ListNode *ins = pos._node; diff --git a/src/ui/tool/node.h b/src/ui/tool/node.h index 101af4817..5c907910b 100644 --- a/src/ui/tool/node.h +++ b/src/ui/tool/node.h @@ -406,9 +406,13 @@ public: void setClosed(bool c) { _closed = c; } iterator before(double t, double *fracpart = NULL); + iterator before(Geom::PathPosition const &pvp); const_iterator before(double t, double *fracpart = NULL) const { return const_iterator(before(t, fracpart)._node); } + const_iterator before(Geom::PathPosition const &pvp) const { + return const_iterator(before(pvp)._node); + } // list operations diff --git a/src/ui/tool/path-manipulator.cpp b/src/ui/tool/path-manipulator.cpp index 6b0c95f68..2356e60bf 100644 --- a/src/ui/tool/path-manipulator.cpp +++ b/src/ui/tool/path-manipulator.cpp @@ -996,7 +996,7 @@ NodeList::iterator PathManipulator::subdivideSegment(NodeList::iterator first, d Geom::CubicBezier temp(first->position(), first->front()->position(), second->back()->position(), second->position()); std::pair div = temp.subdivide(t); - std::vector seg1 = div.first.points(), seg2 = div.second.points(); + std::vector seg1 = div.first.controlPoints(), seg2 = div.second.controlPoints(); // set new handle positions Node *n = new Node(_multi_path_manipulator._path_data.node_data, seg2[0]); @@ -1141,7 +1141,7 @@ void PathManipulator::_createControlPointsFromGeometry() pathv *= (_edit_transform * _i2d_transform); // in this loop, we know that there are no zero-segment subpaths - for (Geom::PathVector::const_iterator pit = pathv.begin(); pit != pathv.end(); ++pit) { + for (Geom::PathVector::iterator pit = pathv.begin(); pit != pathv.end(); ++pit) { // prepare new subpath SubpathPtr subpath(new NodeList(_subpaths)); _subpaths.push_back(subpath); @@ -1151,7 +1151,7 @@ void PathManipulator::_createControlPointsFromGeometry() Geom::Curve const &cseg = pit->back_closed(); bool fuse_ends = pit->closed() && Geom::are_near(cseg.initialPoint(), cseg.finalPoint()); - for (Geom::Path::const_iterator cit = pit->begin(); cit != pit->end_open(); ++cit) { + for (Geom::Path::iterator cit = pit->begin(); cit != pit->end_open(); ++cit) { Geom::Point pos = cit->finalPoint(); Node *current_node; // if the closing segment is degenerate and the path is closed, we need to move @@ -1271,7 +1271,7 @@ double PathManipulator::_bsplineHandlePosition(Handle *h, Handle *h2) line_inside_nodes->moveto(n->position()); line_inside_nodes->lineto(next_node->position()); if(!are_near(h->position(), n->position())){ - pos = Geom::nearest_point(Geom::Point(h->position()[X] - HANDLE_CUBIC_GAP, h->position()[Y] - HANDLE_CUBIC_GAP), *line_inside_nodes->first_segment()); + pos = Geom::nearest_time(Geom::Point(h->position()[X] - HANDLE_CUBIC_GAP, h->position()[Y] - HANDLE_CUBIC_GAP), *line_inside_nodes->first_segment()); } } if (pos == NO_POWER && !h2){ @@ -1425,7 +1425,7 @@ void PathManipulator::_updateOutline() Geom::PathVector arrows; for (Geom::PathVector::iterator i = pv.begin(); i != pv.end(); ++i) { Geom::Path &path = *i; - for (Geom::Path::const_iterator j = path.begin(); j != path.end_default(); ++j) { + for (Geom::Path::iterator j = path.begin(); j != path.end_default(); ++j) { Geom::Point at = j->pointAt(0.5); Geom::Point ut = j->unitTangentAt(0.5); // rotate the point @@ -1647,23 +1647,24 @@ void PathManipulator::_updateDragPoint(Geom::Point const &evp) { Geom::Affine to_desktop = _edit_transform * _i2d_transform; Geom::PathVector pv = _spcurve->get_pathvector(); - boost::optional pvp - = Geom::nearestPoint(pv, _desktop->w2d(evp) * to_desktop.inverse()); - if (!pvp) return; - Geom::Point nearest_point = _desktop->d2w(pv.at(pvp->path_nr).pointAt(pvp->t) * to_desktop); + if (pv.empty()) return; + + boost::optional pvp = + pv.nearestPosition(_desktop->w2d(evp) * to_desktop.inverse()); + Geom::Point nearest_pt = _desktop->d2w(pv.pointAt(*pvp) * to_desktop); - double fracpart; + double fracpart = pvp->t; std::list::iterator spi = _subpaths.begin(); - for (unsigned i = 0; i < pvp->path_nr; ++i, ++spi) {} - NodeList::iterator first = (*spi)->before(pvp->t, &fracpart); + for (unsigned i = 0; i < pvp->path_index; ++i, ++spi) {} + NodeList::iterator first = (*spi)->before(pvp->asPathPosition()); double stroke_tolerance = _getStrokeTolerance(); if (first && first.next() && fracpart != 0.0 && - Geom::distance(evp, nearest_point) < stroke_tolerance) + Geom::distance(evp, nearest_pt) < stroke_tolerance) { _dragpoint->setVisible(true); - _dragpoint->setPosition(_desktop->w2d(nearest_point)); + _dragpoint->setPosition(_desktop->w2d(nearest_pt)); _dragpoint->setSize(2 * stroke_tolerance); _dragpoint->setTimeValue(fracpart); _dragpoint->setIterator(first); diff --git a/src/ui/tools/gradient-tool.cpp b/src/ui/tools/gradient-tool.cpp index b27859ebb..61baa7d66 100644 --- a/src/ui/tools/gradient-tool.cpp +++ b/src/ui/tools/gradient-tool.cpp @@ -207,7 +207,7 @@ sp_gradient_context_is_over_line (GradientTool *rc, SPItem *item, Geom::Point ev SPCtrlLine* line = SP_CTRLLINE(item); Geom::LineSegment ls(line->s, line->e); - Geom::Point nearest = ls.pointAt(ls.nearestPoint(rc->mousepoint_doc)); + Geom::Point nearest = ls.pointAt(ls.nearestTime(rc->mousepoint_doc)); double dist_screen = Geom::L2 (rc->mousepoint_doc - nearest) * desktop->current_zoom(); double tolerance = (double) SP_EVENT_CONTEXT(rc)->tolerance; diff --git a/src/ui/tools/mesh-tool.cpp b/src/ui/tools/mesh-tool.cpp index 67ed7aef1..86d816e85 100644 --- a/src/ui/tools/mesh-tool.cpp +++ b/src/ui/tools/mesh-tool.cpp @@ -275,7 +275,7 @@ sp_mesh_context_is_over_line (MeshTool *rc, SPItem *item, Geom::Point event_p) SPCtrlCurve *curve = SP_CTRLCURVE(item); Geom::BezierCurveN<3> b( curve->p0, curve->p1, curve->p2, curve->p3 ); - Geom::Coord coord = b.nearestPoint( rc->mousepoint_doc ); // Coord == double + Geom::Coord coord = b.nearestTime( rc->mousepoint_doc ); // Coord == double Geom::Point nearest = b( coord ); double dist_screen = Geom::L2 (rc->mousepoint_doc - nearest) * desktop->current_zoom(); diff --git a/src/ui/tools/pen-tool.cpp b/src/ui/tools/pen-tool.cpp index daffc7032..3eb838089 100644 --- a/src/ui/tools/pen-tool.cpp +++ b/src/ui/tools/pen-tool.cpp @@ -57,8 +57,7 @@ #include #include <2geom/pathvector.h> #include <2geom/affine.h> -#include <2geom/bezier-curve.h> -#include <2geom/hvlinesegment.h> +#include <2geom/curves.h> #include "helper/geom-nodetype.h" #include "helper/geom-curves.h" @@ -71,7 +70,7 @@ #define INKSCAPE_LPE_BSPLINE_C #include "live_effects/lpe-bspline.h" -#include <2geom/nearest-point.h> +#include <2geom/nearest-time.h> #include "live_effects/effect.h" @@ -1522,7 +1521,7 @@ void PenTool::_bsplineSpiroMotion(bool shift){ Geom::D2< Geom::SBasis > SBasisweight_power; weight_power->moveto(tmp_curve ->last_segment()->finalPoint()); weight_power->lineto(tmp_curve ->last_segment()->initialPoint()); - float WP = Geom::nearest_point((*cubic)[2],*weight_power->first_segment()); + float WP = Geom::nearest_time((*cubic)[2],*weight_power->first_segment()); weight_power->reset(); weight_power->moveto(this->red_curve->last_segment()->initialPoint()); weight_power->lineto(this->red_curve->last_segment()->finalPoint()); @@ -1744,7 +1743,7 @@ void PenTool::_bsplineSpiroBuild() //from LPE BSPLINE: void PenTool::_bsplineDoEffect(SPCurve * curve) { - const double NO_POWER = 0.0; + //const double NO_POWER = 0.0; const double DEFAULT_START_POWER = 0.3334; const double DEFAULT_END_POWER = 0.6667; if (curve->get_segment_count() < 1) { @@ -1798,12 +1797,12 @@ void PenTool::_bsplineDoEffect(SPCurve * curve) if(are_near((*cubic)[1],(*cubic)[0]) && !are_near((*cubic)[2],(*cubic)[3])) { point_at1 = sbasis_in.valueAt(DEFAULT_START_POWER); } else { - point_at1 = sbasis_in.valueAt(Geom::nearest_point((*cubic)[1], *in->first_segment())); + point_at1 = sbasis_in.valueAt(Geom::nearest_time((*cubic)[1], *in->first_segment())); } if(are_near((*cubic)[2],(*cubic)[3]) && !are_near((*cubic)[1],(*cubic)[0])) { point_at2 = sbasis_in.valueAt(DEFAULT_END_POWER); } else { - point_at2 = sbasis_in.valueAt(Geom::nearest_point((*cubic)[2], *in->first_segment())); + point_at2 = sbasis_in.valueAt(Geom::nearest_time((*cubic)[2], *in->first_segment())); } } else { point_at1 = in->first_segment()->initialPoint(); @@ -1821,7 +1820,7 @@ void PenTool::_bsplineDoEffect(SPCurve * curve) if(are_near((*cubic)[1],(*cubic)[0]) && !are_near((*cubic)[2],(*cubic)[3])) { next_point_at1 = sbasis_in.valueAt(DEFAULT_START_POWER); } else { - next_point_at1 = sbasis_out.valueAt(Geom::nearest_point((*cubic)[1], *out->first_segment())); + next_point_at1 = sbasis_out.valueAt(Geom::nearest_time((*cubic)[1], *out->first_segment())); } } else { next_point_at1 = out->first_segment()->initialPoint(); @@ -1838,7 +1837,7 @@ void PenTool::_bsplineDoEffect(SPCurve * curve) cubic = dynamic_cast(&*path_it->begin()); if (cubic) { line_helper->moveto(sbasis_start.valueAt( - Geom::nearest_point((*cubic)[1], *start->first_segment()))); + Geom::nearest_time((*cubic)[1], *start->first_segment()))); } else { line_helper->moveto(start->first_segment()->initialPoint()); } @@ -1852,7 +1851,7 @@ void PenTool::_bsplineDoEffect(SPCurve * curve) cubic = dynamic_cast(&*curve_it1); if (cubic) { line_helper->lineto(sbasis_end.valueAt( - Geom::nearest_point((*cubic)[2], *end->first_segment()))); + Geom::nearest_time((*cubic)[2], *end->first_segment()))); } else { line_helper->lineto(end->first_segment()->finalPoint()); } -- cgit v1.2.3 From 5f42b9187cc50cdc8407e31752f2ae682e6641a8 Mon Sep 17 00:00:00 2001 From: Tavmjong Bah Date: Tue, 28 Apr 2015 16:26:17 +0200 Subject: Save original text in 'aria-label' attribute for accessibilty reasons. (bzr r14066) --- src/path-chemistry.cpp | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/path-chemistry.cpp b/src/path-chemistry.cpp index 5f6e1495b..988559e30 100644 --- a/src/path-chemistry.cpp +++ b/src/path-chemistry.cpp @@ -362,7 +362,7 @@ bool sp_item_list_to_curves(const GSList *items, GSList **selected, GSList **to_select, bool skip_all_lpeitems) { bool did = false; - + for (; items != NULL; items = items->next) { @@ -488,6 +488,9 @@ sp_selected_item_to_curved_repr(SPItem *item, guint32 /*text_grouping_policy*/) if (dynamic_cast(item) || dynamic_cast(item)) { // Special treatment for text: convert each glyph to separate path, then group the paths Inkscape::XML::Node *g_repr = xml_doc->createElement("svg:g"); + + Glib::ustring original_text; // To save original text of accessibility. + g_repr->setAttribute("transform", item->getRepr()->attribute("transform")); /* Mask */ gchar *mask_str = (gchar *) item->getRepr()->attribute("mask"); @@ -508,6 +511,8 @@ sp_selected_item_to_curved_repr(SPItem *item, guint32 /*text_grouping_policy*/) Inkscape::Text::Layout::iterator iter = te_get_layout(item)->begin(); do { + original_text += (gunichar)te_get_layout(item)->characterAt( iter ); + Inkscape::Text::Layout::iterator iter_next = iter; iter_next.nextGlyph(); // iter_next is one glyph ahead from iter if (iter == iter_next) @@ -547,6 +552,11 @@ sp_selected_item_to_curved_repr(SPItem *item, guint32 /*text_grouping_policy*/) p_repr->setAttribute("style", style_str.c_str()); g_repr->appendChild(p_repr); + + // For accessibility, store original string + if( original_text.size() > 0 ) { + g_repr->setAttribute("aria-label", original_text.c_str() ); + } Inkscape::GC::release(p_repr); if (iter == te_get_layout(item)->end()) -- cgit v1.2.3 From 1b24834a9073b27ffe84dd0a48ebab4ef7cba46f Mon Sep 17 00:00:00 2001 From: mathog <> Date: Tue, 28 Apr 2015 11:11:32 -0700 Subject: enable default pen object for WMF files (bzr r14067) --- src/extension/internal/wmf-inout.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/extension/internal/wmf-inout.cpp b/src/extension/internal/wmf-inout.cpp index 30a028eec..3ab7a4e89 100644 --- a/src/extension/internal/wmf-inout.cpp +++ b/src/extension/internal/wmf-inout.cpp @@ -3085,8 +3085,12 @@ Wmf::open( Inkscape::Extension::Input * /*mod*/, const gchar *uri ) d.dc[0].style.stroke_dasharray.set = 0; d.dc[0].style.stroke_linecap.computed = 2; // U_PS_ENDCAP_SQUARE; d.dc[0].style.stroke_linejoin.computed = 0; // U_PS_JOIN_MITER; - d.dc[0].style.stroke_width.value = 1.0; // will be reset to something reasonable once WMF draying size is known + d.dc[0].style.stroke_width.value = 1.0; // will be reset to something reasonable once WMF drawing size is known d.dc[0].style.stroke.value.color.set( 0, 0, 0 ); + d.dc[0].stroke_set = true; + + // Default brush is none - no fill. WMF files that do not specify a brush are unlikely to look very good! + d.dc[0].fill_set = false; d.dc[0].font_name = strdup("Arial"); // Default font, set only on lowest level, it copies up from there WMF spec says device can pick whatever it wants -- cgit v1.2.3 From cfa7054c950050095e596edd18fedad53e7ed636 Mon Sep 17 00:00:00 2001 From: Krzysztof Kosi??ski Date: Tue, 28 Apr 2015 19:02:19 -0400 Subject: Fix calls to Geom::cross() - sign change. (bzr r14059.2.2) --- src/2geom/path.cpp | 10 ++++++ src/2geom/path.h | 4 +++ src/2geom/pathvector.cpp | 9 ++++- src/2geom/pathvector.h | 2 ++ src/helper/geom-pathstroke.cpp | 12 +++---- src/livarot/PathConversion.cpp | 6 ++-- src/livarot/PathCutting.cpp | 4 +-- src/livarot/PathOutline.cpp | 8 ++--- src/livarot/PathSimplify.cpp | 2 +- src/livarot/PathStroke.cpp | 16 ++++----- src/livarot/Shape.cpp | 4 +-- src/livarot/ShapeSweep.cpp | 38 ++++++++++---------- src/livarot/sweep-tree.cpp | 10 +++--- src/live_effects/lpe-fillet-chamfer.cpp | 2 +- src/live_effects/lpe-knot.cpp | 2 +- src/live_effects/lpe-powerstroke.cpp | 4 +-- src/live_effects/lpe-sketch.cpp | 2 +- .../parameter/filletchamferpointarray.cpp | 2 +- src/sp-offset.cpp | 2 +- src/splivarot.cpp | 40 ++++++++++++++++------ 20 files changed, 111 insertions(+), 68 deletions(-) (limited to 'src') diff --git a/src/2geom/path.cpp b/src/2geom/path.cpp index cf8b15d60..8eb5c7fcb 100644 --- a/src/2geom/path.cpp +++ b/src/2geom/path.cpp @@ -760,6 +760,16 @@ void Path::replace(iterator first, iterator last, Path const &path) replace(first, last, path.begin(), path.end()); } +void Path::snapEnds(Coord precision) +{ + if (!_closed) return; + if (_curves->size() > 1 && are_near(_closing_seg->length(precision), 0, precision)) { + _unshare(); + _closing_seg->setInitial(_closing_seg->finalPoint()); + (_curves->end() - 1)->setFinal(_closing_seg->finalPoint()); + } +} + // replace curves between first and last with contents of source, // void Path::do_update(Sequence::iterator first, Sequence::iterator last, Sequence &source) diff --git a/src/2geom/path.h b/src/2geom/path.h index 1940aa580..8d585cd57 100644 --- a/src/2geom/path.h +++ b/src/2geom/path.h @@ -749,6 +749,10 @@ public: do_append(new CurveType(finalPoint(), a, b, c, d, e, f, g, h, i)); } + /** @brief Reduce the closing segment to a point if it's shorter than precision. + * Do this by moving the final point. */ + void snapEnds(Coord precision = EPSILON); + /// Append a stitching segment ending at the specified point. void stitchTo(Point const &p); diff --git a/src/2geom/pathvector.cpp b/src/2geom/pathvector.cpp index 36364de9b..d2dc468c6 100644 --- a/src/2geom/pathvector.cpp +++ b/src/2geom/pathvector.cpp @@ -126,13 +126,20 @@ OptRect PathVector::boundsExact() const return bound; } +void PathVector::snapEnds(Coord precision) +{ + for (std::size_t i = 0; i < size(); ++i) { + (*this)[i].snapEnds(precision); + } +} + std::vector PathVector::intersect(PathVector const &other, Coord precision) const { typedef PathVectorPosition PVPos; std::vector result; for (std::size_t i = 0; i < size(); ++i) { for (std::size_t j = 0; j < other.size(); ++j) { - std::vector xs = (*this)[i].intersect(other[j]); + std::vector xs = (*this)[i].intersect(other[j], precision); for (std::size_t k = 0; k < xs.size(); ++k) { PVIntersection pvx(PVPos(i, xs[k].first), PVPos(j, xs[k].second), xs[k].point()); result.push_back(pvx); diff --git a/src/2geom/pathvector.h b/src/2geom/pathvector.h index 6765d6bc0..9140e3872 100644 --- a/src/2geom/pathvector.h +++ b/src/2geom/pathvector.h @@ -257,6 +257,8 @@ public: return boost::range::equal(_data, other._data); } + void snapEnds(Coord precision = EPSILON); + std::vector intersect(PathVector const &other, Coord precision = EPSILON) const; /** @brief Determine the winding number at the specified point. diff --git a/src/helper/geom-pathstroke.cpp b/src/helper/geom-pathstroke.cpp index df5e5a82b..97e3c6806 100644 --- a/src/helper/geom-pathstroke.cpp +++ b/src/helper/geom-pathstroke.cpp @@ -90,9 +90,9 @@ static int circle_line_intersection(Circle C0, Point X0, Point X1, Point &p0, Po static Point intersection_point(Point origin_a, Point vector_a, Point origin_b, Point vector_b) { - Coord denom = cross(vector_b, vector_a); + Coord denom = cross(vector_a, vector_b); if (!are_near(denom,0.)) { - Coord t = (cross(origin_a,vector_b) + cross(vector_b,origin_b)) / denom; + Coord t = (cross(vector_b, origin_a) + cross(origin_b, vector_b)) / denom; return origin_a + vector_a*t; } return Point(infinity(), infinity()); @@ -322,7 +322,7 @@ void extrapolate_join(Geom::Path& res, Geom::Curve const& outgoing, double miter Geom::Ray end_ray(center, sol); Geom::Line limit_line(center, 0); // Angle set below - if (Geom::cross(start_ray.versor(), end_ray.versor()) > 0) { + if (Geom::cross(start_ray.versor(), end_ray.versor()) < 0) { limit_line.setAngle(start_ray.angle() - limit_angle); } else { limit_line.setAngle(start_ray.angle() + limit_angle); @@ -412,7 +412,7 @@ bool decide(Geom::Curve const& incoming, Geom::Curve const& outgoing) { Geom::Point tang1 = Geom::unitTangentAt(reverse(incoming.toSBasis()), 0.); Geom::Point tang2 = outgoing.unitTangentAt(0.); - return (Geom::cross(tang1, tang2) < 0); + return (Geom::cross(tang1, tang2) > 0); } void outline_helper(Geom::Path& res, Geom::Path const& to_add, double width, bool on_outside, double miter, Inkscape::LineJoinType join) @@ -488,10 +488,10 @@ void get_cubic_data(Geom::CubicBezier const& bez, double time, double& len, doub } rad = 1e8; } else { - rad = -l * (Geom::dot(der2, der2) / Geom::cross(der3, der2)); + rad = -l * (Geom::dot(der2, der2) / Geom::cross(der2, der3)); } } else { - rad = -l * (Geom::dot(der1, der1) / Geom::cross(der2, der1)); + rad = -l * (Geom::dot(der1, der1) / Geom::cross(der1, der2)); } len = l; } diff --git a/src/livarot/PathConversion.cpp b/src/livarot/PathConversion.cpp index 42df898e6..30e21d546 100644 --- a/src/livarot/PathConversion.cpp +++ b/src/livarot/PathConversion.cpp @@ -716,7 +716,7 @@ static void ArcAnglesAndCenter(Geom::Point const &iS, Geom::Point const &iE, { Geom::Point se = iE - iS; Geom::Point ca(cos(angle), sin(angle)); - Geom::Point cse(dot(se, ca), cross(se, ca)); + Geom::Point cse(dot(ca, se), cross(ca, se)); cse[0] /= rx; cse[1] /= ry; double const lensq = dot(cse,cse); @@ -753,8 +753,8 @@ static void ArcAnglesAndCenter(Geom::Point const &iS, Geom::Point const &iE, csd[1] *= ry; ca[1] = -ca[1]; // because it's the inverse rotation - dr[0] = dot(csd, ca); - dr[1] = cross(csd, ca); + dr[0] = dot(ca, csd); + dr[1] = cross(ca, csd); ca[1] = -ca[1]; diff --git a/src/livarot/PathCutting.cpp b/src/livarot/PathCutting.cpp index 49b2c5a78..12f2386b0 100644 --- a/src/livarot/PathCutting.cpp +++ b/src/livarot/PathCutting.cpp @@ -513,10 +513,10 @@ double Path::Surface() for (std::vector::const_iterator i = pts.begin(); i != pts.end(); ++i) { if ( i->isMoveTo == polyline_moveto ) { - surf += Geom::cross(lastM - lastP, lastM); + surf += Geom::cross(lastM, lastM - lastP); lastP = lastM = i->p; } else { - surf += Geom::cross(i->p - lastP, i->p); + surf += Geom::cross(i->p, i->p - lastP); lastP = i->p; } diff --git a/src/livarot/PathOutline.cpp b/src/livarot/PathOutline.cpp index 211ee31e2..e146bb908 100644 --- a/src/livarot/PathOutline.cpp +++ b/src/livarot/PathOutline.cpp @@ -1108,7 +1108,7 @@ Path::TangentOnCubAt (double at, Geom::Point const &iS, PathDescrCubicTo const & } return; } - rad = -l * (dot(dder,dder)) / (cross(ddder,dder)); + rad = -l * (dot(dder,dder)) / (cross(dder, ddder)); tgt = dder / l; if (before) { tgt = -tgt; @@ -1117,7 +1117,7 @@ Path::TangentOnCubAt (double at, Geom::Point const &iS, PathDescrCubicTo const & } len = l; - rad = -l * (dot(der,der)) / (cross(dder,der)); + rad = -l * (dot(der,der)) / (cross(der, dder)); tgt = der / l; } @@ -1156,7 +1156,7 @@ Path::TangentOnBezAt (double at, Geom::Point const &iS, return; } len = l; - rad = -l * (dot(der,der)) / (cross(dder,der)); + rad = -l * (dot(der,der)) / (cross(der, dder)); tgt = der / l; } @@ -1180,7 +1180,7 @@ Path::OutlineJoin (Path * dest, Geom::Point pos, Geom::Point stNor, Geom::Point TurnInside ^= PrevPos == pos; PrevPos = pos; - const double angSi = cross (enNor,stNor); + const double angSi = cross (stNor, enNor); const double angCo = dot (stNor, enNor); if ((fabs(angSi) < .0000001) && angCo > 0) { // The join is straight -> nothing to do. diff --git a/src/livarot/PathSimplify.cpp b/src/livarot/PathSimplify.cpp index 7d9f3f57d..81ddcd049 100644 --- a/src/livarot/PathSimplify.cpp +++ b/src/livarot/PathSimplify.cpp @@ -128,7 +128,7 @@ static double DistanceToCubic(Geom::Point const &start, PathDescrCubicTo res, Ge } Geom::Point seg = res.p - start; - nnle = Geom::cross(seg, sp); + nnle = Geom::cross(sp, seg); nnle *= nnle; nnle /= Geom::dot(seg, seg); if ( nnle < nle ) { diff --git a/src/livarot/PathStroke.cpp b/src/livarot/PathStroke.cpp index 6ec7fa209..4cfeb887a 100644 --- a/src/livarot/PathStroke.cpp +++ b/src/livarot/PathStroke.cpp @@ -292,7 +292,7 @@ void Path::DoJoin (Shape *dest, double width, JoinType join, Geom::Point pos, Ge { Geom::Point pnor = prev.ccw(); Geom::Point nnor = next.ccw(); - double angSi = cross(next, prev); + double angSi = cross(prev, next); /* FIXED: this special case caused bug 1028953 */ if (angSi > -0.0001 && angSi < 0.0001) { @@ -416,7 +416,7 @@ Path::DoLeftJoin (Shape * dest, double width, JoinType join, Geom::Point pos, { Geom::Point pnor=prev.ccw(); Geom::Point nnor=next.ccw(); - double angSi = cross (next, prev); + double angSi = cross(prev, next); if (angSi > -0.0001 && angSi < 0.0001) { double angCo = dot (prev, next); @@ -444,7 +444,7 @@ Path::DoLeftJoin (Shape * dest, double width, JoinType join, Geom::Point pos, /* Geom::Point biss; biss.x=next.x-prev.x; biss.y=next.y-prev.y; - double c2=cross(biss,next); + double c2=cross(next, biss); double l=width/c2; double projn=l*(dot(biss,next)); double projp=-l*(dot(biss,prev)); @@ -503,7 +503,7 @@ Path::DoLeftJoin (Shape * dest, double width, JoinType join, Geom::Point pos, } else { - double s2 = cross (biss, nnor); + double s2 = cross(nnor, biss); double dec = (l - emiter) * c2 / s2; const Geom::Point tbiss=biss.ccw(); @@ -560,7 +560,7 @@ Path::DoRightJoin (Shape * dest, double width, JoinType join, Geom::Point pos, { const Geom::Point pnor=prev.ccw(); const Geom::Point nnor=next.ccw(); - double angSi = cross (next,prev); + double angSi = cross(prev, next); if (angSi > -0.0001 && angSi < 0.0001) { double angCo = dot (prev, next); @@ -614,7 +614,7 @@ Path::DoRightJoin (Shape * dest, double width, JoinType join, Geom::Point pos, } else { - double s2 = cross (biss, nnor); + double s2 = cross(nnor, biss); double dec = (l - emiter) * c2 / s2; const Geom::Point tbiss=biss.ccw(); @@ -667,7 +667,7 @@ Path::DoRightJoin (Shape * dest, double width, JoinType join, Geom::Point pos, /* Geom::Point biss; biss=next.x-prev.x; biss.y=next.y-prev.y; - double c2=cross(next,biss); + double c2=cross(biss, next); double l=width/c2; double projn=l*(dot(biss,next)); double projp=-l*(dot(biss,prev)); @@ -719,7 +719,7 @@ void Path::RecRound(Shape *dest, int sNo, int eNo, // start and end index sia = 1; } else { double coa = dot(nS, nE); - sia = cross(nS, nE); + sia = cross(nE, nS); ang = acos(coa); if ( coa >= 1 ) { ang = 0; diff --git a/src/livarot/Shape.cpp b/src/livarot/Shape.cpp index ac6c72342..0bb3390e8 100644 --- a/src/livarot/Shape.cpp +++ b/src/livarot/Shape.cpp @@ -1683,7 +1683,7 @@ Shape::CmpToVert (Geom::Point ax, Geom::Point bx,bool as,bool bs) Geom::Point av, bv; av = ax; bv = bx; - double si = cross (bv, av); + double si = cross(av, bv); int tstSi = 0; if (si > 0.000001) tstSi = 1; if (si < -0.000001) tstSi = -1; @@ -2104,7 +2104,7 @@ Shape::PtWinding (const Geom::Point px) const } Geom::Point const diff = px - ast; - double const cote = cross(diff, adir); + double const cote = cross(adir, diff); if (cote == 0) continue; if (cote < 0) { if (ast[0] > px[0]) lr += nWeight; diff --git a/src/livarot/ShapeSweep.cpp b/src/livarot/ShapeSweep.cpp index b04b36bfd..1e6273964 100644 --- a/src/livarot/ShapeSweep.cpp +++ b/src/livarot/ShapeSweep.cpp @@ -1738,7 +1738,7 @@ Shape::TesteIntersection (SweepTree * iL, SweepTree * iR, Geom::Point &atx, doub } } - double ang = cross (rdir, ldir); + double ang = cross (ldir, rdir); // ang*=iL->src->eData[iL->bord].isqlength; // ang*=iR->src->eData[iR->bord].isqlength; if (ang <= 0) return false; // edges in opposite directions: <-left ... right -> @@ -1776,12 +1776,12 @@ Shape::TesteIntersection (SweepTree * iL, SweepTree * iR, Geom::Point &atx, doub double srDot, erDot; sDiff = iL->src->pData[lSt].rx - iR->src->pData[rSt].rx; eDiff = iL->src->pData[lEn].rx - iR->src->pData[rSt].rx; - srDot = cross (sDiff,rdir); - erDot = cross (eDiff,rdir); + srDot = cross(rdir, sDiff); + erDot = cross(rdir, eDiff); sDiff = iR->src->pData[rSt].rx - iL->src->pData[lSt].rx; eDiff = iR->src->pData[rEn].rx - iL->src->pData[lSt].rx; - slDot = cross (sDiff,ldir); - elDot = cross (eDiff,ldir); + slDot = cross(ldir, sDiff); + elDot = cross(ldir, eDiff); if ((srDot >= 0 && erDot >= 0) || (srDot <= 0 && erDot <= 0)) { @@ -2089,7 +2089,7 @@ Shape::Winding (const Geom::Point px) const } diff = px - ast; - double cote = cross (diff,adir); + double cote = cross(adir, diff); if (cote == 0) continue; if (cote < 0) @@ -2563,15 +2563,15 @@ Shape::TesteIntersection (Shape * ils, Shape * irs, int ilb, int irb, double srDot, erDot; sDiff = ils->pData[lSt].rx - irs->pData[rSt].rx; eDiff = ils->pData[lEn].rx - irs->pData[rSt].rx; - srDot = cross (sDiff,rdir ); - erDot = cross (eDiff,rdir ); + srDot = cross(rdir, sDiff); + erDot = cross(rdir, eDiff); if ((srDot >= 0 && erDot >= 0) || (srDot <= 0 && erDot <= 0)) return false; sDiff = irs->pData[rSt].rx - ils->pData[lSt].rx; eDiff = irs->pData[rEn].rx - ils->pData[lSt].rx; - slDot = cross (sDiff,ldir ); - elDot = cross (eDiff,ldir); + slDot = cross(ldir, sDiff); + elDot = cross(ldir, eDiff); if ((slDot >= 0 && elDot >= 0) || (slDot <= 0 && elDot <= 0)) return false; @@ -2615,8 +2615,8 @@ Shape::TesteIntersection (Shape * ils, Shape * irs, int ilb, int irb, double sDot, eDot; sDiff = ils->pData[lSt].rx - irs->pData[rSt].rx; eDiff = ils->pData[lEn].rx - irs->pData[rSt].rx; - sDot = cross (sDiff,rdir ); - eDot = cross (eDiff,rdir); + sDot = cross(rdir, sDiff); + eDot = cross(rdir, eDiff); atx = (sDot * irs->pData[lEn].rx - eDot * irs->pData[lSt].rx) / (sDot - @@ -2625,8 +2625,8 @@ Shape::TesteIntersection (Shape * ils, Shape * irs, int ilb, int irb, sDiff = irs->pData[rSt].rx - ils->pData[lSt].rx; eDiff = irs->pData[rEn].rx - ils->pData[lSt].rx; - sDot = cross (sDiff,ldir ); - eDot = cross (eDiff,ldir ); + sDot = cross(ldir, sDiff); + eDot = cross(ldir, eDiff); atR = sDot / (sDot - eDot); @@ -2669,7 +2669,7 @@ Shape::TesteAdjacency (Shape * a, int no, const Geom::Point atx, int nPt, diff = atx - ast; - double e = IHalfRound ((cross (diff,adir)) * a->eData[no].isqlength); + double e = IHalfRound(cross(adir, diff) * a->eData[no].isqlength); if (-3 < e && e < 3) { double rad = HalfRound (0.501); // when using single precision, 0.505 is better (0.5 would be the correct value, @@ -2684,16 +2684,16 @@ Shape::TesteAdjacency (Shape * a, int no, const Geom::Point atx, int nPt, diff4[1] = diff[1] + rad; double di1, di2; bool adjacent = false; - di1 = cross (diff1,adir); - di2 = cross (diff3,adir); + di1 = cross(adir, diff1); + di2 = cross(adir, diff3); if ((di1 < 0 && di2 > 0) || (di1 > 0 && di2 < 0)) { adjacent = true; } else { - di1 = cross ( diff2,adir); - di2 = cross (diff4,adir); + di1 = cross(adir, diff2); + di2 = cross(adir, diff4); if ((di1 < 0 && di2 > 0) || (di1 > 0 && di2 < 0)) { adjacent = true; diff --git a/src/livarot/sweep-tree.cpp b/src/livarot/sweep-tree.cpp index 7a016a2ee..1b9868f2e 100644 --- a/src/livarot/sweep-tree.cpp +++ b/src/livarot/sweep-tree.cpp @@ -117,9 +117,9 @@ SweepTree::Find(Geom::Point const &px, SweepTree *newOne, SweepTree *&insertL, nNorm=nNorm.ccw(); if (sweepSens) { - y = cross(nNorm, bNorm); - } else { y = cross(bNorm, nNorm); + } else { + y = cross(nNorm, bNorm); } if (y == 0) { y = dot(bNorm, nNorm); @@ -345,7 +345,7 @@ SweepTree::InsertAt(SweepTreeList &list, SweepEventQueue &queue, SweepTree *insertL = NULL; SweepTree *insertR = NULL; - double ang = cross(nNorm, bNorm); + double ang = cross(bNorm, nNorm); if (ang == 0) { insertL = insNode; @@ -384,7 +384,7 @@ SweepTree::InsertAt(SweepTreeList &list, SweepEventQueue &queue, { bNorm = -bNorm; } - ang = cross(nNorm, bNorm); + ang = cross(bNorm, nNorm); if (ang <= 0) { break; @@ -426,7 +426,7 @@ SweepTree::InsertAt(SweepTreeList &list, SweepEventQueue &queue, { bNorm = -bNorm; } - ang = cross(nNorm, bNorm); + ang = cross(bNorm, nNorm); if (ang > 0) { break; diff --git a/src/live_effects/lpe-fillet-chamfer.cpp b/src/live_effects/lpe-fillet-chamfer.cpp index c03312ce2..fe03781d4 100644 --- a/src/live_effects/lpe-fillet-chamfer.cpp +++ b/src/live_effects/lpe-fillet-chamfer.cpp @@ -548,7 +548,7 @@ LPEFilletChamfer::doEffect_path(Geom::PathVector const &path_in) ray2.setPoints(endArcPoint, (*cubic2)[1]); } Point handle2 = endArcPoint - Point::polar(ray2.angle(),k2); - bool ccwToggle = cross(curve_it1->finalPoint() - startArcPoint, endArcPoint - startArcPoint) < 0; + bool ccwToggle = cross(curve_it1->finalPoint() - startArcPoint, endArcPoint - startArcPoint) > 0; double angle = angle_between(ray1, ray2, ccwToggle); double handleAngle = ray1.angle() - angle; if (ccwToggle) { diff --git a/src/live_effects/lpe-knot.cpp b/src/live_effects/lpe-knot.cpp index 84e4deda7..a730d7403 100644 --- a/src/live_effects/lpe-knot.cpp +++ b/src/live_effects/lpe-knot.cpp @@ -433,7 +433,7 @@ LPEKnot::doEffect_path (Geom::PathVector const &path_in) std::vector flag_j = gpaths[j][curveidx].pointAndDerivatives(t,1); - int geom_sign = ( cross(flag_i[1],flag_j[1]) > 0 ? 1 : -1); + int geom_sign = ( cross(flag_i[1], flag_j[1]) < 0 ? 1 : -1); bool i0_is_under = false; if ( crossing_points[p].sign * geom_sign > 0 ){ diff --git a/src/live_effects/lpe-powerstroke.cpp b/src/live_effects/lpe-powerstroke.cpp index e6644c7e9..6a823e943 100644 --- a/src/live_effects/lpe-powerstroke.cpp +++ b/src/live_effects/lpe-powerstroke.cpp @@ -46,9 +46,9 @@ namespace Geom { static boost::optional intersection_point( Point const & origin_a, Point const & vector_a, Point const & origin_b, Point const & vector_b) { - Coord denom = cross(vector_b, vector_a); + Coord denom = cross(vector_a, vector_b); if (!are_near(denom,0.)){ - Coord t = (cross(origin_a,vector_b) + cross(vector_b,origin_b)) / denom; + Coord t = (cross(origin_b, vector_a) + cross(origin_b, vector_b)) / denom; return origin_a + t * vector_a; } return boost::none; diff --git a/src/live_effects/lpe-sketch.cpp b/src/live_effects/lpe-sketch.cpp index 551dbe16a..82d343f6e 100644 --- a/src/live_effects/lpe-sketch.cpp +++ b/src/live_effects/lpe-sketch.cpp @@ -346,7 +346,7 @@ LPESketch::doEffect_pwd2 (Geom::Piecewise > const & pwd2_ //TODO: put this 4 as a parameter in the UI... //TODO: what if with v=0? double l = tgtlength*(1-tgtlength_rdm)/v_t.length(); - double r = std::pow(v_t.length(),3)/cross(a_t,v_t); + double r = std::pow(v_t.length(), 3) / cross(v_t, a_t); r = sqrt((2*fabs(r)-tgtscale)*tgtscale)/v_t.length(); l=(rfinalPoint() - startArcPoint, endArcPoint - startArcPoint) < 0; + bool ccwToggle = cross(A->finalPoint() - startArcPoint, endArcPoint - startArcPoint) > 0; double distanceArc = Geom::distance(startArcPoint,middle_point(startArcPoint,endArcPoint)); double angleBetween = angle_between(ray1, ray2, ccwToggle); rad = distanceArc/sin(angleBetween/2.0); diff --git a/src/sp-offset.cpp b/src/sp-offset.cpp index 15d3821c7..c5336955c 100644 --- a/src/sp-offset.cpp +++ b/src/sp-offset.cpp @@ -890,7 +890,7 @@ sp_offset_distance_to_original (SPOffset * offset, Geom::Point px) if (ab > 0 && ab < len * len) { // we're in the zone of influence of the segment - double ndist = (cross(pxsx,nx)) / len; + double ndist = (cross(nx, pxsx)) / len; if (arSet == false || fabs (ndist) < fabs (arDist)) { diff --git a/src/splivarot.cpp b/src/splivarot.cpp index 95bd179f9..0c62cfe8a 100644 --- a/src/splivarot.cpp +++ b/src/splivarot.cpp @@ -47,6 +47,7 @@ #include "xml/repr.h" #include "xml/repr-sorting.h" #include <2geom/pathvector.h> +#include <2geom/svg-path-writer.h> #include "helper/geom.h" #include "livarot/Path.h" @@ -305,7 +306,9 @@ sp_pathvector_boolop(Geom::PathVector const &pathva, Geom::PathVector const &pat delete originaux[0]; delete originaux[1]; - Geom::PathVector outres = Geom::parse_svg_path(res->svg_dump_path()); + gchar *result_str = res->svg_dump_path(); + Geom::PathVector outres = Geom::parse_svg_path(result_str); + g_free(result_str); delete res; return outres; @@ -447,8 +450,9 @@ sp_selected_path_boolop(Inkscape::Selection *selection, SPDesktop *desktop, bool // reverse if needed // note that the selection list keeps its order if ( reverseOrderForOp ) { - Path* swap=originaux[0];originaux[0]=originaux[1];originaux[1]=swap; - FillRule swai=origWind[0]; origWind[0]=origWind[1]; origWind[1]=swai; + using std::swap; + swap(originaux[0], originaux[1]); + swap(origWind[0], origWind[1]); } // and work @@ -2275,10 +2279,14 @@ Ancetre(Inkscape::XML::Node *a, Inkscape::XML::Node *who) Path * Path_for_pathvector(Geom::PathVector const &epathv) { + /*std::cout << "converting to Livarot path" << std::endl; + + Geom::SVGPathWriter wr; + wr.feed(epathv); + std::cout << wr.str() << std::endl;*/ + Path *dest = new Path; - dest->LoadPathVector(epathv); - delete pathv; - + dest->LoadPathVector(epathv); return dest; } @@ -2289,14 +2297,26 @@ Path_for_item(SPItem *item, bool doTransformation, bool transformFull) if (curve == NULL) return NULL; - + Geom::PathVector *pathv = pathvector_for_curve(item, curve, doTransformation, transformFull, Geom::identity(), Geom::identity()); curve->unref(); - + + /*std::cout << "converting to Livarot path" << std::endl; + + Geom::SVGPathWriter wr; + if (pathv) { + wr.feed(*pathv); + } + std::cout << wr.str() << std::endl;*/ + Path *dest = new Path; dest->LoadPathVector(*pathv); delete pathv; - + + /*gchar *str = dest->svg_dump_path(); + std::cout << "After conversion:\n" << str << std::endl; + g_free(str);*/ + return dest; } @@ -2343,7 +2363,7 @@ pathvector_for_curve(SPItem *item, SPCurve *curve, bool doTransformation, bool t } else { *dest *= extraPreAffine * extraPostAffine; } - + return dest; } -- cgit v1.2.3 From 6839dc4380abd4e892cf65600ffe4c63ed91eb67 Mon Sep 17 00:00:00 2001 From: "Liam P. White" Date: Tue, 28 Apr 2015 19:44:34 -0400 Subject: fix tangent sign problems in path outline code (bzr r14068) --- src/helper/geom-pathstroke.cpp | 159 ++++++++++++++++++++++++----------------- 1 file changed, 94 insertions(+), 65 deletions(-) (limited to 'src') diff --git a/src/helper/geom-pathstroke.cpp b/src/helper/geom-pathstroke.cpp index eb0c432c6..6b35bb290 100644 --- a/src/helper/geom-pathstroke.cpp +++ b/src/helper/geom-pathstroke.cpp @@ -127,87 +127,104 @@ static Circle touching_circle( D2 const &curve, double t, double tol=0.0 namespace { -// Join functions may: -// - inspect any curve of the current path -// - append any type of curve to the current path -// - inspect the outgoing path -// -// Join functions must: -// - append the outgoing curve -// OR -// - end at outgoing.finalPoint - -typedef void join_func(Geom::Path& res, Geom::Curve const& outgoing, double miter, double width); - -void bevel_join(Geom::Path& res, Geom::Curve const& outgoing, double /*miter*/, double /*width*/) +// Internal data structure + +struct join_data +{ + join_data(Geom::Path &_res, Geom::Path const&_outgoing, Geom::Point _in_tang, Geom::Point _out_tang, double _miter, double _width) + : res(_res), outgoing(_outgoing), in_tang(_in_tang) + , out_tang(_out_tang), miter(_miter), width(_width) {} + + // I/O + Geom::Path &res; + Geom::Path const& outgoing; + + // input tangents + Geom::Point in_tang; + Geom::Point out_tang; + + // line parameters + double miter; + double width; +}; + +// Join functions must append the outgoing path + +typedef void join_func(join_data jd); + +void bevel_join(join_data jd) { - res.appendNew(outgoing.initialPoint()); - res.append(outgoing); + jd.res.appendNew(jd.outgoing.initialPoint()); + jd.res.append(jd.outgoing); } -void round_join(Geom::Path& res, Geom::Curve const& outgoing, double /*miter*/, double width) +void round_join(join_data jd) { - res.appendNew(width, width, 0, false, width <= 0, outgoing.initialPoint()); - res.append(outgoing); + jd.res.appendNew(jd.width, jd.width, 0, false, jd.width <= 0, jd.outgoing.initialPoint()); + jd.res.append(jd.outgoing); } -void miter_join_internal(Geom::Path& res, Geom::Curve const& outgoing, double miter, double width, bool clip) +void miter_join_internal(join_data jd, bool clip) { - Geom::Curve const& incoming = res.back(); - Geom::Point tang1 = Geom::unitTangentAt(reverse(incoming.toSBasis()), 0.); - Geom::Point tang2 = outgoing.unitTangentAt(0); - Geom::Point p = Geom::intersection_point(incoming.finalPoint(), tang1, outgoing.initialPoint(), tang2); + using namespace Geom; + + Curve const& incoming = jd.res.back(); + Curve const& outgoing = jd.outgoing.front(); + Path &res = jd.res; + double width = jd.width, miter = jd.miter; + + Point tang1 = jd.in_tang; + Point tang2 = jd.out_tang; + Point p = intersection_point(incoming.finalPoint(), tang1, outgoing.initialPoint(), tang2); bool satisfied = false; bool inc_ls = res.back_open().degreesOfFreedom() <= 4; if (p.isFinite()) { // check size of miter - Geom::Point point_on_path = incoming.finalPoint() + Geom::rot90(tang1)*width; - satisfied = Geom::distance(p, point_on_path) <= miter * 2.0 * width; + Point point_on_path = incoming.finalPoint() + rot90(tang1)*width; + satisfied = distance(p, point_on_path) <= miter * 2.0 * width; if (satisfied) { // miter OK, check to see if we can do a relocation if (inc_ls) { res.setFinal(p); } else { - res.appendNew(p); + res.appendNew(p); } } else if (clip) { // miter needs clipping, find two points - Geom::Point bisector_versor = Geom::Line(point_on_path, p).versor(); - Geom::Point point_limit = point_on_path + miter * 2.0 * width * bisector_versor; + Point bisector_versor = Line(point_on_path, p).versor(); + Point point_limit = point_on_path + miter * 2.0 * width * bisector_versor; - Geom::Point p1 = Geom::intersection_point(incoming.finalPoint(), tang1, point_limit, bisector_versor.cw()); - Geom::Point p2 = Geom::intersection_point(outgoing.initialPoint(), tang2, point_limit, bisector_versor.cw()); + Point p1 = intersection_point(incoming.finalPoint(), tang1, point_limit, bisector_versor.cw()); + Point p2 = intersection_point(outgoing.initialPoint(), tang2, point_limit, bisector_versor.cw()); if (inc_ls) { res.setFinal(p1); } else { - res.appendNew(p1); + res.appendNew(p1); } - res.appendNew(p2); + res.appendNew(p2); } } - res.appendNew(outgoing.initialPoint()); + res.appendNew(outgoing.initialPoint()); // check if we can do another relocation bool out_ls = outgoing.degreesOfFreedom() <= 4; - if ( (satisfied || clip) && out_ls) { + if ((satisfied || clip) && out_ls) { res.setFinal(outgoing.finalPoint()); } else { res.append(outgoing); } -} -void miter_join(Geom::Path& res, Geom::Curve const& outgoing, double miter, double width) { - miter_join_internal( res, outgoing, miter, width, false ); + // either way, add the rest of the path + res.insert(res.end(), ++jd.outgoing.begin(), jd.outgoing.end()); } -void miter_clip_join(Geom::Path& res, Geom::Curve const& outgoing, double miter, double width) { - miter_join_internal( res, outgoing, miter, width, true ); -} +void miter_join(join_data jd) { miter_join_internal(jd, false); } +void miter_clip_join(join_data jd) { miter_join_internal(jd, true); } Geom::Point pick_solution(Geom::Point points[2], Geom::Point tang2, Geom::Point endPt) { @@ -225,15 +242,18 @@ Geom::Point pick_solution(Geom::Point points[2], Geom::Point tang2, Geom::Point return sol; } -void extrapolate_join(Geom::Path& res, Geom::Curve const& outgoing, double miter, double width) +void extrapolate_join(join_data jd) { using namespace Geom; + Geom::Path &res = jd.res; Geom::Curve const& incoming = res.back(); + Geom::Curve const& outgoing = jd.outgoing.front(); Geom::Point startPt = incoming.finalPoint(); Geom::Point endPt = outgoing.initialPoint(); - Geom::Point tang1 = Geom::unitTangentAt(reverse(incoming.toSBasis()), 0.); - Geom::Point tang2 = outgoing.unitTangentAt(0); + Geom::Point tang1 = jd.in_tang; + Geom::Point tang2 = jd.out_tang; + double width = jd.width, miter = jd.miter; Geom::Circle circle1 = Geom::touching_circle(Geom::reverse(incoming.toSBasis()), 0.); Geom::Circle circle2 = Geom::touching_circle(outgoing.toSBasis(), 0); @@ -280,7 +300,7 @@ void extrapolate_join(Geom::Path& res, Geom::Curve const& outgoing, double miter if (solutions != 2) // no solutions available, fall back to miter - return miter_clip_join(res, outgoing, miter, width); + return miter_clip_join(jd); // We have a solution, thus sol is defined. p1 = sol; @@ -381,14 +401,19 @@ void extrapolate_join(Geom::Path& res, Geom::Curve const& outgoing, double miter // Straight line segment: res.appendNew(outgoing.finalPoint()); } - + + // add the rest of the path + res.insert(res.end(), ++jd.outgoing.begin(), jd.outgoing.end()); + delete arc1; delete arc2; } -void join_inside(Geom::Path& res, Geom::Curve const& outgoing) +void join_inside(join_data jd) { + Geom::Path &res = jd.res; Geom::Curve const& incoming = res.back_open(); + Geom::Curve const& outgoing = jd.outgoing.front(); Geom::Crossings cross = Geom::crossings(incoming, outgoing); if (!cross.empty()) { @@ -406,28 +431,35 @@ void join_inside(Geom::Path& res, Geom::Curve const& outgoing) res.appendNew(outgoing.initialPoint()); res.append(outgoing); } + + // add the rest of the path + res.insert(res.end(), ++jd.outgoing.begin(), jd.outgoing.end()); } -bool decide(Geom::Curve const& incoming, Geom::Curve const& outgoing) +void tangents(Geom::Point* tang, Geom::Curve const& incoming, Geom::Curve const& outgoing) { Geom::Point tang1 = Geom::unitTangentAt(reverse(incoming.toSBasis()), 0.); Geom::Point tang2 = outgoing.unitTangentAt(0.); - return (Geom::cross(tang1, tang2) < 0); + tang[0] = tang1, tang[1] = tang2; } -void outline_helper(Geom::Path& res, Geom::Path const& to_add, double width, bool on_outside, double miter, Inkscape::LineJoinType join) +void outline_helper(Geom::Path &res, Geom::Path const& temp, Geom::Point in_tang, Geom::Point out_tang, double width, double miter, Inkscape::LineJoinType join) { - if (res.size() == 0 || to_add.size() == 0) + if (res.size() == 0 || temp.size() == 0) return; - Geom::Curve const& outgoing = to_add[0]; + Geom::Curve const& outgoing = temp.front(); if (Geom::are_near(res.finalPoint(), outgoing.initialPoint())) { // if the points are /that/ close, just ignore this one - res.setFinal(outgoing.initialPoint()); - res.append(outgoing); + res.setFinal(temp.initialPoint()); + res.append(temp); return; } + join_data jd(res, temp, in_tang, out_tang, miter, width); + + bool on_outside = (Geom::cross(in_tang, out_tang) < 0); + if (on_outside) { join_func *jf; switch (join) { @@ -446,9 +478,9 @@ void outline_helper(Geom::Path& res, Geom::Path const& to_add, double width, boo default: jf = &miter_join; } - jf(res, outgoing, miter, width); + jf(jd); } else { - join_inside(res, outgoing); + join_inside(jd); } } @@ -705,6 +737,7 @@ Geom::Path half_outline(Geom::Path const& input, double width, double miter, Lin Geom::Point tang1 = input[0].unitTangentAt(0); Geom::Point start = input.initialPoint() + tang1 * width; Geom::Path temp; + Geom::Point tang[2]; res.start(start); @@ -720,20 +753,16 @@ Geom::Path half_outline(Geom::Path const& input, double width, double miter, Lin if (u == 0) { res.append(temp); } else { - bool on_outside = decide(input[u-1], input[u]); - outline_helper(res, temp, width, on_outside, miter, join); - if (temp.size() > 0) - res.insert(res.end(), ++temp.begin(), temp.end()); + tangents(tang, input[u-1], input[u]); + outline_helper(res, temp, tang[0], tang[1], width, miter, join); } // odd number of paths if (u < k - 1) { temp = Geom::Path(); offset_curve(temp, &input[u+1], width); - bool on_outside = decide(input[u], input[u+1]); - outline_helper(res, temp, width, on_outside, miter, join); - if (temp.size() > 0) - res.insert(res.end(), ++temp.begin(), temp.end()); + tangents(tang, input[u], input[u+1]); + outline_helper(res, temp, tang[0], tang[1], width, miter, join); } } @@ -744,8 +773,8 @@ Geom::Path half_outline(Geom::Path const& input, double width, double miter, Lin temp.append(c1); Geom::Path temp2; temp2.append(c2); - bool on_outside = decide(input.back(), input.front()); - outline_helper(temp, temp2, width, on_outside, miter, join); + tangents(tang, input.back(), input.front()); + outline_helper(temp, temp2, tang[0], tang[1], width, miter, join); res.erase(res.begin()); res.erase_last(); // -- cgit v1.2.3 From 5a3f7c27245b1a1858036210efbde031d199ebdc Mon Sep 17 00:00:00 2001 From: "Liam P. White" Date: Tue, 28 Apr 2015 21:10:13 -0400 Subject: Catch more intersections (can still be improved somewhat I think) (bzr r14069) --- src/helper/geom-pathstroke.cpp | 38 +++++++++++++++++--------------------- 1 file changed, 17 insertions(+), 21 deletions(-) (limited to 'src') diff --git a/src/helper/geom-pathstroke.cpp b/src/helper/geom-pathstroke.cpp index 6b35bb290..a33fb005b 100644 --- a/src/helper/geom-pathstroke.cpp +++ b/src/helper/geom-pathstroke.cpp @@ -412,31 +412,27 @@ void extrapolate_join(join_data jd) void join_inside(join_data jd) { Geom::Path &res = jd.res; - Geom::Curve const& incoming = res.back_open(); - Geom::Curve const& outgoing = jd.outgoing.front(); - Geom::Crossings cross = Geom::crossings(incoming, outgoing); - - if (!cross.empty()) { - // yeah if we could avoid allocing that'd be great - Geom::Curve *d1 = incoming.portion(0., cross[0].ta); - res.erase_last(); - res.append(*d1); - delete d1; - - Geom::Curve *d2 = outgoing.portion(cross[0].tb, 1.); - res.setFinal(d2->initialPoint()); - res.append(*d2); - delete d2; + Geom::Path const& temp = jd.outgoing; + Geom::Crossings cross = Geom::crossings(res, temp); + + if (cross.size() == 1) { + Geom::Path d1 = res.portion(0., cross[0].ta); + Geom::Path d2 = temp.portion(cross[0].tb, temp.size()); + + // Watch for bugs in 2geom crossing regarding severe inflection points + res.clear(); + res.append(d1); + res.setFinal(d2.initialPoint()); + res.append(d2); } else { - res.appendNew(outgoing.initialPoint()); - res.append(outgoing); + res.appendNew(temp.initialPoint()); + res.append(temp); + // add the rest of the path + res.insert(res.end(), ++jd.outgoing.begin(), jd.outgoing.end()); } - - // add the rest of the path - res.insert(res.end(), ++jd.outgoing.begin(), jd.outgoing.end()); } -void tangents(Geom::Point* tang, Geom::Curve const& incoming, Geom::Curve const& outgoing) +void tangents(Geom::Point tang[2], Geom::Curve const& incoming, Geom::Curve const& outgoing) { Geom::Point tang1 = Geom::unitTangentAt(reverse(incoming.toSBasis()), 0.); Geom::Point tang2 = outgoing.unitTangentAt(0.); -- cgit v1.2.3 From 658291159764636339acd95389827eb8ae159ecb Mon Sep 17 00:00:00 2001 From: "Liam P. White" Date: Tue, 28 Apr 2015 21:25:47 -0400 Subject: Increase precision (long thin paths had a ton of width variance), fix logic error (bzr r14070) --- src/helper/geom-pathstroke.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'src') diff --git a/src/helper/geom-pathstroke.cpp b/src/helper/geom-pathstroke.cpp index a33fb005b..292ba3044 100644 --- a/src/helper/geom-pathstroke.cpp +++ b/src/helper/geom-pathstroke.cpp @@ -427,8 +427,6 @@ void join_inside(join_data jd) } else { res.appendNew(temp.initialPoint()); res.append(temp); - // add the rest of the path - res.insert(res.end(), ++jd.outgoing.begin(), jd.outgoing.end()); } } @@ -607,7 +605,7 @@ void offset_quadratic(Geom::Path& p, Geom::QuadraticBezier const& bez, double wi void offset_curve(Geom::Path& res, Geom::Curve const* current, double width) { - double const tolerance = 0.005; + double const tolerance = 0.0025; size_t levels = 8; if (current->isDegenerate()) return; // don't do anything -- cgit v1.2.3 From c9402117b96cbde93c13cc52f1596b723861e8ec Mon Sep 17 00:00:00 2001 From: jabiertxof Date: Wed, 29 Apr 2015 11:25:54 -0400 Subject: Fix a bug linking a path parameter to a transformed element (bzr r14071) --- src/live_effects/parameter/path.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/live_effects/parameter/path.cpp b/src/live_effects/parameter/path.cpp index ba95affd9..32e82ff8c 100644 --- a/src/live_effects/parameter/path.cpp +++ b/src/live_effects/parameter/path.cpp @@ -427,7 +427,13 @@ PathParam::paste_param_path(const char *svgd) if (svgd && *svgd) { // remove possible link to path remove_link(); - + SPItem * item = SP_ACTIVE_DESKTOP->getSelection()->singleItem(); + if (item != NULL) { + Geom::PathVector path_clipboard = sp_svg_read_pathv(svgd); + path_clipboard *= item->i2doc_affine().inverse(); + svgd = sp_svg_write_path( path_clipboard ); + } + param_write_to_repr(svgd); signal_path_pasted.emit(); } -- cgit v1.2.3 From 556a53bca1b75b43730da749313f8a6827f2461d Mon Sep 17 00:00:00 2001 From: Tavmjong Bah Date: Wed, 29 Apr 2015 19:24:49 +0200 Subject: Fix regression: Update default font-family if nothing is selected on canvas. (bzr r14072) --- src/libnrtype/FontFactory.h | 2 +- src/widgets/text-toolbar.cpp | 14 ++++++++++---- 2 files changed, 11 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/libnrtype/FontFactory.h b/src/libnrtype/FontFactory.h index bd5a4460c..4c8c2cb29 100644 --- a/src/libnrtype/FontFactory.h +++ b/src/libnrtype/FontFactory.h @@ -68,7 +68,7 @@ public: }; // Map type for gathering UI family and style names -typedef std::map > FamilyToStylesMap; +// typedef std::map > FamilyToStylesMap; class font_factory { public: diff --git a/src/widgets/text-toolbar.cpp b/src/widgets/text-toolbar.cpp index 3d2e6eef8..ec011fffd 100644 --- a/src/widgets/text-toolbar.cpp +++ b/src/widgets/text-toolbar.cpp @@ -162,11 +162,17 @@ static void sp_text_fontfamily_value_changed( Ink_ComboBoxEntry_Action *act, GOb fontlister->fill_css( css ); SPDesktop *desktop = SP_ACTIVE_DESKTOP; - sp_desktop_set_style (desktop, css, true, true); // Results in selection change called twice. + if( desktop->getSelection()->isEmpty() ) { + // Update default + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + prefs->mergeStyle("/tools/text/style", css); + } else { + // If there is a selection, update + sp_desktop_set_style (desktop, css, true, true); // Results in selection change called twice. + DocumentUndo::done(desktop->getDocument(), SP_VERB_CONTEXT_TEXT, + _("Text: Change font family")); + } sp_repr_css_attr_unref (css); - - DocumentUndo::done(desktop->getDocument(), SP_VERB_CONTEXT_TEXT, - _("Text: Change font family")); } // unfreeze -- cgit v1.2.3 From f4c56b0f307b4f0f2ab499e7f10cf2a9644688c4 Mon Sep 17 00:00:00 2001 From: "Liam P. White" Date: Wed, 29 Apr 2015 16:23:05 -0400 Subject: Better solution picking (bzr r14073) --- src/helper/geom-pathstroke.cpp | 25 ++++++++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/helper/geom-pathstroke.cpp b/src/helper/geom-pathstroke.cpp index 292ba3044..1df17acf5 100644 --- a/src/helper/geom-pathstroke.cpp +++ b/src/helper/geom-pathstroke.cpp @@ -415,9 +415,28 @@ void join_inside(join_data jd) Geom::Path const& temp = jd.outgoing; Geom::Crossings cross = Geom::crossings(res, temp); - if (cross.size() == 1) { - Geom::Path d1 = res.portion(0., cross[0].ta); - Geom::Path d2 = temp.portion(cross[0].tb, temp.size()); + int solution = -1; // lol, really hope there aren't more than INT_MAX crossings + if (cross.size() == 1) solution = 0; + else if (cross.size() > 1) { + // I am not sure how well this will work -- we pick the join node closest + // to the cross point of the paths + Geom::Point original = res.finalPoint()+Geom::rot90(jd.in_tang)*jd.width; + Geom::Coord trial = Geom::L2(res.pointAt(cross[0].ta)-original); + solution = 0; + for (size_t i = 1; i < cross.size(); ++i) { + //printf("Trying %d\n", i); + Geom::Coord test = Geom::L2(res.pointAt(cross[i].ta)-original); + if (test < trial) { + trial = test; + solution = i; + //printf("Found improved solution: %f\n", trial); + } + } + } + + if (solution != -1) { + Geom::Path d1 = res.portion(0., cross[solution].ta); + Geom::Path d2 = temp.portion(cross[solution].tb, temp.size()); // Watch for bugs in 2geom crossing regarding severe inflection points res.clear(); -- cgit v1.2.3 From 71fcf846f0cb03e8f73ef72f1174b7e05f03d1c0 Mon Sep 17 00:00:00 2001 From: Marc Jeanmougin Date: Wed, 29 Apr 2015 23:03:20 +0200 Subject: corrected test file (bzr r13922.1.20) --- src/object-test.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/object-test.h b/src/object-test.h index 06363c372..4f0be3251 100644 --- a/src/object-test.h +++ b/src/object-test.h @@ -204,7 +204,8 @@ public: assert(n_group != NULL); begin = clock(); - sp_item_group_ungroup(n_group, NULL, false); + std::vector ch; + sp_item_group_ungroup(n_group, ch, false); end = clock(); std::cout << "Took " << double(end - begin) / double(CLOCKS_PER_SEC) << " seconds to ungroup a with " << num_elements << " elements\n"; -- cgit v1.2.3 From 7aac87804be5fe99db56130848d94da4d07e2382 Mon Sep 17 00:00:00 2001 From: Marc Jeanmougin Date: Wed, 29 Apr 2015 23:30:20 +0200 Subject: uint -> unsigned int (bzr r14075) --- src/selection.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/selection.cpp b/src/selection.cpp index b2fb6447e..017089ec5 100644 --- a/src/selection.cpp +++ b/src/selection.cpp @@ -513,7 +513,7 @@ SPObject *Selection::_objectForXMLNode(Inkscape::XML::Node *repr) const { return object; } -uint Selection::numberOfLayers() { +unsigned int Selection::numberOfLayers() { std::vector const items = const_cast(this)->itemList(); std::set layers; for ( std::vector::const_iterator iter=items.begin();iter!=items.end();iter++ ) { -- cgit v1.2.3 From c848ff33a5f3fd7eabfe83604bb42bb5e705c0b4 Mon Sep 17 00:00:00 2001 From: Marc Jeanmougin Date: Thu, 30 Apr 2015 00:29:17 +0200 Subject: unsigned int -> size_t (bzr r14076) --- src/selection.cpp | 4 ++-- src/selection.h | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/selection.cpp b/src/selection.cpp index 017089ec5..53772c381 100644 --- a/src/selection.cpp +++ b/src/selection.cpp @@ -513,7 +513,7 @@ SPObject *Selection::_objectForXMLNode(Inkscape::XML::Node *repr) const { return object; } -unsigned int Selection::numberOfLayers() { +size_t Selection::numberOfLayers() { std::vector const items = const_cast(this)->itemList(); std::set layers; for ( std::vector::const_iterator iter=items.begin();iter!=items.end();iter++ ) { @@ -523,7 +523,7 @@ unsigned int Selection::numberOfLayers() { return layers.size(); } -guint Selection::numberOfParents() { +size_t Selection::numberOfParents() { std::vector const items = const_cast(this)->itemList(); std::set parents; for ( std::vector::const_iterator iter=items.begin();iter!=items.end();iter++ ) { diff --git a/src/selection.h b/src/selection.h index 7ac0f40f3..952dde51d 100644 --- a/src/selection.h +++ b/src/selection.h @@ -259,10 +259,10 @@ public: std::list const box3DList(Persp3D *persp = NULL); /** Returns the number of layers in which there are selected objects. */ - unsigned int numberOfLayers(); + size_t numberOfLayers(); /** Returns the number of parents to which the selected objects belong. */ - unsigned int numberOfParents(); + size_t numberOfParents(); /** Returns the bounding rectangle of the selection. */ Geom::OptRect bounds(SPItem::BBoxType type) const; -- cgit v1.2.3 From ce75639406465cb3e60b097d70defa51bfdc10a6 Mon Sep 17 00:00:00 2001 From: Bryce Harrington Date: Wed, 29 Apr 2015 18:52:55 -0400 Subject: cmake: Include missing source file in build rules (bzr r14070.1.4) --- src/libuemf/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) (limited to 'src') diff --git a/src/libuemf/CMakeLists.txt b/src/libuemf/CMakeLists.txt index f5a97f212..922d404a6 100644 --- a/src/libuemf/CMakeLists.txt +++ b/src/libuemf/CMakeLists.txt @@ -4,6 +4,7 @@ set(libuemf_SRC uemf.c uemf_endian.c uemf_print.c + uemf_safe.c uemf_utf.c uwmf.c uwmf_endian.c -- cgit v1.2.3 From e5abbfaf9a7767bff95f45bdbfed4999ba894a99 Mon Sep 17 00:00:00 2001 From: "Liam P. White" Date: Wed, 29 Apr 2015 22:38:25 -0400 Subject: Fix dbus build (bzr r14077) --- src/extension/dbus/document-interface.cpp | 46 +++++++++++++++---------------- 1 file changed, 23 insertions(+), 23 deletions(-) (limited to 'src') diff --git a/src/extension/dbus/document-interface.cpp b/src/extension/dbus/document-interface.cpp index 4fde6885f..d64bdbc5c 100644 --- a/src/extension/dbus/document-interface.cpp +++ b/src/extension/dbus/document-interface.cpp @@ -186,10 +186,10 @@ selection_get_center_y (Inkscape::Selection *sel){ * know we never bothered to implement it seperatly. Although * they might see the selection box flicker if used in a loop. */ -const GSList * +std::vector selection_swap(Inkscape::Selection *sel, gchar *name, GError **error) { - const GSList *oldsel = g_slist_copy((GSList *)sel->list()); + std::vector oldsel = sel->list(); sel->set(get_object_by_name(sel->layers()->getDocument(), name, error)); return oldsel; @@ -199,9 +199,11 @@ selection_swap(Inkscape::Selection *sel, gchar *name, GError **error) * See selection_swap, above */ void -selection_restore(Inkscape::Selection *sel, const GSList * oldsel) +selection_restore(Inkscape::Selection *sel, std::vector oldsel) { - sel->setList(oldsel); + // ... setList used to work here + sel->clear(); + sel->add(oldsel.begin(), oldsel.end()); } /* @@ -708,8 +710,8 @@ gboolean document_interface_move (DocumentInterface *doc_interface, gchar *name, gdouble x, gdouble y, GError **error) { - const GSList *oldsel = selection_swap(doc_interface->target.getSelection(), name, error); - if (!oldsel) + std::vector oldsel = selection_swap(doc_interface->target.getSelection(), name, error); + if (oldsel.empty()) return FALSE; sp_selection_move (doc_interface->target.getSelection(), x, 0 - y); selection_restore(doc_interface->target.getSelection(), oldsel); @@ -720,8 +722,8 @@ gboolean document_interface_move_to (DocumentInterface *doc_interface, gchar *name, gdouble x, gdouble y, GError **error) { - const GSList *oldsel = selection_swap(doc_interface->target.getSelection(), name, error); - if (!oldsel) + std::vector oldsel = selection_swap(doc_interface->target.getSelection(), name, error); + if (oldsel.empty()) return FALSE; Inkscape::Selection * sel = doc_interface->target.getSelection(); sp_selection_move (doc_interface->target.getSelection(), x - selection_get_center_x(sel), @@ -734,8 +736,8 @@ gboolean document_interface_object_to_path (DocumentInterface *doc_interface, char *shape, GError **error) { - const GSList *oldsel = selection_swap(doc_interface->target.getSelection(), shape, error); - if (!oldsel) + std::vector oldsel = selection_swap(doc_interface->target.getSelection(), shape, error); + if (oldsel.empty()) return FALSE; dbus_call_verb (doc_interface, SP_VERB_OBJECT_TO_CURVE, error); selection_restore(doc_interface->target.getSelection(), oldsel); @@ -849,8 +851,8 @@ gboolean document_interface_move_to_layer (DocumentInterface *doc_interface, gchar *shape, gchar *layerstr, GError **error) { - const GSList *oldsel = selection_swap(doc_interface->target.getSelection(), shape, error); - if (!oldsel) + std::vector oldsel = selection_swap(doc_interface->target.getSelection(), shape, error); + if (oldsel.empty()) return FALSE; document_interface_selection_move_to_layer(doc_interface, layerstr, error); @@ -1085,15 +1087,15 @@ void document_interface_update(DocumentInterface *doc_interface, GError ** error gboolean document_interface_selection_get(DocumentInterface *doc_interface, char ***out, GError ** /*error*/) { Inkscape::Selection * sel = doc_interface->target.getSelection(); - GSList const *oldsel = sel->list(); + std::vector oldsel = sel->list(); - int size = g_slist_length((GSList *) oldsel); + int size = oldsel.size(); *out = g_new0 (char *, size + 1); int i = 0; - for (GSList const *iter = oldsel; iter != NULL; iter = iter->next) { - (*out)[i] = g_strdup(SP_OBJECT(iter->data)->getRepr()->attribute("id")); + for (std::vector::iterator iter = oldsel.begin(), e = oldsel.end(); iter != e; ++iter) { + (*out)[i] = g_strdup((*iter)->getId()); i++; } (*out)[i] = NULL; @@ -1426,23 +1428,21 @@ gboolean dbus_send_ping (SPDesktop* desk, SPItem *item) gboolean document_interface_get_children (DocumentInterface *doc_interface, char *name, char ***out, GError **error) { - SPItem* parent=(SPItem* )get_object_by_name(doc_interface->target.getDocument(), name, error); + SPItem* parent=(SPItem* )get_object_by_name(doc_interface->target.getDocument(), name, error); + std::vector children = parent->childList(false); - GSList const *children = parent->childList(false); - - int size = g_slist_length((GSList *) children); + int size = children.size(); *out = g_new0 (char *, size + 1); int i = 0; - for (GSList const *iter = children; iter != NULL; iter = iter->next) { - (*out)[i] = g_strdup(SP_OBJECT(iter->data)->getRepr()->attribute("id")); + for (std::vector::iterator iter = children.begin(), e = children.end(); iter != e; ++iter) { + (*out)[i] = g_strdup((*iter)->getId()); i++; } (*out)[i] = NULL; return TRUE; - } -- cgit v1.2.3 From 6a9762c7603a32c7ec5cc0aaed8048d84daee6e8 Mon Sep 17 00:00:00 2001 From: Krzysztof Kosi??ski Date: Thu, 30 Apr 2015 11:17:07 +0200 Subject: Update 2Geom to r2347 (bzr r14059.2.3) --- src/2geom/Makefile_insert | 1 - src/2geom/ellipse.cpp | 50 +++++++++--------- src/2geom/forward.h | 4 +- src/2geom/intersection-graph.cpp | 4 +- src/2geom/intersection-graph.h | 2 +- src/2geom/path.cpp | 49 ++++++++---------- src/2geom/path.h | 98 ++++++++++++++++++------------------ src/2geom/pathvector.cpp | 30 +++++------ src/2geom/pathvector.h | 53 ++++++++++--------- src/2geom/point-ops.h | 25 --------- src/live_effects/lpe-attach-path.cpp | 4 +- src/ui/tool/node.cpp | 2 +- src/ui/tool/node.h | 4 +- src/ui/tool/path-manipulator.cpp | 6 +-- 14 files changed, 150 insertions(+), 182 deletions(-) delete mode 100644 src/2geom/point-ops.h (limited to 'src') diff --git a/src/2geom/Makefile_insert b/src/2geom/Makefile_insert index 86e64333d..aeb0b20a1 100644 --- a/src/2geom/Makefile_insert +++ b/src/2geom/Makefile_insert @@ -84,7 +84,6 @@ 2geom/piecewise.h \ 2geom/point.cpp \ 2geom/point.h \ - 2geom/point-ops.h \ 2geom/poly.cpp \ 2geom/poly.h \ 2geom/quadtree.cpp \ diff --git a/src/2geom/ellipse.cpp b/src/2geom/ellipse.cpp index 4e26707ef..9e927c9e8 100644 --- a/src/2geom/ellipse.cpp +++ b/src/2geom/ellipse.cpp @@ -170,33 +170,31 @@ EllipticalArc * Ellipse::arc(Point const &ip, Point const &inner, Point const &fp, bool _svg_compliant) { - Point sp_cp = ip - center(); - Point ep_cp = fp - center(); - Point ip_cp = inner - center(); - - double angle1 = angle_between(sp_cp, ep_cp); - double angle2 = angle_between(sp_cp, ip_cp); - double angle3 = angle_between(ip_cp, ep_cp); - - bool large_arc_flag = true; - bool sweep_flag = true; + // This is resistant to degenerate ellipses: + // both flags evaluate to false in that case. + + bool large_arc_flag = false; + bool sweep_flag = false; + + // Determination of large arc flag: + // The arc is larger than half of the ellipse if the inner point + // is on the same side of the line going from the initial + // to the final point as the center of the ellipse + Line chord(ip, fp); + Point versor = fp - ip; + double sdist_c = cross(versor, _center - ip); + double sdist_inner = cross(versor, inner - ip); + + // if we have exactly half of an arc, do not set the large flag. + if (sdist_c != 0 && sgn(sdist_c) == sgn(sdist_inner)) { + large_arc_flag = true; + } - if (angle1 > 0) { - if (angle2 > 0 && angle3 > 0) { - large_arc_flag = false; - sweep_flag = true; - } else { - large_arc_flag = true; - sweep_flag = false; - } - } else { - if (angle2 < 0 && angle3 < 0) { - large_arc_flag = false; - sweep_flag = false; - } else { - large_arc_flag = true; - sweep_flag = true; - } + // Determination of sweep flag: + // If the inner point is on the left side of the ip-fp line, + // we go in clockwise direction. + if (sdist_inner < 0) { + sweep_flag = true; } EllipticalArc *ret_arc; diff --git a/src/2geom/forward.h b/src/2geom/forward.h index f3ab657e8..a6e420122 100644 --- a/src/2geom/forward.h +++ b/src/2geom/forward.h @@ -78,9 +78,9 @@ class SVGEllipticalArc; // paths and path sequences class Path; class PathVector; -struct PathPosition; +struct PathTime; class PathInterval; -struct PathVectorPosition; +struct PathVectorTime; // errors class Exception; diff --git a/src/2geom/intersection-graph.cpp b/src/2geom/intersection-graph.cpp index abe462e3f..b9e2feeed 100644 --- a/src/2geom/intersection-graph.cpp +++ b/src/2geom/intersection-graph.cpp @@ -119,7 +119,7 @@ PathIntersectionGraph::PathIntersectionGraph(PathVector const &a, PathVector con std::size_t pi = i->pos.path_index; PathInterval ival = forward_interval(i->pos, n->pos, pv[pi].size()); - PathPosition mid = ival.inside(precision); + PathTime mid = ival.inside(precision); // TODO check for degenerate cases // requires changes in the winding routine @@ -216,7 +216,7 @@ PathVector PathIntersectionGraph::_getResult(bool enter_a, bool enter_b) // append portion of path PathInterval ival = PathInterval::from_direction( - prev->pos.asPathPosition(), i->pos.asPathPosition(), + prev->pos.asPathTime(), i->pos.asPathTime(), reverse, (*cur)[pi].size()); (*cur)[pi].appendPortionTo(result.back(), ival, prev->p, i->p); diff --git a/src/2geom/intersection-graph.h b/src/2geom/intersection-graph.h index 2fe858c5d..dd70d3d5b 100644 --- a/src/2geom/intersection-graph.h +++ b/src/2geom/intersection-graph.h @@ -51,7 +51,7 @@ enum InOutFlag { struct IntersectionVertex { boost::intrusive::list_member_hook<> _hook; - PathVectorPosition pos; + PathVectorTime pos; Point p; // guarantees that endpoints are exact IntersectionVertex *neighbor; bool entry; // going in +t direction enters the other path diff --git a/src/2geom/path.cpp b/src/2geom/path.cpp index 8eb5c7fcb..71b7b25bb 100644 --- a/src/2geom/path.cpp +++ b/src/2geom/path.cpp @@ -53,7 +53,7 @@ PathInterval::PathInterval() , _reverse(false) {} -PathInterval::PathInterval(Position const &from, Position const &to, bool cross_start, size_type path_size) +PathInterval::PathInterval(PathTime const &from, PathTime const &to, bool cross_start, size_type path_size) : _from(from) , _to(to) , _path_size(path_size) @@ -78,7 +78,7 @@ PathInterval::PathInterval(Position const &from, Position const &to, bool cross_ } } -bool PathInterval::contains(Position const &pos) const { +bool PathInterval::contains(PathTime const &pos) const { if (_cross_start) { if (_reverse) { return pos >= _to || _from >= pos; @@ -94,14 +94,14 @@ bool PathInterval::contains(Position const &pos) const { } } -PathPosition PathInterval::inside(Coord min_dist) const +PathTime PathInterval::inside(Coord min_dist) const { // If there is some node further than min_dist (in time coord) from the ends, // return that node. Otherwise, return the middle. - PathPosition result(0, 0.0); + PathTime result(0, 0.0); if (!_cross_start && _from.curve_index == _to.curve_index) { - PathPosition result(_from.curve_index, lerp(0.5, _from.t, _to.t)); + PathTime result(_from.curve_index, lerp(0.5, _from.t, _to.t)); return result; } // If _cross_start, then we can be sure that at least one node is in the domain. @@ -181,7 +181,7 @@ PathPosition PathInterval::inside(Coord min_dist) const return result; } -PathInterval PathInterval::from_direction(Position const &from, Position const &to, bool reversed, size_type path_size) +PathInterval PathInterval::from_direction(PathTime const &from, PathTime const &to, bool reversed, size_type path_size) { PathInterval result; result._from = from; @@ -351,7 +351,7 @@ Interval Path::timeRange() const Curve const &Path::curveAt(Coord t, Coord *rest) const { - Position pos = _getPosition(t); + PathTime pos = _factorTime(t); if (rest) { *rest = pos.t; } @@ -360,34 +360,34 @@ Curve const &Path::curveAt(Coord t, Coord *rest) const Point Path::pointAt(Coord t) const { - return pointAt(_getPosition(t)); + return pointAt(_factorTime(t)); } Coord Path::valueAt(Coord t, Dim2 d) const { - return valueAt(_getPosition(t), d); + return valueAt(_factorTime(t), d); } -Curve const &Path::curveAt(Position const &pos) const +Curve const &Path::curveAt(PathTime const &pos) const { return at(pos.curve_index); } -Point Path::pointAt(Position const &pos) const +Point Path::pointAt(PathTime const &pos) const { return at(pos.curve_index).pointAt(pos.t); } -Coord Path::valueAt(Position const &pos, Dim2 d) const +Coord Path::valueAt(PathTime const &pos, Dim2 d) const { return at(pos.curve_index).valueAt(pos.t, d); } -std::vector Path::roots(Coord v, Dim2 d) const +std::vector Path::roots(Coord v, Dim2 d) const { - std::vector res; + std::vector res; for (unsigned i = 0; i <= size(); i++) { std::vector temp = (*this)[i].roots(v, d); for (unsigned j = 0; j < temp.size(); j++) - res.push_back(PathPosition(i, temp[j])); + res.push_back(PathTime(i, temp[j])); } return res; } @@ -402,7 +402,7 @@ std::vector Path::intersect(Path const &other, Coord precision for (size_type j = 0; j < other.size(); ++j) { std::vector cx = (*this)[i].intersect(other[j], precision); for (std::size_t ci = 0; ci < cx.size(); ++ci) { - PathPosition a(i, cx[ci].first), b(j, cx[ci].second); + PathTime a(i, cx[ci].first), b(j, cx[ci].second); PathIntersection px(a, b, cx[ci].point()); result.push_back(px); } @@ -550,16 +550,10 @@ std::vector Path::nearestTimePerCurve(Point const &p) const return np; } -Coord Path::nearestTime(Point const &p, Coord *dist) const -{ - Position pos = nearestPosition(p, dist); - return pos.curve_index + pos.t; -} - -PathPosition Path::nearestPosition(Point const &p, Coord *dist) const +PathTime Path::nearestTime(Point const &p, Coord *dist) const { Coord mindist = std::numeric_limits::max(); - Position ret; + PathTime ret; if (_curves->size() == 1) { // naked moveto @@ -639,7 +633,7 @@ void Path::appendPortionTo(Path &target, PathInterval const &ival, return; } - Position const &from = ival.from(), &to = ival.to(); + PathTime const &from = ival.from(), &to = ival.to(); bool reverse = ival.reverse(); int di = reverse ? -1 : 1; @@ -872,14 +866,15 @@ void Path::checkContinuity() const } } -PathPosition Path::_getPosition(Coord t) const +// breaks time value into integral and fractional part +PathTime Path::_factorTime(Coord t) const { size_type sz = size_default(); if (t < 0 || t > sz) { THROW_RANGEERROR("parameter t out of bounds"); } - Position ret; + PathTime ret; Coord k; ret.t = modf(t, &k); ret.curve_index = k; diff --git a/src/2geom/path.h b/src/2geom/path.h index 8d585cd57..6a6fa05ee 100644 --- a/src/2geom/path.h +++ b/src/2geom/path.h @@ -109,7 +109,7 @@ class BaseIterator } -/** @brief Position (generalized time value) in the path. +/** @brief Generalized time value in the path. * * This class exists because when mapping the range of multiple curves onto the same interval * as the curve index, we lose some precision. For instance, a path with 16 curves will @@ -119,44 +119,46 @@ class BaseIterator * call the method again to obtain a high precision result. * * @ingroup Paths */ -struct PathPosition - : boost::totally_ordered +struct PathTime + : boost::totally_ordered { typedef PathInternal::Sequence::size_type size_type; Coord t; ///< Time value in the curve size_type curve_index; ///< Index of the curve in the path - PathPosition() : t(0), curve_index(0) {} - PathPosition(size_type idx, Coord tval) : t(tval), curve_index(idx) {} + PathTime() : t(0), curve_index(0) {} + PathTime(size_type idx, Coord tval) : t(tval), curve_index(idx) {} - bool operator<(PathPosition const &other) const { + bool operator<(PathTime const &other) const { if (curve_index < other.curve_index) return true; if (curve_index == other.curve_index) { return t < other.t; } return false; } - bool operator==(PathPosition const &other) const { + bool operator==(PathTime const &other) const { return curve_index == other.curve_index && t == other.t; } - /// Convert positions at or beyond 1 to 0 on the next curve. + /// Convert times at or beyond 1 to 0 on the next curve. void normalizeForward(size_type path_size) { if (t >= 1) { curve_index = (curve_index + 1) % path_size; t = 0; } } - /// Convert positions at or before 0 to 1 on the previous curve. + /// Convert times at or before 0 to 1 on the previous curve. void normalizeBackward(size_type path_size) { if (t <= 0) { curve_index = (curve_index - 1) % path_size; t = 1; } } + + Coord asFlatTime() const { return curve_index + t; } }; -inline std::ostream &operator<<(std::ostream &os, PathPosition const &pos) { +inline std::ostream &operator<<(std::ostream &os, PathTime const &pos) { os << pos.curve_index << ": " << pos.t; return os; } @@ -169,7 +171,6 @@ inline std::ostream &operator<<(std::ostream &os, PathPosition const &pos) { * @ingroup Paths */ class PathInterval { public: - typedef PathPosition Position; typedef PathInternal::Sequence::size_type size_type; /** @brief Default interval. @@ -177,22 +178,22 @@ public: PathInterval(); /** @brief Construct an interval in the path's parameter domain. - * @param from Initial position - * @param to Final position + * @param from Initial time + * @param to Final time * @param cross_start If true, the interval will proceed from the initial to final - * position through the initial point of the path, wrapping around the closing segment; + * time through the initial point of the path, wrapping around the closing segment; * otherwise it will not wrap around the closing segment. * @param path_size Size of the path to which this interval applies, required * to clean up degenerate cases */ - PathInterval(Position const &from, Position const &to, bool cross_start, size_type path_size); + PathInterval(PathTime const &from, PathTime const &to, bool cross_start, size_type path_size); - /// Get the position of the initial point. - Position const &initialPosition() const { return _from; } - /// Get the position of the final point. - Position const &finalPosition() const { return _to; } + /// Get the time value of the initial point. + PathTime const &initialTime() const { return _from; } + /// Get the time value of the final point. + PathTime const &finalTime() const { return _to; } - Position const &from() const { return _from; } - Position const &to() const { return _to; } + PathTime const &from() const { return _from; } + PathTime const &to() const { return _to; } /// Check whether the interval has only one point. bool isDegenerate() const { return _from == _to; } @@ -201,19 +202,19 @@ public: /// True if the interior of the interval contains the initial point of the path. bool crossesStart() const { return _cross_start; } - /// Test a path position for inclusion. - bool contains(Position const &pos) const; + /// Test a path time for inclusion. + bool contains(PathTime const &pos) const; - /// Get a position at least @a min_dist away in parameter space from the ends. - /// If no such position exists, the middle point between these positions is returned. - Position inside(Coord min_dist = EPSILON) const; + /// Get a time at least @a min_dist away in parameter space from the ends. + /// If no such time exists, the middle point is returned. + PathTime inside(Coord min_dist = EPSILON) const; /// Select one of two intervals with given endpoints by parameter direction. - static PathInterval from_direction(Position const &from, Position const &to, + static PathInterval from_direction(PathTime const &from, PathTime const &to, bool reversed, size_type path_size); /// Select one of two intervals with given endpoints by whether it includes the initial point. - static PathInterval from_start_crossing(Position const &from, Position const &to, + static PathInterval from_start_crossing(PathTime const &from, PathTime const &to, bool cross_start, size_type path_size) { PathInterval result(from, to, cross_start, path_size); return result; @@ -222,14 +223,14 @@ public: size_type pathSize() const { return _path_size; } private: - Position _from, _to; + PathTime _from, _to; size_type _path_size; bool _cross_start, _reverse; }; /// Create an interval in the direction of increasing time value. /// @relates PathInterval -inline PathInterval forward_interval(PathPosition const &from, PathPosition const &to, +inline PathInterval forward_interval(PathTime const &from, PathTime const &to, PathInterval::size_type path_size) { PathInterval result = PathInterval::from_direction(from, to, false, path_size); @@ -238,7 +239,7 @@ inline PathInterval forward_interval(PathPosition const &from, PathPosition cons /// Create an interval in the direction of decreasing time value. /// @relates PathInterval -inline PathInterval backward_interval(PathPosition const &from, PathPosition const &to, +inline PathInterval backward_interval(PathTime const &from, PathTime const &to, PathInterval::size_type path_size) { PathInterval result = PathInterval::from_direction(from, to, true, path_size); @@ -258,11 +259,11 @@ inline std::ostream &operator<<(std::ostream &os, PathInterval const &ival) { return os; } -typedef Intersection PathIntersection; +typedef Intersection PathIntersection; template <> struct ShapeTraits { - typedef PathPosition TimeType; + typedef PathTime TimeType; typedef PathInterval IntervalType; typedef Path AffineClosureType; typedef PathIntersection IntersectionType; @@ -313,7 +314,6 @@ class Path > > { public: - typedef PathPosition Position; typedef PathInternal::Sequence Sequence; typedef PathInternal::BaseIterator iterator; typedef PathInternal::BaseIterator const_iterator; @@ -490,7 +490,7 @@ public: /** @brief Get the point at the specified time value. * Note that this method has reduced precision with respect to calling pointAt() * directly on the curve. If you want high precision results, use the version - * that takes a Position parameter. + * that takes a PathTime parameter. * * Allowed time values range from zero to the number of curves; you can retrieve * the allowed range of values with timeRange(). */ @@ -499,17 +499,17 @@ public: /// Get one coordinate (X or Y) at the specified time value. Coord valueAt(Coord t, Dim2 d) const; - /// Get the curve at the specified position. - Curve const &curveAt(Position const &pos) const; - /// Get the point at the specified position. - Point pointAt(Position const &pos) const; - /// Get one coordinate at the specified position. - Coord valueAt(Position const &pos, Dim2 d) const; + /// Get the curve at the specified path time. + Curve const &curveAt(PathTime const &pos) const; + /// Get the point at the specified path time. + Point pointAt(PathTime const &pos) const; + /// Get one coordinate at the specified path time. + Coord valueAt(PathTime const &pos, Dim2 d) const; Point operator()(Coord t) const { return pointAt(t); } /// Compute intersections with axis-aligned line. - std::vector roots(Coord v, Dim2 d) const; + std::vector roots(Coord v, Dim2 d) const; /// Compute intersections with another path. std::vector intersect(Path const &other, Coord precision = EPSILON) const; @@ -531,9 +531,8 @@ public: return allNearestTimes(p, 0, size_default()); } - Coord nearestTime(Point const &p, Coord *dist = NULL) const; + PathTime nearestTime(Point const &p, Coord *dist = NULL) const; std::vector nearestTimePerCurve(Point const &p) const; - Position nearestPosition(Point const &p, Coord *dist = NULL) const; void appendPortionTo(Path &p, Coord f, Coord t) const; @@ -541,7 +540,7 @@ public: * An extra stitching segment will be inserted if the start point of the portion * and the final point of the target path do not match exactly. * The closing segment of the target path will be modified. */ - void appendPortionTo(Path &p, Position const &from, Position const &to, bool cross_start = false) const { + void appendPortionTo(Path &p, PathTime const &from, PathTime const &to, bool cross_start = false) const { PathInterval ival(from, to, cross_start, size_closed()); appendPortionTo(p, ival, boost::none, boost::none); } @@ -573,7 +572,7 @@ public: * and will cross the initial point of the path. Therefore, when @a from is larger * than @a to and @a cross_start is true, the returned portion will not be reversed, * but will "wrap around" the end of the path. */ - Path portion(Position const &from, Position const &to, bool cross_start = false) const { + Path portion(PathTime const &from, PathTime const &to, bool cross_start = false) const { Path ret; ret.close(false); appendPortionTo(ret, from, to, cross_start); @@ -785,7 +784,7 @@ private: _closing_seg = static_cast(&_curves->back()); } } - Position _getPosition(Coord t) const; + PathTime _factorTime(Coord t) const; void stitch(Sequence::iterator first_replaced, Sequence::iterator last_replaced, Sequence &sequence); void do_update(Sequence::iterator first, Sequence::iterator last, Sequence &source); @@ -801,7 +800,10 @@ private: Piecewise > paths_to_pw(PathVector const &paths); -inline Coord nearest_time(Point const &p, Path const &c) { return c.nearestTime(p); } +inline Coord nearest_time(Point const &p, Path const &c) { + PathTime pt = c.nearestTime(p); + return pt.curve_index + pt.t; +} } // end namespace Geom diff --git a/src/2geom/pathvector.cpp b/src/2geom/pathvector.cpp index d2dc468c6..720428e97 100644 --- a/src/2geom/pathvector.cpp +++ b/src/2geom/pathvector.cpp @@ -77,7 +77,7 @@ Path &PathVector::pathAt(Coord t, Coord *rest) } Path const &PathVector::pathAt(Coord t, Coord *rest) const { - Position pos = _getPosition(t); + PathVectorTime pos = _factorTime(t); if (rest) { *rest = Coord(pos.curve_index) + pos.t; } @@ -85,7 +85,7 @@ Path const &PathVector::pathAt(Coord t, Coord *rest) const } Curve const &PathVector::curveAt(Coord t, Coord *rest) const { - Position pos = _getPosition(t); + PathVectorTime pos = _factorTime(t); if (rest) { *rest = pos.t; } @@ -93,12 +93,12 @@ Curve const &PathVector::curveAt(Coord t, Coord *rest) const } Coord PathVector::valueAt(Coord t, Dim2 d) const { - Position pos = _getPosition(t); + PathVectorTime pos = _factorTime(t); return at(pos.path_index).at(pos.curve_index).valueAt(pos.t, d); } Point PathVector::pointAt(Coord t) const { - Position pos = _getPosition(t); + PathVectorTime pos = _factorTime(t); return at(pos.path_index).at(pos.curve_index).pointAt(pos.t); } @@ -135,7 +135,7 @@ void PathVector::snapEnds(Coord precision) std::vector PathVector::intersect(PathVector const &other, Coord precision) const { - typedef PathVectorPosition PVPos; + typedef PathVectorTime PVPos; std::vector result; for (std::size_t i = 0; i < size(); ++i) { for (std::size_t j = 0; j < other.size(); ++j) { @@ -158,17 +158,17 @@ int PathVector::winding(Point const &p) const return wind; } -boost::optional PathVector::nearestPosition(Point const &p, Coord *dist) const +boost::optional PathVector::nearestTime(Point const &p, Coord *dist) const { - boost::optional retval; + boost::optional retval; Coord mindist = infinity(); for (size_type i = 0; i < size(); ++i) { Coord d; - PathPosition pos = (*this)[i].nearestPosition(p, &d); + PathTime pos = (*this)[i].nearestTime(p, &d); if (d < mindist) { mindist = d; - retval = Position(i, pos.curve_index, pos.t); + retval = PathVectorTime(i, pos.curve_index, pos.t); } } @@ -178,20 +178,20 @@ boost::optional PathVector::nearestPosition(Point const &p, return retval; } -std::vector PathVector::allNearestPositions(Point const &p, Coord *dist) const +std::vector PathVector::allNearestTimes(Point const &p, Coord *dist) const { - std::vector retval; + std::vector retval; Coord mindist = infinity(); for (size_type i = 0; i < size(); ++i) { Coord d; - PathPosition pos = (*this)[i].nearestPosition(p, &d); + PathTime pos = (*this)[i].nearestTime(p, &d); if (d < mindist) { mindist = d; retval.clear(); } if (d <= mindist) { - retval.push_back(Position(i, pos.curve_index, pos.t)); + retval.push_back(PathVectorTime(i, pos.curve_index, pos.t)); } } @@ -201,9 +201,9 @@ std::vector PathVector::allNearestPositions(Point const &p, return retval; } -PathVectorPosition PathVector::_getPosition(Coord t) const +PathVectorTime PathVector::_factorTime(Coord t) const { - Position ret; + PathVectorTime ret; Coord rest = 0; ret.t = modf(t, &rest); ret.curve_index = rest; diff --git a/src/2geom/pathvector.h b/src/2geom/pathvector.h index 9140e3872..375c4f0a0 100644 --- a/src/2geom/pathvector.h +++ b/src/2geom/pathvector.h @@ -43,7 +43,7 @@ namespace Geom { -/** @brief Position (generalized time value) in the path vector. +/** @brief Generalized time value in the path vector. * * This class exists because mapping the range of multiple curves onto the same interval * as the curve index, we lose some precision. For instance, a path with 16 curves will @@ -52,41 +52,41 @@ namespace Geom { * pointAt(), nearestTime() and so on. * * @ingroup Paths */ -struct PathVectorPosition - : public PathPosition - , boost::totally_ordered +struct PathVectorTime + : public PathTime + , boost::totally_ordered { size_type path_index; ///< Index of the path in the vector - PathVectorPosition() : PathPosition(0, 0), path_index(0) {} - PathVectorPosition(size_type _i, size_type _c, Coord _t) - : PathPosition(_c, _t), path_index(_i) {} - PathVectorPosition(size_type _i, PathPosition const &pos) - : PathPosition(pos), path_index(_i) {} + PathVectorTime() : PathTime(0, 0), path_index(0) {} + PathVectorTime(size_type _i, size_type _c, Coord _t) + : PathTime(_c, _t), path_index(_i) {} + PathVectorTime(size_type _i, PathTime const &pos) + : PathTime(pos), path_index(_i) {} - bool operator<(PathVectorPosition const &other) const { + bool operator<(PathVectorTime const &other) const { if (path_index < other.path_index) return true; if (path_index == other.path_index) { - return static_cast(*this) < static_cast(other); + return static_cast(*this) < static_cast(other); } return false; } - bool operator==(PathVectorPosition const &other) const { + bool operator==(PathVectorTime const &other) const { return path_index == other.path_index - && static_cast(*this) == static_cast(other); + && static_cast(*this) == static_cast(other); } - PathPosition const &asPathPosition() const { - return *static_cast(this); + PathTime const &asPathTime() const { + return *static_cast(this); } }; -typedef Intersection PathVectorIntersection; +typedef Intersection PathVectorIntersection; typedef PathVectorIntersection PVIntersection; ///< Alias to save typing template <> struct ShapeTraits { - typedef PathVectorPosition TimeType; + typedef PathVectorTime TimeType; //typedef PathVectorInterval IntervalType; typedef PathVector AffineClosureType; typedef PathVectorIntersection IntersectionType; @@ -118,7 +118,7 @@ class PathVector { typedef std::vector Sequence; public: - typedef PathVectorPosition Position; + typedef PathVectorTime Position; typedef Sequence::iterator iterator; typedef Sequence::const_iterator const_iterator; typedef Sequence::size_type size_type; @@ -224,19 +224,19 @@ public: Coord valueAt(Coord t, Dim2 d) const; Point pointAt(Coord t) const; - Path &pathAt(Position const &pos) { + Path &pathAt(PathVectorTime const &pos) { return const_cast(static_cast(this)->pathAt(pos)); } - Path const &pathAt(Position const &pos) const { + Path const &pathAt(PathVectorTime const &pos) const { return at(pos.path_index); } - Curve const &curveAt(Position const &pos) const { + Curve const &curveAt(PathVectorTime const &pos) const { return at(pos.path_index).at(pos.curve_index); } - Point pointAt(Position const &pos) const { + Point pointAt(PathVectorTime const &pos) const { return at(pos.path_index).at(pos.curve_index).pointAt(pos.t); } - Coord valueAt(Position const &pos, Dim2 d) const { + Coord valueAt(PathVectorTime const &pos, Dim2 d) const { return at(pos.path_index).at(pos.curve_index).valueAt(pos.t, d); } @@ -265,12 +265,11 @@ public: * This is simply the sum of winding numbers for constituent paths. */ int winding(Point const &p) const; - Coord nearestTime(Point const &p) const; - boost::optional nearestPosition(Point const &p, Coord *dist = NULL) const; - std::vector allNearestPositions(Point const &p, Coord *dist = NULL) const; + boost::optional nearestTime(Point const &p, Coord *dist = NULL) const; + std::vector allNearestTimes(Point const &p, Coord *dist = NULL) const; private: - Position _getPosition(Coord t) const; + PathVectorTime _factorTime(Coord t) const; Sequence _data; }; diff --git a/src/2geom/point-ops.h b/src/2geom/point-ops.h deleted file mode 100644 index 6f5eab56b..000000000 --- a/src/2geom/point-ops.h +++ /dev/null @@ -1,25 +0,0 @@ -//[[[cog -import operators - -setContext("Point", "Matrix", "Point") -make({'*':'*='}, {'/':'/='}) -apsnd({'*':'/'}, "b.inverse()") - -setContext("Point", "double", "Point") -make({'*=':'*'}, {'/=':'/'}, {'*':'*'}, {'*':'/'}) - -setContext("Point", "Point", "bool") -make({'==':'!='}) - -setContext("Point", "Point", "Point") -make({'+=':'+', '-=':'-'}) -]]] - -************** -GENERATED CODE -************** -If you wish to modify, move function out of generation region and remove the -cause of its generation. -*/ - -//[[[end]]] diff --git a/src/live_effects/lpe-attach-path.cpp b/src/live_effects/lpe-attach-path.cpp index 0fcd725ce..21459f322 100644 --- a/src/live_effects/lpe-attach-path.cpp +++ b/src/live_effects/lpe-attach-path.cpp @@ -87,7 +87,7 @@ void LPEAttachPath::doEffect (SPCurve * curve) Geom::Coord length = derivs[deriv_n].length(); if ( ! Geom::are_near(length, 0) ) { if (set_start_end) { - start_path_position.param_set_value(transformedpath.nearestTime(start_path_curve_end.getOrigin())); + start_path_position.param_set_value(transformedpath.nearestTime(start_path_curve_end.getOrigin()).asFlatTime()); } if (start_path_position > transformedpath.size()) { @@ -142,7 +142,7 @@ void LPEAttachPath::doEffect (SPCurve * curve) Geom::Coord length = derivs[deriv_n].length(); if ( ! Geom::are_near(length, 0) ) { if (set_end_end) { - end_path_position.param_set_value(transformedpath.nearestTime(end_path_curve_end.getOrigin())); + end_path_position.param_set_value(transformedpath.nearestTime(end_path_curve_end.getOrigin()).asFlatTime()); } if (end_path_position > transformedpath.size()) { diff --git a/src/ui/tool/node.cpp b/src/ui/tool/node.cpp index ea8b53991..b3b76b9c0 100644 --- a/src/ui/tool/node.cpp +++ b/src/ui/tool/node.cpp @@ -1567,7 +1567,7 @@ NodeList::iterator NodeList::before(double t, double *fracpart) return ret; } -NodeList::iterator NodeList::before(Geom::PathPosition const &pvp) +NodeList::iterator NodeList::before(Geom::PathTime const &pvp) { iterator ret = begin(); std::advance(ret, pvp.curve_index); diff --git a/src/ui/tool/node.h b/src/ui/tool/node.h index 5c907910b..025c460e2 100644 --- a/src/ui/tool/node.h +++ b/src/ui/tool/node.h @@ -406,11 +406,11 @@ public: void setClosed(bool c) { _closed = c; } iterator before(double t, double *fracpart = NULL); - iterator before(Geom::PathPosition const &pvp); + iterator before(Geom::PathTime const &pvp); const_iterator before(double t, double *fracpart = NULL) const { return const_iterator(before(t, fracpart)._node); } - const_iterator before(Geom::PathPosition const &pvp) const { + const_iterator before(Geom::PathTime const &pvp) const { return const_iterator(before(pvp)._node); } diff --git a/src/ui/tool/path-manipulator.cpp b/src/ui/tool/path-manipulator.cpp index 2356e60bf..e54764216 100644 --- a/src/ui/tool/path-manipulator.cpp +++ b/src/ui/tool/path-manipulator.cpp @@ -1649,14 +1649,14 @@ void PathManipulator::_updateDragPoint(Geom::Point const &evp) Geom::PathVector pv = _spcurve->get_pathvector(); if (pv.empty()) return; - boost::optional pvp = - pv.nearestPosition(_desktop->w2d(evp) * to_desktop.inverse()); + boost::optional pvp = + pv.nearestTime(_desktop->w2d(evp) * to_desktop.inverse()); Geom::Point nearest_pt = _desktop->d2w(pv.pointAt(*pvp) * to_desktop); double fracpart = pvp->t; std::list::iterator spi = _subpaths.begin(); for (unsigned i = 0; i < pvp->path_index; ++i, ++spi) {} - NodeList::iterator first = (*spi)->before(pvp->asPathPosition()); + NodeList::iterator first = (*spi)->before(pvp->asPathTime()); double stroke_tolerance = _getStrokeTolerance(); if (first && first.next() && -- cgit v1.2.3 From 6307c00b5774db5e914415127b302cca5e21345b Mon Sep 17 00:00:00 2001 From: Marc Jeanmougin Date: Fri, 1 May 2015 02:26:56 +0200 Subject: Fixed crash bug due to some overlooked function changed in the recent merge. Also fixed the layer ordering in the widget, which was messed up by the same bug in a way i haven't quite sorted out (so the fact that this patch fixed it is quite a mystery, but i won't complain) (bzr r14079) --- src/selection-chemistry.cpp | 12 ++++++------ src/splivarot.cpp | 2 +- src/xml/repr-util.cpp | 17 +++++++++++------ src/xml/repr.h | 3 ++- 4 files changed, 20 insertions(+), 14 deletions(-) (limited to 'src') diff --git a/src/selection-chemistry.cpp b/src/selection-chemistry.cpp index 7255e80cb..c30d22503 100644 --- a/src/selection-chemistry.cpp +++ b/src/selection-chemistry.cpp @@ -459,7 +459,7 @@ void sp_selection_duplicate(SPDesktop *desktop, bool suppressDone) // sorting items from different parents sorts each parent's subset without possibly mixing // them, just what we need - sort(reprs.begin(),reprs.end(),sp_repr_compare_position); + sort(reprs.begin(),reprs.end(),sp_repr_compare_position_bool); std::vector newsel; @@ -677,7 +677,7 @@ void sp_edit_invert_in_all_layers(SPDesktop *desktop) static void sp_selection_group_impl(std::vector p, Inkscape::XML::Node *group, Inkscape::XML::Document *xml_doc, SPDocument *doc) { - sort(p.begin(),p.end(),sp_repr_compare_position); + sort(p.begin(),p.end(),sp_repr_compare_position_bool); // Remember the position and parent of the topmost object. gint topmost = p.back()->position(); @@ -1002,7 +1002,7 @@ void sp_selection_raise_to_top(Inkscape::Selection *selection, SPDesktop *deskto } std::vector rl(selection->reprList()); - sort(rl.begin(),rl.end(),sp_repr_compare_position); + sort(rl.begin(),rl.end(),sp_repr_compare_position_bool); for (std::vector::const_iterator l=rl.begin(); l!=rl.end();l++) { Inkscape::XML::Node *repr =(*l); @@ -1086,7 +1086,7 @@ void sp_selection_lower_to_bottom(Inkscape::Selection *selection, SPDesktop *des } std::vector rl(selection->reprList()); - sort(rl.begin(),rl.end(),sp_repr_compare_position); + sort(rl.begin(),rl.end(),sp_repr_compare_position_bool); for (std::vector::const_reverse_iterator l=rl.rbegin();l!=rl.rend();l++) { gint minpos; @@ -2549,7 +2549,7 @@ void sp_selection_clone(SPDesktop *desktop) selection->clear(); // sorting items from different parents sorts each parent's subset without possibly mixing them, just what we need - sort(reprs.begin(),reprs.end(),sp_repr_compare_position); + sort(reprs.begin(),reprs.end(),sp_repr_compare_position_bool); std::vector newsel; @@ -3709,7 +3709,7 @@ void sp_selection_set_clipgroup(SPDesktop *desktop) std::vector p(selection->reprList()); - sort(p.begin(),p.end(),sp_repr_compare_position); + sort(p.begin(),p.end(),sp_repr_compare_position_bool); selection->clear(); diff --git a/src/splivarot.cpp b/src/splivarot.cpp index f61a30462..bec300936 100644 --- a/src/splivarot.cpp +++ b/src/splivarot.cpp @@ -688,7 +688,7 @@ sp_selected_path_boolop(Inkscape::Selection *selection, SPDesktop *desktop, bool // find out the bottom object std::vector sorted(selection->reprList()); - sort(sorted.begin(),sorted.end(),sp_repr_compare_position); + sort(sorted.begin(),sorted.end(),sp_repr_compare_position_bool); source = doc->getObjectByRepr(sorted.front()); } diff --git a/src/xml/repr-util.cpp b/src/xml/repr-util.cpp index 3858f08a7..305f1b292 100644 --- a/src/xml/repr-util.cpp +++ b/src/xml/repr-util.cpp @@ -260,7 +260,7 @@ gchar const *sp_xml_ns_prefix_uri(gchar const *prefix) * -1 first object's position is less than the second * @todo Rewrite this function's description to be understandable */ -bool sp_repr_compare_position(Inkscape::XML::Node const *first, Inkscape::XML::Node const *second) +int sp_repr_compare_position(Inkscape::XML::Node const *first, Inkscape::XML::Node const *second) { int p1, p2; if (first->parent() == second->parent()) { @@ -277,9 +277,9 @@ bool sp_repr_compare_position(Inkscape::XML::Node const *first, Inkscape::XML::N g_assert(ancestor != NULL); if (ancestor == first) { - return false; + return 1; } else if (ancestor == second) { - return true; + return -1; } else { Inkscape::XML::Node const *to_first = AncetreFils(first, ancestor); Inkscape::XML::Node const *to_second = AncetreFils(second, ancestor); @@ -289,9 +289,9 @@ bool sp_repr_compare_position(Inkscape::XML::Node const *first, Inkscape::XML::N } } - if (p1 > p2) return false; - if (p1 < p2) return true; - return false; + if (p1 > p2) return 1; + if (p1 < p2) return -1; + return 0; /* effic: Assuming that the parent--child relationship is consistent (i.e. that the parent really does contain first and second among @@ -310,6 +310,11 @@ bool sp_repr_compare_position(Inkscape::XML::Node const *first, Inkscape::XML::N pjrm */ } +bool sp_repr_compare_position_bool(Inkscape::XML::Node const *first, Inkscape::XML::Node const *second){ + return sp_repr_compare_position_bool(first, second)<0; +} + + /** * Find an element node using an unique attribute. * diff --git a/src/xml/repr.h b/src/xml/repr.h index fbe25ec12..17763195a 100644 --- a/src/xml/repr.h +++ b/src/xml/repr.h @@ -121,7 +121,8 @@ unsigned sp_repr_set_point(Inkscape::XML::Node *repr, char const *key, Geom::Poi unsigned sp_repr_get_point(Inkscape::XML::Node *repr, char const *key, Geom::Point *val); //c++-style comparison : returns (bool)(a Date: Sat, 2 May 2015 01:08:34 +0200 Subject: Fix segfault due to an infinite recursion (due to a typo) (bzr r14083) --- src/xml/repr-util.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/xml/repr-util.cpp b/src/xml/repr-util.cpp index 305f1b292..4cbe930a1 100644 --- a/src/xml/repr-util.cpp +++ b/src/xml/repr-util.cpp @@ -311,7 +311,7 @@ int sp_repr_compare_position(Inkscape::XML::Node const *first, Inkscape::XML::No } bool sp_repr_compare_position_bool(Inkscape::XML::Node const *first, Inkscape::XML::Node const *second){ - return sp_repr_compare_position_bool(first, second)<0; + return sp_repr_compare_position(first, second)<0; } -- cgit v1.2.3 From fee6f2b2bd4ade26b957f91de04d45c38541b05a Mon Sep 17 00:00:00 2001 From: Marc Jeanmougin Date: Sat, 2 May 2015 03:14:58 +0200 Subject: fixed selection after ungroup fixed some regression with displacement of clones of clones when ungrouping (test case: icons.svg) (bzr r14084) --- src/sp-item-group.cpp | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/sp-item-group.cpp b/src/sp-item-group.cpp index 9bd42665d..72cd5d7fa 100644 --- a/src/sp-item-group.cpp +++ b/src/sp-item-group.cpp @@ -375,7 +375,7 @@ void sp_item_group_ungroup_handle_clones(SPItem *parent, Geom::Affine const g) { for(std::list::const_iterator refd=parent->hrefList.begin();refd!=parent->hrefList.end();refd++){ SPItem *citem = dynamic_cast(*refd); - if (citem) { + if (citem && !citem->cloned) { SPUse *useitem = dynamic_cast(citem); if (useitem && useitem->get_original() == parent) { Geom::Affine ctrans; @@ -541,15 +541,12 @@ sp_item_group_ungroup (SPGroup *group, std::vector &children, bool do_d if (item) { item->doWriteTransform(repr, item->transform, NULL, false); + children.insert(children.begin(),item); } else { g_assert_not_reached(); } Inkscape::GC::release(repr); - if (!children.empty() && item) { - children.insert(children.begin(),item); - } - items = g_slist_remove (items, items->data); } -- cgit v1.2.3 From 280053e5ddfcdf158f62d2d6a72681b3092d2168 Mon Sep 17 00:00:00 2001 From: Marc Jeanmougin Date: Sat, 2 May 2015 03:47:39 +0200 Subject: Fixed comparison function used in sorts (bzr r14085) --- src/selection-chemistry.cpp | 6 +++--- src/seltrans.cpp | 2 +- src/sp-object.cpp | 4 ++++ src/sp-object.h | 1 + src/ui/clipboard.cpp | 2 +- 5 files changed, 10 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/selection-chemistry.cpp b/src/selection-chemistry.cpp index c30d22503..68adf5381 100644 --- a/src/selection-chemistry.cpp +++ b/src/selection-chemistry.cpp @@ -326,7 +326,7 @@ static void sp_selection_copy_impl(std::vector const &items, std::vecto { // Sort items: std::vector sorted_items(items); - sort(sorted_items.begin(),sorted_items.end(),sp_object_compare_position); + sort(sorted_items.begin(),sorted_items.end(),sp_object_compare_position_bool); // Copy item reprs: for (std::vector::const_iterator i = sorted_items.begin(); i != sorted_items.end(); i++) { @@ -3245,7 +3245,7 @@ sp_selection_tile(SPDesktop *desktop, bool apply) std::vector items (selection->itemList()); - sort(items.begin(),items.end(),sp_object_compare_position); + sort(items.begin(),items.end(),sp_object_compare_position_bool); // bottommost object, after sorting SPObject *parent = items[0]->parent; @@ -3836,7 +3836,7 @@ void sp_selection_set_mask(SPDesktop *desktop, bool apply_clip_path, bool apply_ std::vector items(selection->itemList()); - sort(items.begin(),items.end(),sp_object_compare_position); + sort(items.begin(),items.end(),sp_object_compare_position_bool); // See lp bug #542004 selection->clear(); diff --git a/src/seltrans.cpp b/src/seltrans.cpp index bfb8d53f1..f7562923f 100644 --- a/src/seltrans.cpp +++ b/src/seltrans.cpp @@ -529,7 +529,7 @@ void Inkscape::SelTrans::stamp() } else { /* Build cache */ l = selection->itemList(); - sort(l.begin(),l.end(),sp_object_compare_position); + sort(l.begin(),l.end(),sp_object_compare_position_bool); _stamp_cache = l; } diff --git a/src/sp-object.cpp b/src/sp-object.cpp index d4b8a15c0..0bb8c240f 100644 --- a/src/sp-object.cpp +++ b/src/sp-object.cpp @@ -357,6 +357,10 @@ int sp_object_compare_position(SPObject const *first, SPObject const *second) return result; } +bool sp_object_compare_position_bool(SPObject const *first, SPObject const *second){ + return sp_object_compare_position(first,second)<0; +} + SPObject *SPObject::appendChildRepr(Inkscape::XML::Node *repr) { if ( !cloned ) { diff --git a/src/sp-object.h b/src/sp-object.h index f5d47be05..7bc02fad5 100644 --- a/src/sp-object.h +++ b/src/sp-object.h @@ -876,6 +876,7 @@ public: * -1 first object's position is less than the second \endverbatim */ int sp_object_compare_position(SPObject const *first, SPObject const *second); +bool sp_object_compare_position_bool(SPObject const *first, SPObject const *second); #endif // SP_OBJECT_H_SEEN diff --git a/src/ui/clipboard.cpp b/src/ui/clipboard.cpp index a3620b754..d6cf1f980 100644 --- a/src/ui/clipboard.cpp +++ b/src/ui/clipboard.cpp @@ -674,7 +674,7 @@ void ClipboardManagerImpl::_copySelection(Inkscape::Selection *selection) // copy the representation of the items std::vector sorted_items(itemlist); - sort(sorted_items.begin(),sorted_items.end(),sp_object_compare_position); + sort(sorted_items.begin(),sorted_items.end(),sp_object_compare_position_bool); for(std::vector::const_iterator i=sorted_items.begin();i!=sorted_items.end();i++){ SPItem *item = *i; -- cgit v1.2.3 From 2f156df97e50f3a1fa2ddc994ddb24dce76a77f2 Mon Sep 17 00:00:00 2001 From: Bryce Harrington Date: Fri, 1 May 2015 22:25:08 -0400 Subject: bzrignore: Fix *.cmake ignorance Only certain .cmake files should be ignored (bzr r14086) --- src/extension/CMakeLists.txt | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src') diff --git a/src/extension/CMakeLists.txt b/src/extension/CMakeLists.txt index 47292fd97..d1104f3cc 100644 --- a/src/extension/CMakeLists.txt +++ b/src/extension/CMakeLists.txt @@ -57,6 +57,7 @@ set(extension_SRC internal/vsd-input.cpp internal/wmf-inout.cpp internal/wmf-print.cpp + internal/wpg-input.cpp internal/filter/filter-all.cpp internal/filter/filter-file.cpp @@ -142,6 +143,7 @@ set(extension_SRC internal/vsd-input.h internal/wmf-inout.h internal/wmf-print.h + internal/wpg-input.h ) if(WIN32) -- cgit v1.2.3 From d990da7606e88039bbb5b133559b4b1b201a1363 Mon Sep 17 00:00:00 2001 From: Bryce Harrington Date: Sat, 2 May 2015 02:09:38 -0400 Subject: sp-text: Whitespace cleanup (bzr r14088) --- src/sp-text.cpp | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) (limited to 'src') diff --git a/src/sp-text.cpp b/src/sp-text.cpp index 0dca42bb4..d351e58e3 100644 --- a/src/sp-text.cpp +++ b/src/sp-text.cpp @@ -149,7 +149,7 @@ void SPText::remove_child(Inkscape::XML::Node *rch) { void SPText::update(SPCtx *ctx, guint flags) { unsigned childflags = (flags & SP_OBJECT_MODIFIED_CASCADE); if (flags & SP_OBJECT_MODIFIED_FLAG) { - childflags |= SP_OBJECT_PARENT_MODIFIED_FLAG; + childflags |= SP_OBJECT_PARENT_MODIFIED_FLAG; } // Create temporary list of children @@ -519,7 +519,7 @@ unsigned SPText::_buildLayoutInput(SPObject *root, Inkscape::Text::Layout::Optio } } } - + if (SP_IS_TEXT(root)) { SP_TEXT(root)->attributes.mergeInto(&optional_attrs, parent_optional_attrs, parent_attrs_offset, true, true); if (SP_TEXT(root)->attributes.getTextLength()->_set) { // set textLength on the entire layout, see note in TNG-Layout.h @@ -571,7 +571,7 @@ unsigned SPText::_buildLayoutInput(SPObject *root, Inkscape::Text::Layout::Optio child_attrs_offset--; } } - + for (SPObject *child = root->firstChild() ; child ; child = child->getNext() ) { SPString *str = dynamic_cast(child); if (str) { @@ -691,15 +691,15 @@ bool TextTagAttributes::readSingleAttribute(unsigned key, gchar const *value) case SP_ATTR_DX: attr_vector = &attributes.dx; break; case SP_ATTR_DY: attr_vector = &attributes.dy; break; case SP_ATTR_ROTATE: attr_vector = &attributes.rotate; break; - case SP_ATTR_TEXTLENGTH: - attributes.textLength.readOrUnset(value); - return true; + case SP_ATTR_TEXTLENGTH: + attributes.textLength.readOrUnset(value); + return true; break; - case SP_ATTR_LENGTHADJUST: - attributes.lengthAdjust = (value && !strcmp(value, "spacingAndGlyphs")? - Inkscape::Text::Layout::LENGTHADJUST_SPACINGANDGLYPHS : + case SP_ATTR_LENGTHADJUST: + attributes.lengthAdjust = (value && !strcmp(value, "spacingAndGlyphs")? + Inkscape::Text::Layout::LENGTHADJUST_SPACINGANDGLYPHS : Inkscape::Text::Layout::LENGTHADJUST_SPACING); // default is "spacing" - return true; + return true; break; default: return false; } @@ -724,7 +724,7 @@ void TextTagAttributes::writeTo(Inkscape::XML::Node *node) const node->setAttribute("lengthAdjust", "spacing"); } else if (attributes.lengthAdjust == Inkscape::Text::Layout::LENGTHADJUST_SPACINGANDGLYPHS) { node->setAttribute("lengthAdjust", "spacingAndGlyphs"); - } + } } } @@ -734,7 +734,7 @@ void TextTagAttributes::writeSingleAttributeLength(Inkscape::XML::Node *node, gc gchar single_value_string[32]; g_ascii_formatd(single_value_string, sizeof (single_value_string), "%.8g", length.computed); node->setAttribute(key, single_value_string); - } else + } else node->setAttribute(key, NULL); } @@ -802,7 +802,7 @@ void TextTagAttributes::mergeInto(Inkscape::Text::Layout::OptionalTextTagAttrs * output->textLength.unit = attributes.textLength.unit; output->textLength._set = attributes.textLength._set; output->lengthAdjust = attributes.lengthAdjust; - } + } } void TextTagAttributes::mergeSingleAttribute(std::vector *output_list, std::vector const &parent_list, unsigned parent_offset, std::vector const *overlay_list) -- cgit v1.2.3 From 6ebb6cfcf28dfd36a22ce4fe11324971c34ee70c Mon Sep 17 00:00:00 2001 From: Tomasz Boczkowski Date: Sat, 2 May 2015 14:54:37 +0200 Subject: gtk3 compile fix (bzr r14059.1.13) --- src/extension/param/color.cpp | 1 - src/ui/dialog/objects.h | 4 ---- src/ui/selected-color.cpp | 8 ++------ src/ui/selected-color.h | 14 +++++--------- src/ui/widget/color-notebook.h | 10 +++------- src/widgets/paint-selector.h | 4 ---- 6 files changed, 10 insertions(+), 31 deletions(-) (limited to 'src') diff --git a/src/extension/param/color.cpp b/src/extension/param/color.cpp index e3410fba8..e68dbf8bf 100644 --- a/src/extension/param/color.cpp +++ b/src/extension/param/color.cpp @@ -24,7 +24,6 @@ #include "color.h" #include -#include "widgets/sp-color-selector.h" #include "ui/widget/color-notebook.h" #include "preferences.h" diff --git a/src/ui/dialog/objects.h b/src/ui/dialog/objects.h index aa50353c2..7a826d02e 100644 --- a/src/ui/dialog/objects.h +++ b/src/ui/dialog/objects.h @@ -16,10 +16,6 @@ # include #endif -#if GLIBMM_DISABLE_DEPRECATED && HAVE_GLIBMM_THREADS_H -# include -#endif - #include #include #include diff --git a/src/ui/selected-color.cpp b/src/ui/selected-color.cpp index 0d3505c45..7652e5acf 100644 --- a/src/ui/selected-color.cpp +++ b/src/ui/selected-color.cpp @@ -14,15 +14,11 @@ # include "config.h" #endif -#if GLIBMM_DISABLE_DEPRECATED && HAVE_GLIBMM_THREADS_H -#include -#endif - +#include #include -#include -#include "selected-color.h" #include "svg/svg-icc-color.h" +#include "ui/selected-color.h" namespace Inkscape { namespace UI { diff --git a/src/ui/selected-color.h b/src/ui/selected-color.h index b4268f553..168099c82 100644 --- a/src/ui/selected-color.h +++ b/src/ui/selected-color.h @@ -13,18 +13,14 @@ #ifndef SEEN_SELECTED_COLOR #define SEEN_SELECTED_COLOR -#ifdef HAVE_CONFIG_H -# include -#endif - -#if GLIBMM_DISABLE_DEPRECATED && HAVE_GLIBMM_THREADS_H -#include -#endif - #include -#include #include "color.h" +namespace Gtk +{ + class Widget; +} + namespace Inkscape { namespace UI { diff --git a/src/ui/widget/color-notebook.h b/src/ui/widget/color-notebook.h index 8b74f20f1..9e2aa8ec9 100644 --- a/src/ui/widget/color-notebook.h +++ b/src/ui/widget/color-notebook.h @@ -18,18 +18,14 @@ # include #endif -#if GLIBMM_DISABLE_DEPRECATED && HAVE_GLIBMM_THREADS_H -#include -#endif - #include -#include -#include -#if GTK_CHECK_VERSION(3,0,0) +#if WITH_GTKMM_3_0 #include #else #include #endif +#include +#include #include "color.h" #include "ui/selected-color.h" diff --git a/src/widgets/paint-selector.h b/src/widgets/paint-selector.h index 0e8a2967d..55f0e8ec9 100644 --- a/src/widgets/paint-selector.h +++ b/src/widgets/paint-selector.h @@ -16,10 +16,6 @@ # include #endif -#if GLIBMM_DISABLE_DEPRECATED && HAVE_GLIBMM_THREADS_H -#include -#endif - #include #include -- cgit v1.2.3 From f893425c4e9d23a438fb34b9f4bccd409650d484 Mon Sep 17 00:00:00 2001 From: Marc Jeanmougin Date: Sat, 2 May 2015 21:48:52 +0200 Subject: fix crash when setting clip (bzr r14094) --- src/selection-chemistry.cpp | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/selection-chemistry.cpp b/src/selection-chemistry.cpp index 68adf5381..f444f4217 100644 --- a/src/selection-chemistry.cpp +++ b/src/selection-chemistry.cpp @@ -3884,17 +3884,18 @@ void sp_selection_set_mask(SPDesktop *desktop, bool apply_clip_path, bool apply_ items_to_select.push_back(*i); } } else { - GSList *i = NULL; - for (std::vector::const_iterator i=items.begin();i!=items.end();i++) { - apply_to_items = g_slist_prepend(apply_to_items, *i); - items_to_select.push_back(*i); + SPItem *i = NULL; + for (std::vector::const_iterator j=items.begin();j!=items.end();j++) { + i=*j; + apply_to_items = g_slist_prepend(apply_to_items, i); + items_to_select.push_back(i); } - Inkscape::XML::Node *dup = SP_OBJECT(i->data)->getRepr()->duplicate(xml_doc); + Inkscape::XML::Node *dup = SP_OBJECT(i)->getRepr()->duplicate(xml_doc); mask_items = g_slist_prepend(mask_items, dup); if (remove_original) { - SPObject *item = reinterpret_cast(i->data); + SPObject *item = reinterpret_cast(i); items_to_delete = g_slist_prepend(items_to_delete, item); } } -- cgit v1.2.3 From 2fee41cb4965333df801ae5fd97ac5ea95df049a Mon Sep 17 00:00:00 2001 From: Tomasz Boczkowski Date: Sun, 3 May 2015 10:19:47 +0200 Subject: Removed unnecessary inclusion of glibmm/threads.h (bzr r14059.1.14) --- src/ui/widget/color-entry.cpp | 12 ++---------- src/ui/widget/color-entry.h | 8 -------- src/ui/widget/color-icc-selector.cpp | 9 +++------ src/ui/widget/color-icc-selector.h | 6 +----- src/ui/widget/color-notebook.cpp | 5 ----- src/ui/widget/color-scales.cpp | 8 ++------ src/ui/widget/color-scales.h | 9 +-------- src/ui/widget/color-slider.cpp | 7 +++---- src/ui/widget/color-slider.h | 8 -------- src/ui/widget/color-wheel-selector.h | 8 +------- 10 files changed, 13 insertions(+), 67 deletions(-) (limited to 'src') diff --git a/src/ui/widget/color-entry.cpp b/src/ui/widget/color-entry.cpp index e26cb4ade..89a63c6d0 100644 --- a/src/ui/widget/color-entry.cpp +++ b/src/ui/widget/color-entry.cpp @@ -7,17 +7,9 @@ * Copyright (C) 2014 Authors * Released under GNU GPL, read the file 'COPYING' for more information */ - -#ifdef HAVE_CONFIG_H -# include -#endif - -#if GLIBMM_DISABLE_DEPRECATED && HAVE_GLIBMM_THREADS_H -#include -#endif - -#include +#include #include +#include #include "color-entry.h" diff --git a/src/ui/widget/color-entry.h b/src/ui/widget/color-entry.h index 148b5dfe9..ecb0518b1 100644 --- a/src/ui/widget/color-entry.h +++ b/src/ui/widget/color-entry.h @@ -11,14 +11,6 @@ #ifndef SEEN_COLOR_ENTRY_H #define SEEN_COLOR_ENTRY_H_ -#ifdef HAVE_CONFIG_H -# include -#endif - -#if GLIBMM_DISABLE_DEPRECATED && HAVE_GLIBMM_THREADS_H -#include -#endif - #include #include "ui/selected-color.h" diff --git a/src/ui/widget/color-icc-selector.cpp b/src/ui/widget/color-icc-selector.cpp index db73c9111..e8d5be8a7 100644 --- a/src/ui/widget/color-icc-selector.cpp +++ b/src/ui/widget/color-icc-selector.cpp @@ -2,14 +2,11 @@ # include "config.h" #endif -#if GLIBMM_DISABLE_DEPRECATED && HAVE_GLIBMM_THREADS_H -#include -#endif - #include -#include -#include #include +#include + +#include #include #include #include diff --git a/src/ui/widget/color-icc-selector.h b/src/ui/widget/color-icc-selector.h index b917066dd..6066586f5 100644 --- a/src/ui/widget/color-icc-selector.h +++ b/src/ui/widget/color-icc-selector.h @@ -5,12 +5,8 @@ # include #endif -#if GLIBMM_DISABLE_DEPRECATED && HAVE_GLIBMM_THREADS_H -#include -#endif - #include -#if GTK_CHECK_VERSION(3,0,0) +#if WITH_GTKMM_3_0 #include #else #include diff --git a/src/ui/widget/color-notebook.cpp b/src/ui/widget/color-notebook.cpp index 0a4473a3b..ddffb0246 100644 --- a/src/ui/widget/color-notebook.cpp +++ b/src/ui/widget/color-notebook.cpp @@ -19,16 +19,11 @@ # include "config.h" #endif -#if GLIBMM_DISABLE_DEPRECATED && HAVE_GLIBMM_THREADS_H -#include -#endif - #include "widgets/icon.h" #include #include #include #include -#include #include #include #include diff --git a/src/ui/widget/color-scales.cpp b/src/ui/widget/color-scales.cpp index 1771644d1..e9931e938 100644 --- a/src/ui/widget/color-scales.cpp +++ b/src/ui/widget/color-scales.cpp @@ -6,14 +6,10 @@ # include "config.h" #endif -#if GLIBMM_DISABLE_DEPRECATED && HAVE_GLIBMM_THREADS_H -#include -#endif - #include -#include -#include #include +#include +#include #include "svg/svg-icc-color.h" #include "ui/dialog-events.h" diff --git a/src/ui/widget/color-scales.h b/src/ui/widget/color-scales.h index 0f0c4f90e..af7f726f1 100644 --- a/src/ui/widget/color-scales.h +++ b/src/ui/widget/color-scales.h @@ -5,14 +5,7 @@ # include #endif -#if GLIBMM_DISABLE_DEPRECATED && HAVE_GLIBMM_THREADS_H -#include -#endif - -#include -#include -#include -#if GTK_CHECK_VERSION(3,0,0) +#if WITH_GTKMM_3_0 #include #else #include diff --git a/src/ui/widget/color-slider.cpp b/src/ui/widget/color-slider.cpp index ad9662c6c..bf8b85dbd 100644 --- a/src/ui/widget/color-slider.cpp +++ b/src/ui/widget/color-slider.cpp @@ -15,20 +15,19 @@ # include "config.h" #endif -#include "color-slider.h" - -#include #include #include #include #include -#if GTK_CHECK_VERSION(3,0,0) +#if WITH_GTKMM_3_0 #include #else #include #endif +#include #include "ui/widget/color-scales.h" +#include "ui/widget/color-slider.h" #include "preferences.h" static const gint SLIDER_WIDTH = 96; diff --git a/src/ui/widget/color-slider.h b/src/ui/widget/color-slider.h index 48d067bb8..2f2e7b2db 100644 --- a/src/ui/widget/color-slider.h +++ b/src/ui/widget/color-slider.h @@ -12,14 +12,6 @@ #ifndef SEEN_COLOR_SLIDER_H #define SEEN_COLOR_SLIDER_H -#ifdef HAVE_CONFIG_H -# include -#endif - -#if GLIBMM_DISABLE_DEPRECATED && HAVE_GLIBMM_THREADS_H -#include -#endif - #include #include diff --git a/src/ui/widget/color-wheel-selector.h b/src/ui/widget/color-wheel-selector.h index f5213fad7..ec30cc7c5 100644 --- a/src/ui/widget/color-wheel-selector.h +++ b/src/ui/widget/color-wheel-selector.h @@ -16,13 +16,7 @@ # include #endif -#if GLIBMM_DISABLE_DEPRECATED && HAVE_GLIBMM_THREADS_H -#include -#endif - -#include -#include -#if GTK_CHECK_VERSION(3,0,0) +#if WITH_GTKMM_3_0 #include #else #include -- cgit v1.2.3 From f107d4347aefa08df9738e23cf078da73277711e Mon Sep 17 00:00:00 2001 From: Tomasz Boczkowski Date: Sun, 3 May 2015 11:01:16 +0200 Subject: Introduced fixes after merge proposal review (bzr r14059.1.16) --- src/extension/internal/cairo-render-context.cpp | 1 - src/extension/param/color.cpp | 2 +- src/ui/widget/color-entry.cpp | 5 +- src/ui/widget/color-icc-selector.cpp | 45 ++++++----------- src/ui/widget/color-scales.cpp | 67 +++++++++++-------------- src/ui/widget/color-scales.h | 2 +- 6 files changed, 47 insertions(+), 75 deletions(-) (limited to 'src') diff --git a/src/extension/internal/cairo-render-context.cpp b/src/extension/internal/cairo-render-context.cpp index 7162ca658..abfdd9f1c 100644 --- a/src/extension/internal/cairo-render-context.cpp +++ b/src/extension/internal/cairo-render-context.cpp @@ -1018,7 +1018,6 @@ CairoRenderContext::_createPatternPainter(SPPaintServer const *const paintserver TRACE(("%f x %f pattern\n", width, height)); if (pbox && pat->get_pattern_units() == SPPattern::UNITS_OBJECTBOUNDINGBOX) { - //Geom::Affine bbox2user (pbox->x1 - pbox->x0, 0.0, 0.0, pbox->y1 - pbox->y0, pbox->x0, pbox->y0); bbox_width_scaler = pbox->width(); bbox_height_scaler = pbox->height(); ps2user[4] = x * bbox_width_scaler + pbox->left(); diff --git a/src/extension/param/color.cpp b/src/extension/param/color.cpp index e68dbf8bf..3162e8a40 100644 --- a/src/extension/param/color.cpp +++ b/src/extension/param/color.cpp @@ -78,7 +78,7 @@ ParamColor::ParamColor (const gchar * name, const gchar * guitext, const gchar * void ParamColor::string(std::string &string) const { char str[16]; - sprintf(str, "%i", _color.value()); + snprintf(str, 16, "%i", _color.value()); string += str; } diff --git a/src/ui/widget/color-entry.cpp b/src/ui/widget/color-entry.cpp index 89a63c6d0..a1fabf181 100644 --- a/src/ui/widget/color-entry.cpp +++ b/src/ui/widget/color-entry.cpp @@ -49,9 +49,8 @@ void ColorEntry::on_changed() { text.erase(0, 1); if (text.size() == 6) { // it was a standard RGB hex - unsigned int alph = SP_COLOR_F_TO_U(_color.alpha()); - Glib::ustring tmp = Glib::ustring::format(std::hex, std::setw(2), std::setfill(L'0'), alph); - text += tmp; + unsigned int alpha = SP_COLOR_F_TO_U(_color.alpha()); + text += Glib::ustring::format(std::hex, std::setw(2), std::setfill(L'0'), alpha); } } diff --git a/src/ui/widget/color-icc-selector.cpp b/src/ui/widget/color-icc-selector.cpp index e8d5be8a7..48c098604 100644 --- a/src/ui/widget/color-icc-selector.cpp +++ b/src/ui/widget/color-icc-selector.cpp @@ -236,23 +236,6 @@ std::vector colorspace::getColorSpaceInfo( Inkscape::Colo #endif // defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) - - - - - - - - - - - - - - - - - namespace Inkscape { namespace UI { namespace Widget { @@ -263,23 +246,23 @@ namespace Widget { class ComponentUI { public: - ComponentUI() : - _component(), - _adj(0), - _slider(0), - _btn(0), - _label(0), - _map(0) + ComponentUI() + : _component() + , _adj(0) + , _slider(0) + , _btn(0) + , _label(0) + , _map(0) { } - ComponentUI(colorspace::Component const &component) : - _component(component), - _adj(0), - _slider(0), - _btn(0), - _label(0), - _map(0) + ComponentUI(colorspace::Component const &component) + : _component(component) + , _adj(0) + , _slider(0) + , _btn(0) + , _label(0) + , _map(0) { } diff --git a/src/ui/widget/color-scales.cpp b/src/ui/widget/color-scales.cpp index e9931e938..9f18b2d96 100644 --- a/src/ui/widget/color-scales.cpp +++ b/src/ui/widget/color-scales.cpp @@ -176,43 +176,36 @@ void ColorScales::_initUI(SPColorScalesMode mode) setMode(mode); } -void ColorScales::_recalcColor( gboolean changing ) +void ColorScales::_recalcColor() { - if ( changing ) + SPColor color; + gfloat alpha = 1.0; + gfloat c[5]; + + switch (_mode) { + case SP_COLOR_SCALES_MODE_RGB: + case SP_COLOR_SCALES_MODE_HSV: + _getRgbaFloatv(c); + color.set( c[0], c[1], c[2] ); + alpha = c[3]; + break; + case SP_COLOR_SCALES_MODE_CMYK: { - SPColor color; - gfloat alpha = 1.0; - gfloat c[5]; - - switch (_mode) { - case SP_COLOR_SCALES_MODE_RGB: - case SP_COLOR_SCALES_MODE_HSV: - _getRgbaFloatv(c); - color.set( c[0], c[1], c[2] ); - alpha = c[3]; - break; - case SP_COLOR_SCALES_MODE_CMYK: - { - _getCmykaFloatv( c ); - - float rgb[3]; - sp_color_cmyk_to_rgb_floatv( rgb, c[0], c[1], c[2], c[3] ); - color.set( rgb[0], rgb[1], rgb[2] ); - alpha = c[4]; - break; - } - default: - g_warning ("file %s: line %d: Illegal color selector mode %d", __FILE__, __LINE__, _mode); - break; - } - - _color.preserveICC(); - _color.setColorAlpha(color, alpha); + _getCmykaFloatv( c ); + + float rgb[3]; + sp_color_cmyk_to_rgb_floatv( rgb, c[0], c[1], c[2], c[3] ); + color.set( rgb[0], rgb[1], rgb[2] ); + alpha = c[4]; + break; } - else - { - // _updateInternals( _color, _alpha, _dragging ); + default: + g_warning ("file %s: line %d: Illegal color selector mode %d", __FILE__, __LINE__, _mode); + break; } + + _color.preserveICC(); + _color.setColorAlpha(color, alpha); } /* Helpers for setting color value */ @@ -479,7 +472,6 @@ void ColorScales::_sliderAnyGrabbed() if (!_dragging) { _dragging = TRUE; _color.setHeld(true); - _recalcColor( FALSE ); } } @@ -491,7 +483,6 @@ void ColorScales::_sliderAnyReleased() if (_dragging) { _dragging = FALSE; _color.setHeld(false); - _recalcColor( FALSE ); } } @@ -500,7 +491,7 @@ void ColorScales::_sliderAnyChanged() if (_updating) { return; } - _recalcColor( TRUE ); + _recalcColor(); } void ColorScales::_adjustmentChanged( ColorScales *scales, guint channel ) @@ -510,7 +501,7 @@ void ColorScales::_adjustmentChanged( ColorScales *scales, guint channel ) } scales->_updateSliders( (1 << channel) ); - scales->_recalcColor (TRUE); + scales->_recalcColor(); } void ColorScales::_updateSliders( guint channels ) @@ -627,7 +618,7 @@ void ColorScales::_updateSliders( guint channels ) // Force the internal color to be updated if ( !_updating ) { - _recalcColor( TRUE ); + _recalcColor(); } #ifdef SPCS_PREVIEW diff --git a/src/ui/widget/color-scales.h b/src/ui/widget/color-scales.h index af7f726f1..0744a645c 100644 --- a/src/ui/widget/color-scales.h +++ b/src/ui/widget/color-scales.h @@ -63,7 +63,7 @@ protected: void _getCmykaFloatv(gfloat *cmyka); guint32 _getRgba32(); void _updateSliders(guint channels); - void _recalcColor(gboolean changing); + void _recalcColor(); void _setRangeLimit( gdouble upper ); -- cgit v1.2.3 From 5afcb9ce46813689190a622590aee6ab618fb6f4 Mon Sep 17 00:00:00 2001 From: Tomasz Boczkowski Date: Sun, 3 May 2015 11:05:46 +0200 Subject: Removed commented out code from ColorNotebook (bzr r14059.1.17) --- src/ui/widget/color-notebook.cpp | 149 --------------------------------------- src/ui/widget/color-notebook.h | 15 ---- 2 files changed, 164 deletions(-) (limited to 'src') diff --git a/src/ui/widget/color-notebook.cpp b/src/ui/widget/color-notebook.cpp index ddffb0246..92b1d7086 100644 --- a/src/ui/widget/color-notebook.cpp +++ b/src/ui/widget/color-notebook.cpp @@ -168,55 +168,6 @@ void ColorNotebook::_initUI() // restore the last active page Inkscape::Preferences *prefs = Inkscape::Preferences::get(); _setCurrentPage(prefs->getInt("/colorselector/page", 0)); - - - /* Commented out: see comment at the bottom of the header file - { - gboolean found = FALSE; - - _popup = gtk_menu_new(); - GtkMenu *menu = GTK_MENU (_popup); - - for (int i = 0; i < _trackerList->len; i++ ) - { - SPColorNotebookTracker *entry = reinterpret_cast< SPColorNotebookTracker* > (g_ptr_array_index (_trackerList, i)); - if ( entry ) - { - GtkWidget *item = gtk_check_menu_item_new_with_label (_(entry->name)); - gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), entry->enabledFull); - gtk_widget_show (item); - gtk_menu_shell_append (GTK_MENU_SHELL(menu), item); - - g_signal_connect (G_OBJECT (item), "activate", - G_CALLBACK (sp_color_notebook_menuitem_response), - reinterpret_cast< gpointer > (entry) ); - found = TRUE; - } - } - - GtkWidget *arrow = gtk_arrow_new(GTK_ARROW_RIGHT, GTK_SHADOW_NONE); - gtk_widget_show (arrow); - - _btn = gtk_button_new (); - gtk_widget_show (_btn); - gtk_container_add (GTK_CONTAINER (_btn), arrow); - - GtkWidget *align = gtk_alignment_new (1.0, 0.0, 0.0, 0.0); - gtk_widget_show (align); - gtk_container_add (GTK_CONTAINER (align), _btn); - - // uncomment to reenable the "show/hide modes" menu, - // but first fix it so it remembers its settings in prefs and does not take that much space (entire vertical column!) - gtk_table_attach (GTK_TABLE (table), align, 2, 3, row, row + 1, GTK_FILL, GTK_FILL, XPAD, YPAD); - - g_signal_connect_swapped(G_OBJECT(_btn), "event", G_CALLBACK (sp_color_notebook_menu_handler), G_OBJECT(_csel)); - if ( !found ) - { - gtk_widget_set_sensitive (_btn, FALSE); - } - } - */ - row++; #if GTK_CHECK_VERSION(3,0,0) @@ -420,106 +371,6 @@ void ColorNotebook::_addPage(Page& page) { } } -/* Commented out: see comment at the bottom of the header file - -GtkWidget* ColorNotebook::getPage(GType page_type, guint submode) -{ - gint count = 0; - gint i = 0; - GtkWidget* page = 0; - -// count = gtk_notebook_get_n_pages (_book); - count = 200; - for ( i = 0; i < count && !page; i++ ) - { - page = gtk_notebook_get_nth_page (GTK_NOTEBOOK (_book), i); - if ( page ) - { - SPColorSelector* csel; - guint pagemode; - csel = SP_COLOR_SELECTOR (page); - pagemode = csel->base->getSubmode(); - if ( G_TYPE_FROM_INSTANCE (page) == page_type - && pagemode == submode ) - { - // found it. - break; - } - else - { - page = 0; - } - } - else - { - break; - } - } - return page; -} - -void ColorNotebook::removePage( GType page_type, guint submode ) -{ - GtkWidget *page = 0; - - page = getPage(page_type, submode); - if ( page ) - { - gint where = gtk_notebook_page_num (GTK_NOTEBOOK (_book), page); - if ( where >= 0 ) - { - if ( gtk_notebook_get_current_page (GTK_NOTEBOOK (_book)) == where ) - { -// getColorAlpha(_color, &_alpha); - } - gtk_notebook_remove_page (GTK_NOTEBOOK (_book), where); - } - } -} - - -static gint sp_color_notebook_menu_handler( GtkWidget *widget, GdkEvent *event ) -{ - if (event->type == GDK_BUTTON_PRESS) - { - SPColorSelector* csel = SP_COLOR_SELECTOR(widget); - (dynamic_cast(csel->base))->menuHandler( event ); - - // Tell calling code that we have handled this event; the buck - // stops here. - return TRUE; - } - - //Tell calling code that we have not handled this event; pass it on. - return FALSE; -} - -gint ColorNotebook::menuHandler( GdkEvent* event ) -{ - GdkEventButton *bevent = (GdkEventButton *) event; - gtk_menu_popup (GTK_MENU( _popup ), NULL, NULL, NULL, NULL, - bevent->button, bevent->time); - return TRUE; -} - -static void sp_color_notebook_menuitem_response (GtkMenuItem *menuitem, gpointer user_data) -{ - gboolean active = gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (menuitem)); - SPColorNotebookTracker *entry = reinterpret_cast< SPColorNotebookTracker* > (user_data); - if ( entry ) - { - if ( active ) - { - (dynamic_cast(SP_COLOR_SELECTOR(entry->backPointer)->base))->addPage(entry->type, entry->submode); - } - else - { - (dynamic_cast(SP_COLOR_SELECTOR(entry->backPointer)->base))->removePage(entry->type, entry->submode); - } - } -} -*/ - /* Local Variables: mode:c++ diff --git a/src/ui/widget/color-notebook.h b/src/ui/widget/color-notebook.h index 9e2aa8ec9..9909aa39c 100644 --- a/src/ui/widget/color-notebook.h +++ b/src/ui/widget/color-notebook.h @@ -82,21 +82,6 @@ private: // By default, disallow copy constructor and assignment operator ColorNotebook( const ColorNotebook& obj ); ColorNotebook& operator=( const ColorNotebook& obj ); - - /* Following methods support the pop-up menu to choose - * active color selectors (notebook tabs). This function - * is not used in Inkscape. If you want to re-enable it you have to - * * port the code to c++ - * * fix it so it remembers its settings in prefs - * * fix it so it does not take that much space (entire vertical column!) - * Current class design supports dynamic addtion and removal of color selectors - * - GtkWidget* addPage( GType page_type, guint submode ); - void removePage( GType page_type, guint submode ); - GtkWidget* getPage( GType page_type, guint submode ); - gint menuHandler( GdkEvent* event ); - - */ }; } -- cgit v1.2.3 From d41a1b907e503a5e6c587c35607a5fa2015eb0ae Mon Sep 17 00:00:00 2001 From: Tomasz Boczkowski Date: Sun, 3 May 2015 11:42:05 +0200 Subject: Reformatted refactored files (bzr r14059.1.18) --- src/ui/widget/color-entry.cpp | 18 +- src/ui/widget/color-entry.h | 3 +- src/ui/widget/color-icc-selector.cpp | 784 +++++++++++++++-------------- src/ui/widget/color-icc-selector.h | 27 +- src/ui/widget/color-notebook.cpp | 200 ++++---- src/ui/widget/color-notebook.h | 16 +- src/ui/widget/color-scales.cpp | 888 ++++++++++++++++----------------- src/ui/widget/color-scales.h | 27 +- src/ui/widget/color-slider.cpp | 491 +++++++++--------- src/ui/widget/color-slider.h | 43 +- src/ui/widget/color-wheel-selector.cpp | 96 ++-- src/ui/widget/color-wheel-selector.h | 22 +- 12 files changed, 1291 insertions(+), 1324 deletions(-) (limited to 'src') diff --git a/src/ui/widget/color-entry.cpp b/src/ui/widget/color-entry.cpp index a1fabf181..473d7de65 100644 --- a/src/ui/widget/color-entry.cpp +++ b/src/ui/widget/color-entry.cpp @@ -30,12 +30,14 @@ ColorEntry::ColorEntry(SelectedColor &color) set_tooltip_text(_("Hexadecimal RGBA value of the color")); } -ColorEntry::~ColorEntry() { +ColorEntry::~ColorEntry() +{ _color_changed_connection.disconnect(); _color_dragged_connection.disconnect(); } -void ColorEntry::on_changed() { +void ColorEntry::on_changed() +{ if (_updating) { return; } @@ -43,7 +45,7 @@ void ColorEntry::on_changed() { Glib::ustring text = get_text(); bool changed = false; - //Coerce the value format to eight hex digits + // Coerce the value format to eight hex digits if (!text.empty() && text[0] == '#') { changed = true; text.erase(0, 1); @@ -54,8 +56,8 @@ void ColorEntry::on_changed() { } } - gchar* str = g_strdup(text.c_str()); - gchar* end = 0; + gchar *str = g_strdup(text.c_str()); + gchar *end = 0; guint64 rgba = g_ascii_strtoull(str, &end, 16); if (end != str) { ptrdiff_t len = end - str; @@ -72,11 +74,12 @@ void ColorEntry::on_changed() { } -void ColorEntry::_onColorChanged() { +void ColorEntry::_onColorChanged() +{ SPColor color = _color.color(); gdouble alpha = _color.alpha(); - guint32 rgba = color.toRGBA32( alpha ); + guint32 rgba = color.toRGBA32(alpha); Glib::ustring text = Glib::ustring::format(std::hex, std::setw(8), std::setfill(L'0'), rgba); Glib::ustring old_text = get_text(); @@ -86,7 +89,6 @@ void ColorEntry::_onColorChanged() { _updating = false; } } - } } } diff --git a/src/ui/widget/color-entry.h b/src/ui/widget/color-entry.h index ecb0518b1..cd7d6164a 100644 --- a/src/ui/widget/color-entry.h +++ b/src/ui/widget/color-entry.h @@ -18,7 +18,8 @@ namespace Inkscape { namespace UI { namespace Widget { -class ColorEntry: public Gtk::Entry { +class ColorEntry : public Gtk::Entry +{ public: ColorEntry(SelectedColor &color); virtual ~ColorEntry(); diff --git a/src/ui/widget/color-icc-selector.cpp b/src/ui/widget/color-icc-selector.cpp index 48c098604..a7e75bfc5 100644 --- a/src/ui/widget/color-icc-selector.cpp +++ b/src/ui/widget/color-icc-selector.cpp @@ -1,5 +1,5 @@ #ifdef HAVE_CONFIG_H -# include "config.h" +#include "config.h" #endif #include @@ -36,40 +36,30 @@ #ifdef DEBUG_LCMS extern guint update_in_progress; -#define DEBUG_MESSAGE(key, ...) \ -{\ - Inkscape::Preferences *prefs = Inkscape::Preferences::get();\ - bool dump = prefs->getBool("/options/scislac/" #key);\ - bool dumpD = prefs->getBool("/options/scislac/" #key "D");\ - bool dumpD2 = prefs->getBool("/options/scislac/" #key "D2");\ - dumpD &&= ( (update_in_progress == 0) || dumpD2 );\ - if ( dump )\ - {\ - g_message( __VA_ARGS__ );\ -\ - }\ - if ( dumpD )\ - {\ - GtkWidget *dialog = gtk_message_dialog_new(NULL,\ - GTK_DIALOG_DESTROY_WITH_PARENT, \ - GTK_MESSAGE_INFO, \ - GTK_BUTTONS_OK, \ - __VA_ARGS__ \ - );\ - g_signal_connect_swapped(dialog, "response",\ - G_CALLBACK(gtk_widget_destroy), \ - dialog); \ - gtk_widget_show_all( dialog );\ - }\ -} +#define DEBUG_MESSAGE(key, ...) \ + { \ + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); \ + bool dump = prefs->getBool("/options/scislac/" #key); \ + bool dumpD = prefs->getBool("/options/scislac/" #key "D"); \ + bool dumpD2 = prefs->getBool("/options/scislac/" #key "D2"); \ + dumpD && = ((update_in_progress == 0) || dumpD2); \ + if (dump) { \ + g_message(__VA_ARGS__); \ + } \ + if (dumpD) { \ + GtkWidget *dialog = gtk_message_dialog_new(NULL, GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_INFO, \ + GTK_BUTTONS_OK, __VA_ARGS__); \ + g_signal_connect_swapped(dialog, "response", G_CALLBACK(gtk_widget_destroy), dialog); \ + gtk_widget_show_all(dialog); \ + } \ + } #endif // DEBUG_LCMS #define XPAD 4 #define YPAD 1 -namespace -{ +namespace { size_t maxColorspaceComponentCount = 0; @@ -94,41 +84,35 @@ GtkAttachOptions operator|(GtkAttachOptions lhs, GtkAttachOptions rhs) /** * Helper function to handle GTK2/GTK3 attachment #ifdef code. */ -void attachToGridOrTable(GtkWidget *parent, - GtkWidget *child, - guint left, - guint top, - guint width, - guint height, - bool hexpand = false, - bool centered = false, - guint xpadding = XPAD, - guint ypadding = YPAD) +void attachToGridOrTable(GtkWidget *parent, GtkWidget *child, guint left, guint top, guint width, guint height, + bool hexpand = false, bool centered = false, guint xpadding = XPAD, guint ypadding = YPAD) { -#if GTK_CHECK_VERSION(3,0,0) - #if GTK_CHECK_VERSION(3,12,0) - gtk_widget_set_margin_start( child, xpadding ); - gtk_widget_set_margin_end( child, xpadding ); - #else - gtk_widget_set_margin_left( child, xpadding ); - gtk_widget_set_margin_right( child, xpadding ); - #endif - - gtk_widget_set_margin_top( child, ypadding ); - gtk_widget_set_margin_bottom( child, ypadding ); +#if GTK_CHECK_VERSION(3, 0, 0) + #if GTK_CHECK_VERSION(3, 12, 0) + gtk_widget_set_margin_start(child, xpadding); + gtk_widget_set_margin_end(child, xpadding); + #else + gtk_widget_set_margin_left(child, xpadding); + gtk_widget_set_margin_right(child, xpadding); + #endif + + gtk_widget_set_margin_top(child, ypadding); + gtk_widget_set_margin_bottom(child, ypadding); if (hexpand) { gtk_widget_set_hexpand(child, TRUE); } if (centered) { - gtk_widget_set_halign( child, GTK_ALIGN_CENTER ); - gtk_widget_set_valign( child, GTK_ALIGN_CENTER ); + gtk_widget_set_halign(child, GTK_ALIGN_CENTER); + gtk_widget_set_valign(child, GTK_ALIGN_CENTER); } - gtk_grid_attach( GTK_GRID(parent), child, left, top, width, height ); + gtk_grid_attach(GTK_GRID(parent), child, left, top, width, height); #else - GtkAttachOptions xoptions = centered ? static_cast(0) : hexpand ? (GTK_EXPAND | GTK_FILL) : GTK_FILL; + GtkAttachOptions xoptions = + centered ? static_cast(0) : hexpand ? (GTK_EXPAND | GTK_FILL) : GTK_FILL; GtkAttachOptions yoptions = centered ? static_cast(0) : GTK_FILL; - gtk_table_attach( GTK_TABLE(parent), child, left, left + width, top, top + height, xoptions, yoptions, xpadding, ypadding ); + gtk_table_attach(GTK_TABLE(parent), child, left, left + width, top, top + height, xoptions, yoptions, xpadding, + ypadding); #endif } @@ -145,32 +129,32 @@ icSigCmyData #if defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) -static cmsUInt16Number* getScratch() { +static cmsUInt16Number *getScratch() +{ // bytes per pixel * input channels * width - static cmsUInt16Number* scritch = static_cast(g_new(cmsUInt16Number, 4 * 1024)); + static cmsUInt16Number *scritch = static_cast(g_new(cmsUInt16Number, 4 * 1024)); return scritch; } -colorspace::Component::Component() : - name(), - tip(), - scale(1) +colorspace::Component::Component() + : name() + , tip() + , scale(1) { } -colorspace::Component::Component(std::string const &name, std::string const &tip, guint scale) : - name(name), - tip(tip), - scale(scale) +colorspace::Component::Component(std::string const &name, std::string const &tip, guint scale) + : name(name) + , tip(tip) + , scale(scale) { } -std::vector colorspace::getColorSpaceInfo( uint32_t space ) +std::vector colorspace::getColorSpaceInfo(uint32_t space) { static std::map > sets; - if (sets.empty()) - { + if (sets.empty()) { sets[cmsSigXYZData].push_back(Component("_X", "X", 2)); // TYPE_XYZ_16 sets[cmsSigXYZData].push_back(Component("_Y", "Y", 1)); sets[cmsSigXYZData].push_back(Component("_Z", "Z", 2)); @@ -179,7 +163,7 @@ std::vector colorspace::getColorSpaceInfo( uint32_t space sets[cmsSigLabData].push_back(Component("_a", "a", 256)); sets[cmsSigLabData].push_back(Component("_b", "b", 256)); - //cmsSigLuvData + // cmsSigLuvData sets[cmsSigYCbCrData].push_back(Component("_Y", "Y", 1)); // TYPE_YCbCr_16 sets[cmsSigYCbCrData].push_back(Component("C_b", "Cb", 1)); @@ -212,8 +196,7 @@ std::vector colorspace::getColorSpaceInfo( uint32_t space sets[cmsSigCmyData].push_back(Component(_("_M:"), _("Magenta"), 1)); sets[cmsSigCmyData].push_back(Component(_("_Y:"), _("Yellow"), 1)); - for (std::map >::iterator it = sets.begin(); it != sets.end(); ++it) - { + for (std::map >::iterator it = sets.begin(); it != sets.end(); ++it) { knownColorspaces.insert(it->first); maxColorspaceComponentCount = std::max(maxColorspaceComponentCount, it->second.size()); } @@ -221,17 +204,16 @@ std::vector colorspace::getColorSpaceInfo( uint32_t space std::vector target; - if (sets.find(space) != sets.end()) - { + if (sets.find(space) != sets.end()) { target = sets[space]; } return target; } -std::vector colorspace::getColorSpaceInfo( Inkscape::ColorProfile *prof ) +std::vector colorspace::getColorSpaceInfo(Inkscape::ColorProfile *prof) { - return getColorSpaceInfo( asICColorSpaceSig(prof->getColorSpace()) ); + return getColorSpaceInfo(asICColorSpaceSig(prof->getColorSpace())); } #endif // defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) @@ -243,9 +225,8 @@ namespace Widget { /** * Class containing the parts for a single color component's UI presence. */ -class ComponentUI -{ -public: +class ComponentUI { + public: ComponentUI() : _component() , _adj(0) @@ -269,37 +250,35 @@ public: colorspace::Component _component; GtkAdjustment *_adj; // Component adjustment Inkscape::UI::Widget::ColorSlider *_slider; - GtkWidget *_btn; // spinbutton - GtkWidget *_label; // Label - guchar *_map; + GtkWidget *_btn; // spinbutton + GtkWidget *_label; // Label + guchar *_map; }; /** * Class that implements the internals of the selector. */ -class ColorICCSelectorImpl -{ -public: - +class ColorICCSelectorImpl { + public: ColorICCSelectorImpl(ColorICCSelector *owner, SelectedColor &color); ~ColorICCSelectorImpl(); - static void _adjustmentChanged ( GtkAdjustment *adjustment, ColorICCSelectorImpl *cs ); + static void _adjustmentChanged(GtkAdjustment *adjustment, ColorICCSelectorImpl *cs); void _sliderGrabbed(); void _sliderReleased(); void _sliderChanged(); - static void _profileSelected( GtkWidget* src, gpointer data ); - static void _fixupHit( GtkWidget* src, gpointer data ); + static void _profileSelected(GtkWidget *src, gpointer data); + static void _fixupHit(GtkWidget *src, gpointer data); #if defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) - void _setProfile( SVGICCColor* profile ); - void _switchToProfile( gchar const* name ); + void _setProfile(SVGICCColor *profile); + void _switchToProfile(gchar const *name); #endif - void _updateSliders( gint ignore ); - void _profilesChanged( std::string const & name ); + void _updateSliders(gint ignore); + void _profilesChanged(std::string const &name); ColorICCSelector *_owner; SelectedColor &_color; @@ -308,19 +287,19 @@ public: gboolean _dragging : 1; guint32 _fixupNeeded; - GtkWidget* _fixupBtn; - GtkWidget* _profileSel; + GtkWidget *_fixupBtn; + GtkWidget *_profileSel; std::vector _compUI; - GtkAdjustment* _adj; // Channel adjustment - Inkscape::UI::Widget::ColorSlider* _slider; - GtkWidget* _sbtn; // Spinbutton - GtkWidget* _label; // Label + GtkAdjustment *_adj; // Channel adjustment + Inkscape::UI::Widget::ColorSlider *_slider; + GtkWidget *_sbtn; // Spinbutton + GtkWidget *_label; // Label #if defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) std::string _profileName; - Inkscape::ColorProfile* _prof; + Inkscape::ColorProfile *_prof; guint _profChannelCount; gulong _profChangedID; #endif // defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) @@ -328,8 +307,7 @@ public: - -const gchar* ColorICCSelector::MODE_NAME = N_("CMS"); +const gchar *ColorICCSelector::MODE_NAME = N_("CMS"); ColorICCSelector::ColorICCSelector(SelectedColor &color) : _impl(NULL) @@ -337,13 +315,12 @@ ColorICCSelector::ColorICCSelector(SelectedColor &color) _impl = new ColorICCSelectorImpl(this, color); init(); color.signal_changed.connect(sigc::mem_fun(this, &ColorICCSelector::_colorChanged)); - //color.signal_dragged.connect(sigc::mem_fun(this, &ColorICCSelector::_colorChanged)); + // color.signal_dragged.connect(sigc::mem_fun(this, &ColorICCSelector::_colorChanged)); } ColorICCSelector::~ColorICCSelector() { - if (_impl) - { + if (_impl) { delete _impl; _impl = 0; } @@ -351,25 +328,24 @@ ColorICCSelector::~ColorICCSelector() -ColorICCSelectorImpl::ColorICCSelectorImpl(ColorICCSelector *owner, SelectedColor &color) : - _owner(owner), - _color(color), - _updating( FALSE ), - _dragging( FALSE ), - _fixupNeeded(0), - _fixupBtn(0), - _profileSel(0), - _compUI(), - _adj(0), - _slider(0), - _sbtn(0), - _label(0) +ColorICCSelectorImpl::ColorICCSelectorImpl(ColorICCSelector *owner, SelectedColor &color) + : _owner(owner) + , _color(color) + , _updating(FALSE) + , _dragging(FALSE) + , _fixupNeeded(0) + , _fixupBtn(0) + , _profileSel(0) + , _compUI() + , _adj(0) + , _slider(0) + , _sbtn(0) + , _label(0) #if defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) - , - _profileName(), - _prof(0), - _profChannelCount(0), - _profChangedID(0) + , _profileName() + , _prof(0) + , _profChannelCount(0) + , _profChangedID(0) #endif // defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) { } @@ -388,9 +364,9 @@ void ColorICCSelector::init() _impl->_updating = FALSE; _impl->_dragging = FALSE; - GtkWidget* t = GTK_WIDGET(gobj()); + GtkWidget *t = GTK_WIDGET(gobj()); - gtk_widget_show (t); + gtk_widget_show(t); _impl->_compUI.clear(); @@ -399,50 +375,53 @@ void ColorICCSelector::init() _impl->_fixupBtn = gtk_button_new_with_label(_("Fix")); - g_signal_connect( G_OBJECT(_impl->_fixupBtn), "clicked", G_CALLBACK(ColorICCSelectorImpl::_fixupHit), (gpointer)_impl ); - gtk_widget_set_sensitive( _impl->_fixupBtn, FALSE ); - gtk_widget_set_tooltip_text( _impl->_fixupBtn, _("Fix RGB fallback to match icc-color() value.") ); - //gtk_misc_set_alignment( GTK_MISC (_impl->_fixupBtn), 1.0, 0.5 ); - gtk_widget_show( _impl->_fixupBtn ); + g_signal_connect(G_OBJECT(_impl->_fixupBtn), "clicked", G_CALLBACK(ColorICCSelectorImpl::_fixupHit), + (gpointer)_impl); + gtk_widget_set_sensitive(_impl->_fixupBtn, FALSE); + gtk_widget_set_tooltip_text(_impl->_fixupBtn, _("Fix RGB fallback to match icc-color() value.")); + // gtk_misc_set_alignment( GTK_MISC (_impl->_fixupBtn), 1.0, 0.5 ); + gtk_widget_show(_impl->_fixupBtn); attachToGridOrTable(t, _impl->_fixupBtn, 0, row, 1, 1); // Combobox and store with 2 columns : label (0) and full name (1) - GtkListStore *store = gtk_list_store_new (2, G_TYPE_STRING, G_TYPE_STRING); - _impl->_profileSel = gtk_combo_box_new_with_model (GTK_TREE_MODEL (store)); + GtkListStore *store = gtk_list_store_new(2, G_TYPE_STRING, G_TYPE_STRING); + _impl->_profileSel = gtk_combo_box_new_with_model(GTK_TREE_MODEL(store)); - GtkCellRenderer *renderer = gtk_cell_renderer_text_new (); + GtkCellRenderer *renderer = gtk_cell_renderer_text_new(); gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(_impl->_profileSel), renderer, TRUE); gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(_impl->_profileSel), renderer, "text", 0, NULL); GtkTreeIter iter; - gtk_list_store_append (store, &iter); - gtk_list_store_set (store, &iter, 0, _(""), 1, _(""), -1); + gtk_list_store_append(store, &iter); + gtk_list_store_set(store, &iter, 0, _(""), 1, _(""), -1); - gtk_widget_show( _impl->_profileSel ); - gtk_combo_box_set_active( GTK_COMBO_BOX(_impl->_profileSel), 0 ); + gtk_widget_show(_impl->_profileSel); + gtk_combo_box_set_active(GTK_COMBO_BOX(_impl->_profileSel), 0); attachToGridOrTable(t, _impl->_profileSel, 1, row, 1, 1); #if defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) - _impl->_profChangedID = g_signal_connect( G_OBJECT(_impl->_profileSel), "changed", G_CALLBACK(ColorICCSelectorImpl::_profileSelected), (gpointer)_impl ); + _impl->_profChangedID = g_signal_connect(G_OBJECT(_impl->_profileSel), "changed", + G_CALLBACK(ColorICCSelectorImpl::_profileSelected), (gpointer)_impl); #else - gtk_widget_set_sensitive( _impl->_profileSel, false ); + gtk_widget_set_sensitive(_impl->_profileSel, false); #endif // defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) row++; - // populate the data for colorspaces and channels: +// populate the data for colorspaces and channels: #if defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) - std::vector things = colorspace::getColorSpaceInfo( cmsSigRgbData ); + std::vector things = colorspace::getColorSpaceInfo(cmsSigRgbData); #endif // defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) - for ( size_t i = 0; i < maxColorspaceComponentCount; i++ ) { + for (size_t i = 0; i < maxColorspaceComponentCount; i++) { #if defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) if (i < things.size()) { _impl->_compUI.push_back(ComponentUI(things[i])); - } else { + } + else { _impl->_compUI.push_back(ComponentUI()); } @@ -453,9 +432,9 @@ void ColorICCSelector::init() std::string labelStr = "."; #endif - _impl->_compUI[i]._label = gtk_label_new_with_mnemonic( labelStr.c_str() ); - gtk_misc_set_alignment( GTK_MISC (_impl->_compUI[i]._label), 1.0, 0.5 ); - gtk_widget_show( _impl->_compUI[i]._label ); + _impl->_compUI[i]._label = gtk_label_new_with_mnemonic(labelStr.c_str()); + gtk_misc_set_alignment(GTK_MISC(_impl->_compUI[i]._label), 1.0, 0.5); + gtk_widget_show(_impl->_compUI[i]._label); attachToGridOrTable(t, _impl->_compUI[i]._label, 0, row, 1, 1); @@ -464,10 +443,11 @@ void ColorICCSelector::init() gdouble step = static_cast(scaleValue) / 100.0; gdouble page = static_cast(scaleValue) / 10.0; gint digits = (step > 0.9) ? 0 : 2; - _impl->_compUI[i]._adj = GTK_ADJUSTMENT( gtk_adjustment_new( 0.0, 0.0, scaleValue, step, page, page ) ); + _impl->_compUI[i]._adj = GTK_ADJUSTMENT(gtk_adjustment_new(0.0, 0.0, scaleValue, step, page, page)); // Slider - _impl->_compUI[i]._slider = Gtk::manage(new Inkscape::UI::Widget::ColorSlider(Glib::wrap(_impl->_compUI[i]._adj, true))); + _impl->_compUI[i]._slider = + Gtk::manage(new Inkscape::UI::Widget::ColorSlider(Glib::wrap(_impl->_compUI[i]._adj, true))); #if defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) _impl->_compUI[i]._slider->set_tooltip_text((i < things.size()) ? things[i].tip.c_str() : ""); #else @@ -477,28 +457,31 @@ void ColorICCSelector::init() attachToGridOrTable(t, _impl->_compUI[i]._slider->gobj(), 1, row, 1, 1, true); - _impl->_compUI[i]._btn = gtk_spin_button_new( _impl->_compUI[i]._adj, step, digits ); + _impl->_compUI[i]._btn = gtk_spin_button_new(_impl->_compUI[i]._adj, step, digits); #if defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) - gtk_widget_set_tooltip_text( _impl->_compUI[i]._btn, (i < things.size()) ? things[i].tip.c_str() : "" ); + gtk_widget_set_tooltip_text(_impl->_compUI[i]._btn, (i < things.size()) ? things[i].tip.c_str() : ""); #else - gtk_widget_set_tooltip_text( _impl->_compUI[i]._btn, "." ); + gtk_widget_set_tooltip_text(_impl->_compUI[i]._btn, "."); #endif // defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) - sp_dialog_defocus_on_enter( _impl->_compUI[i]._btn ); - gtk_label_set_mnemonic_widget( GTK_LABEL(_impl->_compUI[i]._label), _impl->_compUI[i]._btn ); - gtk_widget_show( _impl->_compUI[i]._btn ); + sp_dialog_defocus_on_enter(_impl->_compUI[i]._btn); + gtk_label_set_mnemonic_widget(GTK_LABEL(_impl->_compUI[i]._label), _impl->_compUI[i]._btn); + gtk_widget_show(_impl->_compUI[i]._btn); attachToGridOrTable(t, _impl->_compUI[i]._btn, 2, row, 1, 1, false, true); - _impl->_compUI[i]._map = g_new( guchar, 4 * 1024 ); - memset( _impl->_compUI[i]._map, 0x0ff, 1024 * 4 ); + _impl->_compUI[i]._map = g_new(guchar, 4 * 1024); + memset(_impl->_compUI[i]._map, 0x0ff, 1024 * 4); // Signals - g_signal_connect( G_OBJECT( _impl->_compUI[i]._adj ), "value_changed", G_CALLBACK( ColorICCSelectorImpl::_adjustmentChanged ), _impl ); + g_signal_connect(G_OBJECT(_impl->_compUI[i]._adj), "value_changed", + G_CALLBACK(ColorICCSelectorImpl::_adjustmentChanged), _impl); _impl->_compUI[i]._slider->signal_grabbed.connect(sigc::mem_fun(_impl, &ColorICCSelectorImpl::_sliderGrabbed)); - _impl->_compUI[i]._slider->signal_released.connect(sigc::mem_fun(_impl, &ColorICCSelectorImpl::_sliderReleased)); - _impl->_compUI[i]._slider->signal_value_changed.connect(sigc::mem_fun(_impl, &ColorICCSelectorImpl::_sliderChanged)); + _impl->_compUI[i]._slider->signal_released.connect( + sigc::mem_fun(_impl, &ColorICCSelectorImpl::_sliderReleased)); + _impl->_compUI[i]._slider->signal_value_changed.connect( + sigc::mem_fun(_impl, &ColorICCSelectorImpl::_sliderChanged)); row++; } @@ -520,9 +503,8 @@ void ColorICCSelector::init() attachToGridOrTable(t, _impl->_slider->gobj(), 1, row, 1, 1, true); - _impl->_slider->setColors(SP_RGBA32_F_COMPOSE( 1.0, 1.0, 1.0, 0.0 ), - SP_RGBA32_F_COMPOSE( 1.0, 1.0, 1.0, 0.5 ), - SP_RGBA32_F_COMPOSE( 1.0, 1.0, 1.0, 1.0 ) ); + _impl->_slider->setColors(SP_RGBA32_F_COMPOSE(1.0, 1.0, 1.0, 0.0), SP_RGBA32_F_COMPOSE(1.0, 1.0, 1.0, 0.5), + SP_RGBA32_F_COMPOSE(1.0, 1.0, 1.0, 1.0)); // Spinbutton @@ -535,66 +517,69 @@ void ColorICCSelector::init() attachToGridOrTable(t, _impl->_sbtn, 2, row, 1, 1, false, true); // Signals - g_signal_connect(G_OBJECT(_impl->_adj), "value_changed", G_CALLBACK(ColorICCSelectorImpl::_adjustmentChanged), _impl); + g_signal_connect(G_OBJECT(_impl->_adj), "value_changed", G_CALLBACK(ColorICCSelectorImpl::_adjustmentChanged), + _impl); _impl->_slider->signal_grabbed.connect(sigc::mem_fun(_impl, &ColorICCSelectorImpl::_sliderGrabbed)); _impl->_slider->signal_released.connect(sigc::mem_fun(_impl, &ColorICCSelectorImpl::_sliderReleased)); _impl->_slider->signal_value_changed.connect(sigc::mem_fun(_impl, &ColorICCSelectorImpl::_sliderChanged)); } -void ColorICCSelectorImpl::_fixupHit( GtkWidget* /*src*/, gpointer data ) +void ColorICCSelectorImpl::_fixupHit(GtkWidget * /*src*/, gpointer data) { - ColorICCSelectorImpl* self = reinterpret_cast(data); - gtk_widget_set_sensitive( self->_fixupBtn, FALSE ); - self->_adjustmentChanged( self->_compUI[0]._adj, self ); + ColorICCSelectorImpl *self = reinterpret_cast(data); + gtk_widget_set_sensitive(self->_fixupBtn, FALSE); + self->_adjustmentChanged(self->_compUI[0]._adj, self); } #if defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) -void ColorICCSelectorImpl::_profileSelected( GtkWidget* /*src*/, gpointer data ) +void ColorICCSelectorImpl::_profileSelected(GtkWidget * /*src*/, gpointer data) { - ColorICCSelectorImpl* self = reinterpret_cast(data); + ColorICCSelectorImpl *self = reinterpret_cast(data); - GtkTreeIter iter; + GtkTreeIter iter; if (gtk_combo_box_get_active_iter(GTK_COMBO_BOX(self->_profileSel), &iter)) { GtkTreeModel *store = gtk_combo_box_get_model(GTK_COMBO_BOX(self->_profileSel)); - gchar* name = 0; + gchar *name = 0; gtk_tree_model_get(store, &iter, 1, &name, -1); - self->_switchToProfile( name ); - gtk_widget_set_tooltip_text(self->_profileSel, name ); + self->_switchToProfile(name); + gtk_widget_set_tooltip_text(self->_profileSel, name); - if ( name ) { - g_free( name ); + if (name) { + g_free(name); } } } #endif // defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) #if defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) -void ColorICCSelectorImpl::_switchToProfile( gchar const* name ) +void ColorICCSelectorImpl::_switchToProfile(gchar const *name) { bool dirty = false; - SPColor tmp( _color.color() ); + SPColor tmp(_color.color()); - if ( name ) { - if ( tmp.icc && tmp.icc->colorProfile == name ) { + if (name) { + if (tmp.icc && tmp.icc->colorProfile == name) { #ifdef DEBUG_LCMS - g_message("Already at name [%s]", name ); + g_message("Already at name [%s]", name); #endif // DEBUG_LCMS - } else { + } + else { #ifdef DEBUG_LCMS - g_message("Need to switch to profile [%s]", name ); + g_message("Need to switch to profile [%s]", name); #endif // DEBUG_LCMS - if ( tmp.icc ) { + if (tmp.icc) { tmp.icc->colors.clear(); - } else { + } + else { tmp.icc = new SVGICCColor(); } tmp.icc->colorProfile = name; - Inkscape::ColorProfile* newProf = SP_ACTIVE_DOCUMENT->profileManager->find(name); - if ( newProf ) { + Inkscape::ColorProfile *newProf = SP_ACTIVE_DOCUMENT->profileManager->find(name); + if (newProf) { cmsHTRANSFORM trans = newProf->getTransfFromSRGB8(); - if ( trans ) { + if (trans) { guint32 val = _color.color().toRGBA32(0); guchar pre[4] = { static_cast(SP_RGBA32_R_U(val)), @@ -604,29 +589,31 @@ void ColorICCSelectorImpl::_switchToProfile( gchar const* name ) #ifdef DEBUG_LCMS g_message("Shoving in [%02x] [%02x] [%02x]", pre[0], pre[1], pre[2]); #endif // DEBUG_LCMS - cmsUInt16Number post[4] = {0,0,0,0}; - cmsDoTransform( trans, pre, post, 1 ); + cmsUInt16Number post[4] = { 0, 0, 0, 0 }; + cmsDoTransform(trans, pre, post, 1); #ifdef DEBUG_LCMS g_message("got on out [%04x] [%04x] [%04x] [%04x]", post[0], post[1], post[2], post[3]); #endif // DEBUG_LCMS #if HAVE_LIBLCMS1 - guint count = _cmsChannelsOf( asICColorSpaceSig(newProf->getColorSpace()) ); + guint count = _cmsChannelsOf(asICColorSpaceSig(newProf->getColorSpace())); #elif HAVE_LIBLCMS2 - guint count = cmsChannelsOf( asICColorSpaceSig(newProf->getColorSpace()) ); + guint count = cmsChannelsOf(asICColorSpaceSig(newProf->getColorSpace())); #endif - std::vector things = colorspace::getColorSpaceInfo(asICColorSpaceSig(newProf->getColorSpace())); + std::vector things = + colorspace::getColorSpaceInfo(asICColorSpaceSig(newProf->getColorSpace())); - for ( guint i = 0; i < count; i++ ) { - gdouble val = (((gdouble)post[i])/65535.0) * (gdouble)((i < things.size()) ? things[i].scale : 1); + for (guint i = 0; i < count; i++) { + gdouble val = + (((gdouble)post[i]) / 65535.0) * (gdouble)((i < things.size()) ? things[i].scale : 1); #ifdef DEBUG_LCMS g_message(" scaled %d by %d to be %f", i, ((i < things.size()) ? things[i].scale : 1), val); #endif // DEBUG_LCMS tmp.icc->colors.push_back(val); } cmsHTRANSFORM retrans = newProf->getTransfToSRGB8(); - if ( retrans ) { - cmsDoTransform( retrans, post, pre, 1 ); + if (retrans) { + cmsDoTransform(retrans, post, pre, 1); #ifdef DEBUG_LCMS g_message(" back out [%02x] [%02x] [%02x]", pre[0], pre[1], pre[2]); #endif // DEBUG_LCMS @@ -636,28 +623,30 @@ void ColorICCSelectorImpl::_switchToProfile( gchar const* name ) } dirty = true; } - } else { + } + else { #ifdef DEBUG_LCMS - g_message("NUKE THE ICC"); + g_message("NUKE THE ICC"); #endif // DEBUG_LCMS - if ( tmp.icc ) { + if (tmp.icc) { delete tmp.icc; tmp.icc = 0; dirty = true; - _fixupHit( 0, this ); - } else { + _fixupHit(0, this); + } + else { #ifdef DEBUG_LCMS - g_message("No icc to nuke"); + g_message("No icc to nuke"); #endif // DEBUG_LCMS } } - if ( dirty ) { + if (dirty) { #ifdef DEBUG_LCMS g_message("+----------------"); g_message("+ new color is [%s]", tmp.toString().c_str()); #endif // DEBUG_LCMS - _setProfile( tmp.icc ); + _setProfile(tmp.icc); //_adjustmentChanged( _compUI[0]._adj, SP_COLOR_ICC_SELECTOR(_csel) ); _color.setColor(tmp); #ifdef DEBUG_LCMS @@ -668,45 +657,43 @@ void ColorICCSelectorImpl::_switchToProfile( gchar const* name ) #endif // defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) #if defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) -void ColorICCSelectorImpl::_profilesChanged( std::string const & name ) +void ColorICCSelectorImpl::_profilesChanged(std::string const &name) { - GtkComboBox* combo = GTK_COMBO_BOX(_profileSel); + GtkComboBox *combo = GTK_COMBO_BOX(_profileSel); - g_signal_handler_block( G_OBJECT(_profileSel), _profChangedID ); + g_signal_handler_block(G_OBJECT(_profileSel), _profChangedID); GtkListStore *store = GTK_LIST_STORE(gtk_combo_box_get_model(combo)); gtk_list_store_clear(store); GtkTreeIter iter; - gtk_list_store_append (store, &iter); + gtk_list_store_append(store, &iter); gtk_list_store_set(store, &iter, 0, _(""), 1, _(""), -1); - gtk_combo_box_set_active( combo, 0 ); + gtk_combo_box_set_active(combo, 0); int index = 1; - const GSList *current = SP_ACTIVE_DOCUMENT->getResourceList( "iccprofile" ); - while ( current ) { - SPObject* obj = SP_OBJECT(current->data); - Inkscape::ColorProfile* prof = reinterpret_cast(obj); + const GSList *current = SP_ACTIVE_DOCUMENT->getResourceList("iccprofile"); + while (current) { + SPObject *obj = SP_OBJECT(current->data); + Inkscape::ColorProfile *prof = reinterpret_cast(obj); - gtk_list_store_append (store, &iter); + gtk_list_store_append(store, &iter); gtk_list_store_set(store, &iter, 0, gr_ellipsize_text(prof->name, 25).c_str(), 1, prof->name, -1); - if ( name == prof->name ) { - gtk_combo_box_set_active( combo, index ); - gtk_widget_set_tooltip_text(_profileSel, prof->name ); + if (name == prof->name) { + gtk_combo_box_set_active(combo, index); + gtk_widget_set_tooltip_text(_profileSel, prof->name); } index++; current = g_slist_next(current); } - g_signal_handler_unblock( G_OBJECT(_profileSel), _profChangedID ); + g_signal_handler_unblock(G_OBJECT(_profileSel), _profChangedID); } #else -void ColorICCSelectorImpl::_profilesChanged( std::string const & /*name*/ ) -{ -} +void ColorICCSelectorImpl::_profilesChanged(std::string const & /*name*/) {} #endif // defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) // Helpers for setting color value @@ -714,190 +701,199 @@ void ColorICCSelectorImpl::_profilesChanged( std::string const & /*name*/ ) void ColorICCSelector::_colorChanged() { _impl->_updating = TRUE; - //sp_color_icc_set_color( SP_COLOR_ICC( _icc ), &color ); +// sp_color_icc_set_color( SP_COLOR_ICC( _icc ), &color ); #ifdef DEBUG_LCMS - g_message( "/^^^^^^^^^ %p::_colorChanged(%08x:%s)", this, - _impl->_color.color().toRGBA32(_impl->_color.alpha()), ( (_impl->_color.color().icc) ? _impl->_color.color().icc->colorProfile.c_str(): "" ) - ); + g_message("/^^^^^^^^^ %p::_colorChanged(%08x:%s)", this, _impl->_color.color().toRGBA32(_impl->_color.alpha()), + ((_impl->_color.color().icc) ? _impl->_color.color().icc->colorProfile.c_str() : "")); #endif // DEBUG_LCMS #ifdef DEBUG_LCMS - g_message("FLIPPIES!!!! %p '%s'", _impl->_color.color().icc, (_impl->_color.color().icc ? _impl->_color.color().icc->colorProfile.c_str():"")); + g_message("FLIPPIES!!!! %p '%s'", _impl->_color.color().icc, + (_impl->_color.color().icc ? _impl->_color.color().icc->colorProfile.c_str() : "")); #endif // DEBUG_LCMS - _impl->_profilesChanged( (_impl->_color.color().icc) ? _impl->_color.color().icc->colorProfile : std::string("") ); - ColorScales::setScaled( _impl->_adj, _impl->_color.alpha() ); + _impl->_profilesChanged((_impl->_color.color().icc) ? _impl->_color.color().icc->colorProfile : std::string("")); + ColorScales::setScaled(_impl->_adj, _impl->_color.alpha()); #if defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) - _impl->_setProfile( _impl->_color.color().icc ); + _impl->_setProfile(_impl->_color.color().icc); _impl->_fixupNeeded = 0; - gtk_widget_set_sensitive( _impl->_fixupBtn, FALSE ); + gtk_widget_set_sensitive(_impl->_fixupBtn, FALSE); if (_impl->_prof) { - if (_impl->_prof->getTransfToSRGB8() ) { + if (_impl->_prof->getTransfToSRGB8()) { cmsUInt16Number tmp[4]; - for ( guint i = 0; i < _impl->_profChannelCount; i++ ) { + for (guint i = 0; i < _impl->_profChannelCount; i++) { gdouble val = 0.0; - if ( _impl->_color.color().icc->colors.size() > i ) { - if ( _impl->_compUI[i]._component.scale == 256 ) { - val = (_impl->_color.color().icc->colors[i] + 128.0) / static_cast(_impl->_compUI[i]._component.scale); - } else { - val = _impl->_color.color().icc->colors[i] / static_cast(_impl->_compUI[i]._component.scale); + if (_impl->_color.color().icc->colors.size() > i) { + if (_impl->_compUI[i]._component.scale == 256) { + val = (_impl->_color.color().icc->colors[i] + 128.0) / + static_cast(_impl->_compUI[i]._component.scale); + } + else { + val = _impl->_color.color().icc->colors[i] / + static_cast(_impl->_compUI[i]._component.scale); } } tmp[i] = val * 0x0ffff; } - guchar post[4] = {0,0,0,0}; + guchar post[4] = { 0, 0, 0, 0 }; cmsHTRANSFORM trans = _impl->_prof->getTransfToSRGB8(); - if ( trans ) { - cmsDoTransform( trans, tmp, post, 1 ); - guint32 other = SP_RGBA32_U_COMPOSE(post[0], post[1], post[2], 255 ); - if ( other != _impl->_color.color().toRGBA32(255) ) { + if (trans) { + cmsDoTransform(trans, tmp, post, 1); + guint32 other = SP_RGBA32_U_COMPOSE(post[0], post[1], post[2], 255); + if (other != _impl->_color.color().toRGBA32(255)) { _impl->_fixupNeeded = other; - gtk_widget_set_sensitive( _impl->_fixupBtn, TRUE ); + gtk_widget_set_sensitive(_impl->_fixupBtn, TRUE); #ifdef DEBUG_LCMS - g_message("Color needs to change 0x%06x to 0x%06x", _color.toRGBA32(255) >> 8, other >> 8 ); + g_message("Color needs to change 0x%06x to 0x%06x", _color.toRGBA32(255) >> 8, other >> 8); #endif // DEBUG_LCMS } } } } #else - //(void)color; +//(void)color; #endif // defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) - _impl->_updateSliders( -1 ); + _impl->_updateSliders(-1); _impl->_updating = FALSE; #ifdef DEBUG_LCMS - g_message( "\\_________ %p::_colorChanged()", this ); + g_message("\\_________ %p::_colorChanged()", this); #endif // DEBUG_LCMS } #if defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) -void ColorICCSelectorImpl::_setProfile( SVGICCColor* profile ) +void ColorICCSelectorImpl::_setProfile(SVGICCColor *profile) { #ifdef DEBUG_LCMS - g_message( "/^^^^^^^^^ %p::_setProfile(%s)", this, - ( (profile) ? profile->colorProfile.c_str() : "") - ); + g_message("/^^^^^^^^^ %p::_setProfile(%s)", this, ((profile) ? profile->colorProfile.c_str() : "")); #endif // DEBUG_LCMS bool profChanged = false; - if ( _prof && (!profile || (_profileName != profile->colorProfile) ) ) { + if (_prof && (!profile || (_profileName != profile->colorProfile))) { // Need to clear out the prior one profChanged = true; _profileName.clear(); _prof = 0; _profChannelCount = 0; - } else if ( profile && !_prof ) { + } + else if (profile && !_prof) { profChanged = true; } - for ( size_t i = 0; i < _compUI.size(); i++ ) { - gtk_widget_hide( _compUI[i]._label ); + for (size_t i = 0; i < _compUI.size(); i++) { + gtk_widget_hide(_compUI[i]._label); _compUI[i]._slider->hide(); - gtk_widget_hide( _compUI[i]._btn ); + gtk_widget_hide(_compUI[i]._btn); } - if ( profile ) { + if (profile) { _prof = SP_ACTIVE_DOCUMENT->profileManager->find(profile->colorProfile.c_str()); - if ( _prof && (asICColorProfileClassSig(_prof->getProfileClass()) != cmsSigNamedColorClass) ) { + if (_prof && (asICColorProfileClassSig(_prof->getProfileClass()) != cmsSigNamedColorClass)) { #if HAVE_LIBLCMS1 - _profChannelCount = _cmsChannelsOf( asICColorSpaceSig(_prof->getColorSpace()) ); + _profChannelCount = _cmsChannelsOf(asICColorSpaceSig(_prof->getColorSpace())); #elif HAVE_LIBLCMS2 - _profChannelCount = cmsChannelsOf( asICColorSpaceSig(_prof->getColorSpace()) ); + _profChannelCount = cmsChannelsOf(asICColorSpaceSig(_prof->getColorSpace())); #endif - if ( profChanged ) { - std::vector things = colorspace::getColorSpaceInfo(asICColorSpaceSig(_prof->getColorSpace())); - for (size_t i = 0; (i < things.size()) && (i < _profChannelCount); ++i) - { + if (profChanged) { + std::vector things = + colorspace::getColorSpaceInfo(asICColorSpaceSig(_prof->getColorSpace())); + for (size_t i = 0; (i < things.size()) && (i < _profChannelCount); ++i) { _compUI[i]._component = things[i]; } - for ( guint i = 0; i < _profChannelCount; i++ ) { - gtk_label_set_text_with_mnemonic( GTK_LABEL(_compUI[i]._label), (i < things.size()) ? things[i].name.c_str() : ""); + for (guint i = 0; i < _profChannelCount; i++) { + gtk_label_set_text_with_mnemonic(GTK_LABEL(_compUI[i]._label), + (i < things.size()) ? things[i].name.c_str() : ""); - _compUI[i]._slider->set_tooltip_text((i < things.size()) ? things[i].tip.c_str() : ""); - gtk_widget_set_tooltip_text( _compUI[i]._btn, (i < things.size()) ? things[i].tip.c_str() : "" ); + _compUI[i]._slider->set_tooltip_text((i < things.size()) ? things[i].tip.c_str() : ""); + gtk_widget_set_tooltip_text(_compUI[i]._btn, (i < things.size()) ? things[i].tip.c_str() : ""); _compUI[i]._slider->setColors(SPColor(0.0, 0.0, 0.0).toRGBA32(0xff), - SPColor(0.5, 0.5, 0.5).toRGBA32(0xff), - SPColor(1.0, 1.0, 1.0).toRGBA32(0xff) ); -/* - _compUI[i]._adj = GTK_ADJUSTMENT( gtk_adjustment_new( val, 0.0, _fooScales[i], step, page, page ) ); - g_signal_connect( G_OBJECT( _compUI[i]._adj ), "value_changed", G_CALLBACK( _adjustmentChanged ), _csel ); - - sp_color_slider_set_adjustment( SP_COLOR_SLIDER(_compUI[i]._slider), _compUI[i]._adj ); - gtk_spin_button_set_adjustment( GTK_SPIN_BUTTON(_compUI[i]._btn), _compUI[i]._adj ); - gtk_spin_button_set_digits( GTK_SPIN_BUTTON(_compUI[i]._btn), digits ); -*/ - gtk_widget_show( _compUI[i]._label ); + SPColor(0.5, 0.5, 0.5).toRGBA32(0xff), + SPColor(1.0, 1.0, 1.0).toRGBA32(0xff)); + /* + _compUI[i]._adj = GTK_ADJUSTMENT( gtk_adjustment_new( val, 0.0, _fooScales[i], + step, page, page ) ); + g_signal_connect( G_OBJECT( _compUI[i]._adj ), "value_changed", G_CALLBACK( + _adjustmentChanged ), _csel ); + + sp_color_slider_set_adjustment( SP_COLOR_SLIDER(_compUI[i]._slider), + _compUI[i]._adj ); + gtk_spin_button_set_adjustment( GTK_SPIN_BUTTON(_compUI[i]._btn), + _compUI[i]._adj ); + gtk_spin_button_set_digits( GTK_SPIN_BUTTON(_compUI[i]._btn), digits ); + */ + gtk_widget_show(_compUI[i]._label); _compUI[i]._slider->show(); - gtk_widget_show( _compUI[i]._btn ); - //gtk_adjustment_set_value( _compUI[i]._adj, 0.0 ); - //gtk_adjustment_set_value( _compUI[i]._adj, val ); + gtk_widget_show(_compUI[i]._btn); + // gtk_adjustment_set_value( _compUI[i]._adj, 0.0 ); + // gtk_adjustment_set_value( _compUI[i]._adj, val ); } - for ( size_t i = _profChannelCount; i < _compUI.size(); i++ ) { - gtk_widget_hide( _compUI[i]._label ); + for (size_t i = _profChannelCount; i < _compUI.size(); i++) { + gtk_widget_hide(_compUI[i]._label); _compUI[i]._slider->hide(); - gtk_widget_hide( _compUI[i]._btn ); + gtk_widget_hide(_compUI[i]._btn); } } - } else { + } + else { // Give up for now on named colors _prof = 0; } } #ifdef DEBUG_LCMS - g_message( "\\_________ %p::_setProfile()", this ); + g_message("\\_________ %p::_setProfile()", this); #endif // DEBUG_LCMS } #endif // defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) -void ColorICCSelectorImpl::_updateSliders( gint ignore ) +void ColorICCSelectorImpl::_updateSliders(gint ignore) { #if defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) - if ( _color.color().icc ) - { - for ( guint i = 0; i < _profChannelCount; i++ ) { + if (_color.color().icc) { + for (guint i = 0; i < _profChannelCount; i++) { gdouble val = 0.0; - if ( _color.color().icc->colors.size() > i ) { - if ( _compUI[i]._component.scale == 256 ) { + if (_color.color().icc->colors.size() > i) { + if (_compUI[i]._component.scale == 256) { val = (_color.color().icc->colors[i] + 128.0) / static_cast(_compUI[i]._component.scale); - } else { + } + else { val = _color.color().icc->colors[i] / static_cast(_compUI[i]._component.scale); } } - gtk_adjustment_set_value( _compUI[i]._adj, val ); + gtk_adjustment_set_value(_compUI[i]._adj, val); } - if ( _prof ) { - if ( _prof->getTransfToSRGB8() ) { - for ( guint i = 0; i < _profChannelCount; i++ ) { - if ( static_cast(i) != ignore ) { - cmsUInt16Number* scratch = getScratch(); - cmsUInt16Number filler[4] = {0, 0, 0, 0}; - for ( guint j = 0; j < _profChannelCount; j++ ) { - filler[j] = 0x0ffff * ColorScales::getScaled( _compUI[j]._adj ); + if (_prof) { + if (_prof->getTransfToSRGB8()) { + for (guint i = 0; i < _profChannelCount; i++) { + if (static_cast(i) != ignore) { + cmsUInt16Number *scratch = getScratch(); + cmsUInt16Number filler[4] = { 0, 0, 0, 0 }; + for (guint j = 0; j < _profChannelCount; j++) { + filler[j] = 0x0ffff * ColorScales::getScaled(_compUI[j]._adj); } - - cmsUInt16Number* p = scratch; - for ( guint x = 0; x < 1024; x++ ) { - for ( guint j = 0; j < _profChannelCount; j++ ) { - if ( j == i ) { + + cmsUInt16Number *p = scratch; + for (guint x = 0; x < 1024; x++) { + for (guint j = 0; j < _profChannelCount; j++) { + if (j == i) { *p++ = x * 0x0ffff / 1024; - } else { + } + else { *p++ = filler[j]; } } } - + cmsHTRANSFORM trans = _prof->getTransfToSRGB8(); - if ( trans ) { - cmsDoTransform( trans, scratch, _compUI[i]._map, 1024 ); + if (trans) { + cmsDoTransform(trans, scratch, _compUI[i]._map, 1024); _compUI[i]._slider->setMap(_compUI[i]._map); } } @@ -909,15 +905,15 @@ void ColorICCSelectorImpl::_updateSliders( gint ignore ) (void)ignore; #endif // defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) - guint32 start = _color.color().toRGBA32( 0x00 ); - guint32 mid = _color.color().toRGBA32( 0x7f ); - guint32 end = _color.color().toRGBA32( 0xff ); + guint32 start = _color.color().toRGBA32(0x00); + guint32 mid = _color.color().toRGBA32(0x7f); + guint32 end = _color.color().toRGBA32(0xff); _slider->setColors(start, mid, end); } -void ColorICCSelectorImpl::_adjustmentChanged( GtkAdjustment *adjustment, ColorICCSelectorImpl *cs ) +void ColorICCSelectorImpl::_adjustmentChanged(GtkAdjustment *adjustment, ColorICCSelectorImpl *cs) { // // TODO check this. It looks questionable: // // if a value is entered between 0 and 1 exclusive, normalize it to (int) 0..255 or 0..100 @@ -926,130 +922,132 @@ void ColorICCSelectorImpl::_adjustmentChanged( GtkAdjustment *adjustment, ColorI // } #ifdef DEBUG_LCMS - g_message( "/^^^^^^^^^ %p::_adjustmentChanged()", cs ); + g_message("/^^^^^^^^^ %p::_adjustmentChanged()", cs); #endif // DEBUG_LCMS - ColorICCSelector* iccSelector = cs->_owner; - if (iccSelector->_impl->_updating) { - return; - } + ColorICCSelector *iccSelector = cs->_owner; + if (iccSelector->_impl->_updating) { + return; + } - iccSelector->_impl->_updating = TRUE; + iccSelector->_impl->_updating = TRUE; - gint match = -1; + gint match = -1; - SPColor newColor( iccSelector->_impl->_color.color() ); - gfloat scaled = ColorScales::getScaled( iccSelector->_impl->_adj ); - if ( iccSelector->_impl->_adj == adjustment ) { + SPColor newColor(iccSelector->_impl->_color.color()); + gfloat scaled = ColorScales::getScaled(iccSelector->_impl->_adj); + if (iccSelector->_impl->_adj == adjustment) { #ifdef DEBUG_LCMS - g_message("ALPHA"); + g_message("ALPHA"); #endif // DEBUG_LCMS - } else { + } + else { #if defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) - for ( size_t i = 0; i < iccSelector->_impl->_compUI.size(); i++ ) { - if ( iccSelector->_impl->_compUI[i]._adj == adjustment ) { - match = i; - break; - } - } - if ( match >= 0 ) { + for (size_t i = 0; i < iccSelector->_impl->_compUI.size(); i++) { + if (iccSelector->_impl->_compUI[i]._adj == adjustment) { + match = i; + break; + } + } + if (match >= 0) { #ifdef DEBUG_LCMS - g_message(" channel %d", match ); + g_message(" channel %d", match); #endif // DEBUG_LCMS - } + } - cmsUInt16Number tmp[4]; - for ( guint i = 0; i < 4; i++ ) { - tmp[i] = ColorScales::getScaled( iccSelector->_impl->_compUI[i]._adj ) * 0x0ffff; - } - guchar post[4] = {0,0,0,0}; + cmsUInt16Number tmp[4]; + for (guint i = 0; i < 4; i++) { + tmp[i] = ColorScales::getScaled(iccSelector->_impl->_compUI[i]._adj) * 0x0ffff; + } + guchar post[4] = { 0, 0, 0, 0 }; - cmsHTRANSFORM trans = iccSelector->_impl->_prof->getTransfToSRGB8(); - if ( trans ) { - cmsDoTransform( trans, tmp, post, 1 ); - } + cmsHTRANSFORM trans = iccSelector->_impl->_prof->getTransfToSRGB8(); + if (trans) { + cmsDoTransform(trans, tmp, post, 1); + } - SPColor other( SP_RGBA32_U_COMPOSE(post[0], post[1], post[2], 255) ); - other.icc = new SVGICCColor(); - if ( iccSelector->_impl->_color.color().icc ) { - other.icc->colorProfile = iccSelector->_impl->_color.color().icc->colorProfile; - } + SPColor other(SP_RGBA32_U_COMPOSE(post[0], post[1], post[2], 255)); + other.icc = new SVGICCColor(); + if (iccSelector->_impl->_color.color().icc) { + other.icc->colorProfile = iccSelector->_impl->_color.color().icc->colorProfile; + } - guint32 prior = iccSelector->_impl->_color.color().toRGBA32(255); - guint32 newer = other.toRGBA32(255); + guint32 prior = iccSelector->_impl->_color.color().toRGBA32(255); + guint32 newer = other.toRGBA32(255); - if ( prior != newer ) { + if (prior != newer) { #ifdef DEBUG_LCMS - g_message("Transformed color from 0x%08x to 0x%08x", prior, newer ); - g_message(" ~~~~ FLIP"); + g_message("Transformed color from 0x%08x to 0x%08x", prior, newer); + g_message(" ~~~~ FLIP"); #endif // DEBUG_LCMS - newColor = other; - newColor.icc->colors.clear(); - for ( guint i = 0; i < iccSelector->_impl->_profChannelCount; i++ ) { - gdouble val = ColorScales::getScaled( iccSelector->_impl->_compUI[i]._adj ); - val *= iccSelector->_impl->_compUI[i]._component.scale; - if ( iccSelector->_impl->_compUI[i]._component.scale == 256 ) { - val -= 128; - } - newColor.icc->colors.push_back( val ); - } - } + newColor = other; + newColor.icc->colors.clear(); + for (guint i = 0; i < iccSelector->_impl->_profChannelCount; i++) { + gdouble val = ColorScales::getScaled(iccSelector->_impl->_compUI[i]._adj); + val *= iccSelector->_impl->_compUI[i]._component.scale; + if (iccSelector->_impl->_compUI[i]._component.scale == 256) { + val -= 128; + } + newColor.icc->colors.push_back(val); + } + } #endif // defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) - } - iccSelector->_impl->_color.setColorAlpha(newColor, scaled); - //iccSelector->_updateInternals( newColor, scaled, iccSelector->_impl->_dragging ); - iccSelector->_impl->_updateSliders( match ); + } + iccSelector->_impl->_color.setColorAlpha(newColor, scaled); + // iccSelector->_updateInternals( newColor, scaled, iccSelector->_impl->_dragging ); + iccSelector->_impl->_updateSliders(match); - iccSelector->_impl->_updating = FALSE; + iccSelector->_impl->_updating = FALSE; #ifdef DEBUG_LCMS - g_message( "\\_________ %p::_adjustmentChanged()", cs ); + g_message("\\_________ %p::_adjustmentChanged()", cs); #endif // DEBUG_LCMS } void ColorICCSelectorImpl::_sliderGrabbed() { -// ColorICCSelector* iccSelector = dynamic_cast(SP_COLOR_SELECTOR(cs)->base); -// if (!iccSelector->_dragging) { -// iccSelector->_dragging = TRUE; -// iccSelector->_grabbed(); -// iccSelector->_updateInternals( iccSelector->_color, ColorScales::getScaled( iccSelector->_impl->_adj ), iccSelector->_dragging ); -// } + // ColorICCSelector* iccSelector = dynamic_cast(SP_COLOR_SELECTOR(cs)->base); + // if (!iccSelector->_dragging) { + // iccSelector->_dragging = TRUE; + // iccSelector->_grabbed(); + // iccSelector->_updateInternals( iccSelector->_color, ColorScales::getScaled( iccSelector->_impl->_adj ), + // iccSelector->_dragging ); + // } } void ColorICCSelectorImpl::_sliderReleased() { -// ColorICCSelector* iccSelector = dynamic_cast(SP_COLOR_SELECTOR(cs)->base); -// if (iccSelector->_dragging) { -// iccSelector->_dragging = FALSE; -// iccSelector->_released(); -// iccSelector->_updateInternals( iccSelector->_color, ColorScales::getScaled( iccSelector->_adj ), iccSelector->_dragging ); -// } + // ColorICCSelector* iccSelector = dynamic_cast(SP_COLOR_SELECTOR(cs)->base); + // if (iccSelector->_dragging) { + // iccSelector->_dragging = FALSE; + // iccSelector->_released(); + // iccSelector->_updateInternals( iccSelector->_color, ColorScales::getScaled( iccSelector->_adj ), + // iccSelector->_dragging ); + // } } #ifdef DEBUG_LCMS -void ColorICCSelectorImpl::_sliderChanged( SPColorSlider *slider, SPColorICCSelector *cs ) +void ColorICCSelectorImpl::_sliderChanged(SPColorSlider *slider, SPColorICCSelector *cs) #else void ColorICCSelectorImpl::_sliderChanged() #endif // DEBUG_LCMS { #ifdef DEBUG_LCMS - g_message("Changed %p and %p", slider, cs ); + g_message("Changed %p and %p", slider, cs); #endif // DEBUG_LCMS -// ColorICCSelector* iccSelector = dynamic_cast(SP_COLOR_SELECTOR(cs)->base); + // ColorICCSelector* iccSelector = dynamic_cast(SP_COLOR_SELECTOR(cs)->base); -// iccSelector->_updateInternals( iccSelector->_color, ColorScales::getScaled( iccSelector->_adj ), iccSelector->_dragging ); + // iccSelector->_updateInternals( iccSelector->_color, ColorScales::getScaled( iccSelector->_adj ), + // iccSelector->_dragging ); } -Gtk::Widget *ColorICCSelectorFactory::createWidget(Inkscape::UI::SelectedColor &color) const { +Gtk::Widget *ColorICCSelectorFactory::createWidget(Inkscape::UI::SelectedColor &color) const +{ Gtk::Widget *w = Gtk::manage(new ColorICCSelector(color)); return w; } -Glib::ustring ColorICCSelectorFactory::modeName() const { - return gettext(ColorICCSelector::MODE_NAME); -} - +Glib::ustring ColorICCSelectorFactory::modeName() const { return gettext(ColorICCSelector::MODE_NAME); } } } } diff --git a/src/ui/widget/color-icc-selector.h b/src/ui/widget/color-icc-selector.h index 6066586f5..37201de3b 100644 --- a/src/ui/widget/color-icc-selector.h +++ b/src/ui/widget/color-icc-selector.h @@ -2,7 +2,7 @@ #define SEEN_SP_COLOR_ICC_SELECTOR_H #ifdef HAVE_CONFIG_H -# include +#include #endif #include @@ -24,42 +24,41 @@ namespace Widget { class ColorICCSelectorImpl; class ColorICCSelector -#if GTK_CHECK_VERSION(3,0,0) +#if GTK_CHECK_VERSION(3, 0, 0) : public Gtk::Grid #else : public Gtk::Table #endif -{ -public: - static const gchar* MODE_NAME; + { + public: + static const gchar *MODE_NAME; ColorICCSelector(SelectedColor &color); virtual ~ColorICCSelector(); virtual void init(); -protected: + protected: virtual void _colorChanged(); - void _recalcColor( gboolean changing ); + void _recalcColor(gboolean changing); -private: + private: friend class ColorICCSelectorImpl; // By default, disallow copy constructor and assignment operator - ColorICCSelector( const ColorICCSelector& obj ); - ColorICCSelector& operator=( const ColorICCSelector& obj ); + ColorICCSelector(const ColorICCSelector &obj); + ColorICCSelector &operator=(const ColorICCSelector &obj); ColorICCSelectorImpl *_impl; }; -class ColorICCSelectorFactory: public ColorSelectorFactory { -public: - Gtk::Widget* createWidget(SelectedColor &color) const; +class ColorICCSelectorFactory : public ColorSelectorFactory { + public: + Gtk::Widget *createWidget(SelectedColor &color) const; Glib::ustring modeName() const; }; - } } } diff --git a/src/ui/widget/color-notebook.cpp b/src/ui/widget/color-notebook.cpp index 92b1d7086..0150f2ca2 100644 --- a/src/ui/widget/color-notebook.cpp +++ b/src/ui/widget/color-notebook.cpp @@ -16,7 +16,7 @@ #define noDUMP_CHANGE_INFO #ifdef HAVE_CONFIG_H -# include "config.h" +#include "config.h" #endif #include "widgets/icon.h" @@ -56,7 +56,7 @@ namespace Widget { ColorNotebook::ColorNotebook(SelectedColor &color) -#if GTK_CHECK_VERSION(3,0,0) +#if GTK_CHECK_VERSION(3, 0, 0) : Gtk::Grid() #else : Gtk::Table(2, 3, false) @@ -87,12 +87,10 @@ ColorNotebook::ColorNotebook(SelectedColor &color) ColorNotebook::~ColorNotebook() { - if ( _buttons ) - { - delete [] _buttons; + if (_buttons) { + delete[] _buttons; _buttons = 0; } - } ColorNotebook::Page::Page(Inkscape::UI::ColorSelectorFactory *selector_factory, bool enabled_full) @@ -112,57 +110,57 @@ void ColorNotebook::_initUI() notebook->set_show_tabs(false); _book = GTK_WIDGET(notebook->gobj()); -#if GTK_CHECK_VERSION(3,0,0) +#if GTK_CHECK_VERSION(3, 0, 0) _buttonbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 2); gtk_box_set_homogeneous(GTK_BOX(_buttonbox), TRUE); #else - _buttonbox = gtk_hbox_new (TRUE, 2); + _buttonbox = gtk_hbox_new(TRUE, 2); #endif - gtk_widget_show (_buttonbox); + gtk_widget_show(_buttonbox); _buttons = new GtkWidget *[_available_pages.size()]; - for (int i = 0; static_cast(i) < _available_pages.size(); i++ ) - { + for (int i = 0; static_cast(i) < _available_pages.size(); i++) { _addPage(_available_pages[i]); } - sp_set_font_size_smaller (_buttonbox); + sp_set_font_size_smaller(_buttonbox); -#if GTK_CHECK_VERSION(3,0,0) - #if GTK_CHECK_VERSION(3,12,0) +#if GTK_CHECK_VERSION(3, 0, 0) + #if GTK_CHECK_VERSION(3, 12, 0) gtk_widget_set_margin_start(_buttonbox, XPAD); gtk_widget_set_margin_end(_buttonbox, XPAD); - #else + #else gtk_widget_set_margin_left(_buttonbox, XPAD); gtk_widget_set_margin_right(_buttonbox, XPAD); - #endif + #endif gtk_widget_set_margin_top(_buttonbox, YPAD); gtk_widget_set_margin_bottom(_buttonbox, YPAD); gtk_widget_set_hexpand(_buttonbox, TRUE); gtk_widget_set_valign(_buttonbox, GTK_ALIGN_CENTER); attach(*Glib::wrap(_buttonbox), 0, row, 2, 1); #else - attach(*Glib::wrap(_buttonbox), 0, 2, row, row+1, Gtk::EXPAND | Gtk::FILL, static_cast(0), XPAD, YPAD); + attach(*Glib::wrap(_buttonbox), 0, 2, row, row + 1, Gtk::EXPAND | Gtk::FILL, static_cast(0), + XPAD, YPAD); #endif row++; -#if GTK_CHECK_VERSION(3,0,0) - #if GTK_CHECK_VERSION(3,12,0) - gtk_widget_set_margin_start(_book, XPAD*2); - gtk_widget_set_margin_end(_book, XPAD*2); - #else - gtk_widget_set_margin_left(_book, XPAD*2); - gtk_widget_set_margin_right(_book, XPAD*2); - #endif +#if GTK_CHECK_VERSION(3, 0, 0) +#if GTK_CHECK_VERSION(3, 12, 0) + gtk_widget_set_margin_start(_book, XPAD * 2); + gtk_widget_set_margin_end(_book, XPAD * 2); +#else + gtk_widget_set_margin_left(_book, XPAD * 2); + gtk_widget_set_margin_right(_book, XPAD * 2); +#endif gtk_widget_set_margin_top(_book, YPAD); gtk_widget_set_margin_bottom(_book, YPAD); gtk_widget_set_hexpand(_book, TRUE); gtk_widget_set_vexpand(_book, TRUE); attach(*notebook, 0, row, 2, 1); #else - attach(*notebook, 0, 2, row, row+1, Gtk::EXPAND | Gtk::FILL, Gtk::EXPAND | Gtk::FILL, XPAD * 2, YPAD); + attach(*notebook, 0, 2, row, row + 1, Gtk::EXPAND | Gtk::FILL, Gtk::EXPAND | Gtk::FILL, XPAD * 2, YPAD); #endif // restore the last active page @@ -170,72 +168,72 @@ void ColorNotebook::_initUI() _setCurrentPage(prefs->getInt("/colorselector/page", 0)); row++; -#if GTK_CHECK_VERSION(3,0,0) +#if GTK_CHECK_VERSION(3, 0, 0) GtkWidget *rgbabox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0); #else - GtkWidget *rgbabox = gtk_hbox_new (FALSE, 0); + GtkWidget *rgbabox = gtk_hbox_new(FALSE, 0); #endif #if defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) /* Create color management icons */ - _box_colormanaged = gtk_event_box_new (); - GtkWidget *colormanaged = gtk_image_new_from_icon_name ("color-management-icon", GTK_ICON_SIZE_SMALL_TOOLBAR); - gtk_container_add (GTK_CONTAINER (_box_colormanaged), colormanaged); - gtk_widget_set_tooltip_text (_box_colormanaged, _("Color Managed")); - gtk_widget_set_sensitive (_box_colormanaged, false); + _box_colormanaged = gtk_event_box_new(); + GtkWidget *colormanaged = gtk_image_new_from_icon_name("color-management-icon", GTK_ICON_SIZE_SMALL_TOOLBAR); + gtk_container_add(GTK_CONTAINER(_box_colormanaged), colormanaged); + gtk_widget_set_tooltip_text(_box_colormanaged, _("Color Managed")); + gtk_widget_set_sensitive(_box_colormanaged, false); gtk_box_pack_start(GTK_BOX(rgbabox), _box_colormanaged, FALSE, FALSE, 2); - _box_outofgamut = gtk_event_box_new (); - GtkWidget *outofgamut = gtk_image_new_from_icon_name ("out-of-gamut-icon", GTK_ICON_SIZE_SMALL_TOOLBAR); - gtk_container_add (GTK_CONTAINER (_box_outofgamut), outofgamut); - gtk_widget_set_tooltip_text (_box_outofgamut, _("Out of gamut!")); - gtk_widget_set_sensitive (_box_outofgamut, false); + _box_outofgamut = gtk_event_box_new(); + GtkWidget *outofgamut = gtk_image_new_from_icon_name("out-of-gamut-icon", GTK_ICON_SIZE_SMALL_TOOLBAR); + gtk_container_add(GTK_CONTAINER(_box_outofgamut), outofgamut); + gtk_widget_set_tooltip_text(_box_outofgamut, _("Out of gamut!")); + gtk_widget_set_sensitive(_box_outofgamut, false); gtk_box_pack_start(GTK_BOX(rgbabox), _box_outofgamut, FALSE, FALSE, 2); - _box_toomuchink = gtk_event_box_new (); - GtkWidget *toomuchink = gtk_image_new_from_icon_name ("too-much-ink-icon", GTK_ICON_SIZE_SMALL_TOOLBAR); - gtk_container_add (GTK_CONTAINER (_box_toomuchink), toomuchink); - gtk_widget_set_tooltip_text (_box_toomuchink, _("Too much ink!")); - gtk_widget_set_sensitive (_box_toomuchink, false); + _box_toomuchink = gtk_event_box_new(); + GtkWidget *toomuchink = gtk_image_new_from_icon_name("too-much-ink-icon", GTK_ICON_SIZE_SMALL_TOOLBAR); + gtk_container_add(GTK_CONTAINER(_box_toomuchink), toomuchink); + gtk_widget_set_tooltip_text(_box_toomuchink, _("Too much ink!")); + gtk_widget_set_sensitive(_box_toomuchink, false); gtk_box_pack_start(GTK_BOX(rgbabox), _box_toomuchink, FALSE, FALSE, 2); -#endif //defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) +#endif // defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) /* Color picker */ - GtkWidget *picker = gtk_image_new_from_icon_name ("color-picker", GTK_ICON_SIZE_SMALL_TOOLBAR); - _btn_picker = gtk_button_new (); + GtkWidget *picker = gtk_image_new_from_icon_name("color-picker", GTK_ICON_SIZE_SMALL_TOOLBAR); + _btn_picker = gtk_button_new(); gtk_button_set_relief(GTK_BUTTON(_btn_picker), GTK_RELIEF_NONE); - gtk_container_add (GTK_CONTAINER (_btn_picker), picker); - gtk_widget_set_tooltip_text (_btn_picker, _("Pick colors from image")); + gtk_container_add(GTK_CONTAINER(_btn_picker), picker); + gtk_widget_set_tooltip_text(_btn_picker, _("Pick colors from image")); gtk_box_pack_start(GTK_BOX(rgbabox), _btn_picker, FALSE, FALSE, 2); g_signal_connect(G_OBJECT(_btn_picker), "clicked", G_CALLBACK(ColorNotebook::_onPickerClicked), this); /* Create RGBA entry and color preview */ - _rgbal = gtk_label_new_with_mnemonic (_("RGBA_:")); - gtk_misc_set_alignment (GTK_MISC (_rgbal), 1.0, 0.5); + _rgbal = gtk_label_new_with_mnemonic(_("RGBA_:")); + gtk_misc_set_alignment(GTK_MISC(_rgbal), 1.0, 0.5); gtk_box_pack_start(GTK_BOX(rgbabox), _rgbal, TRUE, TRUE, 2); - ColorEntry* rgba_entry = Gtk::manage(new ColorEntry(_selected_color)); - sp_dialog_defocus_on_enter (GTK_WIDGET(rgba_entry->gobj())); + ColorEntry *rgba_entry = Gtk::manage(new ColorEntry(_selected_color)); + sp_dialog_defocus_on_enter(GTK_WIDGET(rgba_entry->gobj())); gtk_box_pack_start(GTK_BOX(rgbabox), GTK_WIDGET(rgba_entry->gobj()), FALSE, FALSE, 0); - gtk_label_set_mnemonic_widget (GTK_LABEL(_rgbal), GTK_WIDGET(rgba_entry->gobj())); + gtk_label_set_mnemonic_widget(GTK_LABEL(_rgbal), GTK_WIDGET(rgba_entry->gobj())); - sp_set_font_size_smaller (rgbabox); - gtk_widget_show_all (rgbabox); + sp_set_font_size_smaller(rgbabox); + gtk_widget_show_all(rgbabox); #if defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) - //the "too much ink" icon is initially hidden + // the "too much ink" icon is initially hidden gtk_widget_hide(GTK_WIDGET(_box_toomuchink)); -#endif //defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) +#endif // defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) -#if GTK_CHECK_VERSION(3,0,0) - #if GTK_CHECK_VERSION(3,12,0) +#if GTK_CHECK_VERSION(3, 0, 0) + #if GTK_CHECK_VERSION(3, 12, 0) gtk_widget_set_margin_start(rgbabox, XPAD); gtk_widget_set_margin_end(rgbabox, XPAD); - #else + #else gtk_widget_set_margin_left(rgbabox, XPAD); gtk_widget_set_margin_right(rgbabox, XPAD); - #endif + #endif gtk_widget_set_margin_top(rgbabox, YPAD); gtk_widget_set_margin_bottom(rgbabox, YPAD); attach(*Glib::wrap(rgbabox), 0, row, 2, 1); @@ -244,13 +242,12 @@ void ColorNotebook::_initUI() #endif #ifdef SPCS_PREVIEW - _p = sp_color_preview_new (0xffffffff); - gtk_widget_show (_p); + _p = sp_color_preview_new(0xffffffff); + gtk_widget_show(_p); attach(*Glib::wrap(_p), 2, 3, row, row + 1, Gtk::FILL, Gtk::FILL, XPAD, YPAD); #endif - g_signal_connect(G_OBJECT (_book), "switch-page", - G_CALLBACK (ColorNotebook::_onPageSwitched), this); + g_signal_connect(G_OBJECT(_book), "switch-page", G_CALLBACK(ColorNotebook::_onPageSwitched), this); } void ColorNotebook::_onPickerClicked(GtkWidget * /*widget*/, ColorNotebook * /*colorbook*/) @@ -261,27 +258,22 @@ void ColorNotebook::_onPickerClicked(GtkWidget * /*widget*/, ColorNotebook * /*c Inkscape::UI::Tools::sp_toggle_dropper(SP_ACTIVE_DESKTOP); } -void ColorNotebook::_onButtonClicked(GtkWidget *widget, ColorNotebook *nb) +void ColorNotebook::_onButtonClicked(GtkWidget *widget, ColorNotebook *nb) { - if (!gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(widget))) { + if (!gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget))) { return; } - for(gint i = 0; i < gtk_notebook_get_n_pages (GTK_NOTEBOOK (nb->_book)); i++) { + for (gint i = 0; i < gtk_notebook_get_n_pages(GTK_NOTEBOOK(nb->_book)); i++) { if (nb->_buttons[i] == widget) { - gtk_notebook_set_current_page (GTK_NOTEBOOK (nb->_book), i); + gtk_notebook_set_current_page(GTK_NOTEBOOK(nb->_book), i); } } } -void ColorNotebook::_onSelectedColorChanged() { - _updateICCButtons(); -} +void ColorNotebook::_onSelectedColorChanged() { _updateICCButtons(); } -void ColorNotebook::_onPageSwitched(GtkNotebook *notebook, - GtkWidget *page, - guint page_num, - ColorNotebook *colorbook) +void ColorNotebook::_onPageSwitched(GtkNotebook *notebook, GtkWidget *page, guint page_num, ColorNotebook *colorbook) { if (colorbook) { // remember the page we switched to @@ -297,41 +289,45 @@ void ColorNotebook::_updateICCButtons() SPColor color = _selected_color.color(); gfloat alpha = _selected_color.alpha(); - g_return_if_fail( ( 0.0 <= alpha ) && ( alpha <= 1.0 ) ); + g_return_if_fail((0.0 <= alpha) && (alpha <= 1.0)); #if defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) /* update color management icon*/ - gtk_widget_set_sensitive (_box_colormanaged, color.icc != NULL); + gtk_widget_set_sensitive(_box_colormanaged, color.icc != NULL); /* update out-of-gamut icon */ - gtk_widget_set_sensitive (_box_outofgamut, false); - if (color.icc){ - Inkscape::ColorProfile* target_profile = SP_ACTIVE_DOCUMENT->profileManager->find(color.icc->colorProfile.c_str()); - if ( target_profile ) + gtk_widget_set_sensitive(_box_outofgamut, false); + if (color.icc) { + Inkscape::ColorProfile *target_profile = + SP_ACTIVE_DOCUMENT->profileManager->find(color.icc->colorProfile.c_str()); + if (target_profile) gtk_widget_set_sensitive(_box_outofgamut, target_profile->GamutCheck(color)); } /* update too-much-ink icon */ - gtk_widget_set_sensitive (_box_toomuchink, false); - if (color.icc){ - Inkscape::ColorProfile* prof = SP_ACTIVE_DOCUMENT->profileManager->find(color.icc->colorProfile.c_str()); - if ( prof && CMSSystem::isPrintColorSpace(prof) ) { + gtk_widget_set_sensitive(_box_toomuchink, false); + if (color.icc) { + Inkscape::ColorProfile *prof = SP_ACTIVE_DOCUMENT->profileManager->find(color.icc->colorProfile.c_str()); + if (prof && CMSSystem::isPrintColorSpace(prof)) { gtk_widget_show(GTK_WIDGET(_box_toomuchink)); double ink_sum = 0; - for (unsigned int i=0; icolors.size(); i++){ + for (unsigned int i = 0; i < color.icc->colors.size(); i++) { ink_sum += color.icc->colors[i]; } - /* Some literature states that when the sum of paint values exceed 320%, it is considered to be a satured color, - which means the paper can get too wet due to an excessive ammount of ink. This may lead to several issues + /* Some literature states that when the sum of paint values exceed 320%, it is considered to be a satured + color, + which means the paper can get too wet due to an excessive ammount of ink. This may lead to several + issues such as misalignment and poor quality of printing in general.*/ - if ( ink_sum > 3.2 ) - gtk_widget_set_sensitive (_box_toomuchink, true); - } else { + if (ink_sum > 3.2) + gtk_widget_set_sensitive(_box_toomuchink, true); + } + else { gtk_widget_hide(GTK_WIDGET(_box_toomuchink)); } } -#endif //defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) +#endif // defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) } void ColorNotebook::_setCurrentPage(int i) @@ -343,7 +339,8 @@ void ColorNotebook::_setCurrentPage(int i) } } -void ColorNotebook::_addPage(Page& page) { +void ColorNotebook::_addPage(Page &page) +{ Gtk::Widget *selector_widget; selector_widget = page.selector_factory->createWidget(_selected_color); @@ -351,22 +348,21 @@ void ColorNotebook::_addPage(Page& page) { selector_widget->show(); Glib::ustring mode_name = page.selector_factory->modeName(); - Gtk::Widget* tab_label = Gtk::manage(new Gtk::Label(mode_name)); - gint page_num = gtk_notebook_append_page( GTK_NOTEBOOK(_book), selector_widget->gobj(), tab_label->gobj()); + Gtk::Widget *tab_label = Gtk::manage(new Gtk::Label(mode_name)); + gint page_num = gtk_notebook_append_page(GTK_NOTEBOOK(_book), selector_widget->gobj(), tab_label->gobj()); _buttons[page_num] = gtk_radio_button_new_with_label(NULL, mode_name.c_str()); gtk_toggle_button_set_mode(GTK_TOGGLE_BUTTON(_buttons[page_num]), FALSE); if (page_num > 0) { - GSList *group = gtk_radio_button_get_group (GTK_RADIO_BUTTON(_buttons[0])); - gtk_radio_button_set_group (GTK_RADIO_BUTTON(_buttons[page_num]), group); + GSList *group = gtk_radio_button_get_group(GTK_RADIO_BUTTON(_buttons[0])); + gtk_radio_button_set_group(GTK_RADIO_BUTTON(_buttons[page_num]), group); } - gtk_widget_show (_buttons[page_num]); - gtk_box_pack_start (GTK_BOX (_buttonbox), _buttons[page_num], TRUE, TRUE, 0); + gtk_widget_show(_buttons[page_num]); + gtk_box_pack_start(GTK_BOX(_buttonbox), _buttons[page_num], TRUE, TRUE, 0); - g_signal_connect (G_OBJECT (_buttons[page_num]), "clicked", G_CALLBACK (_onButtonClicked), this); + g_signal_connect(G_OBJECT(_buttons[page_num]), "clicked", G_CALLBACK(_onButtonClicked), this); } } - } } } diff --git a/src/ui/widget/color-notebook.h b/src/ui/widget/color-notebook.h index 9909aa39c..d28028c72 100644 --- a/src/ui/widget/color-notebook.h +++ b/src/ui/widget/color-notebook.h @@ -15,7 +15,7 @@ #define SEEN_SP_COLOR_NOTEBOOK_H #ifdef HAVE_CONFIG_H -# include +#include #endif #include @@ -35,7 +35,7 @@ namespace UI { namespace Widget { class ColorNotebook -#if GTK_CHECK_VERSION(3,0,0) +#if GTK_CHECK_VERSION(3, 0, 0) : public Gtk::Grid #else : public Gtk::Table @@ -54,12 +54,11 @@ protected: }; virtual void _initUI(); - void _addPage(Page& page); + void _addPage(Page &page); static void _onButtonClicked(GtkWidget *widget, ColorNotebook *colorbook); static void _onPickerClicked(GtkWidget *widget, ColorNotebook *colorbook); - static void _onPageSwitched(GtkNotebook *notebook, GtkWidget *page, - guint page_num, ColorNotebook *colorbook); + static void _onPageSwitched(GtkNotebook *notebook, GtkWidget *page, guint page_num, ColorNotebook *colorbook); virtual void _onSelectedColorChanged(); void _updateICCButtons(); @@ -73,17 +72,16 @@ protected: GtkWidget *_rgbal; /* RGBA entry */ #if defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) GtkWidget *_box_outofgamut, *_box_colormanaged, *_box_toomuchink; -#endif //defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) +#endif // defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) GtkWidget *_btn_picker; GtkWidget *_p; /* Color preview */ boost::ptr_vector _available_pages; private: // By default, disallow copy constructor and assignment operator - ColorNotebook( const ColorNotebook& obj ); - ColorNotebook& operator=( const ColorNotebook& obj ); + ColorNotebook(const ColorNotebook &obj); + ColorNotebook &operator=(const ColorNotebook &obj); }; - } } } diff --git a/src/ui/widget/color-scales.cpp b/src/ui/widget/color-scales.cpp index 9f18b2d96..5fa5af902 100644 --- a/src/ui/widget/color-scales.cpp +++ b/src/ui/widget/color-scales.cpp @@ -3,7 +3,7 @@ */ #ifdef HAVE_CONFIG_H -# include "config.h" +#include "config.h" #endif #include @@ -41,26 +41,20 @@ namespace UI { namespace Widget { -static const gchar * sp_color_scales_hue_map (); +static const gchar *sp_color_scales_hue_map(); -const gchar* ColorScales::SUBMODE_NAMES[] = { - N_("None"), - N_("RGB"), - N_("HSL"), - N_("CMYK") -}; +const gchar *ColorScales::SUBMODE_NAMES[] = { N_("None"), N_("RGB"), N_("HSL"), N_("CMYK") }; ColorScales::ColorScales(SelectedColor &color, SPColorScalesMode mode) -#if GTK_CHECK_VERSION(3,0,0) +#if GTK_CHECK_VERSION(3, 0, 0) : Gtk::Grid() #else : Gtk::Table(5, 3, false) #endif , _color(color) - , - _rangeLimit( 255.0 ), - _updating( FALSE ), - _dragging( FALSE ) + , _rangeLimit(255.0) + , _updating(FALSE) + , _dragging(FALSE) { for (gint i = 0; i < 5; i++) { _l[i] = 0; @@ -73,7 +67,6 @@ ColorScales::ColorScales(SelectedColor &color, SPColorScalesMode mode) _color.signal_changed.connect(sigc::mem_fun(this, &ColorScales::_onColorChanged)); _color.signal_dragged.connect(sigc::mem_fun(this, &ColorScales::_onColorChanged)); - } ColorScales::~ColorScales() @@ -88,92 +81,92 @@ ColorScales::~ColorScales() void ColorScales::_initUI(SPColorScalesMode mode) { - gint i; + gint i; - _updating = FALSE; - _dragging = FALSE; + _updating = FALSE; + _dragging = FALSE; - GtkWidget *t = GTK_WIDGET(gobj()); + GtkWidget *t = GTK_WIDGET(gobj()); - /* Create components */ - for (i = 0; i < static_cast< gint > (G_N_ELEMENTS(_a)) ; i++) { - /* Label */ - _l[i] = gtk_label_new(""); - gtk_misc_set_alignment (GTK_MISC (_l[i]), 1.0, 0.5); - gtk_widget_show (_l[i]); + /* Create components */ + for (i = 0; i < static_cast(G_N_ELEMENTS(_a)); i++) { + /* Label */ + _l[i] = gtk_label_new(""); + gtk_misc_set_alignment(GTK_MISC(_l[i]), 1.0, 0.5); + gtk_widget_show(_l[i]); -#if GTK_CHECK_VERSION(3,0,0) - #if GTK_CHECK_VERSION(3,12,0) - gtk_widget_set_margin_start(_l[i], XPAD); - gtk_widget_set_margin_end(_l[i], XPAD); +#if GTK_CHECK_VERSION(3, 0, 0) + #if GTK_CHECK_VERSION(3, 12, 0) + gtk_widget_set_margin_start(_l[i], XPAD); + gtk_widget_set_margin_end(_l[i], XPAD); #else - gtk_widget_set_margin_left(_l[i], XPAD); - gtk_widget_set_margin_right(_l[i], XPAD); + gtk_widget_set_margin_left(_l[i], XPAD); + gtk_widget_set_margin_right(_l[i], XPAD); #endif - gtk_widget_set_margin_top(_l[i], YPAD); - gtk_widget_set_margin_bottom(_l[i], YPAD); - gtk_grid_attach(GTK_GRID(t), _l[i], 0, i, 1, 1); + gtk_widget_set_margin_top(_l[i], YPAD); + gtk_widget_set_margin_bottom(_l[i], YPAD); + gtk_grid_attach(GTK_GRID(t), _l[i], 0, i, 1, 1); #else - gtk_table_attach (GTK_TABLE (t), _l[i], 0, 1, i, i + 1, GTK_FILL, GTK_FILL, XPAD, YPAD); + gtk_table_attach(GTK_TABLE(t), _l[i], 0, 1, i, i + 1, GTK_FILL, GTK_FILL, XPAD, YPAD); #endif - /* Adjustment */ - _a[i] = GTK_ADJUSTMENT(gtk_adjustment_new(0.0, 0.0, _rangeLimit, 1.0, 10.0, 10.0)); - /* Slider */ - _s[i] = Gtk::manage(new Inkscape::UI::Widget::ColorSlider(Glib::wrap(_a[i], true))); - _s[i]->show(); + /* Adjustment */ + _a[i] = GTK_ADJUSTMENT(gtk_adjustment_new(0.0, 0.0, _rangeLimit, 1.0, 10.0, 10.0)); + /* Slider */ + _s[i] = Gtk::manage(new Inkscape::UI::Widget::ColorSlider(Glib::wrap(_a[i], true))); + _s[i]->show(); -#if GTK_CHECK_VERSION(3,0,0) - #if GTK_CHECK_VERSION(3,12,0) - _s[i]->set_margin_start(XPAD); - _s[i]->set_margin_end(XPAD); +#if GTK_CHECK_VERSION(3, 0, 0) + #if GTK_CHECK_VERSION(3, 12, 0) + _s[i]->set_margin_start(XPAD); + _s[i]->set_margin_end(XPAD); #else - _s[i]->set_margin_left(XPAD); - _s[i]->set_margin_right(XPAD); + _s[i]->set_margin_left(XPAD); + _s[i]->set_margin_right(XPAD); #endif - _s[i]->set_margin_top(YPAD); - _s[i]->set_margin_bottom(YPAD); - _s[i]->set_hexpand(true); - gtk_grid_attach(GTK_GRID(t), _s[i]->gobj(), 1, i, 1, 1); + _s[i]->set_margin_top(YPAD); + _s[i]->set_margin_bottom(YPAD); + _s[i]->set_hexpand(true); + gtk_grid_attach(GTK_GRID(t), _s[i]->gobj(), 1, i, 1, 1); #else - gtk_table_attach (GTK_TABLE (t), _s[i]->gobj(), 1, 2, i, i + 1, (GtkAttachOptions)(GTK_EXPAND | GTK_FILL), GTK_FILL, XPAD, YPAD); + gtk_table_attach(GTK_TABLE(t), _s[i]->gobj(), 1, 2, i, i + 1, (GtkAttachOptions)(GTK_EXPAND | GTK_FILL), + GTK_FILL, XPAD, YPAD); #endif - /* Spinbutton */ - _b[i] = gtk_spin_button_new (GTK_ADJUSTMENT (_a[i]), 1.0, 0); - sp_dialog_defocus_on_enter (_b[i]); - gtk_label_set_mnemonic_widget (GTK_LABEL(_l[i]), _b[i]); - gtk_widget_show (_b[i]); + /* Spinbutton */ + _b[i] = gtk_spin_button_new(GTK_ADJUSTMENT(_a[i]), 1.0, 0); + sp_dialog_defocus_on_enter(_b[i]); + gtk_label_set_mnemonic_widget(GTK_LABEL(_l[i]), _b[i]); + gtk_widget_show(_b[i]); -#if GTK_CHECK_VERSION(3,0,0) - #if GTK_CHECK_VERSION(3,12,0) - gtk_widget_set_margin_start(_b[i], XPAD); - gtk_widget_set_margin_end(_b[i], XPAD); +#if GTK_CHECK_VERSION(3, 0, 0) + #if GTK_CHECK_VERSION(3, 12, 0) + gtk_widget_set_margin_start(_b[i], XPAD); + gtk_widget_set_margin_end(_b[i], XPAD); #else - gtk_widget_set_margin_left(_b[i], XPAD); - gtk_widget_set_margin_right(_b[i], XPAD); + gtk_widget_set_margin_left(_b[i], XPAD); + gtk_widget_set_margin_right(_b[i], XPAD); #endif - gtk_widget_set_margin_top(_b[i], YPAD); - gtk_widget_set_margin_bottom(_b[i], YPAD); - gtk_widget_set_halign(_b[i], GTK_ALIGN_CENTER); - gtk_widget_set_valign(_b[i], GTK_ALIGN_CENTER); - gtk_grid_attach(GTK_GRID(t), _b[i], 2, i, 1, 1); + gtk_widget_set_margin_top(_b[i], YPAD); + gtk_widget_set_margin_bottom(_b[i], YPAD); + gtk_widget_set_halign(_b[i], GTK_ALIGN_CENTER); + gtk_widget_set_valign(_b[i], GTK_ALIGN_CENTER); + gtk_grid_attach(GTK_GRID(t), _b[i], 2, i, 1, 1); #else - gtk_table_attach (GTK_TABLE (t), _b[i], 2, 3, i, i + 1, (GtkAttachOptions)0, (GtkAttachOptions)0, XPAD, YPAD); + gtk_table_attach(GTK_TABLE(t), _b[i], 2, 3, i, i + 1, (GtkAttachOptions)0, (GtkAttachOptions)0, XPAD, YPAD); #endif - /* Attach channel value to adjustment */ - g_object_set_data (G_OBJECT (_a[i]), "channel", GINT_TO_POINTER (i)); - /* Signals */ - g_signal_connect (G_OBJECT (_a[i]), "value_changed", - G_CALLBACK (_adjustmentAnyChanged), this); - _s[i]->signal_grabbed.connect(sigc::mem_fun(this, &ColorScales::_sliderAnyGrabbed)); - _s[i]->signal_released.connect(sigc::mem_fun(this, &ColorScales::_sliderAnyReleased)); - _s[i]->signal_value_changed.connect(sigc::mem_fun(this, &ColorScales::_sliderAnyChanged)); - } - - /* Initial mode is none, so it works */ - setMode(mode); + /* Attach channel value to adjustment */ + g_object_set_data(G_OBJECT(_a[i]), "channel", GINT_TO_POINTER(i)); + /* Signals */ + g_signal_connect(G_OBJECT(_a[i]), "value_changed", G_CALLBACK(_adjustmentAnyChanged), this); + _s[i]->signal_grabbed.connect(sigc::mem_fun(this, &ColorScales::_sliderAnyGrabbed)); + _s[i]->signal_released.connect(sigc::mem_fun(this, &ColorScales::_sliderAnyReleased)); + _s[i]->signal_value_changed.connect(sigc::mem_fun(this, &ColorScales::_sliderAnyChanged)); + } + + /* Initial mode is none, so it works */ + setMode(mode); } void ColorScales::_recalcColor() @@ -183,25 +176,24 @@ void ColorScales::_recalcColor() gfloat c[5]; switch (_mode) { - case SP_COLOR_SCALES_MODE_RGB: - case SP_COLOR_SCALES_MODE_HSV: - _getRgbaFloatv(c); - color.set( c[0], c[1], c[2] ); - alpha = c[3]; - break; - case SP_COLOR_SCALES_MODE_CMYK: - { - _getCmykaFloatv( c ); - - float rgb[3]; - sp_color_cmyk_to_rgb_floatv( rgb, c[0], c[1], c[2], c[3] ); - color.set( rgb[0], rgb[1], rgb[2] ); - alpha = c[4]; - break; - } - default: - g_warning ("file %s: line %d: Illegal color selector mode %d", __FILE__, __LINE__, _mode); - break; + case SP_COLOR_SCALES_MODE_RGB: + case SP_COLOR_SCALES_MODE_HSV: + _getRgbaFloatv(c); + color.set(c[0], c[1], c[2]); + alpha = c[3]; + break; + case SP_COLOR_SCALES_MODE_CMYK: { + _getCmykaFloatv(c); + + float rgb[3]; + sp_color_cmyk_to_rgb_floatv(rgb, c[0], c[1], c[2], c[3]); + color.set(rgb[0], rgb[1], rgb[2]); + alpha = c[4]; + break; + } + default: + g_warning("file %s: line %d: Illegal color selector mode %d", __FILE__, __LINE__, _mode); + break; } _color.preserveICC(); @@ -209,25 +201,25 @@ void ColorScales::_recalcColor() } /* Helpers for setting color value */ -gfloat ColorScales::getScaled( const GtkAdjustment *a ) +gfloat ColorScales::getScaled(const GtkAdjustment *a) { - gfloat val = gtk_adjustment_get_value (const_cast(a)) - / gtk_adjustment_get_upper (const_cast(a)); + gfloat val = gtk_adjustment_get_value(const_cast(a)) / + gtk_adjustment_get_upper(const_cast(a)); return val; } -void ColorScales::setScaled( GtkAdjustment *a, gfloat v ) +void ColorScales::setScaled(GtkAdjustment *a, gfloat v) { - gfloat val = v * gtk_adjustment_get_upper (a); - gtk_adjustment_set_value( a, val ); + gfloat val = v * gtk_adjustment_get_upper(a); + gtk_adjustment_set_value(a, val); } -void ColorScales::_setRangeLimit( gdouble upper ) +void ColorScales::_setRangeLimit(gdouble upper) { _rangeLimit = upper; - for ( gint i = 0; i < static_cast(G_N_ELEMENTS(_a)); i++ ) { - gtk_adjustment_set_upper (_a[i], upper); - gtk_adjustment_changed( _a[i] ); + for (gint i = 0; i < static_cast(G_N_ELEMENTS(_a)); i++) { + gtk_adjustment_set_upper(_a[i], upper); + gtk_adjustment_changed(_a[i]); } } @@ -237,231 +229,230 @@ void ColorScales::_onColorChanged() return; } #ifdef DUMP_CHANGE_INFO - g_message("ColorScales::_onColorChanged( this=%p, %f, %f, %f, %f)", this, _color.color().v.c[0], _color.color().v.c[1], _color.color().v.c[2], _color.alpha() ); + g_message("ColorScales::_onColorChanged( this=%p, %f, %f, %f, %f)", this, _color.color().v.c[0], + _color.color().v.c[1], _color.color().v.c[2], _color.alpha()); #endif gfloat tmp[3]; - gfloat c[5] = {0.0, 0.0, 0.0, 0.0}; + gfloat c[5] = { 0.0, 0.0, 0.0, 0.0 }; SPColor color = _color.color(); switch (_mode) { - case SP_COLOR_SCALES_MODE_RGB: - sp_color_get_rgb_floatv( &color, c ); - c[3] = _color.alpha(); - c[4] = 0.0; - break; - case SP_COLOR_SCALES_MODE_HSV: - sp_color_get_rgb_floatv( &color, tmp ); - sp_color_rgb_to_hsl_floatv (c, tmp[0], tmp[1], tmp[2]); - c[3] = _color.alpha(); - c[4] = 0.0; - break; - case SP_COLOR_SCALES_MODE_CMYK: - sp_color_get_cmyk_floatv( &color, c ); - c[4] = _color.alpha(); - break; - default: - g_warning ("file %s: line %d: Illegal color selector mode %d", __FILE__, __LINE__, _mode); - break; + case SP_COLOR_SCALES_MODE_RGB: + sp_color_get_rgb_floatv(&color, c); + c[3] = _color.alpha(); + c[4] = 0.0; + break; + case SP_COLOR_SCALES_MODE_HSV: + sp_color_get_rgb_floatv(&color, tmp); + sp_color_rgb_to_hsl_floatv(c, tmp[0], tmp[1], tmp[2]); + c[3] = _color.alpha(); + c[4] = 0.0; + break; + case SP_COLOR_SCALES_MODE_CMYK: + sp_color_get_cmyk_floatv(&color, c); + c[4] = _color.alpha(); + break; + default: + g_warning("file %s: line %d: Illegal color selector mode %d", __FILE__, __LINE__, _mode); + break; } _updating = TRUE; - setScaled( _a[0], c[0] ); - setScaled( _a[1], c[1] ); - setScaled( _a[2], c[2] ); - setScaled( _a[3], c[3] ); - setScaled( _a[4], c[4] ); - _updateSliders( CSC_CHANNELS_ALL ); + setScaled(_a[0], c[0]); + setScaled(_a[1], c[1]); + setScaled(_a[2], c[2]); + setScaled(_a[3], c[3]); + setScaled(_a[4], c[4]); + _updateSliders(CSC_CHANNELS_ALL); _updating = FALSE; } -void ColorScales::_getRgbaFloatv( gfloat *rgba ) +void ColorScales::_getRgbaFloatv(gfloat *rgba) { - g_return_if_fail (rgba != NULL); - - switch (_mode) { - case SP_COLOR_SCALES_MODE_RGB: - rgba[0] = getScaled(_a[0]); - rgba[1] = getScaled(_a[1]); - rgba[2] = getScaled(_a[2]); - rgba[3] = getScaled(_a[3]); - break; - case SP_COLOR_SCALES_MODE_HSV: - sp_color_hsl_to_rgb_floatv (rgba, getScaled(_a[0]), getScaled(_a[1]), getScaled(_a[2])); - rgba[3] = getScaled(_a[3]); - break; - case SP_COLOR_SCALES_MODE_CMYK: - sp_color_cmyk_to_rgb_floatv (rgba, getScaled(_a[0]), getScaled(_a[1]), getScaled(_a[2]), getScaled(_a[3])); - rgba[3] = getScaled(_a[4]); - break; - default: - g_warning ("file %s: line %d: Illegal color selector mode", __FILE__, __LINE__); - break; - } + g_return_if_fail(rgba != NULL); + + switch (_mode) { + case SP_COLOR_SCALES_MODE_RGB: + rgba[0] = getScaled(_a[0]); + rgba[1] = getScaled(_a[1]); + rgba[2] = getScaled(_a[2]); + rgba[3] = getScaled(_a[3]); + break; + case SP_COLOR_SCALES_MODE_HSV: + sp_color_hsl_to_rgb_floatv(rgba, getScaled(_a[0]), getScaled(_a[1]), getScaled(_a[2])); + rgba[3] = getScaled(_a[3]); + break; + case SP_COLOR_SCALES_MODE_CMYK: + sp_color_cmyk_to_rgb_floatv(rgba, getScaled(_a[0]), getScaled(_a[1]), getScaled(_a[2]), getScaled(_a[3])); + rgba[3] = getScaled(_a[4]); + break; + default: + g_warning("file %s: line %d: Illegal color selector mode", __FILE__, __LINE__); + break; + } } -void ColorScales::_getCmykaFloatv( gfloat *cmyka ) +void ColorScales::_getCmykaFloatv(gfloat *cmyka) { - gfloat rgb[3]; - - g_return_if_fail (cmyka != NULL); - - switch (_mode) { - case SP_COLOR_SCALES_MODE_RGB: - sp_color_rgb_to_cmyk_floatv (cmyka, getScaled(_a[0]), getScaled(_a[1]), getScaled(_a[2])); - cmyka[4] = getScaled(_a[3]); - break; - case SP_COLOR_SCALES_MODE_HSV: - sp_color_hsl_to_rgb_floatv (rgb, getScaled(_a[0]), getScaled(_a[1]), getScaled(_a[2])); - sp_color_rgb_to_cmyk_floatv (cmyka, rgb[0], rgb[1], rgb[2]); - cmyka[4] = getScaled(_a[3]); - break; - case SP_COLOR_SCALES_MODE_CMYK: - cmyka[0] = getScaled(_a[0]); - cmyka[1] = getScaled(_a[1]); - cmyka[2] = getScaled(_a[2]); - cmyka[3] = getScaled(_a[3]); - cmyka[4] = getScaled(_a[4]); - break; - default: - g_warning ("file %s: line %d: Illegal color selector mode", __FILE__, __LINE__); - break; - } + gfloat rgb[3]; + + g_return_if_fail(cmyka != NULL); + + switch (_mode) { + case SP_COLOR_SCALES_MODE_RGB: + sp_color_rgb_to_cmyk_floatv(cmyka, getScaled(_a[0]), getScaled(_a[1]), getScaled(_a[2])); + cmyka[4] = getScaled(_a[3]); + break; + case SP_COLOR_SCALES_MODE_HSV: + sp_color_hsl_to_rgb_floatv(rgb, getScaled(_a[0]), getScaled(_a[1]), getScaled(_a[2])); + sp_color_rgb_to_cmyk_floatv(cmyka, rgb[0], rgb[1], rgb[2]); + cmyka[4] = getScaled(_a[3]); + break; + case SP_COLOR_SCALES_MODE_CMYK: + cmyka[0] = getScaled(_a[0]); + cmyka[1] = getScaled(_a[1]); + cmyka[2] = getScaled(_a[2]); + cmyka[3] = getScaled(_a[3]); + cmyka[4] = getScaled(_a[4]); + break; + default: + g_warning("file %s: line %d: Illegal color selector mode", __FILE__, __LINE__); + break; + } } guint32 ColorScales::_getRgba32() { - gfloat c[4]; - guint32 rgba; + gfloat c[4]; + guint32 rgba; - _getRgbaFloatv(c); + _getRgbaFloatv(c); - rgba = SP_RGBA32_F_COMPOSE (c[0], c[1], c[2], c[3]); + rgba = SP_RGBA32_F_COMPOSE(c[0], c[1], c[2], c[3]); - return rgba; + return rgba; } void ColorScales::setMode(SPColorScalesMode mode) { - gfloat rgba[4]; - gfloat c[4]; - - if (_mode == mode) return; - - if ((_mode == SP_COLOR_SCALES_MODE_RGB) || - (_mode == SP_COLOR_SCALES_MODE_HSV) || - (_mode == SP_COLOR_SCALES_MODE_CMYK)) { - _getRgbaFloatv(rgba); - } else { - rgba[0] = rgba[1] = rgba[2] = rgba[3] = 1.0; - } - - _mode = mode; - - switch (mode) { - case SP_COLOR_SCALES_MODE_RGB: - _setRangeLimit(255.0); - gtk_label_set_markup_with_mnemonic (GTK_LABEL (_l[0]), _("_R:")); - _s[0]->set_tooltip_text(_("Red")); - gtk_widget_set_tooltip_text (_b[0], _("Red")); - gtk_label_set_markup_with_mnemonic (GTK_LABEL (_l[1]), _("_G:")); - _s[1]->set_tooltip_text(_("Green")); - gtk_widget_set_tooltip_text (_b[1], _("Green")); - gtk_label_set_markup_with_mnemonic (GTK_LABEL (_l[2]), _("_B:")); - _s[2]->set_tooltip_text(_("Blue")); - gtk_widget_set_tooltip_text (_b[2], _("Blue")); - gtk_label_set_markup_with_mnemonic (GTK_LABEL (_l[3]), _("_A:")); - _s[3]->set_tooltip_text(_("Alpha (opacity)")); - gtk_widget_set_tooltip_text (_b[3], _("Alpha (opacity)")); - _s[0]->setMap(NULL); - gtk_widget_hide (_l[4]); - _s[4]->hide(); - gtk_widget_hide (_b[4]); - _updating = TRUE; - setScaled( _a[0], rgba[0] ); - setScaled( _a[1], rgba[1] ); - setScaled( _a[2], rgba[2] ); - setScaled( _a[3], rgba[3] ); - _updating = FALSE; - _updateSliders( CSC_CHANNELS_ALL ); - break; - case SP_COLOR_SCALES_MODE_HSV: - _setRangeLimit(255.0); - gtk_label_set_markup_with_mnemonic (GTK_LABEL (_l[0]), _("_H:")); - _s[0]->set_tooltip_text(_("Hue")); - gtk_widget_set_tooltip_text (_b[0], _("Hue")); - gtk_label_set_markup_with_mnemonic (GTK_LABEL (_l[1]), _("_S:")); - _s[1]->set_tooltip_text(_("Saturation")); - gtk_widget_set_tooltip_text (_b[1], _("Saturation")); - gtk_label_set_markup_with_mnemonic (GTK_LABEL (_l[2]), _("_L:")); - _s[2]->set_tooltip_text(_("Lightness")); - gtk_widget_set_tooltip_text (_b[2], _("Lightness")); - gtk_label_set_markup_with_mnemonic (GTK_LABEL (_l[3]), _("_A:")); - _s[3]->set_tooltip_text(_("Alpha (opacity)")); - gtk_widget_set_tooltip_text (_b[3], _("Alpha (opacity)")); - _s[0]->setMap((guchar *)(sp_color_scales_hue_map())); - gtk_widget_hide (_l[4]); - _s[4]->hide(); - gtk_widget_hide (_b[4]); - _updating = TRUE; - c[0] = 0.0; - sp_color_rgb_to_hsl_floatv (c, rgba[0], rgba[1], rgba[2]); - setScaled( _a[0], c[0] ); - setScaled( _a[1], c[1] ); - setScaled( _a[2], c[2] ); - setScaled( _a[3], rgba[3] ); - _updating = FALSE; - _updateSliders( CSC_CHANNELS_ALL ); - break; - case SP_COLOR_SCALES_MODE_CMYK: - _setRangeLimit(100.0); - gtk_label_set_markup_with_mnemonic (GTK_LABEL (_l[0]), _("_C:")); - _s[0]->set_tooltip_text(_("Cyan")); - gtk_widget_set_tooltip_text (_b[0], _("Cyan")); - gtk_label_set_markup_with_mnemonic (GTK_LABEL (_l[1]), _("_M:")); - _s[1]->set_tooltip_text(_("Magenta")); - gtk_widget_set_tooltip_text (_b[1], _("Magenta")); - gtk_label_set_markup_with_mnemonic (GTK_LABEL (_l[2]), _("_Y:")); - _s[2]->set_tooltip_text(_("Yellow")); - gtk_widget_set_tooltip_text (_b[2], _("Yellow")); - gtk_label_set_markup_with_mnemonic (GTK_LABEL (_l[3]), _("_K:")); - _s[3]->set_tooltip_text(_("Black")); - gtk_widget_set_tooltip_text (_b[3], _("Black")); - gtk_label_set_markup_with_mnemonic (GTK_LABEL (_l[4]), _("_A:")); - _s[4]->set_tooltip_text(_("Alpha (opacity)")); - gtk_widget_set_tooltip_text (_b[4], _("Alpha (opacity)")); - _s[0]->setMap(NULL); - gtk_widget_show (_l[4]); - _s[4]->show(); - gtk_widget_show (_b[4]); - _updating = TRUE; - - sp_color_rgb_to_cmyk_floatv (c, rgba[0], rgba[1], rgba[2]); - setScaled( _a[0], c[0] ); - setScaled( _a[1], c[1] ); - setScaled( _a[2], c[2] ); - setScaled( _a[3], c[3] ); - - setScaled( _a[4], rgba[3] ); - _updating = FALSE; - _updateSliders( CSC_CHANNELS_ALL ); - break; - default: - g_warning ("file %s: line %d: Illegal color selector mode", __FILE__, __LINE__); - break; - } -} + gfloat rgba[4]; + gfloat c[4]; -SPColorScalesMode ColorScales::getMode() const -{ - return _mode; + if (_mode == mode) + return; + + if ((_mode == SP_COLOR_SCALES_MODE_RGB) || (_mode == SP_COLOR_SCALES_MODE_HSV) || + (_mode == SP_COLOR_SCALES_MODE_CMYK)) { + _getRgbaFloatv(rgba); + } + else { + rgba[0] = rgba[1] = rgba[2] = rgba[3] = 1.0; + } + + _mode = mode; + + switch (mode) { + case SP_COLOR_SCALES_MODE_RGB: + _setRangeLimit(255.0); + gtk_label_set_markup_with_mnemonic(GTK_LABEL(_l[0]), _("_R:")); + _s[0]->set_tooltip_text(_("Red")); + gtk_widget_set_tooltip_text(_b[0], _("Red")); + gtk_label_set_markup_with_mnemonic(GTK_LABEL(_l[1]), _("_G:")); + _s[1]->set_tooltip_text(_("Green")); + gtk_widget_set_tooltip_text(_b[1], _("Green")); + gtk_label_set_markup_with_mnemonic(GTK_LABEL(_l[2]), _("_B:")); + _s[2]->set_tooltip_text(_("Blue")); + gtk_widget_set_tooltip_text(_b[2], _("Blue")); + gtk_label_set_markup_with_mnemonic(GTK_LABEL(_l[3]), _("_A:")); + _s[3]->set_tooltip_text(_("Alpha (opacity)")); + gtk_widget_set_tooltip_text(_b[3], _("Alpha (opacity)")); + _s[0]->setMap(NULL); + gtk_widget_hide(_l[4]); + _s[4]->hide(); + gtk_widget_hide(_b[4]); + _updating = TRUE; + setScaled(_a[0], rgba[0]); + setScaled(_a[1], rgba[1]); + setScaled(_a[2], rgba[2]); + setScaled(_a[3], rgba[3]); + _updating = FALSE; + _updateSliders(CSC_CHANNELS_ALL); + break; + case SP_COLOR_SCALES_MODE_HSV: + _setRangeLimit(255.0); + gtk_label_set_markup_with_mnemonic(GTK_LABEL(_l[0]), _("_H:")); + _s[0]->set_tooltip_text(_("Hue")); + gtk_widget_set_tooltip_text(_b[0], _("Hue")); + gtk_label_set_markup_with_mnemonic(GTK_LABEL(_l[1]), _("_S:")); + _s[1]->set_tooltip_text(_("Saturation")); + gtk_widget_set_tooltip_text(_b[1], _("Saturation")); + gtk_label_set_markup_with_mnemonic(GTK_LABEL(_l[2]), _("_L:")); + _s[2]->set_tooltip_text(_("Lightness")); + gtk_widget_set_tooltip_text(_b[2], _("Lightness")); + gtk_label_set_markup_with_mnemonic(GTK_LABEL(_l[3]), _("_A:")); + _s[3]->set_tooltip_text(_("Alpha (opacity)")); + gtk_widget_set_tooltip_text(_b[3], _("Alpha (opacity)")); + _s[0]->setMap((guchar *)(sp_color_scales_hue_map())); + gtk_widget_hide(_l[4]); + _s[4]->hide(); + gtk_widget_hide(_b[4]); + _updating = TRUE; + c[0] = 0.0; + sp_color_rgb_to_hsl_floatv(c, rgba[0], rgba[1], rgba[2]); + setScaled(_a[0], c[0]); + setScaled(_a[1], c[1]); + setScaled(_a[2], c[2]); + setScaled(_a[3], rgba[3]); + _updating = FALSE; + _updateSliders(CSC_CHANNELS_ALL); + break; + case SP_COLOR_SCALES_MODE_CMYK: + _setRangeLimit(100.0); + gtk_label_set_markup_with_mnemonic(GTK_LABEL(_l[0]), _("_C:")); + _s[0]->set_tooltip_text(_("Cyan")); + gtk_widget_set_tooltip_text(_b[0], _("Cyan")); + gtk_label_set_markup_with_mnemonic(GTK_LABEL(_l[1]), _("_M:")); + _s[1]->set_tooltip_text(_("Magenta")); + gtk_widget_set_tooltip_text(_b[1], _("Magenta")); + gtk_label_set_markup_with_mnemonic(GTK_LABEL(_l[2]), _("_Y:")); + _s[2]->set_tooltip_text(_("Yellow")); + gtk_widget_set_tooltip_text(_b[2], _("Yellow")); + gtk_label_set_markup_with_mnemonic(GTK_LABEL(_l[3]), _("_K:")); + _s[3]->set_tooltip_text(_("Black")); + gtk_widget_set_tooltip_text(_b[3], _("Black")); + gtk_label_set_markup_with_mnemonic(GTK_LABEL(_l[4]), _("_A:")); + _s[4]->set_tooltip_text(_("Alpha (opacity)")); + gtk_widget_set_tooltip_text(_b[4], _("Alpha (opacity)")); + _s[0]->setMap(NULL); + gtk_widget_show(_l[4]); + _s[4]->show(); + gtk_widget_show(_b[4]); + _updating = TRUE; + + sp_color_rgb_to_cmyk_floatv(c, rgba[0], rgba[1], rgba[2]); + setScaled(_a[0], c[0]); + setScaled(_a[1], c[1]); + setScaled(_a[2], c[2]); + setScaled(_a[3], c[3]); + + setScaled(_a[4], rgba[3]); + _updating = FALSE; + _updateSliders(CSC_CHANNELS_ALL); + break; + default: + g_warning("file %s: line %d: Illegal color selector mode", __FILE__, __LINE__); + break; + } } -void ColorScales::_adjustmentAnyChanged( GtkAdjustment *adjustment, ColorScales *cs ) +SPColorScalesMode ColorScales::getMode() const { return _mode; } + +void ColorScales::_adjustmentAnyChanged(GtkAdjustment *adjustment, ColorScales *cs) { - gint channel = GPOINTER_TO_INT (g_object_get_data(G_OBJECT (adjustment), "channel")); + gint channel = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(adjustment), "channel")); - _adjustmentChanged(cs, channel); + _adjustmentChanged(cs, channel); } void ColorScales::_sliderAnyGrabbed() @@ -469,10 +460,10 @@ void ColorScales::_sliderAnyGrabbed() if (_updating) { return; } - if (!_dragging) { - _dragging = TRUE; + if (!_dragging) { + _dragging = TRUE; _color.setHeld(true); - } + } } void ColorScales::_sliderAnyReleased() @@ -480,10 +471,10 @@ void ColorScales::_sliderAnyReleased() if (_updating) { return; } - if (_dragging) { - _dragging = FALSE; + if (_dragging) { + _dragging = FALSE; _color.setHeld(false); - } + } } void ColorScales::_sliderAnyChanged() @@ -494,160 +485,159 @@ void ColorScales::_sliderAnyChanged() _recalcColor(); } -void ColorScales::_adjustmentChanged( ColorScales *scales, guint channel ) +void ColorScales::_adjustmentChanged(ColorScales *scales, guint channel) { - if (scales->_updating) { - return; - } + if (scales->_updating) { + return; + } - scales->_updateSliders( (1 << channel) ); - scales->_recalcColor(); + scales->_updateSliders((1 << channel)); + scales->_recalcColor(); } -void ColorScales::_updateSliders( guint channels ) +void ColorScales::_updateSliders(guint channels) { - gfloat rgb0[3], rgbm[3], rgb1[3]; + gfloat rgb0[3], rgbm[3], rgb1[3]; #ifdef SPCS_PREVIEW - guint32 rgba; + guint32 rgba; #endif - switch (_mode) { - case SP_COLOR_SCALES_MODE_RGB: - if ((channels != CSC_CHANNEL_R) && (channels != CSC_CHANNEL_A)) { - /* Update red */ - _s[0]->setColors(SP_RGBA32_F_COMPOSE (0.0, getScaled(_a[1]), getScaled(_a[2]), 1.0), - SP_RGBA32_F_COMPOSE (0.5, getScaled(_a[1]), getScaled(_a[2]), 1.0), - SP_RGBA32_F_COMPOSE (1.0, getScaled(_a[1]), getScaled(_a[2]), 1.0)); - } - if ((channels != CSC_CHANNEL_G) && (channels != CSC_CHANNEL_A)) { - /* Update green */ - _s[1]->setColors(SP_RGBA32_F_COMPOSE(getScaled(_a[0]), 0.0, getScaled(_a[2]), 1.0), - SP_RGBA32_F_COMPOSE(getScaled(_a[0]), 0.5, getScaled(_a[2]), 1.0), - SP_RGBA32_F_COMPOSE(getScaled(_a[0]), 1.0, getScaled(_a[2]), 1.0)); - } - if ((channels != CSC_CHANNEL_B) && (channels != CSC_CHANNEL_A)) { - /* Update blue */ - _s[2]->setColors(SP_RGBA32_F_COMPOSE (getScaled(_a[0]), getScaled(_a[1]), 0.0, 1.0), - SP_RGBA32_F_COMPOSE (getScaled(_a[0]), getScaled(_a[1]), 0.5, 1.0), - SP_RGBA32_F_COMPOSE (getScaled(_a[0]), getScaled(_a[1]), 1.0, 1.0)); - } - if (channels != CSC_CHANNEL_A) { - /* Update alpha */ - _s[3]->setColors(SP_RGBA32_F_COMPOSE (getScaled(_a[0]), getScaled(_a[1]), getScaled(_a[2]), 0.0), - SP_RGBA32_F_COMPOSE (getScaled(_a[0]), getScaled(_a[1]), getScaled(_a[2]), 0.5), - SP_RGBA32_F_COMPOSE (getScaled(_a[0]), getScaled(_a[1]), getScaled(_a[2]), 1.0)); - } - break; - case SP_COLOR_SCALES_MODE_HSV: - /* Hue is never updated */ - if ((channels != CSC_CHANNEL_S) && (channels != CSC_CHANNEL_A)) { - /* Update saturation */ - sp_color_hsl_to_rgb_floatv (rgb0, getScaled(_a[0]), 0.0, getScaled(_a[2])); - sp_color_hsl_to_rgb_floatv (rgbm, getScaled(_a[0]), 0.5, getScaled(_a[2])); - sp_color_hsl_to_rgb_floatv (rgb1, getScaled(_a[0]), 1.0, getScaled(_a[2])); - _s[1]->setColors(SP_RGBA32_F_COMPOSE (rgb0[0], rgb0[1], rgb0[2], 1.0), - SP_RGBA32_F_COMPOSE (rgbm[0], rgbm[1], rgbm[2], 1.0), - SP_RGBA32_F_COMPOSE (rgb1[0], rgb1[1], rgb1[2], 1.0)); - } - if ((channels != CSC_CHANNEL_V) && (channels != CSC_CHANNEL_A)) { - /* Update value */ - sp_color_hsl_to_rgb_floatv (rgb0, getScaled(_a[0]), getScaled(_a[1]), 0.0); - sp_color_hsl_to_rgb_floatv (rgbm, getScaled(_a[0]), getScaled(_a[1]), 0.5); - sp_color_hsl_to_rgb_floatv (rgb1, getScaled(_a[0]), getScaled(_a[1]), 1.0); - _s[2]->setColors(SP_RGBA32_F_COMPOSE (rgb0[0], rgb0[1], rgb0[2], 1.0), - SP_RGBA32_F_COMPOSE (rgbm[0], rgbm[1], rgbm[2], 1.0), - SP_RGBA32_F_COMPOSE (rgb1[0], rgb1[1], rgb1[2], 1.0)); - } - if (channels != CSC_CHANNEL_A) { - /* Update alpha */ - sp_color_hsl_to_rgb_floatv (rgb0, getScaled(_a[0]), getScaled(_a[1]), getScaled(_a[2])); - _s[3]->setColors(SP_RGBA32_F_COMPOSE (rgb0[0], rgb0[1], rgb0[2], 0.0), - SP_RGBA32_F_COMPOSE (rgb0[0], rgb0[1], rgb0[2], 0.5), - SP_RGBA32_F_COMPOSE (rgb0[0], rgb0[1], rgb0[2], 1.0)); - } - break; - case SP_COLOR_SCALES_MODE_CMYK: - if ((channels != CSC_CHANNEL_C) && (channels != CSC_CHANNEL_CMYKA)) { - /* Update C */ - sp_color_cmyk_to_rgb_floatv (rgb0, 0.0, getScaled(_a[1]), getScaled(_a[2]), getScaled(_a[3])); - sp_color_cmyk_to_rgb_floatv (rgbm, 0.5, getScaled(_a[1]), getScaled(_a[2]), getScaled(_a[3])); - sp_color_cmyk_to_rgb_floatv (rgb1, 1.0, getScaled(_a[1]), getScaled(_a[2]), getScaled(_a[3])); - _s[0]->setColors(SP_RGBA32_F_COMPOSE (rgb0[0], rgb0[1], rgb0[2], 1.0), - SP_RGBA32_F_COMPOSE (rgbm[0], rgbm[1], rgbm[2], 1.0), - SP_RGBA32_F_COMPOSE (rgb1[0], rgb1[1], rgb1[2], 1.0)); - } - if ((channels != CSC_CHANNEL_M) && (channels != CSC_CHANNEL_CMYKA)) { - /* Update M */ - sp_color_cmyk_to_rgb_floatv (rgb0, getScaled(_a[0]), 0.0, getScaled(_a[2]), getScaled(_a[3])); - sp_color_cmyk_to_rgb_floatv (rgbm, getScaled(_a[0]), 0.5, getScaled(_a[2]), getScaled(_a[3])); - sp_color_cmyk_to_rgb_floatv (rgb1, getScaled(_a[0]), 1.0, getScaled(_a[2]), getScaled(_a[3])); - _s[1]->setColors(SP_RGBA32_F_COMPOSE (rgb0[0], rgb0[1], rgb0[2], 1.0), - SP_RGBA32_F_COMPOSE (rgbm[0], rgbm[1], rgbm[2], 1.0), - SP_RGBA32_F_COMPOSE (rgb1[0], rgb1[1], rgb1[2], 1.0)); - } - if ((channels != CSC_CHANNEL_Y) && (channels != CSC_CHANNEL_CMYKA)) { - /* Update Y */ - sp_color_cmyk_to_rgb_floatv (rgb0, getScaled(_a[0]), getScaled(_a[1]), 0.0, getScaled(_a[3])); - sp_color_cmyk_to_rgb_floatv (rgbm, getScaled(_a[0]), getScaled(_a[1]), 0.5, getScaled(_a[3])); - sp_color_cmyk_to_rgb_floatv (rgb1, getScaled(_a[0]), getScaled(_a[1]), 1.0, getScaled(_a[3])); - _s[2]->setColors(SP_RGBA32_F_COMPOSE (rgb0[0], rgb0[1], rgb0[2], 1.0), - SP_RGBA32_F_COMPOSE (rgbm[0], rgbm[1], rgbm[2], 1.0), - SP_RGBA32_F_COMPOSE (rgb1[0], rgb1[1], rgb1[2], 1.0)); - } - if ((channels != CSC_CHANNEL_K) && (channels != CSC_CHANNEL_CMYKA)) { - /* Update K */ - sp_color_cmyk_to_rgb_floatv (rgb0, getScaled(_a[0]), getScaled(_a[1]), getScaled(_a[2]), 0.0); - sp_color_cmyk_to_rgb_floatv (rgbm, getScaled(_a[0]), getScaled(_a[1]), getScaled(_a[2]), 0.5); - sp_color_cmyk_to_rgb_floatv (rgb1, getScaled(_a[0]), getScaled(_a[1]), getScaled(_a[2]), 1.0); - _s[3]->setColors(SP_RGBA32_F_COMPOSE (rgb0[0], rgb0[1], rgb0[2], 1.0), - SP_RGBA32_F_COMPOSE (rgbm[0], rgbm[1], rgbm[2], 1.0), - SP_RGBA32_F_COMPOSE (rgb1[0], rgb1[1], rgb1[2], 1.0)); - } - if (channels != CSC_CHANNEL_CMYKA) { - /* Update alpha */ - sp_color_cmyk_to_rgb_floatv (rgb0, getScaled(_a[0]), getScaled(_a[1]), getScaled(_a[2]), getScaled(_a[3])); - _s[4]->setColors(SP_RGBA32_F_COMPOSE (rgb0[0], rgb0[1], rgb0[2], 0.0), - SP_RGBA32_F_COMPOSE (rgb0[0], rgb0[1], rgb0[2], 0.5), - SP_RGBA32_F_COMPOSE (rgb0[0], rgb0[1], rgb0[2], 1.0)); - } - break; - default: - g_warning ("file %s: line %d: Illegal color selector mode", __FILE__, __LINE__); - break; - } - - // Force the internal color to be updated - if ( !_updating ) - { + switch (_mode) { + case SP_COLOR_SCALES_MODE_RGB: + if ((channels != CSC_CHANNEL_R) && (channels != CSC_CHANNEL_A)) { + /* Update red */ + _s[0]->setColors(SP_RGBA32_F_COMPOSE(0.0, getScaled(_a[1]), getScaled(_a[2]), 1.0), + SP_RGBA32_F_COMPOSE(0.5, getScaled(_a[1]), getScaled(_a[2]), 1.0), + SP_RGBA32_F_COMPOSE(1.0, getScaled(_a[1]), getScaled(_a[2]), 1.0)); + } + if ((channels != CSC_CHANNEL_G) && (channels != CSC_CHANNEL_A)) { + /* Update green */ + _s[1]->setColors(SP_RGBA32_F_COMPOSE(getScaled(_a[0]), 0.0, getScaled(_a[2]), 1.0), + SP_RGBA32_F_COMPOSE(getScaled(_a[0]), 0.5, getScaled(_a[2]), 1.0), + SP_RGBA32_F_COMPOSE(getScaled(_a[0]), 1.0, getScaled(_a[2]), 1.0)); + } + if ((channels != CSC_CHANNEL_B) && (channels != CSC_CHANNEL_A)) { + /* Update blue */ + _s[2]->setColors(SP_RGBA32_F_COMPOSE(getScaled(_a[0]), getScaled(_a[1]), 0.0, 1.0), + SP_RGBA32_F_COMPOSE(getScaled(_a[0]), getScaled(_a[1]), 0.5, 1.0), + SP_RGBA32_F_COMPOSE(getScaled(_a[0]), getScaled(_a[1]), 1.0, 1.0)); + } + if (channels != CSC_CHANNEL_A) { + /* Update alpha */ + _s[3]->setColors(SP_RGBA32_F_COMPOSE(getScaled(_a[0]), getScaled(_a[1]), getScaled(_a[2]), 0.0), + SP_RGBA32_F_COMPOSE(getScaled(_a[0]), getScaled(_a[1]), getScaled(_a[2]), 0.5), + SP_RGBA32_F_COMPOSE(getScaled(_a[0]), getScaled(_a[1]), getScaled(_a[2]), 1.0)); + } + break; + case SP_COLOR_SCALES_MODE_HSV: + /* Hue is never updated */ + if ((channels != CSC_CHANNEL_S) && (channels != CSC_CHANNEL_A)) { + /* Update saturation */ + sp_color_hsl_to_rgb_floatv(rgb0, getScaled(_a[0]), 0.0, getScaled(_a[2])); + sp_color_hsl_to_rgb_floatv(rgbm, getScaled(_a[0]), 0.5, getScaled(_a[2])); + sp_color_hsl_to_rgb_floatv(rgb1, getScaled(_a[0]), 1.0, getScaled(_a[2])); + _s[1]->setColors(SP_RGBA32_F_COMPOSE(rgb0[0], rgb0[1], rgb0[2], 1.0), + SP_RGBA32_F_COMPOSE(rgbm[0], rgbm[1], rgbm[2], 1.0), + SP_RGBA32_F_COMPOSE(rgb1[0], rgb1[1], rgb1[2], 1.0)); + } + if ((channels != CSC_CHANNEL_V) && (channels != CSC_CHANNEL_A)) { + /* Update value */ + sp_color_hsl_to_rgb_floatv(rgb0, getScaled(_a[0]), getScaled(_a[1]), 0.0); + sp_color_hsl_to_rgb_floatv(rgbm, getScaled(_a[0]), getScaled(_a[1]), 0.5); + sp_color_hsl_to_rgb_floatv(rgb1, getScaled(_a[0]), getScaled(_a[1]), 1.0); + _s[2]->setColors(SP_RGBA32_F_COMPOSE(rgb0[0], rgb0[1], rgb0[2], 1.0), + SP_RGBA32_F_COMPOSE(rgbm[0], rgbm[1], rgbm[2], 1.0), + SP_RGBA32_F_COMPOSE(rgb1[0], rgb1[1], rgb1[2], 1.0)); + } + if (channels != CSC_CHANNEL_A) { + /* Update alpha */ + sp_color_hsl_to_rgb_floatv(rgb0, getScaled(_a[0]), getScaled(_a[1]), getScaled(_a[2])); + _s[3]->setColors(SP_RGBA32_F_COMPOSE(rgb0[0], rgb0[1], rgb0[2], 0.0), + SP_RGBA32_F_COMPOSE(rgb0[0], rgb0[1], rgb0[2], 0.5), + SP_RGBA32_F_COMPOSE(rgb0[0], rgb0[1], rgb0[2], 1.0)); + } + break; + case SP_COLOR_SCALES_MODE_CMYK: + if ((channels != CSC_CHANNEL_C) && (channels != CSC_CHANNEL_CMYKA)) { + /* Update C */ + sp_color_cmyk_to_rgb_floatv(rgb0, 0.0, getScaled(_a[1]), getScaled(_a[2]), getScaled(_a[3])); + sp_color_cmyk_to_rgb_floatv(rgbm, 0.5, getScaled(_a[1]), getScaled(_a[2]), getScaled(_a[3])); + sp_color_cmyk_to_rgb_floatv(rgb1, 1.0, getScaled(_a[1]), getScaled(_a[2]), getScaled(_a[3])); + _s[0]->setColors(SP_RGBA32_F_COMPOSE(rgb0[0], rgb0[1], rgb0[2], 1.0), + SP_RGBA32_F_COMPOSE(rgbm[0], rgbm[1], rgbm[2], 1.0), + SP_RGBA32_F_COMPOSE(rgb1[0], rgb1[1], rgb1[2], 1.0)); + } + if ((channels != CSC_CHANNEL_M) && (channels != CSC_CHANNEL_CMYKA)) { + /* Update M */ + sp_color_cmyk_to_rgb_floatv(rgb0, getScaled(_a[0]), 0.0, getScaled(_a[2]), getScaled(_a[3])); + sp_color_cmyk_to_rgb_floatv(rgbm, getScaled(_a[0]), 0.5, getScaled(_a[2]), getScaled(_a[3])); + sp_color_cmyk_to_rgb_floatv(rgb1, getScaled(_a[0]), 1.0, getScaled(_a[2]), getScaled(_a[3])); + _s[1]->setColors(SP_RGBA32_F_COMPOSE(rgb0[0], rgb0[1], rgb0[2], 1.0), + SP_RGBA32_F_COMPOSE(rgbm[0], rgbm[1], rgbm[2], 1.0), + SP_RGBA32_F_COMPOSE(rgb1[0], rgb1[1], rgb1[2], 1.0)); + } + if ((channels != CSC_CHANNEL_Y) && (channels != CSC_CHANNEL_CMYKA)) { + /* Update Y */ + sp_color_cmyk_to_rgb_floatv(rgb0, getScaled(_a[0]), getScaled(_a[1]), 0.0, getScaled(_a[3])); + sp_color_cmyk_to_rgb_floatv(rgbm, getScaled(_a[0]), getScaled(_a[1]), 0.5, getScaled(_a[3])); + sp_color_cmyk_to_rgb_floatv(rgb1, getScaled(_a[0]), getScaled(_a[1]), 1.0, getScaled(_a[3])); + _s[2]->setColors(SP_RGBA32_F_COMPOSE(rgb0[0], rgb0[1], rgb0[2], 1.0), + SP_RGBA32_F_COMPOSE(rgbm[0], rgbm[1], rgbm[2], 1.0), + SP_RGBA32_F_COMPOSE(rgb1[0], rgb1[1], rgb1[2], 1.0)); + } + if ((channels != CSC_CHANNEL_K) && (channels != CSC_CHANNEL_CMYKA)) { + /* Update K */ + sp_color_cmyk_to_rgb_floatv(rgb0, getScaled(_a[0]), getScaled(_a[1]), getScaled(_a[2]), 0.0); + sp_color_cmyk_to_rgb_floatv(rgbm, getScaled(_a[0]), getScaled(_a[1]), getScaled(_a[2]), 0.5); + sp_color_cmyk_to_rgb_floatv(rgb1, getScaled(_a[0]), getScaled(_a[1]), getScaled(_a[2]), 1.0); + _s[3]->setColors(SP_RGBA32_F_COMPOSE(rgb0[0], rgb0[1], rgb0[2], 1.0), + SP_RGBA32_F_COMPOSE(rgbm[0], rgbm[1], rgbm[2], 1.0), + SP_RGBA32_F_COMPOSE(rgb1[0], rgb1[1], rgb1[2], 1.0)); + } + if (channels != CSC_CHANNEL_CMYKA) { + /* Update alpha */ + sp_color_cmyk_to_rgb_floatv(rgb0, getScaled(_a[0]), getScaled(_a[1]), getScaled(_a[2]), + getScaled(_a[3])); + _s[4]->setColors(SP_RGBA32_F_COMPOSE(rgb0[0], rgb0[1], rgb0[2], 0.0), + SP_RGBA32_F_COMPOSE(rgb0[0], rgb0[1], rgb0[2], 0.5), + SP_RGBA32_F_COMPOSE(rgb0[0], rgb0[1], rgb0[2], 1.0)); + } + break; + default: + g_warning("file %s: line %d: Illegal color selector mode", __FILE__, __LINE__); + break; + } + + // Force the internal color to be updated + if (!_updating) { _recalcColor(); } #ifdef SPCS_PREVIEW - rgba = sp_color_scales_get_rgba32 (cs); - sp_color_preview_set_rgba32 (SP_COLOR_PREVIEW (_p), rgba); + rgba = sp_color_scales_get_rgba32(cs); + sp_color_preview_set_rgba32(SP_COLOR_PREVIEW(_p), rgba); #endif } -static const gchar * -sp_color_scales_hue_map (void) +static const gchar *sp_color_scales_hue_map(void) { - static gchar *map = NULL; - - if (!map) { - gchar *p; - gint h; - map = g_new (gchar, 4 * 1024); - p = map; - for (h = 0; h < 1024; h++) { - gfloat rgb[3]; - sp_color_hsl_to_rgb_floatv (rgb, h / 1024.0, 1.0, 0.5); - *p++ = SP_COLOR_F_TO_U (rgb[0]); - *p++ = SP_COLOR_F_TO_U (rgb[1]); - *p++ = SP_COLOR_F_TO_U (rgb[2]); - *p++ = 255; - } - } - - return map; + static gchar *map = NULL; + + if (!map) { + gchar *p; + gint h; + map = g_new(gchar, 4 * 1024); + p = map; + for (h = 0; h < 1024; h++) { + gfloat rgb[3]; + sp_color_hsl_to_rgb_floatv(rgb, h / 1024.0, 1.0, 0.5); + *p++ = SP_COLOR_F_TO_U(rgb[0]); + *p++ = SP_COLOR_F_TO_U(rgb[1]); + *p++ = SP_COLOR_F_TO_U(rgb[2]); + *p++ = 255; + } + } + + return map; } ColorScalesFactory::ColorScalesFactory(SPColorScalesMode submode) @@ -655,10 +645,10 @@ ColorScalesFactory::ColorScalesFactory(SPColorScalesMode submode) { } -ColorScalesFactory::~ColorScalesFactory() { -} +ColorScalesFactory::~ColorScalesFactory() {} -Gtk::Widget *ColorScalesFactory::createWidget(Inkscape::UI::SelectedColor &color) const { +Gtk::Widget *ColorScalesFactory::createWidget(Inkscape::UI::SelectedColor &color) const +{ Gtk::Widget *w = Gtk::manage(new ColorScales(color, _submode)); return w; } diff --git a/src/ui/widget/color-scales.h b/src/ui/widget/color-scales.h index 0744a645c..025f92e2d 100644 --- a/src/ui/widget/color-scales.h +++ b/src/ui/widget/color-scales.h @@ -2,7 +2,7 @@ #define SEEN_SP_COLOR_SCALES_H #ifdef HAVE_CONFIG_H -# include +#include #endif #if WITH_GTKMM_3_0 @@ -19,7 +19,6 @@ namespace Widget { class ColorSlider; - typedef enum { SP_COLOR_SCALES_MODE_NONE = 0, SP_COLOR_SCALES_MODE_RGB = 1, @@ -27,20 +26,18 @@ typedef enum { SP_COLOR_SCALES_MODE_CMYK = 3 } SPColorScalesMode; - - class ColorScales -#if GTK_CHECK_VERSION(3,0,0) +#if GTK_CHECK_VERSION(3, 0, 0) : public Gtk::Grid #else : public Gtk::Table #endif { public: - static const gchar* SUBMODE_NAMES[]; + static const gchar *SUBMODE_NAMES[]; - static gfloat getScaled( const GtkAdjustment *a ); - static void setScaled( GtkAdjustment *a, gfloat v); + static gfloat getScaled(const GtkAdjustment *a); + static void setScaled(GtkAdjustment *a, gfloat v); ColorScales(SelectedColor &color, SPColorScalesMode mode); virtual ~ColorScales(); @@ -65,26 +62,26 @@ protected: void _updateSliders(guint channels); void _recalcColor(); - void _setRangeLimit( gdouble upper ); + void _setRangeLimit(gdouble upper); SelectedColor &_color; SPColorScalesMode _mode; gdouble _rangeLimit; gboolean _updating : 1; gboolean _dragging : 1; - GtkAdjustment *_a[5]; /* Channel adjustments */ + GtkAdjustment *_a[5]; /* Channel adjustments */ Inkscape::UI::Widget::ColorSlider *_s[5]; /* Channel sliders */ - GtkWidget *_b[5]; /* Spinbuttons */ - GtkWidget *_l[5]; /* Labels */ + GtkWidget *_b[5]; /* Spinbuttons */ + GtkWidget *_l[5]; /* Labels */ private: // By default, disallow copy constructor and assignment operator ColorScales(ColorScales const &obj); - ColorScales &operator=(ColorScales const &obj ); + ColorScales &operator=(ColorScales const &obj); }; - -class ColorScalesFactory: public Inkscape::UI::ColorSelectorFactory { +class ColorScalesFactory : public Inkscape::UI::ColorSelectorFactory +{ public: ColorScalesFactory(SPColorScalesMode submode); ~ColorScalesFactory(); diff --git a/src/ui/widget/color-slider.cpp b/src/ui/widget/color-slider.cpp index bf8b85dbd..0c9586a67 100644 --- a/src/ui/widget/color-slider.cpp +++ b/src/ui/widget/color-slider.cpp @@ -12,7 +12,7 @@ */ #ifdef HAVE_CONFIG_H -# include "config.h" +#include "config.h" #endif #include @@ -34,20 +34,20 @@ static const gint SLIDER_WIDTH = 96; static const gint SLIDER_HEIGHT = 8; static const gint ARROW_SIZE = 7; -static const guchar *sp_color_slider_render_gradient (gint x0, gint y0, gint width, gint height, - gint c[], gint dc[], guint b0, guint b1, guint mask); -static const guchar *sp_color_slider_render_map (gint x0, gint y0, gint width, gint height, - guchar *map, gint start, gint step, guint b0, guint b1, guint mask); +static const guchar *sp_color_slider_render_gradient(gint x0, gint y0, gint width, gint height, gint c[], gint dc[], + guint b0, guint b1, guint mask); +static const guchar *sp_color_slider_render_map(gint x0, gint y0, gint width, gint height, guchar *map, gint start, + gint step, guint b0, guint b1, guint mask); namespace Inkscape { namespace UI { namespace Widget { -#if GTK_CHECK_VERSION(3,0,0) +#if GTK_CHECK_VERSION(3, 0, 0) ColorSlider::ColorSlider(Glib::RefPtr adjustment) : _dragging(false) #else -ColorSlider::ColorSlider(Gtk::Adjustment* adjustment) +ColorSlider::ColorSlider(Gtk::Adjustment *adjustment) : _dragging(false) , _adjustment(NULL) #endif @@ -78,11 +78,12 @@ ColorSlider::ColorSlider(Gtk::Adjustment* adjustment) setAdjustment(adjustment); } -ColorSlider::~ColorSlider() { +ColorSlider::~ColorSlider() +{ if (_adjustment) { _adjustment_changed_connection.disconnect(); _adjustment_value_changed_connection.disconnect(); -#if GTK_CHECK_VERSION(3,0,0) +#if GTK_CHECK_VERSION(3, 0, 0) _adjustment.reset(); #else _adjustment->unreference(); @@ -91,103 +92,102 @@ ColorSlider::~ColorSlider() { } } -void ColorSlider::on_realize() { +void ColorSlider::on_realize() +{ set_realized(); - if(!_gdk_window) - { - GdkWindowAttr attributes; - gint attributes_mask; - Gtk::Allocation allocation = get_allocation(); - - memset(&attributes, 0, sizeof(attributes)); - attributes.x = allocation.get_x(); - attributes.y = allocation.get_y(); - attributes.width = allocation.get_width(); - attributes.height = allocation.get_height(); - attributes.window_type = GDK_WINDOW_CHILD; - attributes.wclass = GDK_INPUT_OUTPUT; - attributes.visual = gdk_screen_get_system_visual(gdk_screen_get_default()); -#if !GTK_CHECK_VERSION(3,0,0) - attributes.colormap = gdk_screen_get_system_colormap(gdk_screen_get_default()); + if (!_gdk_window) { + GdkWindowAttr attributes; + gint attributes_mask; + Gtk::Allocation allocation = get_allocation(); + + memset(&attributes, 0, sizeof(attributes)); + attributes.x = allocation.get_x(); + attributes.y = allocation.get_y(); + attributes.width = allocation.get_width(); + attributes.height = allocation.get_height(); + attributes.window_type = GDK_WINDOW_CHILD; + attributes.wclass = GDK_INPUT_OUTPUT; + attributes.visual = gdk_screen_get_system_visual(gdk_screen_get_default()); +#if !GTK_CHECK_VERSION(3, 0, 0) + attributes.colormap = gdk_screen_get_system_colormap(gdk_screen_get_default()); #endif - attributes.event_mask = get_events (); - attributes.event_mask |= (Gdk::EXPOSURE_MASK | - Gdk::BUTTON_PRESS_MASK | - Gdk::BUTTON_RELEASE_MASK | - Gdk::POINTER_MOTION_MASK | - Gdk::ENTER_NOTIFY_MASK | - Gdk::LEAVE_NOTIFY_MASK); - -#if GTK_CHECK_VERSION(3,0,0) - attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL; + attributes.event_mask = get_events(); + attributes.event_mask |= (Gdk::EXPOSURE_MASK | Gdk::BUTTON_PRESS_MASK | Gdk::BUTTON_RELEASE_MASK | + Gdk::POINTER_MOTION_MASK | Gdk::ENTER_NOTIFY_MASK | Gdk::LEAVE_NOTIFY_MASK); + +#if GTK_CHECK_VERSION(3, 0, 0) + attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL; #else - attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP; + attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP; #endif - _gdk_window = Gdk::Window::create(get_parent_window(), &attributes, - attributes_mask); - set_window(_gdk_window); - _gdk_window->set_user_data(gobj()); + _gdk_window = Gdk::Window::create(get_parent_window(), &attributes, attributes_mask); + set_window(_gdk_window); + _gdk_window->set_user_data(gobj()); -#if !GTK_CHECK_VERSION(3,0,0) - style_attach(); +#if !GTK_CHECK_VERSION(3, 0, 0) + style_attach(); #endif } } -void ColorSlider::on_unrealize() { +void ColorSlider::on_unrealize() +{ _gdk_window.reset(); Gtk::Widget::on_unrealize(); } -void ColorSlider::on_size_allocate(Gtk::Allocation& allocation) { +void ColorSlider::on_size_allocate(Gtk::Allocation &allocation) +{ set_allocation(allocation); if (get_realized()) { - _gdk_window->move_resize(allocation.get_x(), allocation.get_y(), - allocation.get_width(), allocation.get_height()); + _gdk_window->move_resize(allocation.get_x(), allocation.get_y(), allocation.get_width(), + allocation.get_height()); } } -#if GTK_CHECK_VERSION(3,0,0) +#if GTK_CHECK_VERSION(3, 0, 0) -void ColorSlider::get_preferred_width_vfunc(int& minimum_width, int& natural_width) const +void ColorSlider::get_preferred_width_vfunc(int &minimum_width, int &natural_width) const { - Glib::RefPtrstyle_context = get_style_context(); + Glib::RefPtr style_context = get_style_context(); Gtk::Border padding = style_context->get_padding(get_state_flags()); int width = SLIDER_WIDTH + padding.get_left() + padding.get_right(); minimum_width = natural_width = width; } -void ColorSlider::get_preferred_width_for_height_vfunc(int /*height*/, int& minimum_width, int& natural_width) const +void ColorSlider::get_preferred_width_for_height_vfunc(int /*height*/, int &minimum_width, int &natural_width) const { get_preferred_width(minimum_width, natural_width); } -void ColorSlider::get_preferred_height_vfunc(int& minimum_height, int& natural_height) const +void ColorSlider::get_preferred_height_vfunc(int &minimum_height, int &natural_height) const { - Glib::RefPtrstyle_context = get_style_context(); + Glib::RefPtr style_context = get_style_context(); Gtk::Border padding = style_context->get_padding(get_state_flags()); int height = SLIDER_HEIGHT + padding.get_top() + padding.get_bottom(); minimum_height = natural_height = height; } -void ColorSlider::get_preferred_height_for_width_vfunc(int /*width*/, int& minimum_height, int& natural_height) const +void ColorSlider::get_preferred_height_for_width_vfunc(int /*width*/, int &minimum_height, int &natural_height) const { get_preferred_height(minimum_height, natural_height); } #else -void ColorSlider::on_size_request(Gtk::Requisition* requisition) { +void ColorSlider::on_size_request(Gtk::Requisition *requisition) +{ GtkStyle *style = gtk_widget_get_style(gobj()); requisition->width = SLIDER_WIDTH + style->xthickness * 2; requisition->height = SLIDER_HEIGHT + style->ythickness * 2; } -bool ColorSlider::on_expose_event(GdkEventExpose* event) { +bool ColorSlider::on_expose_event(GdkEventExpose *event) +{ bool result = false; if (get_is_drawable()) { @@ -199,11 +199,12 @@ bool ColorSlider::on_expose_event(GdkEventExpose* event) { #endif -bool ColorSlider::on_button_press_event(GdkEventButton *event) { +bool ColorSlider::on_button_press_event(GdkEventButton *event) +{ if (event->button == 1) { Gtk::Allocation allocation = get_allocation(); gint cx, cw; -#if GTK_CHECK_VERSION(3,0,0) +#if GTK_CHECK_VERSION(3, 0, 0) cx = get_style_context()->get_padding(get_state_flags()).get_left(); #else cx = get_style()->get_xthickness(); @@ -212,33 +213,30 @@ bool ColorSlider::on_button_press_event(GdkEventButton *event) { signal_grabbed.emit(); _dragging = true; _oldvalue = _value; - ColorScales::setScaled( _adjustment->gobj(), CLAMP ((gfloat) (event->x - cx) / cw, 0.0, 1.0) ); + ColorScales::setScaled(_adjustment->gobj(), CLAMP((gfloat)(event->x - cx) / cw, 0.0, 1.0)); signal_dragged.emit(); -#if GTK_CHECK_VERSION(3,0,0) - gdk_device_grab(gdk_event_get_device(reinterpret_cast(event)), - _gdk_window->gobj(), - GDK_OWNERSHIP_NONE, - FALSE, - static_cast(GDK_POINTER_MOTION_MASK | GDK_BUTTON_RELEASE_MASK), - NULL, - event->time); +#if GTK_CHECK_VERSION(3, 0, 0) + gdk_device_grab( + gdk_event_get_device(reinterpret_cast(event)), _gdk_window->gobj(), GDK_OWNERSHIP_NONE, FALSE, + static_cast(GDK_POINTER_MOTION_MASK | GDK_BUTTON_RELEASE_MASK), NULL, event->time); #else gdk_pointer_grab(get_window()->gobj(), FALSE, - static_cast(GDK_POINTER_MOTION_MASK | GDK_BUTTON_RELEASE_MASK), - NULL, NULL, event->time); + static_cast(GDK_POINTER_MOTION_MASK | GDK_BUTTON_RELEASE_MASK), NULL, NULL, + event->time); #endif } return false; } -bool ColorSlider::on_button_release_event(GdkEventButton *event) { +bool ColorSlider::on_button_release_event(GdkEventButton *event) +{ if (event->button == 1) { -#if GTK_CHECK_VERSION(3,0,0) +#if GTK_CHECK_VERSION(3, 0, 0) gdk_device_ungrab(gdk_event_get_device(reinterpret_cast(event)), - gdk_event_get_time(reinterpret_cast(event))); + gdk_event_get_time(reinterpret_cast(event))); #else get_window()->pointer_ungrab(event->time); #endif @@ -253,35 +251,39 @@ bool ColorSlider::on_button_release_event(GdkEventButton *event) { return false; } -bool ColorSlider::on_motion_notify_event(GdkEventMotion *event) { +bool ColorSlider::on_motion_notify_event(GdkEventMotion *event) +{ if (_dragging) { gint cx, cw; Gtk::Allocation allocation = get_allocation(); -#if GTK_CHECK_VERSION(3,0,0) +#if GTK_CHECK_VERSION(3, 0, 0) cx = get_style_context()->get_padding(get_state_flags()).get_left(); #else cx = get_style()->get_xthickness(); #endif cw = allocation.get_width() - 2 * cx; - ColorScales::setScaled( _adjustment->gobj(), CLAMP ((gfloat) (event->x - cx) / cw, 0.0, 1.0) ); + ColorScales::setScaled(_adjustment->gobj(), CLAMP((gfloat)(event->x - cx) / cw, 0.0, 1.0)); signal_dragged.emit(); } return false; } -#if GTK_CHECK_VERSION(3,0,0) -void ColorSlider::setAdjustment(Glib::RefPtr adjustment) { +#if GTK_CHECK_VERSION(3, 0, 0) +void ColorSlider::setAdjustment(Glib::RefPtr adjustment) +{ #else -void ColorSlider::setAdjustment(Gtk::Adjustment *adjustment) { +void ColorSlider::setAdjustment(Gtk::Adjustment *adjustment) +{ #endif if (!adjustment) { -#if GTK_CHECK_VERSION(3,0,0) +#if GTK_CHECK_VERSION(3, 0, 0) _adjustment = Gtk::Adjustment::create(0.0, 0.0, 1.0, 0.01, 0.0, 0.0); #else _adjustment = Gtk::manage(new Gtk::Adjustment(0.0, 0.0, 1.0, 0.01, 0.0, 0.0)); #endif - } else { + } + else { adjustment->set_page_increment(0.0); adjustment->set_page_size(0.0); } @@ -290,16 +292,16 @@ void ColorSlider::setAdjustment(Gtk::Adjustment *adjustment) { if (_adjustment) { _adjustment_changed_connection.disconnect(); _adjustment_value_changed_connection.disconnect(); -#if !GTK_CHECK_VERSION(3,0,0) +#if !GTK_CHECK_VERSION(3, 0, 0) _adjustment->unreference(); #endif } _adjustment = adjustment; - _adjustment_changed_connection = _adjustment->signal_changed().connect( - sigc::mem_fun(this, &ColorSlider::_onAdjustmentChanged)); - _adjustment_value_changed_connection = _adjustment->signal_value_changed().connect( - sigc::mem_fun(this, &ColorSlider::_onAdjustmentValueChanged)); + _adjustment_changed_connection = + _adjustment->signal_changed().connect(sigc::mem_fun(this, &ColorSlider::_onAdjustmentChanged)); + _adjustment_value_changed_connection = + _adjustment->signal_value_changed().connect(sigc::mem_fun(this, &ColorSlider::_onAdjustmentValueChanged)); _value = ColorScales::getScaled(_adjustment->gobj()); @@ -307,15 +309,14 @@ void ColorSlider::setAdjustment(Gtk::Adjustment *adjustment) { } } -void ColorSlider::_onAdjustmentChanged() { - queue_draw(); -} +void ColorSlider::_onAdjustmentChanged() { queue_draw(); } -void ColorSlider::_onAdjustmentValueChanged() { - if (_value != ColorScales::getScaled( _adjustment->gobj() )) { +void ColorSlider::_onAdjustmentValueChanged() +{ + if (_value != ColorScales::getScaled(_adjustment->gobj())) { gint cx, cy, cw, ch; -#if GTK_CHECK_VERSION(3,0,0) - Glib::RefPtrstyle_context = get_style_context(); +#if GTK_CHECK_VERSION(3, 0, 0) + Glib::RefPtr style_context = get_style_context(); Gtk::Allocation allocation = get_allocation(); Gtk::Border padding = style_context->get_padding(get_state_flags()); cx = padding.get_left(); @@ -328,24 +329,26 @@ void ColorSlider::_onAdjustmentValueChanged() { #endif cw = allocation.get_width() - 2 * cx; ch = allocation.get_height() - 2 * cy; - if ((gint) (ColorScales::getScaled( _adjustment->gobj() ) * cw) != (gint) (_value * cw)) { + if ((gint)(ColorScales::getScaled(_adjustment->gobj()) * cw) != (gint)(_value * cw)) { gint ax, ay; gfloat value; value = _value; - _value = ColorScales::getScaled( _adjustment->gobj() ); + _value = ColorScales::getScaled(_adjustment->gobj()); ax = (int)(cx + value * cw - ARROW_SIZE / 2 - 2); ay = cy; queue_draw_area(ax, ay, ARROW_SIZE + 4, ch); ax = (int)(cx + _value * cw - ARROW_SIZE / 2 - 2); ay = cy; queue_draw_area(ax, ay, ARROW_SIZE + 4, ch); - } else { - _value = ColorScales::getScaled( _adjustment->gobj() ); + } + else { + _value = ColorScales::getScaled(_adjustment->gobj()); } } } -void ColorSlider::setColors(guint32 start, guint32 mid, guint32 end) { +void ColorSlider::setColors(guint32 start, guint32 mid, guint32 end) +{ // Remove any map, if set _map = 0; @@ -367,13 +370,15 @@ void ColorSlider::setColors(guint32 start, guint32 mid, guint32 end) { queue_draw(); } -void ColorSlider::setMap(const guchar *map) { +void ColorSlider::setMap(const guchar *map) +{ _map = const_cast(map); queue_draw(); } -void ColorSlider::setBackground(guint dark, guint light, guint size) { +void ColorSlider::setBackground(guint dark, guint light, guint size) +{ _b0 = dark; _b1 = light; _bmask = size; @@ -381,12 +386,13 @@ void ColorSlider::setBackground(guint dark, guint light, guint size) { queue_draw(); } -bool ColorSlider::on_draw(const Cairo::RefPtr& cr) { +bool ColorSlider::on_draw(const Cairo::RefPtr &cr) +{ gboolean colorsOnTop = Inkscape::Preferences::get()->getBool("/options/workarounds/colorsontop", false); Gtk::Allocation allocation = get_allocation(); -#if GTK_CHECK_VERSION(3,0,0) +#if GTK_CHECK_VERSION(3, 0, 0) Glib::RefPtr style_context = get_style_context(); #else Glib::RefPtr window = get_window(); @@ -395,28 +401,25 @@ bool ColorSlider::on_draw(const Cairo::RefPtr& cr) { // Draw shadow if (colorsOnTop) { -#if GTK_CHECK_VERSION(3,0,0) - style_context->render_frame(cr, 0, 0, - allocation.get_width(), allocation.get_height()); +#if GTK_CHECK_VERSION(3, 0, 0) + style_context->render_frame(cr, 0, 0, allocation.get_width(), allocation.get_height()); #else - gtk_paint_shadow( style->gobj(), window->gobj(), - gtk_widget_get_state(gobj()), GTK_SHADOW_IN, - NULL, gobj(), "colorslider", - 0, 0, - allocation.get_width(), allocation.get_height()); + gtk_paint_shadow(style->gobj(), window->gobj(), gtk_widget_get_state(gobj()), GTK_SHADOW_IN, NULL, gobj(), + "colorslider", 0, 0, allocation.get_width(), allocation.get_height()); #endif } /* Paintable part of color gradient area */ Gdk::Rectangle carea; -#if GTK_CHECK_VERSION(3,0,0) +#if GTK_CHECK_VERSION(3, 0, 0) Gtk::Border padding; padding = style_context->get_padding(get_state_flags()); carea.set_x(padding.get_left()); - carea.set_y(padding.get_top());; + carea.set_y(padding.get_top()); + ; #else carea.set_x(style->get_xthickness()); carea.set_y(style->get_ythickness()); @@ -430,19 +433,18 @@ bool ColorSlider::on_draw(const Cairo::RefPtr& cr) { gint d = (1024 << 16) / carea.get_width(); gint s = 0; - const guchar *b = sp_color_slider_render_map(0, 0, carea.get_width(), carea.get_height(), - _map, s, d, - _b0, _b1, _bmask); + const guchar *b = + sp_color_slider_render_map(0, 0, carea.get_width(), carea.get_height(), _map, s, d, _b0, _b1, _bmask); if (b != NULL && carea.get_width() > 0) { - Glib::RefPtr pb = Gdk::Pixbuf::create_from_data(b, Gdk::COLORSPACE_RGB, - false, 8, carea.get_width(), carea.get_height(), carea.get_width() * 3); + Glib::RefPtr pb = Gdk::Pixbuf::create_from_data( + b, Gdk::COLORSPACE_RGB, false, 8, carea.get_width(), carea.get_height(), carea.get_width() * 3); Gdk::Cairo::set_source_pixbuf(cr, pb, carea.get_x(), carea.get_y()); cr->paint(); } - - } else { + } + else { gint c[4], dc[4]; /* Render gradient */ @@ -451,16 +453,15 @@ bool ColorSlider::on_draw(const Cairo::RefPtr& cr) { if (carea.get_width() > 0) { for (gint i = 0; i < 4; i++) { c[i] = _c0[i] << 16; - dc[i] = ((_cm[i] << 16) - c[i]) / (carea.get_width()/2); + dc[i] = ((_cm[i] << 16) - c[i]) / (carea.get_width() / 2); } - guint wi = carea.get_width()/2; - const guchar *b = sp_color_slider_render_gradient(0, 0, wi, carea.get_height(), - c, dc, _b0, _b1, _bmask); + guint wi = carea.get_width() / 2; + const guchar *b = sp_color_slider_render_gradient(0, 0, wi, carea.get_height(), c, dc, _b0, _b1, _bmask); /* Draw pixelstore 1 */ if (b != NULL && wi > 0) { - Glib::RefPtr pb = Gdk::Pixbuf::create_from_data(b, Gdk::COLORSPACE_RGB, - false, 8, wi, carea.get_height(), wi * 3); + Glib::RefPtr pb = + Gdk::Pixbuf::create_from_data(b, Gdk::COLORSPACE_RGB, false, 8, wi, carea.get_height(), wi * 3); Gdk::Cairo::set_source_pixbuf(cr, pb, carea.get_x(), carea.get_y()); cr->paint(); @@ -471,37 +472,32 @@ bool ColorSlider::on_draw(const Cairo::RefPtr& cr) { if (carea.get_width() > 0) { for (gint i = 0; i < 4; i++) { c[i] = _cm[i] << 16; - dc[i] = ((_c1[i] << 16) - c[i]) / (carea.get_width()/2); + dc[i] = ((_c1[i] << 16) - c[i]) / (carea.get_width() / 2); } - guint wi = carea.get_width()/2; - const guchar *b = sp_color_slider_render_gradient(carea.get_width()/2, 0, wi, carea.get_height(), - c, dc, - _b0, _b1, _bmask); + guint wi = carea.get_width() / 2; + const guchar *b = sp_color_slider_render_gradient(carea.get_width() / 2, 0, wi, carea.get_height(), c, dc, + _b0, _b1, _bmask); /* Draw pixelstore 2 */ if (b != NULL && wi > 0) { - Glib::RefPtr pb = Gdk::Pixbuf::create_from_data(b, Gdk::COLORSPACE_RGB, - false, 8, wi, carea.get_height(), wi * 3); + Glib::RefPtr pb = + Gdk::Pixbuf::create_from_data(b, Gdk::COLORSPACE_RGB, false, 8, wi, carea.get_height(), wi * 3); - Gdk::Cairo::set_source_pixbuf(cr, pb, carea.get_width()/2 + carea.get_x(), carea.get_y()); + Gdk::Cairo::set_source_pixbuf(cr, pb, carea.get_width() / 2 + carea.get_x(), carea.get_y()); cr->paint(); } } } - /* Draw shadow */ - if (!colorsOnTop) { -#if GTK_CHECK_VERSION(3,0,0) - style_context->render_frame(cr, 0, 0, - allocation.get_width(), allocation.get_height()); + /* Draw shadow */ + if (!colorsOnTop) { +#if GTK_CHECK_VERSION(3, 0, 0) + style_context->render_frame(cr, 0, 0, allocation.get_width(), allocation.get_height()); #else - gtk_paint_shadow( style->gobj(), window->gobj(), - gtk_widget_get_state(gobj()), GTK_SHADOW_IN, - NULL, gobj(), "colorslider", - 0, 0, - allocation.get_width(), allocation.get_height()); + gtk_paint_shadow(style->gobj(), window->gobj(), gtk_widget_get_state(gobj()), GTK_SHADOW_IN, NULL, gobj(), + "colorslider", 0, 0, allocation.get_width(), allocation.get_height()); #endif - } + } /* Draw arrow */ gint x = (int)(_value * (carea.get_width() - 1) - ARROW_SIZE / 2 + carea.get_x()); @@ -510,16 +506,16 @@ bool ColorSlider::on_draw(const Cairo::RefPtr& cr) { cr->set_line_width(1.0); // Define top arrow - cr->move_to(x - 0.5, y1 + 0.5); - cr->line_to(x + ARROW_SIZE - 0.5, y1 + 0.5); - cr->line_to(x + (ARROW_SIZE-1)/2.0, y1 + ARROW_SIZE/2.0 + 0.5); - cr->line_to(x - 0.5, y1 + 0.5); + cr->move_to(x - 0.5, y1 + 0.5); + cr->line_to(x + ARROW_SIZE - 0.5, y1 + 0.5); + cr->line_to(x + (ARROW_SIZE - 1) / 2.0, y1 + ARROW_SIZE / 2.0 + 0.5); + cr->line_to(x - 0.5, y1 + 0.5); // Define bottom arrow - cr->move_to(x - 0.5, y2 + 0.5); - cr->line_to(x + ARROW_SIZE - 0.5, y2 + 0.5); - cr->line_to(x + (ARROW_SIZE-1)/2.0, y2 - ARROW_SIZE/2.0 + 0.5); - cr->line_to(x - 0.5, y2 + 0.5); + cr->move_to(x - 0.5, y2 + 0.5); + cr->line_to(x + ARROW_SIZE - 0.5, y2 + 0.5); + cr->line_to(x + (ARROW_SIZE - 1) / 2.0, y2 - ARROW_SIZE / 2.0 + 0.5); + cr->line_to(x - 0.5, y2 + 0.5); // Render both arrows cr->set_source_rgb(1.0, 1.0, 1.0); @@ -530,111 +526,108 @@ bool ColorSlider::on_draw(const Cairo::RefPtr& cr) { return false; } -}//namespace Widget -}//namespace UI -}//namespace Inkscape +} // namespace Widget +} // namespace UI +} // namespace Inkscape /* Colors are << 16 */ -static const guchar * -sp_color_slider_render_gradient (gint x0, gint y0, gint width, gint height, - gint c[], gint dc[], guint b0, guint b1, guint mask) +static const guchar *sp_color_slider_render_gradient(gint x0, gint y0, gint width, gint height, gint c[], gint dc[], + guint b0, guint b1, guint mask) { - static guchar *buf = NULL; - static gint bs = 0; - guchar *dp; - gint x, y; - guint r, g, b, a; - - if (buf && (bs < width * height)) { - g_free (buf); - buf = NULL; - } - if (!buf) { - buf = g_new (guchar, width * height * 3); - bs = width * height; - } - - dp = buf; - r = c[0]; - g = c[1]; - b = c[2]; - a = c[3]; - for (x = x0; x < x0 + width; x++) { - gint cr, cg, cb, ca; - guchar *d; - cr = r >> 16; - cg = g >> 16; - cb = b >> 16; - ca = a >> 16; - d = dp; - for (y = y0; y < y0 + height; y++) { - guint bg, fc; - /* Background value */ - bg = ((x & mask) ^ (y & mask)) ? b0 : b1; - fc = (cr - bg) * ca; - d[0] = bg + ((fc + (fc >> 8) + 0x80) >> 8); - fc = (cg - bg) * ca; - d[1] = bg + ((fc + (fc >> 8) + 0x80) >> 8); - fc = (cb - bg) * ca; - d[2] = bg + ((fc + (fc >> 8) + 0x80) >> 8); - d += 3 * width; - } - r += dc[0]; - g += dc[1]; - b += dc[2]; - a += dc[3]; - dp += 3; - } - - return buf; + static guchar *buf = NULL; + static gint bs = 0; + guchar *dp; + gint x, y; + guint r, g, b, a; + + if (buf && (bs < width * height)) { + g_free(buf); + buf = NULL; + } + if (!buf) { + buf = g_new(guchar, width * height * 3); + bs = width * height; + } + + dp = buf; + r = c[0]; + g = c[1]; + b = c[2]; + a = c[3]; + for (x = x0; x < x0 + width; x++) { + gint cr, cg, cb, ca; + guchar *d; + cr = r >> 16; + cg = g >> 16; + cb = b >> 16; + ca = a >> 16; + d = dp; + for (y = y0; y < y0 + height; y++) { + guint bg, fc; + /* Background value */ + bg = ((x & mask) ^ (y & mask)) ? b0 : b1; + fc = (cr - bg) * ca; + d[0] = bg + ((fc + (fc >> 8) + 0x80) >> 8); + fc = (cg - bg) * ca; + d[1] = bg + ((fc + (fc >> 8) + 0x80) >> 8); + fc = (cb - bg) * ca; + d[2] = bg + ((fc + (fc >> 8) + 0x80) >> 8); + d += 3 * width; + } + r += dc[0]; + g += dc[1]; + b += dc[2]; + a += dc[3]; + dp += 3; + } + + return buf; } /* Positions are << 16 */ -static const guchar * -sp_color_slider_render_map (gint x0, gint y0, gint width, gint height, - guchar *map, gint start, gint step, guint b0, guint b1, guint mask) +static const guchar *sp_color_slider_render_map(gint x0, gint y0, gint width, gint height, guchar *map, gint start, + gint step, guint b0, guint b1, guint mask) { - static guchar *buf = NULL; - static gint bs = 0; - guchar *dp; - gint x, y; - - if (buf && (bs < width * height)) { - g_free (buf); - buf = NULL; - } - if (!buf) { - buf = g_new (guchar, width * height * 3); - bs = width * height; - } - - dp = buf; - for (x = x0; x < x0 + width; x++) { - gint cr, cg, cb, ca; - guchar *d = dp; - guchar *sp = map + 4 * (start >> 16); - cr = *sp++; - cg = *sp++; - cb = *sp++; - ca = *sp++; - for (y = y0; y < y0 + height; y++) { - guint bg, fc; - /* Background value */ - bg = ((x & mask) ^ (y & mask)) ? b0 : b1; - fc = (cr - bg) * ca; - d[0] = bg + ((fc + (fc >> 8) + 0x80) >> 8); - fc = (cg - bg) * ca; - d[1] = bg + ((fc + (fc >> 8) + 0x80) >> 8); - fc = (cb - bg) * ca; - d[2] = bg + ((fc + (fc >> 8) + 0x80) >> 8); - d += 3 * width; - } - dp += 3; - start += step; - } - - return buf; -} + static guchar *buf = NULL; + static gint bs = 0; + guchar *dp; + gint x, y; + + if (buf && (bs < width * height)) { + g_free(buf); + buf = NULL; + } + if (!buf) { + buf = g_new(guchar, width * height * 3); + bs = width * height; + } + dp = buf; + for (x = x0; x < x0 + width; x++) { + gint cr, cg, cb, ca; + guchar *d = dp; + guchar *sp = map + 4 * (start >> 16); + cr = *sp++; + cg = *sp++; + cb = *sp++; + ca = *sp++; + for (y = y0; y < y0 + height; y++) { + guint bg, fc; + /* Background value */ + bg = ((x & mask) ^ (y & mask)) ? b0 : b1; + fc = (cr - bg) * ca; + d[0] = bg + ((fc + (fc >> 8) + 0x80) >> 8); + fc = (cg - bg) * ca; + d[1] = bg + ((fc + (fc >> 8) + 0x80) >> 8); + fc = (cb - bg) * ca; + d[2] = bg + ((fc + (fc >> 8) + 0x80) >> 8); + d += 3 * width; + } + dp += 3; + start += step; + } + + return buf; +} diff --git a/src/ui/widget/color-slider.h b/src/ui/widget/color-slider.h index 2f2e7b2db..253f3123c 100644 --- a/src/ui/widget/color-slider.h +++ b/src/ui/widget/color-slider.h @@ -15,26 +15,23 @@ #include #include -namespace Inkscape -{ -namespace UI -{ -namespace Widget -{ +namespace Inkscape { +namespace UI { +namespace Widget { /* * A slider with colored background */ -class ColorSlider: public Gtk::Widget { +class ColorSlider : public Gtk::Widget { public: -#if GTK_CHECK_VERSION(3,0,0) +#if GTK_CHECK_VERSION(3, 0, 0) ColorSlider(Glib::RefPtr adjustment); #else ColorSlider(Gtk::Adjustment *adjustment); #endif ~ColorSlider(); -#if GTK_CHECK_VERSION(3,0,0) +#if GTK_CHECK_VERSION(3, 0, 0) void setAdjustment(Glib::RefPtr adjustment); #else void setAdjustment(Gtk::Adjustment *adjustment); @@ -42,7 +39,7 @@ public: void setColors(guint32 start, guint32 mid, guint32 end); - void setMap(const guchar* map); + void setMap(const guchar *map); void setBackground(guint dark, guint light, guint size); @@ -52,22 +49,22 @@ public: sigc::signal signal_value_changed; protected: - void on_size_allocate(Gtk::Allocation& allocation); + void on_size_allocate(Gtk::Allocation &allocation); void on_realize(); void on_unrealize(); bool on_button_press_event(GdkEventButton *event); bool on_button_release_event(GdkEventButton *event); bool on_motion_notify_event(GdkEventMotion *event); - bool on_draw(const Cairo::RefPtr& cr); + bool on_draw(const Cairo::RefPtr &cr); -#if GTK_CHECK_VERSION(3,0,0) - void get_preferred_width_vfunc(int& minimum_width, int& natural_width) const; - void get_preferred_width_for_height_vfunc(int height, int& minimum_width, int& natural_width) const; - void get_preferred_height_vfunc(int& minimum_height, int& natural_height) const; - void get_preferred_height_for_width_vfunc(int width, int& minimum_height, int& natural_height) const; +#if GTK_CHECK_VERSION(3, 0, 0) + void get_preferred_width_vfunc(int &minimum_width, int &natural_width) const; + void get_preferred_width_for_height_vfunc(int height, int &minimum_width, int &natural_width) const; + void get_preferred_height_vfunc(int &minimum_height, int &natural_height) const; + void get_preferred_height_for_width_vfunc(int width, int &minimum_height, int &natural_height) const; #else - void on_size_request(Gtk::Requisition* requisition); - bool on_expose_event(GdkEventExpose* event); + void on_size_request(Gtk::Requisition *requisition); + bool on_expose_event(GdkEventExpose *event); #endif private: @@ -76,7 +73,7 @@ private: bool _dragging; -#if GTK_CHECK_VERSION(3,0,0) +#if GTK_CHECK_VERSION(3, 0, 0) Glib::RefPtr _adjustment; #else Gtk::Adjustment *_adjustment; @@ -96,9 +93,9 @@ private: Glib::RefPtr _gdk_window; }; -}//namespace Widget -}//namespace UI -}//namespace Inkscape +} // namespace Widget +} // namespace UI +} // namespace Inkscape #endif /* diff --git a/src/ui/widget/color-wheel-selector.cpp b/src/ui/widget/color-wheel-selector.cpp index e00fb2fab..8c6402d90 100644 --- a/src/ui/widget/color-wheel-selector.cpp +++ b/src/ui/widget/color-wheel-selector.cpp @@ -1,5 +1,5 @@ #ifdef HAVE_CONFIG_H -# include "config.h" +#include "config.h" #endif #include "color-wheel-selector.h" @@ -26,17 +26,17 @@ namespace Widget { #define YPAD 1 -const gchar* ColorWheelSelector::MODE_NAME = N_("Wheel"); +const gchar *ColorWheelSelector::MODE_NAME = N_("Wheel"); ColorWheelSelector::ColorWheelSelector(SelectedColor &color) -#if GTK_CHECK_VERSION(3,0,0) +#if GTK_CHECK_VERSION(3, 0, 0) : Gtk::Grid() #else : Gtk::Table(5, 3, false) #endif , _color(color) , _updating(false) -#if !GTK_CHECK_VERSION(3,0,0) +#if !GTK_CHECK_VERSION(3, 0, 0) , _alpha_adjustment(NULL) #endif , _wheel(0) @@ -45,13 +45,12 @@ ColorWheelSelector::ColorWheelSelector(SelectedColor &color) _initUI(); _color_changed_connection = color.signal_changed.connect(sigc::mem_fun(this, &ColorWheelSelector::_colorChanged)); _color_dragged_connection = color.signal_dragged.connect(sigc::mem_fun(this, &ColorWheelSelector::_colorChanged)); - } ColorWheelSelector::~ColorWheelSelector() { _wheel = 0; -#if !GTK_CHECK_VERSION(3,0,0) +#if !GTK_CHECK_VERSION(3, 0, 0) delete _alpha_adjustment; #endif @@ -59,32 +58,34 @@ ColorWheelSelector::~ColorWheelSelector() _color_dragged_connection.disconnect(); } -void ColorWheelSelector::_initUI() { +void ColorWheelSelector::_initUI() +{ /* Create components */ gint row = 0; _wheel = gimp_color_wheel_new(); - gtk_widget_show( _wheel ); + gtk_widget_show(_wheel); -#if GTK_CHECK_VERSION(3,0,0) +#if GTK_CHECK_VERSION(3, 0, 0) gtk_widget_set_halign(_wheel, GTK_ALIGN_FILL); gtk_widget_set_valign(_wheel, GTK_ALIGN_FILL); gtk_widget_set_hexpand(_wheel, TRUE); gtk_widget_set_vexpand(_wheel, TRUE); gtk_grid_attach(GTK_GRID(gobj()), _wheel, 0, row, 3, 1); #else - gtk_table_attach(GTK_TABLE(gobj()), _wheel, 0, 3, row, row + 1, (GtkAttachOptions)(GTK_EXPAND | GTK_FILL), (GtkAttachOptions)(GTK_EXPAND | GTK_FILL), 0, 0); + gtk_table_attach(GTK_TABLE(gobj()), _wheel, 0, 3, row, row + 1, (GtkAttachOptions)(GTK_EXPAND | GTK_FILL), + (GtkAttachOptions)(GTK_EXPAND | GTK_FILL), 0, 0); #endif row++; /* Label */ - Gtk::Label* label = Gtk::manage(new Gtk::Label(_("_A:"), true)); + Gtk::Label *label = Gtk::manage(new Gtk::Label(_("_A:"), true)); label->set_alignment(1.0, 0.5); label->show(); -#if GTK_CHECK_VERSION(3,0,0) - #if GTK_CHECK_VERSION(3,12,0) +#if GTK_CHECK_VERSION(3, 0, 0) + #if GTK_CHECK_VERSION(3, 12, 0) label->set_margin_start(XPAD); label->set_margin_end(XPAD); #else @@ -100,8 +101,8 @@ void ColorWheelSelector::_initUI() { attach(*label, 0, 1, row, row + 1, Gtk::FILL, Gtk::FILL, XPAD, YPAD); #endif - /* Adjustment */ -#if GTK_CHECK_VERSION(3,0,0) +/* Adjustment */ +#if GTK_CHECK_VERSION(3, 0, 0) _alpha_adjustment = Gtk::Adjustment::create(0.0, 0.0, 255.0, 1.0, 10.0, 10.0); #else _alpha_adjustment = new Gtk::Adjustment(0.0, 0.0, 255.0, 1.0, 10.0, 10.0); @@ -111,8 +112,8 @@ void ColorWheelSelector::_initUI() { _slider->set_tooltip_text(_("Alpha (opacity)")); _slider->show(); -#if GTK_CHECK_VERSION(3,0,0) - #if GTK_CHECK_VERSION(3,12,0) +#if GTK_CHECK_VERSION(3, 0, 0) + #if GTK_CHECK_VERSION(3, 12, 0) _slider->set_margin_start(XPAD); _slider->set_margin_end(XPAD); #else @@ -126,26 +127,25 @@ void ColorWheelSelector::_initUI() { _slider->set_valign(Gtk::ALIGN_FILL); attach(*_slider, 1, row, 1, 1); #else - attach(*_slider, 1, 2, row, row+1, Gtk::EXPAND | Gtk::FILL, Gtk::FILL, XPAD, YPAD); + attach(*_slider, 1, 2, row, row + 1, Gtk::EXPAND | Gtk::FILL, Gtk::FILL, XPAD, YPAD); #endif - _slider->setColors(SP_RGBA32_F_COMPOSE (1.0, 1.0, 1.0, 0.0), - SP_RGBA32_F_COMPOSE (1.0, 1.0, 1.0, 0.5), - SP_RGBA32_F_COMPOSE (1.0, 1.0, 1.0, 1.0)); + _slider->setColors(SP_RGBA32_F_COMPOSE(1.0, 1.0, 1.0, 0.0), SP_RGBA32_F_COMPOSE(1.0, 1.0, 1.0, 0.5), + SP_RGBA32_F_COMPOSE(1.0, 1.0, 1.0, 1.0)); - /* Spinbutton */ -#if GTK_CHECK_VERSION(3,0,0) - Gtk::SpinButton* spin_button = Gtk::manage(new Gtk::SpinButton(_alpha_adjustment, 1.0, 0)); - #else - Gtk::SpinButton* spin_button = Gtk::manage(new Gtk::SpinButton(*_alpha_adjustment, 1.0, 0)); +/* Spinbutton */ +#if GTK_CHECK_VERSION(3, 0, 0) + Gtk::SpinButton *spin_button = Gtk::manage(new Gtk::SpinButton(_alpha_adjustment, 1.0, 0)); +#else + Gtk::SpinButton *spin_button = Gtk::manage(new Gtk::SpinButton(*_alpha_adjustment, 1.0, 0)); #endif spin_button->set_tooltip_text(_("Alpha (opacity)")); sp_dialog_defocus_on_enter(GTK_WIDGET(spin_button->gobj())); label->set_mnemonic_widget(*spin_button); spin_button->show(); -#if GTK_CHECK_VERSION(3,0,0) - #if GTK_CHECK_VERSION(3,12,0) +#if GTK_CHECK_VERSION(3, 0, 0) + #if GTK_CHECK_VERSION(3, 12, 0) spin_button->set_margin_start(XPAD); spin_button->set_margin_end(XPAD); #else @@ -167,27 +167,27 @@ void ColorWheelSelector::_initUI() { _slider->signal_released.connect(sigc::mem_fun(*this, &ColorWheelSelector::_sliderReleased)); _slider->signal_value_changed.connect(sigc::mem_fun(*this, &ColorWheelSelector::_sliderChanged)); - g_signal_connect( G_OBJECT(_wheel), "changed", - G_CALLBACK (_wheelChanged), this ); + g_signal_connect(G_OBJECT(_wheel), "changed", G_CALLBACK(_wheelChanged), this); } void ColorWheelSelector::_colorChanged() { #ifdef DUMP_CHANGE_INFO - g_message("ColorWheelSelector::_colorChanged( this=%p, %f, %f, %f, %f)", this, _color.color().v.c[0], _color.color().v.c[1], _color.color().v.c[2], alpha ); + g_message("ColorWheelSelector::_colorChanged( this=%p, %f, %f, %f, %f)", this, _color.color().v.c[0], + _color.color().v.c[1], _color.color().v.c[2], alpha); #endif bool oldval = _updating; _updating = true; { - float hsv[3] = {0,0,0}; + float hsv[3] = { 0, 0, 0 }; sp_color_rgb_to_hsv_floatv(hsv, _color.color().v.c[0], _color.color().v.c[1], _color.color().v.c[2]); - gimp_color_wheel_set_color( GIMP_COLOR_WHEEL(_wheel), hsv[0], hsv[1], hsv[2] ); + gimp_color_wheel_set_color(GIMP_COLOR_WHEEL(_wheel), hsv[0], hsv[1], hsv[2]); } - guint32 start = _color.color().toRGBA32( 0x00 ); - guint32 mid = _color.color().toRGBA32( 0x7f ); - guint32 end = _color.color().toRGBA32( 0xff ); + guint32 start = _color.color().toRGBA32(0x00); + guint32 mid = _color.color().toRGBA32(0x7f); + guint32 end = _color.color().toRGBA32(0xff); _slider->setColors(start, mid, end); @@ -238,23 +238,23 @@ void ColorWheelSelector::_sliderChanged() void ColorWheelSelector::_wheelChanged(GimpColorWheel *wheel, ColorWheelSelector *wheelSelector) { - if (wheelSelector->_updating){ + if (wheelSelector->_updating) { return; } gdouble h = 0; gdouble s = 0; gdouble v = 0; - gimp_color_wheel_get_color( wheel, &h, &s, &v ); - - float rgb[3] = {0,0,0}; - sp_color_hsv_to_rgb_floatv (rgb, h, s, v); + gimp_color_wheel_get_color(wheel, &h, &s, &v); + + float rgb[3] = { 0, 0, 0 }; + sp_color_hsv_to_rgb_floatv(rgb, h, s, v); SPColor color(rgb[0], rgb[1], rgb[2]); - guint32 start = color.toRGBA32( 0x00 ); - guint32 mid = color.toRGBA32( 0x7f ); - guint32 end = color.toRGBA32( 0xff ); + guint32 start = color.toRGBA32(0x00); + guint32 mid = color.toRGBA32(0x7f); + guint32 end = color.toRGBA32(0xff); wheelSelector->_slider->setColors(start, mid, end); @@ -265,15 +265,13 @@ void ColorWheelSelector::_wheelChanged(GimpColorWheel *wheel, ColorWheelSelector } -Gtk::Widget *ColorWheelSelectorFactory::createWidget(Inkscape::UI::SelectedColor &color) const { +Gtk::Widget *ColorWheelSelectorFactory::createWidget(Inkscape::UI::SelectedColor &color) const +{ Gtk::Widget *w = Gtk::manage(new ColorWheelSelector(color)); return w; } -Glib::ustring ColorWheelSelectorFactory::modeName() const { - return gettext(ColorWheelSelector::MODE_NAME); -} - +Glib::ustring ColorWheelSelectorFactory::modeName() const { return gettext(ColorWheelSelector::MODE_NAME); } } } } diff --git a/src/ui/widget/color-wheel-selector.h b/src/ui/widget/color-wheel-selector.h index ec30cc7c5..f97f70f6a 100644 --- a/src/ui/widget/color-wheel-selector.h +++ b/src/ui/widget/color-wheel-selector.h @@ -13,7 +13,7 @@ #define SEEN_SP_COLOR_WHEEL_SELECTOR_H #ifdef HAVE_CONFIG_H -# include +#include #endif #if WITH_GTKMM_3_0 @@ -33,14 +33,14 @@ namespace Widget { class ColorSlider; class ColorWheelSelector -#if GTK_CHECK_VERSION(3,0,0) +#if GTK_CHECK_VERSION(3, 0, 0) : public Gtk::Grid #else : public Gtk::Table #endif { public: - static const gchar* MODE_NAME; + static const gchar *MODE_NAME; ColorWheelSelector(SelectedColor &color); virtual ~ColorWheelSelector(); @@ -59,30 +59,28 @@ protected: SelectedColor &_color; bool _updating; -#if GTK_CHECK_VERSION(3,0,0) +#if GTK_CHECK_VERSION(3, 0, 0) Glib::RefPtr _alpha_adjustment; #else - Gtk::Adjustment* _alpha_adjustment; + Gtk::Adjustment *_alpha_adjustment; #endif - GtkWidget* _wheel; - Inkscape::UI::Widget::ColorSlider* _slider; + GtkWidget *_wheel; + Inkscape::UI::Widget::ColorSlider *_slider; private: // By default, disallow copy constructor and assignment operator - ColorWheelSelector( const ColorWheelSelector& obj ); - ColorWheelSelector& operator=( const ColorWheelSelector& obj ); + ColorWheelSelector(const ColorWheelSelector &obj); + ColorWheelSelector &operator=(const ColorWheelSelector &obj); sigc::connection _color_changed_connection; sigc::connection _color_dragged_connection; }; - -class ColorWheelSelectorFactory: public ColorSelectorFactory { +class ColorWheelSelectorFactory : public ColorSelectorFactory { public: Gtk::Widget *createWidget(SelectedColor &color) const; Glib::ustring modeName() const; }; - } } } -- cgit v1.2.3 From c1165a6e6713f62f6f6442f172d7b31eae51f264 Mon Sep 17 00:00:00 2001 From: Tomasz Boczkowski Date: Sun, 3 May 2015 11:53:07 +0200 Subject: Reformatted SPPattern (bzr r14059.1.19) --- src/sp-pattern.cpp | 512 +++++++++++++++++++++++++++-------------------------- src/sp-pattern.h | 78 ++++---- 2 files changed, 305 insertions(+), 285 deletions(-) (limited to 'src') diff --git a/src/sp-pattern.cpp b/src/sp-pattern.cpp index c2ba23370..db2017351 100644 --- a/src/sp-pattern.cpp +++ b/src/sp-pattern.cpp @@ -5,7 +5,7 @@ * Lauris Kaplinski * bulia byak * Jon A. Cruz - * Abhishek Sharma + * Abhishek Sharma * * Copyright (C) 2002 Lauris Kaplinski * @@ -13,7 +13,7 @@ */ #ifdef HAVE_CONFIG_H -# include "config.h" +#include "config.h" #endif #include @@ -37,47 +37,51 @@ #include "sp-factory.h" -SPPattern::SPPattern() : SPPaintServer(), SPViewBox() { - this->ref = new SPPatternReference(this); - this->ref->changedSignal().connect(sigc::mem_fun(this, &SPPattern::_on_ref_changed)); +SPPattern::SPPattern() + : SPPaintServer() + , SPViewBox() +{ + this->ref = new SPPatternReference(this); + this->ref->changedSignal().connect(sigc::mem_fun(this, &SPPattern::_on_ref_changed)); - this->patternUnits = UNITS_OBJECTBOUNDINGBOX; - this->patternUnits_set = false; + this->patternUnits = UNITS_OBJECTBOUNDINGBOX; + this->patternUnits_set = false; - this->patternContentUnits = UNITS_USERSPACEONUSE; - this->patternContentUnits_set = false; + this->patternContentUnits = UNITS_USERSPACEONUSE; + this->patternContentUnits_set = false; - this->patternTransform = Geom::identity(); - this->patternTransform_set = false; + this->patternTransform = Geom::identity(); + this->patternTransform_set = false; - this->x.unset(); - this->y.unset(); - this->width.unset(); - this->height.unset(); + this->x.unset(); + this->y.unset(); + this->width.unset(); + this->height.unset(); } -SPPattern::~SPPattern() { -} +SPPattern::~SPPattern() {} -void SPPattern::build(SPDocument* doc, Inkscape::XML::Node* repr) { - SPPaintServer::build(doc, repr); - - this->readAttr( "patternUnits" ); - this->readAttr( "patternContentUnits" ); - this->readAttr( "patternTransform" ); - this->readAttr( "x" ); - this->readAttr( "y" ); - this->readAttr( "width" ); - this->readAttr( "height" ); - this->readAttr( "viewBox" ); - this->readAttr( "preserveAspectRatio" ); - this->readAttr( "xlink:href" ); - - /* Register ourselves */ - doc->addResource("pattern", this); +void SPPattern::build(SPDocument *doc, Inkscape::XML::Node *repr) +{ + SPPaintServer::build(doc, repr); + + this->readAttr("patternUnits"); + this->readAttr("patternContentUnits"); + this->readAttr("patternTransform"); + this->readAttr("x"); + this->readAttr("y"); + this->readAttr("width"); + this->readAttr("height"); + this->readAttr("viewBox"); + this->readAttr("preserveAspectRatio"); + this->readAttr("xlink:href"); + + /* Register ourselves */ + doc->addResource("pattern", this); } -void SPPattern::release() { +void SPPattern::release() +{ if (this->document) { // Unregister ourselves this->document->removeResource("pattern", this); @@ -93,112 +97,121 @@ void SPPattern::release() { SPPaintServer::release(); } -void SPPattern::set(unsigned int key, const gchar* value) { - switch (key) { - case SP_ATTR_PATTERNUNITS: - if (value) { - if (!strcmp (value, "userSpaceOnUse")) { - this->patternUnits = UNITS_USERSPACEONUSE; - } else { - this->patternUnits = UNITS_OBJECTBOUNDINGBOX; - } - - this->patternUnits_set = true; - } else { - this->patternUnits_set = false; - } - - this->requestModified(SP_OBJECT_MODIFIED_FLAG); - break; - - case SP_ATTR_PATTERNCONTENTUNITS: - if (value) { - if (!strcmp (value, "userSpaceOnUse")) { - this->patternContentUnits = UNITS_USERSPACEONUSE; - } else { - this->patternContentUnits = UNITS_OBJECTBOUNDINGBOX; - } - - this->patternContentUnits_set = true; - } else { - this->patternContentUnits_set = false; - } - - this->requestModified(SP_OBJECT_MODIFIED_FLAG); - break; - - case SP_ATTR_PATTERNTRANSFORM: { - Geom::Affine t; - - if (value && sp_svg_transform_read (value, &t)) { - this->patternTransform = t; - this->patternTransform_set = true; - } else { - this->patternTransform = Geom::identity(); - this->patternTransform_set = false; - } - - this->requestModified(SP_OBJECT_MODIFIED_FLAG); - break; - } - case SP_ATTR_X: - this->x.readOrUnset(value); - this->requestModified(SP_OBJECT_MODIFIED_FLAG); - break; - - case SP_ATTR_Y: - this->y.readOrUnset(value); - this->requestModified(SP_OBJECT_MODIFIED_FLAG); - break; - - case SP_ATTR_WIDTH: - this->width.readOrUnset(value); - this->requestModified(SP_OBJECT_MODIFIED_FLAG); - break; - - case SP_ATTR_HEIGHT: - this->height.readOrUnset(value); - this->requestModified(SP_OBJECT_MODIFIED_FLAG); - break; - - case SP_ATTR_VIEWBOX: - set_viewBox( value ); +void SPPattern::set(unsigned int key, const gchar *value) +{ + switch (key) { + case SP_ATTR_PATTERNUNITS: + if (value) { + if (!strcmp(value, "userSpaceOnUse")) { + this->patternUnits = UNITS_USERSPACEONUSE; + } + else { + this->patternUnits = UNITS_OBJECTBOUNDINGBOX; + } + + this->patternUnits_set = true; + } + else { + this->patternUnits_set = false; + } + + this->requestModified(SP_OBJECT_MODIFIED_FLAG); + break; + + case SP_ATTR_PATTERNCONTENTUNITS: + if (value) { + if (!strcmp(value, "userSpaceOnUse")) { + this->patternContentUnits = UNITS_USERSPACEONUSE; + } + else { + this->patternContentUnits = UNITS_OBJECTBOUNDINGBOX; + } + + this->patternContentUnits_set = true; + } + else { + this->patternContentUnits_set = false; + } + + this->requestModified(SP_OBJECT_MODIFIED_FLAG); + break; + + case SP_ATTR_PATTERNTRANSFORM: { + Geom::Affine t; + + if (value && sp_svg_transform_read(value, &t)) { + this->patternTransform = t; + this->patternTransform_set = true; + } + else { + this->patternTransform = Geom::identity(); + this->patternTransform_set = false; + } + + this->requestModified(SP_OBJECT_MODIFIED_FLAG); + break; + } + case SP_ATTR_X: + this->x.readOrUnset(value); + this->requestModified(SP_OBJECT_MODIFIED_FLAG); + break; + + case SP_ATTR_Y: + this->y.readOrUnset(value); + this->requestModified(SP_OBJECT_MODIFIED_FLAG); + break; + + case SP_ATTR_WIDTH: + this->width.readOrUnset(value); + this->requestModified(SP_OBJECT_MODIFIED_FLAG); + break; + + case SP_ATTR_HEIGHT: + this->height.readOrUnset(value); + this->requestModified(SP_OBJECT_MODIFIED_FLAG); + break; + + case SP_ATTR_VIEWBOX: + set_viewBox(value); this->requestModified(SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_VIEWPORT_MODIFIED_FLAG); break; case SP_ATTR_PRESERVEASPECTRATIO: - set_preserveAspectRatio( value ); + set_preserveAspectRatio(value); this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_VIEWPORT_MODIFIED_FLAG); break; - case SP_ATTR_XLINK_HREF: - if ( value && this->href == value ) { - /* Href unchanged, do nothing. */ - } else { - this->href.clear(); - - if (value) { - // First, set the href field; it's only used in the "unchanged" check above. - this->href = value; - // Now do the attaching, which emits the changed signal. - if (value) { - try { - this->ref->attach(Inkscape::URI(value)); - } catch (Inkscape::BadURIException &e) { - g_warning("%s", e.what()); - this->ref->detach(); - } - } else { - this->ref->detach(); - } - } - } - break; - - default: - SPPaintServer::set(key, value); - break; - } + case SP_ATTR_XLINK_HREF: + if (value && this->href == value) { + /* Href unchanged, do nothing. */ + } + else { + this->href.clear(); + + if (value) { + // First, set the href field; it's only used in the "unchanged" check above. + this->href = value; + // Now do the attaching, which emits the changed signal. + if (value) { + try { + this->ref->attach(Inkscape::URI(value)); + } + catch (Inkscape::BadURIException &e) { + g_warning("%s", e.what()); + this->ref->detach(); + } + } + else { + this->ref->detach(); + } + } + } + break; + + default: + SPPaintServer::set(key, value); + break; + } } @@ -206,82 +219,86 @@ void SPPattern::set(unsigned int key, const gchar* value) { /* fixme: We need ::order_changed handler too (Lauris) */ -void SPPattern::_get_children(std::list& l) { +void SPPattern::_get_children(std::list &l) +{ for (SPPattern *pat_i = this; pat_i != NULL; pat_i = pat_i->ref ? pat_i->ref->getObject() : NULL) { if (pat_i->firstChild()) { // find the first one with children - for (SPObject *child = pat_i->firstChild() ; child ; child = child->getNext() ) { - l.push_back(child); - } - break; // do not go further up the chain if children are found + for (SPObject *child = pat_i->firstChild(); child; child = child->getNext()) { + l.push_back(child); + } + break; // do not go further up the chain if children are found } } } -void SPPattern::update(SPCtx* ctx, unsigned int flags) { - typedef std::list::iterator SPObjectIterator; +void SPPattern::update(SPCtx *ctx, unsigned int flags) +{ + typedef std::list::iterator SPObjectIterator; if (flags & SP_OBJECT_MODIFIED_FLAG) { - flags |= SP_OBJECT_PARENT_MODIFIED_FLAG; - } + flags |= SP_OBJECT_PARENT_MODIFIED_FLAG; + } - flags &= SP_OBJECT_MODIFIED_CASCADE; + flags &= SP_OBJECT_MODIFIED_CASCADE; - std::list l; - _get_children(l); + std::list l; + _get_children(l); - for (SPObjectIterator it = l.begin(); it != l.end(); it++) { - SPObject *child = *it; + for (SPObjectIterator it = l.begin(); it != l.end(); it++) { + SPObject *child = *it; - sp_object_ref (child, NULL); + sp_object_ref(child, NULL); - if (flags || (child->mflags & (SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_CHILD_MODIFIED_FLAG))) { - child->updateDisplay(ctx, flags); - } + if (flags || (child->mflags & (SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_CHILD_MODIFIED_FLAG))) { + child->updateDisplay(ctx, flags); + } - sp_object_unref (child, NULL); - } + sp_object_unref(child, NULL); + } } -void SPPattern::modified(unsigned int flags) { - typedef std::list::iterator SPObjectIterator; +void SPPattern::modified(unsigned int flags) +{ + typedef std::list::iterator SPObjectIterator; - if (flags & SP_OBJECT_MODIFIED_FLAG) { - flags |= SP_OBJECT_PARENT_MODIFIED_FLAG; - } + if (flags & SP_OBJECT_MODIFIED_FLAG) { + flags |= SP_OBJECT_PARENT_MODIFIED_FLAG; + } - flags &= SP_OBJECT_MODIFIED_CASCADE; + flags &= SP_OBJECT_MODIFIED_CASCADE; - std::list l; - _get_children(l); + std::list l; + _get_children(l); - for (SPObjectIterator it = l.begin(); it != l.end(); it++) { - SPObject *child = *it; + for (SPObjectIterator it = l.begin(); it != l.end(); it++) { + SPObject *child = *it; - sp_object_ref (child, NULL); + sp_object_ref(child, NULL); - if (flags || (child->mflags & (SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_CHILD_MODIFIED_FLAG))) { - child->emitModified(flags); - } + if (flags || (child->mflags & (SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_CHILD_MODIFIED_FLAG))) { + child->emitModified(flags); + } - sp_object_unref (child, NULL); - } + sp_object_unref(child, NULL); + } } -void SPPattern::_on_ref_changed(SPObject *old_ref, SPObject *ref) { - if (old_ref) { - modified_connection.disconnect(); - } +void SPPattern::_on_ref_changed(SPObject *old_ref, SPObject *ref) +{ + if (old_ref) { + modified_connection.disconnect(); + } - if (SP_IS_PATTERN (ref)) { - modified_connection = ref->connectModified(sigc::mem_fun(this, &SPPattern::_on_ref_modified)); - } + if (SP_IS_PATTERN(ref)) { + modified_connection = ref->connectModified(sigc::mem_fun(this, &SPPattern::_on_ref_modified)); + } - _on_ref_modified(ref, 0); + _on_ref_modified(ref, 0); } -void SPPattern::_on_ref_modified(SPObject */*ref*/, guint /*flags*/) +void SPPattern::_on_ref_modified(SPObject * /*ref*/, guint /*flags*/) { - requestModified(SP_OBJECT_MODIFIED_FLAG); + requestModified(SP_OBJECT_MODIFIED_FLAG); // Conditional to avoid causing infinite loop if there's a cycle in the href chain. } @@ -293,80 +310,78 @@ guint SPPattern::_count_hrefs(SPObject *o) const guint i = 0; SPStyle *style = o->style; - if (style - && style->fill.isPaintserver() - && SP_IS_PATTERN(SP_STYLE_FILL_SERVER(style)) - && SP_PATTERN(SP_STYLE_FILL_SERVER(style)) == this) - { - i ++; - } - if (style - && style->stroke.isPaintserver() - && SP_IS_PATTERN(SP_STYLE_STROKE_SERVER(style)) - && SP_PATTERN(SP_STYLE_STROKE_SERVER(style)) == this) - { - i ++; - } - - for ( SPObject *child = o->firstChild(); child != NULL; child = child->next ) { + if (style && style->fill.isPaintserver() && SP_IS_PATTERN(SP_STYLE_FILL_SERVER(style)) && + SP_PATTERN(SP_STYLE_FILL_SERVER(style)) == this) { + i++; + } + if (style && style->stroke.isPaintserver() && SP_IS_PATTERN(SP_STYLE_STROKE_SERVER(style)) && + SP_PATTERN(SP_STYLE_STROKE_SERVER(style)) == this) { + i++; + } + + for (SPObject *child = o->firstChild(); child != NULL; child = child->next) { i += _count_hrefs(child); } return i; } -SPPattern *SPPattern::_chain() const { +SPPattern *SPPattern::_chain() const +{ Inkscape::XML::Document *xml_doc = document->getReprDoc(); Inkscape::XML::Node *defsrepr = document->getDefs()->getRepr(); Inkscape::XML::Node *repr = xml_doc->createElement("svg:pattern"); repr->setAttribute("inkscape:collect", "always"); Glib::ustring parent_ref = Glib::ustring::compose("#%1", getRepr()->attribute("id")); - repr->setAttribute("xlink:href", parent_ref); + repr->setAttribute("xlink:href", parent_ref); defsrepr->addChild(repr, NULL); const gchar *child_id = repr->attribute("id"); SPObject *child = document->getObjectById(child_id); - g_assert (SP_IS_PATTERN (child)); + g_assert(SP_IS_PATTERN(child)); - return SP_PATTERN (child); + return SP_PATTERN(child); } -SPPattern *SPPattern::clone_if_necessary(SPItem *item, const gchar *property) { +SPPattern *SPPattern::clone_if_necessary(SPItem *item, const gchar *property) +{ SPPattern *pattern = this; if (pattern->href.empty() || pattern->hrefcount > _count_hrefs(item)) { pattern = _chain(); Glib::ustring href = Glib::ustring::compose("url(#%1)", pattern->getRepr()->attribute("id")); - SPCSSAttr *css = sp_repr_css_attr_new (); - sp_repr_css_set_property (css, property, href.c_str()); + SPCSSAttr *css = sp_repr_css_attr_new(); + sp_repr_css_set_property(css, property, href.c_str()); sp_repr_css_change_recursive(item->getRepr(), css, "style"); - } return pattern; } -void SPPattern::transform_multiply(Geom::Affine postmul, bool set) { +void SPPattern::transform_multiply(Geom::Affine postmul, bool set) +{ // this formula is for a different interpretation of pattern transforms as described in (*) in sp-pattern.cpp // for it to work, we also need sp_object_read_attr( item, "transform"); - //pattern->patternTransform = premul * item->transform * pattern->patternTransform * item->transform.inverse() * postmul; + // pattern->patternTransform = premul * item->transform * pattern->patternTransform * item->transform.inverse() * + // postmul; // otherwise the formula is much simpler if (set) { patternTransform = postmul; - } else { + } + else { patternTransform = get_transform() * postmul; } patternTransform_set = true; - Glib::ustring c=sp_svg_transform_write(patternTransform); + Glib::ustring c = sp_svg_transform_write(patternTransform); getRepr()->setAttribute("patternTransform", c); } -const gchar *SPPattern::produce(const std::vector &reprs, Geom::Rect bounds, - SPDocument *document, Geom::Affine transform, Geom::Affine move) +const gchar *SPPattern::produce(const std::vector &reprs, Geom::Rect bounds, + SPDocument *document, Geom::Affine transform, Geom::Affine move) { - typedef std::vector::const_iterator NodePtrIterator; + typedef std::vector::const_iterator NodePtrIterator; Inkscape::XML::Document *xml_doc = document->getReprDoc(); Inkscape::XML::Node *defsrepr = document->getDefs()->getRepr(); @@ -376,7 +391,7 @@ const gchar *SPPattern::produce(const std::vector &reprs, sp_repr_set_svg_double(repr, "width", bounds.dimensions()[Geom::X]); sp_repr_set_svg_double(repr, "height", bounds.dimensions()[Geom::Y]); - Glib::ustring t=sp_svg_transform_write(transform); + Glib::ustring t = sp_svg_transform_write(transform); repr->setAttribute("patternTransform", t); defsrepr->appendChild(repr); @@ -388,7 +403,7 @@ const gchar *SPPattern::produce(const std::vector &reprs, SPItem *copy = SP_ITEM(pat_object->appendChildRepr(node)); Geom::Affine dup_transform; - if (!sp_svg_transform_read (node->attribute("transform"), &dup_transform)) + if (!sp_svg_transform_read(node->attribute("transform"), &dup_transform)) dup_transform = Geom::identity(); dup_transform *= move; @@ -402,11 +417,12 @@ const gchar *SPPattern::produce(const std::vector &reprs, SPPattern *SPPattern::get_root() { for (SPPattern *pat_i = this; pat_i != NULL; pat_i = pat_i->ref ? pat_i->ref->getObject() : NULL) { - if ( pat_i->firstChild() ) { // find the first one with children + if (pat_i->firstChild()) { // find the first one with children return pat_i; } } - return this; // document is broken, we can't get to root; but at least we can return pat which is supposedly a valid pattern + return this; // document is broken, we can't get to root; but at least we can return pat which is supposedly a valid + // pattern } @@ -492,7 +508,7 @@ Geom::OptRect SPPattern::get_viewbox() const bool SPPattern::_has_item_children() const { bool hasChildren = false; - for (SPObject const *child = firstChild() ; child && !hasChildren ; child = child->getNext() ) { + for (SPObject const *child = firstChild(); child && !hasChildren; child = child->getNext()) { if (SP_IS_ITEM(child)) { hasChildren = true; } @@ -502,15 +518,16 @@ bool SPPattern::_has_item_children() const bool SPPattern::isValid() const { - double tile_width = get_width(); - double tile_height = get_height(); + double tile_width = get_width(); + double tile_height = get_height(); - if (tile_width <= 0 || tile_height <= 0) - return false; - return true; + if (tile_width <= 0 || tile_height <= 0) + return false; + return true; } -cairo_pattern_t* SPPattern::pattern_new(cairo_t *base_ct, Geom::OptRect const &bbox, double opacity) { +cairo_pattern_t *SPPattern::pattern_new(cairo_t *base_ct, Geom::OptRect const &bbox, double opacity) +{ bool needs_opacity = (1.0 - opacity) >= 1e-3; bool visible = opacity >= 1e-3; @@ -531,21 +548,21 @@ cairo_pattern_t* SPPattern::pattern_new(cairo_t *base_ct, Geom::OptRect const &b } if (!shown) { - return cairo_pattern_create_rgba(0,0,0,0); + return cairo_pattern_create_rgba(0, 0, 0, 0); } /* Create drawing for rendering */ Inkscape::Drawing drawing; - unsigned int dkey = SPItem::display_key_new (1); + unsigned int dkey = SPItem::display_key_new(1); Inkscape::DrawingGroup *root = new Inkscape::DrawingGroup(drawing); drawing.setRoot(root); - for (SPObject *child = shown->firstChild(); child != NULL; child = child->getNext() ) { - if (SP_IS_ITEM (child)) { + for (SPObject *child = shown->firstChild(); child != NULL; child = child->getNext()) { + if (SP_IS_ITEM(child)) { // for each item in pattern, show it on our drawing, add to the group, // and connect to the release signal in case the item gets deleted Inkscape::DrawingItem *cai; - cai = SP_ITEM(child)->invoke_show (drawing, dkey, SP_ITEM_SHOW_DISPLAY); + cai = SP_ITEM(child)->invoke_show(drawing, dkey, SP_ITEM_SHOW_DISPLAY); root->appendChild(cai); } } @@ -558,40 +575,41 @@ cairo_pattern_t* SPPattern::pattern_new(cairo_t *base_ct, Geom::OptRect const &b // * "x", "y", and "patternTransform" transform tile to user space after tile is generated. // These functions recursively search up the tree to find the values. - double tile_x = get_x(); - double tile_y = get_y(); - double tile_width = get_width(); + double tile_x = get_x(); + double tile_y = get_y(); + double tile_width = get_width(); double tile_height = get_height(); - if ( bbox && (get_pattern_units() == UNITS_OBJECTBOUNDINGBOX) ) { - tile_x *= bbox->width(); - tile_y *= bbox->height(); - tile_width *= bbox->width(); + if (bbox && (get_pattern_units() == UNITS_OBJECTBOUNDINGBOX)) { + tile_x *= bbox->width(); + tile_y *= bbox->height(); + tile_width *= bbox->width(); tile_height *= bbox->height(); } // Pattern size in pattern space Geom::Rect pattern_tile = Geom::Rect::from_xywh(0, 0, tile_width, tile_height); - + // Content to tile (pattern space) Geom::Affine content2ps; Geom::OptRect effective_view_box = get_viewbox(); if (effective_view_box) { - // viewBox to pattern server (using SPViewBox) + // viewBox to pattern server (using SPViewBox) viewBox = *effective_view_box; c2p.setIdentity(); - apply_viewbox( pattern_tile ); + apply_viewbox(pattern_tile); content2ps = c2p; - } else { + } + else { // Content to bbox - if (bbox && (get_pattern_content_units() == UNITS_OBJECTBOUNDINGBOX) ) { - content2ps = Geom::Affine(bbox->width(), 0.0, 0.0, bbox->height(), 0,0); + if (bbox && (get_pattern_content_units() == UNITS_OBJECTBOUNDINGBOX)) { + content2ps = Geom::Affine(bbox->width(), 0.0, 0.0, bbox->height(), 0, 0); } } // Tile (pattern space) to user. - Geom::Affine ps2user = Geom::Translate(tile_x,tile_y) * get_transform(); + Geom::Affine ps2user = Geom::Translate(tile_x, tile_y) * get_transform(); // Transform of object with pattern (includes screen scaling) @@ -611,7 +629,7 @@ cairo_pattern_t* SPPattern::pattern_new(cairo_t *base_ct, Geom::OptRect const &b // to find the optimum tile size for rendering // c is number of pixels in buffer x and y. // Scale factor of 1.1 is too small... see bug #1251039 - Geom::Point c(pattern_tile.dimensions()*ps2user.descrim()*full.descrim()*2.0); + Geom::Point c(pattern_tile.dimensions() * ps2user.descrim() * full.descrim() * 2.0); // Create drawing surface with size of pattern tile (in pattern space) but with number of pixels // based on required resolution (c). @@ -627,16 +645,16 @@ cairo_pattern_t* SPPattern::pattern_new(cairo_t *base_ct, Geom::OptRect const &b } // TODO: make sure there are no leaks. - Inkscape::UpdateContext ctx; // UpdateContext is structure with only ctm! + Inkscape::UpdateContext ctx; // UpdateContext is structure with only ctm! ctx.ctm = content2ps * pattern_surface.drawingTransform(); - dc.transform( pattern_surface.drawingTransform().inverse() ); + dc.transform(pattern_surface.drawingTransform().inverse()); drawing.update(Geom::IntRect::infinite(), ctx); // Render drawing to pattern_surface via drawing context, this calls root->render // which is really DrawingItem->render(). drawing.render(dc, one_tile); - for (SPObject *child = shown->firstChild() ; child != NULL; child = child->getNext() ) { - if (SP_IS_ITEM (child)) { + for (SPObject *child = shown->firstChild(); child != NULL; child = child->getNext()) { + if (SP_IS_ITEM(child)) { SP_ITEM(child)->invoke_hide(dkey); } } @@ -652,12 +670,12 @@ cairo_pattern_t* SPPattern::pattern_new(cairo_t *base_ct, Geom::OptRect const &b if (needs_opacity) { dc.popGroupToSource(); // pop raw pattern - dc.paint(opacity); // apply opacity + dc.paint(opacity); // apply opacity } cairo_pattern_t *cp = cairo_pattern_create_for_surface(pattern_surface.raw()); // Apply transformation to user space. Also compensate for oversampling. - ink_cairo_pattern_set_matrix(cp, ps2user.inverse() * pattern_surface.drawingTransform() ); + ink_cairo_pattern_set_matrix(cp, ps2user.inverse() * pattern_surface.drawingTransform()); cairo_pattern_set_extend(cp, CAIRO_EXTEND_REPEAT); diff --git a/src/sp-pattern.h b/src/sp-pattern.h index 2eb71974f..6c63d0727 100644 --- a/src/sp-pattern.h +++ b/src/sp-pattern.h @@ -30,25 +30,21 @@ namespace Inkscape { namespace XML { class Node; - } } -#define SP_PATTERN(obj) (dynamic_cast((SPObject*)obj)) -#define SP_IS_PATTERN(obj) (dynamic_cast((SPObject*)obj) != NULL) +#define SP_PATTERN(obj) (dynamic_cast((SPObject *)obj)) +#define SP_IS_PATTERN(obj) (dynamic_cast((SPObject *)obj) != NULL) class SPPattern : public SPPaintServer, public SPViewBox { public: - enum PatternUnits { - UNITS_USERSPACEONUSE, - UNITS_OBJECTBOUNDINGBOX - }; + enum PatternUnits { UNITS_USERSPACEONUSE, UNITS_OBJECTBOUNDINGBOX }; - SPPattern(); - virtual ~SPPattern(); + SPPattern(); + virtual ~SPPattern(); /* Reference (href) */ - Glib::ustring href; + Glib::ustring href; SPPatternReference *ref; gdouble get_x() const; @@ -59,7 +55,7 @@ public: SPPattern::PatternUnits get_pattern_units() const; SPPattern::PatternUnits get_pattern_content_units() const; Geom::Affine const &get_transform() const; - SPPattern *get_root(); //TODO: const + SPPattern *get_root(); // TODO: const SPPattern *clone_if_necessary(SPItem *item, const gchar *property); void transform_multiply(Geom::Affine postmul, bool set); @@ -68,39 +64,39 @@ public: * @brief create a new pattern in XML tree * @return created pattern id */ - static const gchar *produce(const std::vector &reprs, - Geom::Rect bounds, SPDocument *document, Geom::Affine transform, Geom::Affine move); + static const gchar *produce(const std::vector &reprs, Geom::Rect bounds, + SPDocument *document, Geom::Affine transform, Geom::Affine move); bool isValid() const; - virtual cairo_pattern_t* pattern_new(cairo_t *ct, Geom::OptRect const &bbox, double opacity); + virtual cairo_pattern_t *pattern_new(cairo_t *ct, Geom::OptRect const &bbox, double opacity); protected: - virtual void build(SPDocument* doc, Inkscape::XML::Node* repr); - virtual void release(); - virtual void set(unsigned int key, const gchar* value); - virtual void update(SPCtx* ctx, unsigned int flags); - virtual void modified(unsigned int flags); + virtual void build(SPDocument *doc, Inkscape::XML::Node *repr); + virtual void release(); + virtual void set(unsigned int key, const gchar *value); + virtual void update(SPCtx *ctx, unsigned int flags); + virtual void modified(unsigned int flags); private: - bool _has_item_children() const; - void _get_children(std::list& l); - SPPattern *_chain() const; + bool _has_item_children() const; + void _get_children(std::list &l); + SPPattern *_chain() const; - /** - Count how many times pattern is used by the styles of o and its descendants - */ - guint _count_hrefs(SPObject* o) const; + /** + Count how many times pattern is used by the styles of o and its descendants + */ + guint _count_hrefs(SPObject *o) const; - /** - Gets called when the pattern is reattached to another - */ - void _on_ref_changed(SPObject *old_ref, SPObject *ref); + /** + Gets called when the pattern is reattached to another + */ + void _on_ref_changed(SPObject *old_ref, SPObject *ref); - /** - Gets called when the referenced is changed - */ - void _on_ref_modified(SPObject *ref, guint flags); + /** + Gets called when the referenced is changed + */ + void _on_ref_modified(SPObject *ref, guint flags); /* patternUnits and patternContentUnits attribute */ PatternUnits patternUnits : 1; @@ -122,14 +118,20 @@ private: class SPPatternReference : public Inkscape::URIReference { public: - SPPatternReference (SPObject *obj) : URIReference(obj) {} - SPPattern *getObject() const { + SPPatternReference(SPObject *obj) + : URIReference(obj) + { + } + + SPPattern *getObject() const + { return reinterpret_cast(URIReference::getObject()); } protected: - virtual bool _acceptObject(SPObject *obj) const { - return SP_IS_PATTERN (obj); + virtual bool _acceptObject(SPObject *obj) const + { + return SP_IS_PATTERN(obj); } }; -- cgit v1.2.3 From 705243e1266aec7527ae76065213ca7536ed7c41 Mon Sep 17 00:00:00 2001 From: Tomasz Boczkowski Date: Sun, 3 May 2015 12:37:06 +0200 Subject: renamed SPPattern methods to match coding style (bzr r14059.1.20) --- src/desktop-style.cpp | 4 +- src/extension/internal/cairo-render-context.cpp | 16 +-- src/extension/internal/emf-print.cpp | 8 +- src/extension/internal/wmf-print.cpp | 4 +- src/knot-holder-entity.cpp | 18 +-- src/selection-chemistry.cpp | 8 +- src/sp-pattern.cpp | 162 ++++++++++++------------ src/sp-pattern.h | 50 ++++---- src/widgets/fill-style.cpp | 4 +- src/widgets/paint-selector.cpp | 4 +- 10 files changed, 139 insertions(+), 139 deletions(-) (limited to 'src') diff --git a/src/desktop-style.cpp b/src/desktop-style.cpp index 275165c9c..fb92ffaf5 100644 --- a/src/desktop-style.cpp +++ b/src/desktop-style.cpp @@ -576,8 +576,8 @@ objects_query_fillstroke (const std::vector &objects, SPStyle *style_re return QUERY_STYLE_MULTIPLE_DIFFERENT; // different kind of server } - SPPattern *pat = SP_PATTERN (server)->get_root(); - SPPattern *pat_res = SP_PATTERN (server_res)->get_root(); + SPPattern *pat = SP_PATTERN (server)->rootPattern(); + SPPattern *pat_res = SP_PATTERN (server_res)->rootPattern(); if (pat_res != pat) { return QUERY_STYLE_MULTIPLE_DIFFERENT; // different pattern roots } diff --git a/src/extension/internal/cairo-render-context.cpp b/src/extension/internal/cairo-render-context.cpp index abfdd9f1c..b5859c283 100644 --- a/src/extension/internal/cairo-render-context.cpp +++ b/src/extension/internal/cairo-render-context.cpp @@ -1008,16 +1008,16 @@ CairoRenderContext::_createPatternPainter(SPPaintServer const *const paintserver ps2user = Geom::identity(); pcs2dev = Geom::identity(); - double x = pat->get_x(); - double y = pat->get_y(); - double width = pat->get_width(); - double height = pat->get_height(); + double x = pat->x(); + double y = pat->y(); + double width = pat->width(); + double height = pat->height(); double bbox_width_scaler; double bbox_height_scaler; TRACE(("%f x %f pattern\n", width, height)); - if (pbox && pat->get_pattern_units() == SPPattern::UNITS_OBJECTBOUNDINGBOX) { + if (pbox && pat->patternUnits() == SPPattern::UNITS_OBJECTBOUNDINGBOX) { bbox_width_scaler = pbox->width(); bbox_height_scaler = pbox->height(); ps2user[4] = x * bbox_width_scaler + pbox->left(); @@ -1030,13 +1030,13 @@ CairoRenderContext::_createPatternPainter(SPPaintServer const *const paintserver } // apply pattern transformation - Geom::Affine pattern_transform(pat->get_transform()); + Geom::Affine pattern_transform(pat->getTransform()); ps2user *= pattern_transform; Geom::Point ori (ps2user[4], ps2user[5]); // create pattern contents coordinate system if (pat->viewBox_set) { - Geom::Rect view_box = *pat->get_viewbox(); + Geom::Rect view_box = *pat->viewbox(); double x, y, w, h; x = 0; @@ -1049,7 +1049,7 @@ CairoRenderContext::_createPatternPainter(SPPaintServer const *const paintserver pcs2dev[3] = h / view_box.height(); pcs2dev[4] = x - view_box.left() * pcs2dev[0]; pcs2dev[5] = y - view_box.top() * pcs2dev[3]; - } else if (pbox && pat->get_pattern_content_units() == SPPattern::UNITS_OBJECTBOUNDINGBOX) { + } else if (pbox && pat->patternContentUnits() == SPPattern::UNITS_OBJECTBOUNDINGBOX) { pcs2dev[0] = pbox->width(); pcs2dev[3] = pbox->height(); } diff --git a/src/extension/internal/emf-print.cpp b/src/extension/internal/emf-print.cpp index 48591fab2..40d0955e3 100644 --- a/src/extension/internal/emf-print.cpp +++ b/src/extension/internal/emf-print.cpp @@ -388,8 +388,8 @@ int PrintEmf::create_brush(SPStyle const *style, PU_COLORREF fcolor) } else if (SP_IS_PATTERN(SP_STYLE_FILL_SERVER(style))) { // must be paint-server SPPaintServer *paintserver = style->fill.value.href->getObject(); SPPattern *pat = SP_PATTERN(paintserver); - double dwidth = pat->get_width(); - double dheight = pat->get_height(); + double dwidth = pat->width(); + double dheight = pat->height(); width = dwidth; height = dheight; brush_classify(pat, 0, &pixbuf, &hatchType, &hatchColor, &bkColor); @@ -573,8 +573,8 @@ int PrintEmf::create_pen(SPStyle const *style, const Geom::Affine &transform) if (SP_IS_PATTERN(SP_STYLE_STROKE_SERVER(style))) { // must be paint-server SPPaintServer *paintserver = style->stroke.value.href->getObject(); SPPattern *pat = SP_PATTERN(paintserver); - double dwidth = pat->get_width(); - double dheight = pat->get_height(); + double dwidth = pat->width(); + double dheight = pat->height(); width = dwidth; height = dheight; brush_classify(pat, 0, &pixbuf, &hatchType, &hatchColor, &bkColor); diff --git a/src/extension/internal/wmf-print.cpp b/src/extension/internal/wmf-print.cpp index 4894b6740..768909173 100644 --- a/src/extension/internal/wmf-print.cpp +++ b/src/extension/internal/wmf-print.cpp @@ -380,8 +380,8 @@ int PrintWmf::create_brush(SPStyle const *style, U_COLORREF *fcolor) } else if (SP_IS_PATTERN(SP_STYLE_FILL_SERVER(style))) { // must be paint-server SPPaintServer *paintserver = style->fill.value.href->getObject(); SPPattern *pat = SP_PATTERN(paintserver); - double dwidth = pat->get_width(); - double dheight = pat->get_height(); + double dwidth = pat->width(); + double dheight = pat->height(); width = dwidth; height = dheight; brush_classify(pat, 0, &pixbuf, &hatchType, &hatchColor, &bkColor); diff --git a/src/knot-holder-entity.cpp b/src/knot-holder-entity.cpp index 69ee4017e..173025920 100644 --- a/src/knot-holder-entity.cpp +++ b/src/knot-holder-entity.cpp @@ -140,19 +140,19 @@ KnotHolderEntity::snap_knot_position_constrained(Geom::Point const &p, Inkscape: static gdouble sp_pattern_extract_theta(SPPattern const *pat) { - Geom::Affine transf = pat->get_transform(); + Geom::Affine transf = pat->getTransform(); return Geom::atan2(transf.xAxis()); } static Geom::Point sp_pattern_extract_scale(SPPattern const *pat) { - Geom::Affine transf = pat->get_transform(); + Geom::Affine transf = pat->getTransform(); return Geom::Point( transf.expansionX(), transf.expansionY() ); } static Geom::Point sp_pattern_extract_trans(SPPattern const *pat) { - return Geom::Point(pat->get_transform()[4], pat->get_transform()[5]); + return Geom::Point(pat->getTransform()[4], pat->getTransform()[5]); } void @@ -191,7 +191,7 @@ PatternKnotHolderEntityAngle::knot_get() const { SPPattern *pat = _fill ? SP_PATTERN(item->style->getFillPaintServer()) : SP_PATTERN(item->style->getStrokePaintServer()); - gdouble x = pat->get_width(); + gdouble x = pat->width(); gdouble y = 0; Geom::Point delta = Geom::Point(x,y); Geom::Point scale = sp_pattern_extract_scale(pat); @@ -240,8 +240,8 @@ PatternKnotHolderEntityScale::knot_set(Geom::Point const &p, Geom::Point const & // Get the new scale from the position of the knotholder Geom::Point d = p_snapped - sp_pattern_extract_trans(pat); - gdouble pat_x = pat->get_width(); - gdouble pat_y = pat->get_height(); + gdouble pat_x = pat->width(); + gdouble pat_y = pat->height(); Geom::Scale scl(1); if ( state & GDK_CONTROL_MASK ) { // if ctrl is pressed: use 1:1 scaling @@ -267,10 +267,10 @@ PatternKnotHolderEntityScale::knot_get() const { SPPattern *pat = _fill ? SP_PATTERN(item->style->getFillPaintServer()) : SP_PATTERN(item->style->getStrokePaintServer()); - gdouble x = pat->get_width(); - gdouble y = pat->get_height(); + gdouble x = pat->width(); + gdouble y = pat->height(); Geom::Point delta = Geom::Point(x,y); - Geom::Affine a = pat->get_transform(); + Geom::Affine a = pat->getTransform(); a[4] = 0; a[5] = 0; delta = delta * a; diff --git a/src/selection-chemistry.cpp b/src/selection-chemistry.cpp index 23468acc3..a604064cc 100644 --- a/src/selection-chemistry.cpp +++ b/src/selection-chemistry.cpp @@ -1939,8 +1939,8 @@ std::vector sp_get_same_fill_or_stroke_color(SPItem *sel, std::vector(sel_server) && dynamic_cast(iter_server)) { - SPPattern *sel_pat = dynamic_cast(sel_server)->get_root(); - SPPattern *iter_pat = dynamic_cast(iter_server)->get_root(); + SPPattern *sel_pat = dynamic_cast(sel_server)->rootPattern(); + SPPattern *iter_pat = dynamic_cast(iter_server)->rootPattern(); if (sel_pat == iter_pat) { match = true; } @@ -3366,9 +3366,9 @@ void sp_selection_untile(SPDesktop *desktop) did = true; - SPPattern *pattern = basePat->get_root(); + SPPattern *pattern = basePat->rootPattern(); - Geom::Affine pat_transform = basePat->get_transform(); + Geom::Affine pat_transform = basePat->getTransform(); pat_transform *= item->transform; for (SPObject *child = pattern->firstChild() ; child != NULL; child = child->next ) { diff --git a/src/sp-pattern.cpp b/src/sp-pattern.cpp index db2017351..755d3d162 100644 --- a/src/sp-pattern.cpp +++ b/src/sp-pattern.cpp @@ -42,21 +42,21 @@ SPPattern::SPPattern() , SPViewBox() { this->ref = new SPPatternReference(this); - this->ref->changedSignal().connect(sigc::mem_fun(this, &SPPattern::_on_ref_changed)); + this->ref->changedSignal().connect(sigc::mem_fun(this, &SPPattern::_onRefChanged)); - this->patternUnits = UNITS_OBJECTBOUNDINGBOX; - this->patternUnits_set = false; + this->_pattern_units = UNITS_OBJECTBOUNDINGBOX; + this->_pattern_units_set = false; - this->patternContentUnits = UNITS_USERSPACEONUSE; - this->patternContentUnits_set = false; + this->_pattern_content_units = UNITS_USERSPACEONUSE; + this->_pattern_content_units_set = false; - this->patternTransform = Geom::identity(); - this->patternTransform_set = false; + this->_pattern_transform = Geom::identity(); + this->_pattern_transform_set = false; - this->x.unset(); - this->y.unset(); - this->width.unset(); - this->height.unset(); + this->_x.unset(); + this->_y.unset(); + this->_width.unset(); + this->_height.unset(); } SPPattern::~SPPattern() {} @@ -88,7 +88,7 @@ void SPPattern::release() } if (this->ref) { - this->modified_connection.disconnect(); + this->_modified_connection.disconnect(); this->ref->detach(); delete this->ref; this->ref = NULL; @@ -103,16 +103,16 @@ void SPPattern::set(unsigned int key, const gchar *value) case SP_ATTR_PATTERNUNITS: if (value) { if (!strcmp(value, "userSpaceOnUse")) { - this->patternUnits = UNITS_USERSPACEONUSE; + this->_pattern_units = UNITS_USERSPACEONUSE; } else { - this->patternUnits = UNITS_OBJECTBOUNDINGBOX; + this->_pattern_units = UNITS_OBJECTBOUNDINGBOX; } - this->patternUnits_set = true; + this->_pattern_units_set = true; } else { - this->patternUnits_set = false; + this->_pattern_units_set = false; } this->requestModified(SP_OBJECT_MODIFIED_FLAG); @@ -121,16 +121,16 @@ void SPPattern::set(unsigned int key, const gchar *value) case SP_ATTR_PATTERNCONTENTUNITS: if (value) { if (!strcmp(value, "userSpaceOnUse")) { - this->patternContentUnits = UNITS_USERSPACEONUSE; + this->_pattern_content_units = UNITS_USERSPACEONUSE; } else { - this->patternContentUnits = UNITS_OBJECTBOUNDINGBOX; + this->_pattern_content_units = UNITS_OBJECTBOUNDINGBOX; } - this->patternContentUnits_set = true; + this->_pattern_content_units_set = true; } else { - this->patternContentUnits_set = false; + this->_pattern_content_units_set = false; } this->requestModified(SP_OBJECT_MODIFIED_FLAG); @@ -140,34 +140,34 @@ void SPPattern::set(unsigned int key, const gchar *value) Geom::Affine t; if (value && sp_svg_transform_read(value, &t)) { - this->patternTransform = t; - this->patternTransform_set = true; + this->_pattern_transform = t; + this->_pattern_transform_set = true; } else { - this->patternTransform = Geom::identity(); - this->patternTransform_set = false; + this->_pattern_transform = Geom::identity(); + this->_pattern_transform_set = false; } this->requestModified(SP_OBJECT_MODIFIED_FLAG); break; } case SP_ATTR_X: - this->x.readOrUnset(value); + this->_x.readOrUnset(value); this->requestModified(SP_OBJECT_MODIFIED_FLAG); break; case SP_ATTR_Y: - this->y.readOrUnset(value); + this->_y.readOrUnset(value); this->requestModified(SP_OBJECT_MODIFIED_FLAG); break; case SP_ATTR_WIDTH: - this->width.readOrUnset(value); + this->_width.readOrUnset(value); this->requestModified(SP_OBJECT_MODIFIED_FLAG); break; case SP_ATTR_HEIGHT: - this->height.readOrUnset(value); + this->_height.readOrUnset(value); this->requestModified(SP_OBJECT_MODIFIED_FLAG); break; @@ -219,7 +219,7 @@ void SPPattern::set(unsigned int key, const gchar *value) /* fixme: We need ::order_changed handler too (Lauris) */ -void SPPattern::_get_children(std::list &l) +void SPPattern::_getChildren(std::list &l) { for (SPPattern *pat_i = this; pat_i != NULL; pat_i = pat_i->ref ? pat_i->ref->getObject() : NULL) { if (pat_i->firstChild()) { // find the first one with children @@ -242,7 +242,7 @@ void SPPattern::update(SPCtx *ctx, unsigned int flags) flags &= SP_OBJECT_MODIFIED_CASCADE; std::list l; - _get_children(l); + _getChildren(l); for (SPObjectIterator it = l.begin(); it != l.end(); it++) { SPObject *child = *it; @@ -268,7 +268,7 @@ void SPPattern::modified(unsigned int flags) flags &= SP_OBJECT_MODIFIED_CASCADE; std::list l; - _get_children(l); + _getChildren(l); for (SPObjectIterator it = l.begin(); it != l.end(); it++) { SPObject *child = *it; @@ -283,26 +283,26 @@ void SPPattern::modified(unsigned int flags) } } -void SPPattern::_on_ref_changed(SPObject *old_ref, SPObject *ref) +void SPPattern::_onRefChanged(SPObject *old_ref, SPObject *ref) { if (old_ref) { - modified_connection.disconnect(); + _modified_connection.disconnect(); } if (SP_IS_PATTERN(ref)) { - modified_connection = ref->connectModified(sigc::mem_fun(this, &SPPattern::_on_ref_modified)); + _modified_connection = ref->connectModified(sigc::mem_fun(this, &SPPattern::_onRefModified)); } - _on_ref_modified(ref, 0); + _onRefModified(ref, 0); } -void SPPattern::_on_ref_modified(SPObject * /*ref*/, guint /*flags*/) +void SPPattern::_onRefModified(SPObject * /*ref*/, guint /*flags*/) { requestModified(SP_OBJECT_MODIFIED_FLAG); // Conditional to avoid causing infinite loop if there's a cycle in the href chain. } -guint SPPattern::_count_hrefs(SPObject *o) const +guint SPPattern::_countHrefs(SPObject *o) const { if (!o) return 1; @@ -320,7 +320,7 @@ guint SPPattern::_count_hrefs(SPObject *o) const } for (SPObject *child = o->firstChild(); child != NULL; child = child->next) { - i += _count_hrefs(child); + i += _countHrefs(child); } return i; @@ -347,7 +347,7 @@ SPPattern *SPPattern::_chain() const SPPattern *SPPattern::clone_if_necessary(SPItem *item, const gchar *property) { SPPattern *pattern = this; - if (pattern->href.empty() || pattern->hrefcount > _count_hrefs(item)) { + if (pattern->href.empty() || pattern->hrefcount > _countHrefs(item)) { pattern = _chain(); Glib::ustring href = Glib::ustring::compose("url(#%1)", pattern->getRepr()->attribute("id")); @@ -367,14 +367,14 @@ void SPPattern::transform_multiply(Geom::Affine postmul, bool set) // otherwise the formula is much simpler if (set) { - patternTransform = postmul; + _pattern_transform = postmul; } else { - patternTransform = get_transform() * postmul; + _pattern_transform = getTransform() * postmul; } - patternTransform_set = true; + _pattern_transform_set = true; - Glib::ustring c = sp_svg_transform_write(patternTransform); + Glib::ustring c = sp_svg_transform_write(_pattern_transform); getRepr()->setAttribute("patternTransform", c); } @@ -414,7 +414,7 @@ const gchar *SPPattern::produce(const std::vector &reprs, return pat_id; } -SPPattern *SPPattern::get_root() +SPPattern *SPPattern::rootPattern() { for (SPPattern *pat_i = this; pat_i != NULL; pat_i = pat_i->ref ? pat_i->ref->getObject() : NULL) { if (pat_i->firstChild()) { // find the first one with children @@ -430,70 +430,70 @@ SPPattern *SPPattern::get_root() // Access functions that look up fields up the chain of referenced patterns and return the first one which is set // FIXME: all of them must use chase_hrefs the same as in SPGradient, to avoid lockup on circular refs -SPPattern::PatternUnits SPPattern::get_pattern_units() const +SPPattern::PatternUnits SPPattern::patternUnits() const { for (SPPattern const *pat_i = this; pat_i != NULL; pat_i = pat_i->ref ? pat_i->ref->getObject() : NULL) { - if (pat_i->patternUnits_set) - return pat_i->patternUnits; + if (pat_i->_pattern_units_set) + return pat_i->_pattern_units; } - return patternUnits; + return _pattern_units; } -SPPattern::PatternUnits SPPattern::get_pattern_content_units() const +SPPattern::PatternUnits SPPattern::patternContentUnits() const { for (SPPattern const *pat_i = this; pat_i != NULL; pat_i = pat_i->ref ? pat_i->ref->getObject() : NULL) { - if (pat_i->patternContentUnits_set) - return pat_i->patternContentUnits; + if (pat_i->_pattern_content_units_set) + return pat_i->_pattern_content_units; } - return patternContentUnits; + return _pattern_content_units; } -Geom::Affine const &SPPattern::get_transform() const +Geom::Affine const &SPPattern::getTransform() const { for (SPPattern const *pat_i = this; pat_i != NULL; pat_i = pat_i->ref ? pat_i->ref->getObject() : NULL) { - if (pat_i->patternTransform_set) - return pat_i->patternTransform; + if (pat_i->_pattern_transform_set) + return pat_i->_pattern_transform; } - return patternTransform; + return _pattern_transform; } -gdouble SPPattern::get_x() const +gdouble SPPattern::x() const { for (SPPattern const *pat_i = this; pat_i != NULL; pat_i = pat_i->ref ? pat_i->ref->getObject() : NULL) { - if (pat_i->x._set) - return pat_i->x.computed; + if (pat_i->_x._set) + return pat_i->_x.computed; } return 0; } -gdouble SPPattern::get_y() const +gdouble SPPattern::y() const { for (SPPattern const *pat_i = this; pat_i != NULL; pat_i = pat_i->ref ? pat_i->ref->getObject() : NULL) { - if (pat_i->y._set) - return pat_i->y.computed; + if (pat_i->_y._set) + return pat_i->_y.computed; } return 0; } -gdouble SPPattern::get_width() const +gdouble SPPattern::width() const { for (SPPattern const *pat_i = this; pat_i != NULL; pat_i = pat_i->ref ? pat_i->ref->getObject() : NULL) { - if (pat_i->width._set) - return pat_i->width.computed; + if (pat_i->_width._set) + return pat_i->_width.computed; } return 0; } -gdouble SPPattern::get_height() const +gdouble SPPattern::height() const { for (SPPattern const *pat_i = this; pat_i != NULL; pat_i = pat_i->ref ? pat_i->ref->getObject() : NULL) { - if (pat_i->height._set) - return pat_i->height.computed; + if (pat_i->_height._set) + return pat_i->_height.computed; } return 0; } -Geom::OptRect SPPattern::get_viewbox() const +Geom::OptRect SPPattern::viewbox() const { Geom::OptRect viewbox; for (SPPattern const *pat_i = this; pat_i != NULL; pat_i = pat_i->ref ? pat_i->ref->getObject() : NULL) { @@ -505,7 +505,7 @@ Geom::OptRect SPPattern::get_viewbox() const return viewbox; } -bool SPPattern::_has_item_children() const +bool SPPattern::_hasItemChildren() const { bool hasChildren = false; for (SPObject const *child = firstChild(); child && !hasChildren; child = child->getNext()) { @@ -518,8 +518,8 @@ bool SPPattern::_has_item_children() const bool SPPattern::isValid() const { - double tile_width = get_width(); - double tile_height = get_height(); + double tile_width = width(); + double tile_height = height(); if (tile_width <= 0 || tile_height <= 0) return false; @@ -541,7 +541,7 @@ cairo_pattern_t *SPPattern::pattern_new(cairo_t *base_ct, Geom::OptRect const &b for (SPPattern *pat_i = this; pat_i != NULL; pat_i = pat_i->ref ? pat_i->ref->getObject() : NULL) { // find the first one with item children - if (pat_i && SP_IS_OBJECT(pat_i) && pat_i->_has_item_children()) { + if (pat_i && SP_IS_OBJECT(pat_i) && pat_i->_hasItemChildren()) { shown = pat_i; break; // do not go further up the chain if children are found } @@ -575,11 +575,11 @@ cairo_pattern_t *SPPattern::pattern_new(cairo_t *base_ct, Geom::OptRect const &b // * "x", "y", and "patternTransform" transform tile to user space after tile is generated. // These functions recursively search up the tree to find the values. - double tile_x = get_x(); - double tile_y = get_y(); - double tile_width = get_width(); - double tile_height = get_height(); - if (bbox && (get_pattern_units() == UNITS_OBJECTBOUNDINGBOX)) { + double tile_x = x(); + double tile_y = y(); + double tile_width = width(); + double tile_height = height(); + if (bbox && (patternUnits() == UNITS_OBJECTBOUNDINGBOX)) { tile_x *= bbox->width(); tile_y *= bbox->height(); tile_width *= bbox->width(); @@ -591,7 +591,7 @@ cairo_pattern_t *SPPattern::pattern_new(cairo_t *base_ct, Geom::OptRect const &b // Content to tile (pattern space) Geom::Affine content2ps; - Geom::OptRect effective_view_box = get_viewbox(); + Geom::OptRect effective_view_box = viewbox(); if (effective_view_box) { // viewBox to pattern server (using SPViewBox) viewBox = *effective_view_box; @@ -602,14 +602,14 @@ cairo_pattern_t *SPPattern::pattern_new(cairo_t *base_ct, Geom::OptRect const &b else { // Content to bbox - if (bbox && (get_pattern_content_units() == UNITS_OBJECTBOUNDINGBOX)) { + if (bbox && (patternContentUnits() == UNITS_OBJECTBOUNDINGBOX)) { content2ps = Geom::Affine(bbox->width(), 0.0, 0.0, bbox->height(), 0, 0); } } // Tile (pattern space) to user. - Geom::Affine ps2user = Geom::Translate(tile_x, tile_y) * get_transform(); + Geom::Affine ps2user = Geom::Translate(tile_x, tile_y) * getTransform(); // Transform of object with pattern (includes screen scaling) diff --git a/src/sp-pattern.h b/src/sp-pattern.h index 6c63d0727..145bb934e 100644 --- a/src/sp-pattern.h +++ b/src/sp-pattern.h @@ -47,15 +47,15 @@ public: Glib::ustring href; SPPatternReference *ref; - gdouble get_x() const; - gdouble get_y() const; - gdouble get_width() const; - gdouble get_height() const; - Geom::OptRect get_viewbox() const; - SPPattern::PatternUnits get_pattern_units() const; - SPPattern::PatternUnits get_pattern_content_units() const; - Geom::Affine const &get_transform() const; - SPPattern *get_root(); // TODO: const + gdouble x() const; + gdouble y() const; + gdouble width() const; + gdouble height() const; + Geom::OptRect viewbox() const; + SPPattern::PatternUnits patternUnits() const; + SPPattern::PatternUnits patternContentUnits() const; + Geom::Affine const &getTransform() const; + SPPattern *rootPattern(); // TODO: const SPPattern *clone_if_necessary(SPItem *item, const gchar *property); void transform_multiply(Geom::Affine postmul, bool set); @@ -79,40 +79,40 @@ protected: virtual void modified(unsigned int flags); private: - bool _has_item_children() const; - void _get_children(std::list &l); + bool _hasItemChildren() const; + void _getChildren(std::list &l); SPPattern *_chain() const; /** Count how many times pattern is used by the styles of o and its descendants */ - guint _count_hrefs(SPObject *o) const; + guint _countHrefs(SPObject *o) const; /** Gets called when the pattern is reattached to another */ - void _on_ref_changed(SPObject *old_ref, SPObject *ref); + void _onRefChanged(SPObject *old_ref, SPObject *ref); /** Gets called when the referenced is changed */ - void _on_ref_modified(SPObject *ref, guint flags); + void _onRefModified(SPObject *ref, guint flags); /* patternUnits and patternContentUnits attribute */ - PatternUnits patternUnits : 1; - bool patternUnits_set : 1; - PatternUnits patternContentUnits : 1; - bool patternContentUnits_set : 1; + PatternUnits _pattern_units : 1; + bool _pattern_units_set : 1; + PatternUnits _pattern_content_units : 1; + bool _pattern_content_units_set : 1; /* patternTransform attribute */ - Geom::Affine patternTransform; - bool patternTransform_set : 1; + Geom::Affine _pattern_transform; + bool _pattern_transform_set : 1; /* Tile rectangle */ - SVGLength x; - SVGLength y; - SVGLength width; - SVGLength height; + SVGLength _x; + SVGLength _y; + SVGLength _width; + SVGLength _height; - sigc::connection modified_connection; + sigc::connection _modified_connection; }; diff --git a/src/widgets/fill-style.cpp b/src/widgets/fill-style.cpp index e29420ac6..264ebff5a 100644 --- a/src/widgets/fill-style.cpp +++ b/src/widgets/fill-style.cpp @@ -300,7 +300,7 @@ void FillNStroke::performUpdate() psel->setGradientProperties( rg->getUnits(), rg->getSpread() ); } else if (SP_IS_PATTERN(server)) { - SPPattern *pat = SP_PATTERN(server)->get_root(); + SPPattern *pat = SP_PATTERN(server)->rootPattern(); psel->updatePatternList( pat ); } } @@ -656,7 +656,7 @@ void FillNStroke::updateFromPaint() SPPaintServer *server = (kind == FILL) ? selobj->style->getFillPaintServer() : selobj->style->getStrokePaintServer(); - if (SP_IS_PATTERN(server) && SP_PATTERN(server)->get_root() == pattern) + if (SP_IS_PATTERN(server) && SP_PATTERN(server)->rootPattern() == pattern) // only if this object's pattern is not rooted in our selected pattern, apply continue; } diff --git a/src/widgets/paint-selector.cpp b/src/widgets/paint-selector.cpp index a2160e3ad..e2483343f 100644 --- a/src/widgets/paint-selector.cpp +++ b/src/widgets/paint-selector.cpp @@ -822,7 +822,7 @@ ink_pattern_list_get (SPDocument *source) GSList *pl = NULL; GSList const *patterns = source->getResourceList("pattern"); for (GSList *l = const_cast(patterns); l != NULL; l = l->next) { - if (SP_PATTERN(l->data) == SP_PATTERN(l->data)->get_root()) { // only if this is a root pattern + if (SP_PATTERN(l->data) == SP_PATTERN(l->data)->rootPattern()) { // only if this is a root pattern pl = g_slist_prepend(pl, l->data); } } @@ -1142,7 +1142,7 @@ SPPattern *SPPaintSelector::getPattern() } g_free(paturn); } else { - pat = SP_PATTERN(patid)->get_root(); + pat = SP_PATTERN(patid)->rootPattern(); } if (pat && !SP_IS_PATTERN(pat)) { -- cgit v1.2.3 From a0ed5b5138836e368e409b9ced656f970b225b38 Mon Sep 17 00:00:00 2001 From: Tavmjong Bah Date: Sun, 3 May 2015 18:58:35 +0200 Subject: First batch (bzr r14095) --- src/conditions.cpp | 4 +- src/display/canvas-grid.cpp | 3 + src/libcroco/cr-statement.c | 1 + src/live_effects/lpe-taperstroke.cpp | 4 +- src/style-enums.h | 137 +++++++++++++++++++++++++++++++++++ src/style.cpp | 8 ++ src/style.h | 18 +++++ 7 files changed, 171 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/conditions.cpp b/src/conditions.cpp index 9b233a74f..39ab16ba8 100644 --- a/src/conditions.cpp +++ b/src/conditions.cpp @@ -77,7 +77,7 @@ static gchar *preprocessLanguageCode(gchar *lngcode) { static bool evaluateSystemLanguage(SPItem const *item, gchar const *value) { if ( NULL == value ) return true; - + std::cout << "evaluateSystemLanguage: " << value << std::endl; std::set language_codes; gchar *str = NULL; gchar **strlist = g_strsplit( value, ",", 0); @@ -105,7 +105,7 @@ static bool evaluateSystemLanguage(SPItem const *item, gchar const *value) { SPDocument *document = item->document; Glib::ustring document_language = document->getLanguage(); - + std::cout << "language: |" << document_language << "|" << std::endl; if (document_language.size() == 0) return false; diff --git a/src/display/canvas-grid.cpp b/src/display/canvas-grid.cpp index 4eda9b194..8285f7e64 100644 --- a/src/display/canvas-grid.cpp +++ b/src/display/canvas-grid.cpp @@ -916,12 +916,14 @@ CanvasXYGrid::Render (SPCanvasBuf *buf) _empcolor = empcolor; } + std::cout << "CanvasXYGrid::Render: " << no_emp_when_zoomed_out << " " << empspacing << " " << _empcolor << " " << scaled << std::endl; cairo_save(buf->ct); cairo_translate(buf->ct, -buf->rect.left(), -buf->rect.top()); cairo_set_line_width(buf->ct, 1.0); cairo_set_line_cap(buf->ct, CAIRO_LINE_CAP_SQUARE); if (!render_dotted) { + // Render lines gint ylinenum; gdouble y; for (y = syg, ylinenum = ylinestart; y < buf->rect.bottom(); y += sw[Geom::Y], ylinenum++) { @@ -944,6 +946,7 @@ CanvasXYGrid::Render (SPCanvasBuf *buf) } } } else { + // Render dots gint ylinenum; gdouble y; for (y = syg, ylinenum = ylinestart; y < buf->rect.bottom(); y += sw[Geom::Y], ylinenum++) { diff --git a/src/libcroco/cr-statement.c b/src/libcroco/cr-statement.c index 4666f26ec..5fb2dd2fd 100644 --- a/src/libcroco/cr-statement.c +++ b/src/libcroco/cr-statement.c @@ -1678,6 +1678,7 @@ CRStatement * cr_statement_new_at_font_face_rule (CRStyleSheet * a_sheet, CRDeclaration * a_font_decls) { + printf("cr_statement_new_at_font_face_rule\n"); CRStatement *result = (CRStatement *)g_try_malloc (sizeof (CRStatement)); if (!result) { diff --git a/src/live_effects/lpe-taperstroke.cpp b/src/live_effects/lpe-taperstroke.cpp index 2c74af6d6..1888bc3f0 100644 --- a/src/live_effects/lpe-taperstroke.cpp +++ b/src/live_effects/lpe-taperstroke.cpp @@ -275,7 +275,7 @@ Geom::PathVector LPETaperStroke::doEffect_path(Geom::PathVector const& path_in) pat_str << "M 1,0 C " << 1 - (double)smoothing << ",0 0,0.5 0,0.5 0,0.5 " << 1 - (double)smoothing << ",1 1,1"; pat_vec = sp_svg_read_pathv(pat_str.str().c_str()); - pwd2.concat(stretch_along(pathv_out[0].toPwSb(), pat_vec[0], -fabs(line_width))); + pwd2.concat(stretch_along(pathv_out[0].toPwSb(), pat_vec[0], fabs(line_width))); throwaway_path = Geom::path_from_piecewise(pwd2, LPE_CONVERSION_TOLERANCE)[0]; real_path.append(throwaway_path); @@ -304,7 +304,7 @@ Geom::PathVector LPETaperStroke::doEffect_path(Geom::PathVector const& path_in) pat_vec = sp_svg_read_pathv(pat_str_1.str().c_str()); pwd2 = Piecewise >(); - pwd2.concat(stretch_along(pathv_out[2].toPwSb(), pat_vec[0], -fabs(line_width))); + pwd2.concat(stretch_along(pathv_out[2].toPwSb(), pat_vec[0], fabs(line_width))); throwaway_path = Geom::path_from_piecewise(pwd2, LPE_CONVERSION_TOLERANCE)[0]; if (!Geom::are_near(real_path.finalPoint(), throwaway_path.initialPoint()) && real_path.size() >= 1) { diff --git a/src/style-enums.h b/src/style-enums.h index f52752018..f235b6699 100644 --- a/src/style-enums.h +++ b/src/style-enums.h @@ -72,6 +72,72 @@ enum SPCSSFontStretch { SP_CSS_FONT_STRETCH_WIDER }; +// Can select more than one +enum SPCSSFontVariantLigatures { + SP_CSS_FONT_VARIANT_LIGATURES_NORMAL, + SP_CSS_FONT_VARIANT_LIGATURES_NONE, + SP_CSS_FONT_VARIANT_LIGATURES_COMMON, + SP_CSS_FONT_VARIANT_LIGATURES_NO_COMMON, + SP_CSS_FONT_VARIANT_LIGATURES_DISCRETIONARY, + SP_CSS_FONT_VARIANT_LIGATURES_NO_DISCRETIONARY, + SP_CSS_FONT_VARIANT_LIGATURES_HISTORICAL, + SP_CSS_FONT_VARIANT_LIGATURES_NO_HISTORICAL, + SP_CSS_FONT_VARIANT_LIGATURES_CONTEXTUAL, + SP_CSS_FONT_VARIANT_LIGATURES_NO_CONTEXTUAL +}; + +enum SPCSSFontVariantPosition { + SP_CSS_FONT_VARIANT_POSITION_NORMAL, + SP_CSS_FONT_VARIANT_POSITION_SUB, + SP_CSS_FONT_VARIANT_POSITION_SUPER +}; + +enum SPCSSFontVariantCaps { + SP_CSS_FONT_VARIANT_CAPS_NORMAL, + SP_CSS_FONT_VARIANT_CAPS_SMALL, + SP_CSS_FONT_VARIANT_CAPS_ALL_SMALL, + SP_CSS_FONT_VARIANT_CAPS_PETITE, + SP_CSS_FONT_VARIANT_CAPS_ALL_PETITE, + SP_CSS_FONT_VARIANT_CAPS_UNICASE, + SP_CSS_FONT_VARIANT_CAPS_TITLING, +}; + +enum SPCSSFontVariantNumeric { + SP_CSS_FONT_VARIANT_NUMERIC_NORMAL, + SP_CSS_FONT_VARIANT_NUMERIC_LINING_NUMS, + SP_CSS_FONT_VARIANT_NUMERIC_OLDSTYLE_NUMS, + SP_CSS_FONT_VARIANT_NUMERIC_PROPORTIONAL_NUMS, + SP_CSS_FONT_VARIANT_NUMERIC_TABULAR_NUMS, + SP_CSS_FONT_VARIANT_NUMERIC_DIAGONAL_FRACTIONS, + SP_CSS_FONT_VARIANT_NUMERIC_STACKED_FRACTIONS, + SP_CSS_FONT_VARIANT_NUMERIC_ORDINAL, + SP_CSS_FONT_VARIANT_NUMERIC_SLASHED_ZERO +}; + +enum SPCSSFontVariantAlternates { + SP_CSS_FONT_VARIANT_ALTERNATES_NORMAL, + SP_CSS_FONT_VARIANT_ALTERNATES_HISTORICAL_FORMS, + SP_CSS_FONT_VARIANT_ALTERNATES_STYLISTIC, + SP_CSS_FONT_VARIANT_ALTERNATES_STYLESET, + SP_CSS_FONT_VARIANT_ALTERNATES_CHARACTER_VARIANT, + SP_CSS_FONT_VARIANT_ALTERNATES_SWASH, + SP_CSS_FONT_VARIANT_ALTERNATES_ORNAMENTS, + SP_CSS_FONT_VARIANT_ALTERNATES_ANNOTATION +}; + +enum SPCSSFontVariantEastAsian { + SP_CSS_FONT_VARIANT_EAST_ASIAN_NORMAL, + SP_CSS_FONT_VARIANT_EAST_ASIAN_JIS78, + SP_CSS_FONT_VARIANT_EAST_ASIAN_JIS83, + SP_CSS_FONT_VARIANT_EAST_ASIAN_JIS90, + SP_CSS_FONT_VARIANT_EAST_ASIAN_JIS04, + SP_CSS_FONT_VARIANT_EAST_ASIAN_SIMPLIFIED, + SP_CSS_FONT_VARIANT_EAST_ASIAN_TRADITIONAL, + SP_CSS_FONT_VARIANT_EAST_ASIAN_FULL_WIDTH, + SP_CSS_FONT_VARIANT_EAST_ASIAN_PROPORTIONAL_WIDTH, + SP_CSS_FONT_VARIANT_EAST_ASIAN_RUBY +}; + enum SPCSSTextAlign { SP_CSS_TEXT_ALIGN_START, SP_CSS_TEXT_ALIGN_END, @@ -309,6 +375,77 @@ static SPStyleEnum const enum_font_stretch[] = { {NULL, -1} }; +static SPStyleEnum const enum_font_variant_ligatures[] = { + {"normal", SP_CSS_FONT_VARIANT_LIGATURES_NORMAL}, + {"none", SP_CSS_FONT_VARIANT_LIGATURES_NONE}, + {"common-ligatures", SP_CSS_FONT_VARIANT_LIGATURES_COMMON}, + {"no-common-ligatures", SP_CSS_FONT_VARIANT_LIGATURES_NO_COMMON}, + {"discretionary-ligatures", SP_CSS_FONT_VARIANT_LIGATURES_DISCRETIONARY}, + {"no-discretionary-ligatures", SP_CSS_FONT_VARIANT_LIGATURES_NO_DISCRETIONARY}, + {"historical-ligatures", SP_CSS_FONT_VARIANT_LIGATURES_HISTORICAL}, + {"nohistorical-ligatures", SP_CSS_FONT_VARIANT_LIGATURES_NO_HISTORICAL}, + {"contextual", SP_CSS_FONT_VARIANT_LIGATURES_CONTEXTUAL}, + {"no-contextual", SP_CSS_FONT_VARIANT_LIGATURES_NO_CONTEXTUAL}, + {NULL, -1} +}; + +static SPStyleEnum const enum_font_variant_position[] = { + {"normal", SP_CSS_FONT_VARIANT_POSITION_NORMAL}, + {"sub", SP_CSS_FONT_VARIANT_POSITION_SUB}, + {"super", SP_CSS_FONT_VARIANT_POSITION_SUPER}, + {NULL, -1} +}; + +static SPStyleEnum const enum_font_variant_caps[] = { + {"normal", SP_CSS_FONT_VARIANT_CAPS_NORMAL}, + {"small-caps", SP_CSS_FONT_VARIANT_CAPS_SMALL}, + {"all-small-caps", SP_CSS_FONT_VARIANT_CAPS_ALL_SMALL}, + {"petite-caps", SP_CSS_FONT_VARIANT_CAPS_PETITE}, + {"all_petite-caps", SP_CSS_FONT_VARIANT_CAPS_ALL_PETITE}, + {"unicase", SP_CSS_FONT_VARIANT_CAPS_UNICASE}, + {"titling", SP_CSS_FONT_VARIANT_CAPS_TITLING}, + {NULL, -1} +}; + +static SPStyleEnum const enum_font_variant_numeric[] = { + {"normal", SP_CSS_FONT_VARIANT_NUMERIC_NORMAL}, + {"lining-nums", SP_CSS_FONT_VARIANT_NUMERIC_LINING_NUMS}, + {"oldstyle-nums", SP_CSS_FONT_VARIANT_NUMERIC_OLDSTYLE_NUMS}, + {"proportional-nums", SP_CSS_FONT_VARIANT_NUMERIC_PROPORTIONAL_NUMS}, + {"tabular-nums", SP_CSS_FONT_VARIANT_NUMERIC_TABULAR_NUMS}, + {"diagonal-fractions", SP_CSS_FONT_VARIANT_NUMERIC_DIAGONAL_FRACTIONS}, + {"stacked-fractions", SP_CSS_FONT_VARIANT_NUMERIC_STACKED_FRACTIONS}, + {"ordinal", SP_CSS_FONT_VARIANT_NUMERIC_ORDINAL}, + {"slashed-zero", SP_CSS_FONT_VARIANT_NUMERIC_SLASHED_ZERO}, + {NULL, -1} +}; + +static SPStyleEnum const enum_font_variant_alternates[] = { + {"normal", SP_CSS_FONT_VARIANT_ALTERNATES_NORMAL}, + {"historical-forms", SP_CSS_FONT_VARIANT_ALTERNATES_HISTORICAL_FORMS}, + {"stylistic", SP_CSS_FONT_VARIANT_ALTERNATES_STYLISTIC}, + {"styleset", SP_CSS_FONT_VARIANT_ALTERNATES_STYLESET}, + {"character_variant", SP_CSS_FONT_VARIANT_ALTERNATES_CHARACTER_VARIANT}, + {"swash", SP_CSS_FONT_VARIANT_ALTERNATES_SWASH}, + {"ornaments", SP_CSS_FONT_VARIANT_ALTERNATES_ORNAMENTS}, + {"annotation", SP_CSS_FONT_VARIANT_ALTERNATES_ANNOTATION}, + {NULL, -1} +}; + +static SPStyleEnum const enum_font_variant_east_asian[] = { + {"normal", SP_CSS_FONT_VARIANT_EAST_ASIAN_NORMAL}, + {"jis78", SP_CSS_FONT_VARIANT_EAST_ASIAN_JIS78}, + {"jis83", SP_CSS_FONT_VARIANT_EAST_ASIAN_JIS83}, + {"jis90", SP_CSS_FONT_VARIANT_EAST_ASIAN_JIS90}, + {"jis04", SP_CSS_FONT_VARIANT_EAST_ASIAN_JIS04}, + {"simplified", SP_CSS_FONT_VARIANT_EAST_ASIAN_SIMPLIFIED}, + {"traditional", SP_CSS_FONT_VARIANT_EAST_ASIAN_TRADITIONAL}, + {"full-width", SP_CSS_FONT_VARIANT_EAST_ASIAN_FULL_WIDTH}, + {"proportional-width", SP_CSS_FONT_VARIANT_EAST_ASIAN_PROPORTIONAL_WIDTH}, + {"ruby", SP_CSS_FONT_VARIANT_EAST_ASIAN_RUBY}, + {NULL, -1} +}; + static SPStyleEnum const enum_text_align[] = { {"start", SP_CSS_TEXT_ALIGN_START}, {"end", SP_CSS_TEXT_ALIGN_END}, diff --git a/src/style.cpp b/src/style.cpp index b65bff53f..943a12f3b 100644 --- a/src/style.cpp +++ b/src/style.cpp @@ -118,6 +118,14 @@ SPStyle::SPStyle(SPDocument *document_in, SPObject *object_in) : font(), // SPIFont font_specification( "-inkscape-font-specification" ), // SPIString + // Font variants + font_variant_ligatures( "font-variant-ligatures", enum_font_variant_ligatures, SP_CSS_FONT_VARIANT_LIGATURES_NORMAL ), + font_variant_position( "font-variant-position", enum_font_variant_position, SP_CSS_FONT_VARIANT_POSITION_NORMAL ), + font_variant_caps( "font-variant-caps", enum_font_variant_caps, SP_CSS_FONT_VARIANT_CAPS_NORMAL ), + font_variant_numeric( "font-variant-numeric", enum_font_variant_numeric, SP_CSS_FONT_VARIANT_NUMERIC_NORMAL ), + font_variant_alternates("font-variant-alternates", enum_font_variant_alternates, SP_CSS_FONT_VARIANT_ALTERNATES_NORMAL ), + font_variant_east_asian("font-variant-east_asian", enum_font_variant_east_asian, SP_CSS_FONT_VARIANT_EAST_ASIAN_NORMAL ), + // Text related properties text_indent( "text-indent", 0.0 ), // SPILength text_align( "text-align", enum_text_align, SP_CSS_TEXT_ALIGN_START ), diff --git a/src/style.h b/src/style.h index ab34476b3..f52c14d89 100644 --- a/src/style.h +++ b/src/style.h @@ -111,6 +111,24 @@ public: /** Full font name, as font_factory::ConstructFontSpecification would give, for internal use. */ SPIString font_specification; + /* Font variants -------------------- */ + /** Font variant ligatures */ + SPIEnum font_variant_ligatures; + /** Font variant position (subscript/superscript) */ + SPIEnum font_variant_position; + /** Font variant caps (small caps) */ + SPIEnum font_variant_caps; + /** Font variant numeric (numerical formatting) */ + SPIEnum font_variant_numeric; + /** Font variant alternates (alternates/swatches) */ + SPIEnum font_variant_alternates; + /** Font variant East Asian */ + SPIEnum font_variant_east_asian; + /** Font variant shorthand (Redefines CSS 2.1 value) */ + // ? font_variant; + /** Font feature settings */ + // ? font_feature_settings; + /* Text ----------------------------- */ /** First line indent of paragraphs (css2 16.1) */ -- cgit v1.2.3 From c7ce360901e191572b207df27dd3e972bff3929f Mon Sep 17 00:00:00 2001 From: Tavmjong Bah Date: Sun, 3 May 2015 19:01:45 +0200 Subject: Revert bad commit (commited to wrong branch). (bzr r14096) --- src/conditions.cpp | 4 +- src/display/canvas-grid.cpp | 3 - src/libcroco/cr-statement.c | 1 - src/live_effects/lpe-taperstroke.cpp | 4 +- src/style-enums.h | 137 ----------------------------------- src/style.cpp | 8 -- src/style.h | 18 ----- 7 files changed, 4 insertions(+), 171 deletions(-) (limited to 'src') diff --git a/src/conditions.cpp b/src/conditions.cpp index 39ab16ba8..9b233a74f 100644 --- a/src/conditions.cpp +++ b/src/conditions.cpp @@ -77,7 +77,7 @@ static gchar *preprocessLanguageCode(gchar *lngcode) { static bool evaluateSystemLanguage(SPItem const *item, gchar const *value) { if ( NULL == value ) return true; - std::cout << "evaluateSystemLanguage: " << value << std::endl; + std::set language_codes; gchar *str = NULL; gchar **strlist = g_strsplit( value, ",", 0); @@ -105,7 +105,7 @@ static bool evaluateSystemLanguage(SPItem const *item, gchar const *value) { SPDocument *document = item->document; Glib::ustring document_language = document->getLanguage(); - std::cout << "language: |" << document_language << "|" << std::endl; + if (document_language.size() == 0) return false; diff --git a/src/display/canvas-grid.cpp b/src/display/canvas-grid.cpp index 8285f7e64..4eda9b194 100644 --- a/src/display/canvas-grid.cpp +++ b/src/display/canvas-grid.cpp @@ -916,14 +916,12 @@ CanvasXYGrid::Render (SPCanvasBuf *buf) _empcolor = empcolor; } - std::cout << "CanvasXYGrid::Render: " << no_emp_when_zoomed_out << " " << empspacing << " " << _empcolor << " " << scaled << std::endl; cairo_save(buf->ct); cairo_translate(buf->ct, -buf->rect.left(), -buf->rect.top()); cairo_set_line_width(buf->ct, 1.0); cairo_set_line_cap(buf->ct, CAIRO_LINE_CAP_SQUARE); if (!render_dotted) { - // Render lines gint ylinenum; gdouble y; for (y = syg, ylinenum = ylinestart; y < buf->rect.bottom(); y += sw[Geom::Y], ylinenum++) { @@ -946,7 +944,6 @@ CanvasXYGrid::Render (SPCanvasBuf *buf) } } } else { - // Render dots gint ylinenum; gdouble y; for (y = syg, ylinenum = ylinestart; y < buf->rect.bottom(); y += sw[Geom::Y], ylinenum++) { diff --git a/src/libcroco/cr-statement.c b/src/libcroco/cr-statement.c index 5fb2dd2fd..4666f26ec 100644 --- a/src/libcroco/cr-statement.c +++ b/src/libcroco/cr-statement.c @@ -1678,7 +1678,6 @@ CRStatement * cr_statement_new_at_font_face_rule (CRStyleSheet * a_sheet, CRDeclaration * a_font_decls) { - printf("cr_statement_new_at_font_face_rule\n"); CRStatement *result = (CRStatement *)g_try_malloc (sizeof (CRStatement)); if (!result) { diff --git a/src/live_effects/lpe-taperstroke.cpp b/src/live_effects/lpe-taperstroke.cpp index 1888bc3f0..2c74af6d6 100644 --- a/src/live_effects/lpe-taperstroke.cpp +++ b/src/live_effects/lpe-taperstroke.cpp @@ -275,7 +275,7 @@ Geom::PathVector LPETaperStroke::doEffect_path(Geom::PathVector const& path_in) pat_str << "M 1,0 C " << 1 - (double)smoothing << ",0 0,0.5 0,0.5 0,0.5 " << 1 - (double)smoothing << ",1 1,1"; pat_vec = sp_svg_read_pathv(pat_str.str().c_str()); - pwd2.concat(stretch_along(pathv_out[0].toPwSb(), pat_vec[0], fabs(line_width))); + pwd2.concat(stretch_along(pathv_out[0].toPwSb(), pat_vec[0], -fabs(line_width))); throwaway_path = Geom::path_from_piecewise(pwd2, LPE_CONVERSION_TOLERANCE)[0]; real_path.append(throwaway_path); @@ -304,7 +304,7 @@ Geom::PathVector LPETaperStroke::doEffect_path(Geom::PathVector const& path_in) pat_vec = sp_svg_read_pathv(pat_str_1.str().c_str()); pwd2 = Piecewise >(); - pwd2.concat(stretch_along(pathv_out[2].toPwSb(), pat_vec[0], fabs(line_width))); + pwd2.concat(stretch_along(pathv_out[2].toPwSb(), pat_vec[0], -fabs(line_width))); throwaway_path = Geom::path_from_piecewise(pwd2, LPE_CONVERSION_TOLERANCE)[0]; if (!Geom::are_near(real_path.finalPoint(), throwaway_path.initialPoint()) && real_path.size() >= 1) { diff --git a/src/style-enums.h b/src/style-enums.h index f235b6699..f52752018 100644 --- a/src/style-enums.h +++ b/src/style-enums.h @@ -72,72 +72,6 @@ enum SPCSSFontStretch { SP_CSS_FONT_STRETCH_WIDER }; -// Can select more than one -enum SPCSSFontVariantLigatures { - SP_CSS_FONT_VARIANT_LIGATURES_NORMAL, - SP_CSS_FONT_VARIANT_LIGATURES_NONE, - SP_CSS_FONT_VARIANT_LIGATURES_COMMON, - SP_CSS_FONT_VARIANT_LIGATURES_NO_COMMON, - SP_CSS_FONT_VARIANT_LIGATURES_DISCRETIONARY, - SP_CSS_FONT_VARIANT_LIGATURES_NO_DISCRETIONARY, - SP_CSS_FONT_VARIANT_LIGATURES_HISTORICAL, - SP_CSS_FONT_VARIANT_LIGATURES_NO_HISTORICAL, - SP_CSS_FONT_VARIANT_LIGATURES_CONTEXTUAL, - SP_CSS_FONT_VARIANT_LIGATURES_NO_CONTEXTUAL -}; - -enum SPCSSFontVariantPosition { - SP_CSS_FONT_VARIANT_POSITION_NORMAL, - SP_CSS_FONT_VARIANT_POSITION_SUB, - SP_CSS_FONT_VARIANT_POSITION_SUPER -}; - -enum SPCSSFontVariantCaps { - SP_CSS_FONT_VARIANT_CAPS_NORMAL, - SP_CSS_FONT_VARIANT_CAPS_SMALL, - SP_CSS_FONT_VARIANT_CAPS_ALL_SMALL, - SP_CSS_FONT_VARIANT_CAPS_PETITE, - SP_CSS_FONT_VARIANT_CAPS_ALL_PETITE, - SP_CSS_FONT_VARIANT_CAPS_UNICASE, - SP_CSS_FONT_VARIANT_CAPS_TITLING, -}; - -enum SPCSSFontVariantNumeric { - SP_CSS_FONT_VARIANT_NUMERIC_NORMAL, - SP_CSS_FONT_VARIANT_NUMERIC_LINING_NUMS, - SP_CSS_FONT_VARIANT_NUMERIC_OLDSTYLE_NUMS, - SP_CSS_FONT_VARIANT_NUMERIC_PROPORTIONAL_NUMS, - SP_CSS_FONT_VARIANT_NUMERIC_TABULAR_NUMS, - SP_CSS_FONT_VARIANT_NUMERIC_DIAGONAL_FRACTIONS, - SP_CSS_FONT_VARIANT_NUMERIC_STACKED_FRACTIONS, - SP_CSS_FONT_VARIANT_NUMERIC_ORDINAL, - SP_CSS_FONT_VARIANT_NUMERIC_SLASHED_ZERO -}; - -enum SPCSSFontVariantAlternates { - SP_CSS_FONT_VARIANT_ALTERNATES_NORMAL, - SP_CSS_FONT_VARIANT_ALTERNATES_HISTORICAL_FORMS, - SP_CSS_FONT_VARIANT_ALTERNATES_STYLISTIC, - SP_CSS_FONT_VARIANT_ALTERNATES_STYLESET, - SP_CSS_FONT_VARIANT_ALTERNATES_CHARACTER_VARIANT, - SP_CSS_FONT_VARIANT_ALTERNATES_SWASH, - SP_CSS_FONT_VARIANT_ALTERNATES_ORNAMENTS, - SP_CSS_FONT_VARIANT_ALTERNATES_ANNOTATION -}; - -enum SPCSSFontVariantEastAsian { - SP_CSS_FONT_VARIANT_EAST_ASIAN_NORMAL, - SP_CSS_FONT_VARIANT_EAST_ASIAN_JIS78, - SP_CSS_FONT_VARIANT_EAST_ASIAN_JIS83, - SP_CSS_FONT_VARIANT_EAST_ASIAN_JIS90, - SP_CSS_FONT_VARIANT_EAST_ASIAN_JIS04, - SP_CSS_FONT_VARIANT_EAST_ASIAN_SIMPLIFIED, - SP_CSS_FONT_VARIANT_EAST_ASIAN_TRADITIONAL, - SP_CSS_FONT_VARIANT_EAST_ASIAN_FULL_WIDTH, - SP_CSS_FONT_VARIANT_EAST_ASIAN_PROPORTIONAL_WIDTH, - SP_CSS_FONT_VARIANT_EAST_ASIAN_RUBY -}; - enum SPCSSTextAlign { SP_CSS_TEXT_ALIGN_START, SP_CSS_TEXT_ALIGN_END, @@ -375,77 +309,6 @@ static SPStyleEnum const enum_font_stretch[] = { {NULL, -1} }; -static SPStyleEnum const enum_font_variant_ligatures[] = { - {"normal", SP_CSS_FONT_VARIANT_LIGATURES_NORMAL}, - {"none", SP_CSS_FONT_VARIANT_LIGATURES_NONE}, - {"common-ligatures", SP_CSS_FONT_VARIANT_LIGATURES_COMMON}, - {"no-common-ligatures", SP_CSS_FONT_VARIANT_LIGATURES_NO_COMMON}, - {"discretionary-ligatures", SP_CSS_FONT_VARIANT_LIGATURES_DISCRETIONARY}, - {"no-discretionary-ligatures", SP_CSS_FONT_VARIANT_LIGATURES_NO_DISCRETIONARY}, - {"historical-ligatures", SP_CSS_FONT_VARIANT_LIGATURES_HISTORICAL}, - {"nohistorical-ligatures", SP_CSS_FONT_VARIANT_LIGATURES_NO_HISTORICAL}, - {"contextual", SP_CSS_FONT_VARIANT_LIGATURES_CONTEXTUAL}, - {"no-contextual", SP_CSS_FONT_VARIANT_LIGATURES_NO_CONTEXTUAL}, - {NULL, -1} -}; - -static SPStyleEnum const enum_font_variant_position[] = { - {"normal", SP_CSS_FONT_VARIANT_POSITION_NORMAL}, - {"sub", SP_CSS_FONT_VARIANT_POSITION_SUB}, - {"super", SP_CSS_FONT_VARIANT_POSITION_SUPER}, - {NULL, -1} -}; - -static SPStyleEnum const enum_font_variant_caps[] = { - {"normal", SP_CSS_FONT_VARIANT_CAPS_NORMAL}, - {"small-caps", SP_CSS_FONT_VARIANT_CAPS_SMALL}, - {"all-small-caps", SP_CSS_FONT_VARIANT_CAPS_ALL_SMALL}, - {"petite-caps", SP_CSS_FONT_VARIANT_CAPS_PETITE}, - {"all_petite-caps", SP_CSS_FONT_VARIANT_CAPS_ALL_PETITE}, - {"unicase", SP_CSS_FONT_VARIANT_CAPS_UNICASE}, - {"titling", SP_CSS_FONT_VARIANT_CAPS_TITLING}, - {NULL, -1} -}; - -static SPStyleEnum const enum_font_variant_numeric[] = { - {"normal", SP_CSS_FONT_VARIANT_NUMERIC_NORMAL}, - {"lining-nums", SP_CSS_FONT_VARIANT_NUMERIC_LINING_NUMS}, - {"oldstyle-nums", SP_CSS_FONT_VARIANT_NUMERIC_OLDSTYLE_NUMS}, - {"proportional-nums", SP_CSS_FONT_VARIANT_NUMERIC_PROPORTIONAL_NUMS}, - {"tabular-nums", SP_CSS_FONT_VARIANT_NUMERIC_TABULAR_NUMS}, - {"diagonal-fractions", SP_CSS_FONT_VARIANT_NUMERIC_DIAGONAL_FRACTIONS}, - {"stacked-fractions", SP_CSS_FONT_VARIANT_NUMERIC_STACKED_FRACTIONS}, - {"ordinal", SP_CSS_FONT_VARIANT_NUMERIC_ORDINAL}, - {"slashed-zero", SP_CSS_FONT_VARIANT_NUMERIC_SLASHED_ZERO}, - {NULL, -1} -}; - -static SPStyleEnum const enum_font_variant_alternates[] = { - {"normal", SP_CSS_FONT_VARIANT_ALTERNATES_NORMAL}, - {"historical-forms", SP_CSS_FONT_VARIANT_ALTERNATES_HISTORICAL_FORMS}, - {"stylistic", SP_CSS_FONT_VARIANT_ALTERNATES_STYLISTIC}, - {"styleset", SP_CSS_FONT_VARIANT_ALTERNATES_STYLESET}, - {"character_variant", SP_CSS_FONT_VARIANT_ALTERNATES_CHARACTER_VARIANT}, - {"swash", SP_CSS_FONT_VARIANT_ALTERNATES_SWASH}, - {"ornaments", SP_CSS_FONT_VARIANT_ALTERNATES_ORNAMENTS}, - {"annotation", SP_CSS_FONT_VARIANT_ALTERNATES_ANNOTATION}, - {NULL, -1} -}; - -static SPStyleEnum const enum_font_variant_east_asian[] = { - {"normal", SP_CSS_FONT_VARIANT_EAST_ASIAN_NORMAL}, - {"jis78", SP_CSS_FONT_VARIANT_EAST_ASIAN_JIS78}, - {"jis83", SP_CSS_FONT_VARIANT_EAST_ASIAN_JIS83}, - {"jis90", SP_CSS_FONT_VARIANT_EAST_ASIAN_JIS90}, - {"jis04", SP_CSS_FONT_VARIANT_EAST_ASIAN_JIS04}, - {"simplified", SP_CSS_FONT_VARIANT_EAST_ASIAN_SIMPLIFIED}, - {"traditional", SP_CSS_FONT_VARIANT_EAST_ASIAN_TRADITIONAL}, - {"full-width", SP_CSS_FONT_VARIANT_EAST_ASIAN_FULL_WIDTH}, - {"proportional-width", SP_CSS_FONT_VARIANT_EAST_ASIAN_PROPORTIONAL_WIDTH}, - {"ruby", SP_CSS_FONT_VARIANT_EAST_ASIAN_RUBY}, - {NULL, -1} -}; - static SPStyleEnum const enum_text_align[] = { {"start", SP_CSS_TEXT_ALIGN_START}, {"end", SP_CSS_TEXT_ALIGN_END}, diff --git a/src/style.cpp b/src/style.cpp index 943a12f3b..b65bff53f 100644 --- a/src/style.cpp +++ b/src/style.cpp @@ -118,14 +118,6 @@ SPStyle::SPStyle(SPDocument *document_in, SPObject *object_in) : font(), // SPIFont font_specification( "-inkscape-font-specification" ), // SPIString - // Font variants - font_variant_ligatures( "font-variant-ligatures", enum_font_variant_ligatures, SP_CSS_FONT_VARIANT_LIGATURES_NORMAL ), - font_variant_position( "font-variant-position", enum_font_variant_position, SP_CSS_FONT_VARIANT_POSITION_NORMAL ), - font_variant_caps( "font-variant-caps", enum_font_variant_caps, SP_CSS_FONT_VARIANT_CAPS_NORMAL ), - font_variant_numeric( "font-variant-numeric", enum_font_variant_numeric, SP_CSS_FONT_VARIANT_NUMERIC_NORMAL ), - font_variant_alternates("font-variant-alternates", enum_font_variant_alternates, SP_CSS_FONT_VARIANT_ALTERNATES_NORMAL ), - font_variant_east_asian("font-variant-east_asian", enum_font_variant_east_asian, SP_CSS_FONT_VARIANT_EAST_ASIAN_NORMAL ), - // Text related properties text_indent( "text-indent", 0.0 ), // SPILength text_align( "text-align", enum_text_align, SP_CSS_TEXT_ALIGN_START ), diff --git a/src/style.h b/src/style.h index f52c14d89..ab34476b3 100644 --- a/src/style.h +++ b/src/style.h @@ -111,24 +111,6 @@ public: /** Full font name, as font_factory::ConstructFontSpecification would give, for internal use. */ SPIString font_specification; - /* Font variants -------------------- */ - /** Font variant ligatures */ - SPIEnum font_variant_ligatures; - /** Font variant position (subscript/superscript) */ - SPIEnum font_variant_position; - /** Font variant caps (small caps) */ - SPIEnum font_variant_caps; - /** Font variant numeric (numerical formatting) */ - SPIEnum font_variant_numeric; - /** Font variant alternates (alternates/swatches) */ - SPIEnum font_variant_alternates; - /** Font variant East Asian */ - SPIEnum font_variant_east_asian; - /** Font variant shorthand (Redefines CSS 2.1 value) */ - // ? font_variant; - /** Font feature settings */ - // ? font_feature_settings; - /* Text ----------------------------- */ /** First line indent of paragraphs (css2 16.1) */ -- cgit v1.2.3 From 2eab6fad30c9c838902d9113c7e0d41b34ce79ea Mon Sep 17 00:00:00 2001 From: houz Date: Mon, 4 May 2015 12:39:09 +0200 Subject: cmake: shorter linker list (remove duplicates) (bzr r14106) --- src/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 27c5e49db..efb604aca 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -519,7 +519,7 @@ add_dependencies(inkscape inkscape_version) target_link_libraries(inkscape # order from automake #sp_LIB - nrtype_LIB + #nrtype_LIB #inkscape_LIB #sp_LIB # annoying, we need both! -- cgit v1.2.3 From 7e3aabae24c09340fd06cb69b0678158abb4a375 Mon Sep 17 00:00:00 2001 From: Tavmjong Bah Date: Mon, 4 May 2015 12:57:06 +0200 Subject: Shorthands are not allowed as presentation attributes. (bzr r14107) --- src/style.cpp | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/style.cpp b/src/style.cpp index b65bff53f..8b41bbbd7 100644 --- a/src/style.cpp +++ b/src/style.cpp @@ -573,7 +573,15 @@ SPStyle::read( SPObject *object, Inkscape::XML::Node *repr ) { /* 3 Presentation attributes */ // std::cout << " MERGING PRESENTATION ATTRIBUTES" << std::endl; for(std::vector::size_type i = 0; i != _properties.size(); ++i) { - _properties[i]->readAttribute( repr ); + + // Shorthands are not allowed as presentation properites. + // Note: text-decoration is converted to a shorthand in CSS 3 but can still be + // read as a non-shorthand so it should not be in this list. + // We could add a flag to SPIBase to avoid string comparison. + if( _properties[i]->name.compare( "font" ) != 0 && + _properties[i]->name.compare( "marker" ) != 0 ) { + _properties[i]->readAttribute( repr ); + } } // for(SPPropMap::iterator i = _propmap.begin(); i != _propmap.end(); ++i ) { // (this->*(i->second)).readAttribute( repr ); -- cgit v1.2.3 From f9afd4f6cdee501fcfd5ae6185643796e9ec646d Mon Sep 17 00:00:00 2001 From: Marc Jeanmougin Date: Mon, 4 May 2015 13:09:20 +0200 Subject: Fix crash in PDF export introduced in r14074 (bzr r14108) --- src/extension/internal/cairo-renderer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/extension/internal/cairo-renderer.cpp b/src/extension/internal/cairo-renderer.cpp index 49e145de0..5a5553e97 100644 --- a/src/extension/internal/cairo-renderer.cpp +++ b/src/extension/internal/cairo-renderer.cpp @@ -296,7 +296,7 @@ static void sp_group_render(SPGroup *group, CairoRenderContext *ctx) std::vector l(group->childList(false)); for(std::vector::const_iterator x = l.begin(); x!= l.end(); x++){ - SPItem *item = static_cast(*x); + SPItem *item = dynamic_cast(*x); if (item) { renderer->renderItem(ctx, item); } -- cgit v1.2.3 From abe296168df89e7f62e9d670602ffea62ad78a22 Mon Sep 17 00:00:00 2001 From: Raphael Rosch Date: Mon, 4 May 2015 12:17:58 -0400 Subject: going from swatch to flat color should start with previous swatch color Fixed bugs: - https://launchpad.net/bugs/1450112 (bzr r14109) --- src/widgets/paint-selector.cpp | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/widgets/paint-selector.cpp b/src/widgets/paint-selector.cpp index 740ce2b0e..221344296 100644 --- a/src/widgets/paint-selector.cpp +++ b/src/widgets/paint-selector.cpp @@ -35,6 +35,7 @@ #include "sp-linear-gradient.h" #include "sp-radial-gradient.h" #include "sp-mesh.h" +#include "sp-stop.h" /* fixme: Move it from dialogs to here */ #include "gradient-selector.h" #include @@ -658,6 +659,20 @@ sp_paint_selector_color_changed(SPColorSelector *csel, SPPaintSelector *psel) static void sp_paint_selector_set_mode_color(SPPaintSelector *psel, SPPaintSelector::Mode /*mode*/) { GtkWidget *csel; + + SPColor newcolor = psel->color; + float newalpha = psel->alpha; + + if ((psel->mode == SPPaintSelector::MODE_SWATCH) + || (psel->mode == SPPaintSelector::MODE_GRADIENT_LINEAR) + || (psel->mode == SPPaintSelector::MODE_GRADIENT_RADIAL) ) { + SPGradientSelector *gsel = getGradientFromData(psel); + if (gsel) { + SPGradient *gradient = gsel->getVector(); + newcolor = gradient->getFirstStop()->specified_color; + newalpha = gradient->getFirstStop()->opacity; + } + } sp_paint_selector_set_style_buttons(psel, psel->solid); gtk_widget_set_sensitive(psel->style, TRUE); @@ -693,8 +708,7 @@ static void sp_paint_selector_set_mode_color(SPPaintSelector *psel, SPPaintSelec psel->selector = vb; /* Set color */ - SP_COLOR_SELECTOR( csel )->base->setColorAlpha( psel->color, psel->alpha ); - + SP_COLOR_SELECTOR( csel )->base->setColorAlpha( newcolor, newalpha ); } gtk_label_set_markup(GTK_LABEL(psel->label), _("Flat color")); -- cgit v1.2.3 From 5af8924e1de466080dc116b47edd7c8d8591652b Mon Sep 17 00:00:00 2001 From: Raphael Rosch Date: Tue, 5 May 2015 13:26:20 -0400 Subject: show filter usage count Fixed bugs: - https://launchpad.net/bugs/1169123 (bzr r14111) --- src/sp-filter.cpp | 10 ++++++++++ src/sp-filter.h | 3 +++ src/style.cpp | 2 ++ src/ui/dialog/filter-effects-dialog.cpp | 31 +++++++++++++++++++++++++------ src/ui/dialog/filter-effects-dialog.h | 4 ++++ 5 files changed, 44 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/sp-filter.cpp b/src/sp-filter.cpp index 2bf1b11a6..1bde69dd1 100644 --- a/src/sp-filter.cpp +++ b/src/sp-filter.cpp @@ -79,6 +79,7 @@ void SPFilter::build(SPDocument *document, Inkscape::XML::Node *repr) { this->readAttr( "height" ); this->readAttr( "filterRes" ); this->readAttr( "xlink:href" ); + this->_refcount = 0; SPObject::build(document, repr); @@ -190,6 +191,15 @@ void SPFilter::set(unsigned int key, gchar const *value) { } } + +/** + * Returns the number of references to the filter. + */ +guint SPFilter::getRefCount() { + // NOTE: this is currently updated by sp_style_filter_ref_changed() in style.cpp + return _refcount; +} + /** * Receives update notifications. */ diff --git a/src/sp-filter.h b/src/sp-filter.h index e6318c569..1c214c6b7 100644 --- a/src/sp-filter.h +++ b/src/sp-filter.h @@ -54,6 +54,9 @@ public: NumberOptNumber filterRes; SPFilterReference *href; sigc::connection modified_connection; + + guint getRefCount(); + guint _refcount; Inkscape::Filters::Filter *_renderer; diff --git a/src/style.cpp b/src/style.cpp index 8b41bbbd7..fa8aed68e 100644 --- a/src/style.cpp +++ b/src/style.cpp @@ -1177,10 +1177,12 @@ void sp_style_filter_ref_changed(SPObject *old_ref, SPObject *ref, SPStyle *style) { if (old_ref) { + (dynamic_cast( old_ref ))->_refcount--; style->filter_modified_connection.disconnect(); } if ( SP_IS_FILTER(ref)) { + (dynamic_cast( ref ))->_refcount++; style->filter_modified_connection = ref->connectModified(sigc::bind(sigc::ptr_fun(&sp_style_filter_ref_modified), style)); } diff --git a/src/ui/dialog/filter-effects-dialog.cpp b/src/ui/dialog/filter-effects-dialog.cpp index f81519ed1..1ff9e4a1b 100644 --- a/src/ui/dialog/filter-effects-dialog.cpp +++ b/src/ui/dialog/filter-effects-dialog.cpp @@ -8,6 +8,7 @@ * Felipe C. da S. Sanches * Jon A. Cruz * Abhishek Sharma + * insaner * * Copyright (C) 2007 Authors * @@ -1360,8 +1361,15 @@ FilterEffectsDialog::FilterModifier::FilterModifier(FilterEffectsDialog& d) ((Gtk::CellRendererText*)_list.get_column(1)->get_first_cell())-> signal_edited().connect(sigc::mem_fun(*this, &FilterEffectsDialog::FilterModifier::on_name_edited)); + _list.append_column("#", _columns.count); + _list.get_column(2)->set_sizing(Gtk::TREE_VIEW_COLUMN_AUTOSIZE); + _list.get_column(2)->set_expand(false); + sw->set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC); _list.get_column(1)->set_resizable(true); + _list.get_column(1)->set_sizing(Gtk::TREE_VIEW_COLUMN_AUTOSIZE); + _list.get_column(1)->set_expand(true); + _list.set_reorderable(true); _list.enable_model_drag_dest (Gdk::ACTION_MOVE); @@ -1494,6 +1502,7 @@ void FilterEffectsDialog::FilterModifier::update_selection(Selection *sel) (*iter)[_columns.sel] = 0; } } + update_counts(); } void FilterEffectsDialog::FilterModifier::on_filter_selection_changed() @@ -1565,6 +1574,15 @@ void FilterEffectsDialog::FilterModifier::on_selection_toggled(const Glib::ustri } } + +void FilterEffectsDialog::FilterModifier::update_counts() +{ + for(Gtk::TreeModel::iterator i = _model->children().begin(); i != _model->children().end(); ++i) { + SPFilter* f = SP_FILTER((*i)[_columns.filter]); + (*i)[_columns.count] = f->getRefCount(); + } +} + /* Add all filters in the document to the combobox. Keeps the same selection if possible, otherwise selects the first element */ void FilterEffectsDialog::FilterModifier::update_filters() @@ -2419,7 +2437,7 @@ bool FilterEffectsDialog::PrimitiveList::on_motion_notify_event(GdkEventMotion* get_visible_rect(vis); int vis_x, vis_y; - int vis_x2, vis_y2; // NOTE: insaner added -- necessary to get the scrolling while dragging to work + int vis_x2, vis_y2; convert_widget_to_tree_coords(vis.get_x(), vis.get_y(), vis_x2, vis_y2); convert_tree_to_widget_coords(vis.get_x(), vis.get_y(), vis_x, vis_y); @@ -2439,7 +2457,6 @@ bool FilterEffectsDialog::PrimitiveList::on_motion_notify_event(GdkEventMotion* else _autoscroll_y = 0; - // NOTE: insaner added -- necessary to get the scrolling while dragging to work double e2 = ( e->x - vis_x2/2); // horizontal scrolling if(e2 < vis_x) @@ -2752,20 +2769,22 @@ FilterEffectsDialog::FilterEffectsDialog() Gtk::ScrolledWindow* sw_infobox = Gtk::manage(new Gtk::ScrolledWindow); Gtk::HBox* infobox = Gtk::manage(new Gtk::HBox(/*homogeneous:*/false, /*spacing:*/4)); Gtk::HBox* hb_prims = Gtk::manage(new Gtk::HBox); + Gtk::VBox* vb_prims = Gtk::manage(new Gtk::VBox); _getContents()->add(*hpaned); hpaned->pack1(_filter_modifier); hpaned->pack2(_primitive_box); _primitive_box.pack_start(*sw_prims); - _primitive_box.pack_start(*hb_prims, false, false); _primitive_box.pack_start(*sw_infobox, false, false); sw_prims->add(_primitive_list); - sw_infobox->add(*infobox); + sw_infobox->add(*vb_prims); infobox->pack_start(_infobox_icon, false, false); infobox->pack_start(_infobox_desc, false, false); _infobox_desc.set_line_wrap(true); - _infobox_desc.set_size_request(200, -1); + _infobox_desc.set_size_request(250, -1); + vb_prims->pack_start(*hb_prims); + vb_prims->pack_start(*infobox); hb_prims->pack_start(_add_primitive, false, false); hb_prims->pack_start(_add_primitive_type, false, false); @@ -2781,7 +2800,7 @@ FilterEffectsDialog::FilterEffectsDialog() _add_primitive_type.signal_changed().connect( sigc::mem_fun(*this, &FilterEffectsDialog::update_primitive_infobox)); - sw_prims->set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC); /* NOTE: insaner -- SCROLL the connections panel thing!!! */ + sw_prims->set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC); sw_prims->set_shadow_type(Gtk::SHADOW_IN); sw_infobox->set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_NEVER); diff --git a/src/ui/dialog/filter-effects-dialog.h b/src/ui/dialog/filter-effects-dialog.h index 3fc19e7de..a067cd70c 100644 --- a/src/ui/dialog/filter-effects-dialog.h +++ b/src/ui/dialog/filter-effects-dialog.h @@ -4,6 +4,7 @@ /* Authors: * Nicholas Bishop * Rodrigo Kumpera + * insaner * * Copyright (C) 2007 Authors * @@ -69,11 +70,13 @@ private: add(filter); add(label); add(sel); + add(count); } Gtk::TreeModelColumn filter; Gtk::TreeModelColumn label; Gtk::TreeModelColumn sel; + Gtk::TreeModelColumn count; }; void setTargetDesktop(SPDesktop *desktop); @@ -89,6 +92,7 @@ private: bool on_filter_move(const Glib::RefPtr& /*context*/, int x, int y, guint /*time*/); void on_selection_toggled(const Glib::ustring&); + void update_counts(); void update_filters(); void filter_list_button_release(GdkEventButton*); void add_filter(); -- cgit v1.2.3 From 6957740e11e8604b8439c3ef331cf3c44400d1fb Mon Sep 17 00:00:00 2001 From: "Jon A. Cruz" Date: Wed, 6 May 2015 01:48:53 -0700 Subject: Changed return type to be consistent with other calls and to make header stand-alone. (bzr r14112) --- src/dir-util.cpp | 2 +- src/dir-util.h | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/dir-util.cpp b/src/dir-util.cpp index c9b88b007..64f7ab7e7 100644 --- a/src/dir-util.cpp +++ b/src/dir-util.cpp @@ -217,7 +217,7 @@ erange: return (NULL); } -gchar *prepend_current_dir_if_relative(gchar const *uri) +char *prepend_current_dir_if_relative(gchar const *uri) { if (!uri) { return NULL; diff --git a/src/dir-util.h b/src/dir-util.h index e78cad6a6..327e1ad5f 100644 --- a/src/dir-util.h +++ b/src/dir-util.h @@ -12,7 +12,7 @@ #include #include -/** +/** * Returns a form of \a path relative to \a base if that is easy to construct (eg if \a path * appears to be in the directory specified by \a base), otherwise returns \a path. * @@ -49,7 +49,7 @@ char *inkscape_rel2abs(char const *path, char const *base, char *result, size_t char *inkscape_abs2rel(char const *path, char const *base, char *result, size_t const size); -gchar *prepend_current_dir_if_relative(char const *filename); +char *prepend_current_dir_if_relative(char const *filename); #endif // !SEEN_DIR_UTIL_H -- cgit v1.2.3 From 12fb2762bc936c08538f041be261c79f43ee80e0 Mon Sep 17 00:00:00 2001 From: Tavmjong Bah Date: Wed, 6 May 2015 13:55:31 +0200 Subject: Compromise solution for dot grid visibilty. See bug #1357611. (bzr r14114) --- src/display/canvas-grid.cpp | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/display/canvas-grid.cpp b/src/display/canvas-grid.cpp index 4eda9b194..decf93626 100644 --- a/src/display/canvas-grid.cpp +++ b/src/display/canvas-grid.cpp @@ -906,7 +906,7 @@ CanvasXYGrid::Render (SPCanvasBuf *buf) gdouble const syg = floor ((buf->rect.top() - ow[Geom::Y]) / sw[Geom::Y]) * sw[Geom::Y] + ow[Geom::Y]; gint const ylinestart = round((syg - ow[Geom::Y]) / sw[Geom::Y]); - //set correct coloring, depending preference (when zoomed out, always major coloring or minor coloring) + // no_emphasize_when_zoomedout determines color (minor or major) when only major grid lines/dots shown. Inkscape::Preferences *prefs = Inkscape::Preferences::get(); guint32 _empcolor; bool no_emp_when_zoomed_out = prefs->getBool("/options/grids/no_emphasize_when_zoomedout", false); @@ -922,6 +922,7 @@ CanvasXYGrid::Render (SPCanvasBuf *buf) cairo_set_line_cap(buf->ct, CAIRO_LINE_CAP_SQUARE); if (!render_dotted) { + // Line grid gint ylinenum; gdouble y; for (y = syg, ylinenum = ylinestart; y < buf->rect.bottom(); y += sw[Geom::Y], ylinenum++) { @@ -944,8 +945,23 @@ CanvasXYGrid::Render (SPCanvasBuf *buf) } } } else { + // Dotted grid gint ylinenum; gdouble y; + + // alpha needs to be larger than in the line case to maintain a similar visual impact but + // setting it to the maximal value makes the dots dominant in some cases. Solution, + // increase the alpha by a factor of 4. This then allows some user adjustment. + guint32 _empdot = (_empcolor & 0xff) << 2; + if (_empdot > 0xff) + _empdot = 0xff; + _empdot += (_empcolor & 0xffffff00); + + guint32 _colordot = (color & 0xff) << 2; + if (_colordot > 0xff) + _colordot = 0xff; + _colordot += (color & 0xffffff00); + for (y = syg, ylinenum = ylinestart; y < buf->rect.bottom(); y += sw[Geom::Y], ylinenum++) { gint const iy = round(y); @@ -957,13 +973,15 @@ CanvasXYGrid::Render (SPCanvasBuf *buf) || (!scaled[Geom::Y] && (ylinenum % empspacing) != 0) || ((scaled[Geom::X] || scaled[Geom::Y]) && no_emp_when_zoomed_out) ) { - grid_dot (buf, ix, iy, color | (guint32)0x000000FF); // put alpha to max value + // Minor point: dot only + grid_dot (buf, ix, iy, _colordot); // | (guint32)0x000000FF); // put alpha to max value } else { + // Major point: small cross gint const pitch = 1; grid_dot (buf, ix-pitch, iy, _empcolor); grid_dot (buf, ix+pitch, iy, _empcolor); - grid_dot (buf, ix, iy, _empcolor | (guint32)0x000000FF); // put alpha to max value + grid_dot (buf, ix, iy, _empdot ); // | (guint32)0x000000FF); // put alpha to max value grid_dot (buf, ix, iy-pitch, _empcolor); grid_dot (buf, ix, iy+pitch, _empcolor); -- cgit v1.2.3 From d71254cf07e2258ab3f8b80fc09b565e4a90f422 Mon Sep 17 00:00:00 2001 From: Tavmjong Bah Date: Wed, 6 May 2015 15:44:14 +0200 Subject: Start of implementing CSS 3 font variants (access to OpenType features). (bzr r14115) --- src/attributes.cpp | 24 ++++++++-- src/attributes.h | 23 +++++++-- src/style-enums.h | 137 +++++++++++++++++++++++++++++++++++++++++++++++++++++ src/style.cpp | 57 ++++++++++++++++++++-- src/style.h | 18 ++++++- 5 files changed, 245 insertions(+), 14 deletions(-) (limited to 'src') diff --git a/src/attributes.cpp b/src/attributes.cpp index 568f0528a..af19360c1 100644 --- a/src/attributes.cpp +++ b/src/attributes.cpp @@ -419,6 +419,16 @@ static SPStyleProp const props[] = { {SP_PROP_FONT_STYLE, "font-style"}, {SP_PROP_FONT_VARIANT, "font-variant"}, {SP_PROP_FONT_WEIGHT, "font-weight"}, + + /* Font Variants CSS 3 */ + {SP_PROP_FONT_VARIANT_LIGATURES, "font-variant-ligatures"}, + {SP_PROP_FONT_VARIANT_POSITION, "font-variant-position"}, + {SP_PROP_FONT_VARIANT_CAPS, "font-variant-caps"}, + {SP_PROP_FONT_VARIANT_NUMERIC, "font-variant-numeric"}, + {SP_PROP_FONT_VARIANT_ALTERNATES, "font-variant-alternates"}, + {SP_PROP_FONT_VARIANT_EAST_ASIAN, "font-variant-east-asian"}, + {SP_PROP_FONT_FEATURE_SETTINGS, "font-feature-settings"}, + /* Text */ {SP_PROP_TEXT_INDENT, "text-indent"}, {SP_PROP_TEXT_ALIGN, "text-align"}, @@ -426,6 +436,7 @@ static SPStyleProp const props[] = { {SP_PROP_LETTER_SPACING, "letter-spacing"}, {SP_PROP_WORD_SPACING, "word-spacing"}, {SP_PROP_TEXT_TRANSFORM, "text-transform"}, + /* Text (css3) */ {SP_PROP_DIRECTION, "direction"}, {SP_PROP_BLOCK_PROGRESSION, "block-progression"}, @@ -439,16 +450,21 @@ static SPStyleProp const props[] = { {SP_PROP_KERNING, "kerning"}, {SP_PROP_TEXT_ANCHOR, "text-anchor"}, {SP_PROP_WHITE_SPACE, "white-space"}, + /* SVG 2 Text Wrapping */ {SP_PROP_SHAPE_INSIDE, "shape-inside"}, {SP_PROP_SHAPE_OUTSIDE, "shape-outside"}, {SP_PROP_SHAPE_PADDING, "shape-padding"}, {SP_PROP_SHAPE_MARGIN, "shape-margin"}, + /* Text Decoration */ - {SP_PROP_TEXT_DECORATION, "text-decoration"}, - {SP_PROP_TEXT_DECORATION_LINE, "text-decoration-line"}, - {SP_PROP_TEXT_DECORATION_STYLE,"text-decoration-style"}, - {SP_PROP_TEXT_DECORATION_COLOR,"text-decoration-color"}, + {SP_PROP_TEXT_DECORATION, "text-decoration"}, + {SP_PROP_TEXT_DECORATION_LINE, "text-decoration-line"}, + {SP_PROP_TEXT_DECORATION_STYLE, "text-decoration-style"}, + {SP_PROP_TEXT_DECORATION_COLOR, "text-decoration-color"}, + {SP_PROP_TEXT_DECORATION_FILL, "text-decoration-fill"}, + {SP_PROP_TEXT_DECORATION_STROKE,"text-decoration-stroke"}, + /* Misc */ {SP_PROP_CLIP, "clip"}, {SP_PROP_COLOR, "color"}, diff --git a/src/attributes.h b/src/attributes.h index 91c8868f9..7d6ea70a0 100644 --- a/src/attributes.h +++ b/src/attributes.h @@ -424,6 +424,15 @@ enum SPAttributeEnum { SP_PROP_FONT_VARIANT, SP_PROP_FONT_WEIGHT, + /* Font Variants CSS 3 */ + SP_PROP_FONT_VARIANT_LIGATURES, + SP_PROP_FONT_VARIANT_POSITION, + SP_PROP_FONT_VARIANT_CAPS, + SP_PROP_FONT_VARIANT_NUMERIC, + SP_PROP_FONT_VARIANT_ALTERNATES, + SP_PROP_FONT_VARIANT_EAST_ASIAN, + SP_PROP_FONT_FEATURE_SETTINGS, + /* Text Layout */ SP_PROP_TEXT_INDENT, SP_PROP_TEXT_ALIGN, @@ -446,16 +455,20 @@ enum SPAttributeEnum { SP_PROP_TEXT_ANCHOR, SP_PROP_WHITE_SPACE, + /* SVG 2 Text Wrapping */ SP_PROP_SHAPE_INSIDE, SP_PROP_SHAPE_OUTSIDE, SP_PROP_SHAPE_PADDING, SP_PROP_SHAPE_MARGIN, - /* Text Decoration */ - SP_PROP_TEXT_DECORATION, /* SVG 1 underline etc.( no color or style) OR SVG2 with _LINE, _STYLE, _COLOR values */ - SP_PROP_TEXT_DECORATION_LINE, /* SVG 2 underline etc. */ - SP_PROP_TEXT_DECORATION_STYLE, /* SVG 2 proposed solid [SVG 1], dotted, etc.)*/ - SP_PROP_TEXT_DECORATION_COLOR, /* SVG 2 proposed same as text [SVG 1], specified*/ + /* Text Decoration CSS 2/CSS 3 Shorthand */ + SP_PROP_TEXT_DECORATION, + /* Text Decoration CSS 3/SVG 2 */ + SP_PROP_TEXT_DECORATION_LINE, + SP_PROP_TEXT_DECORATION_STYLE, + SP_PROP_TEXT_DECORATION_COLOR, + SP_PROP_TEXT_DECORATION_FILL, + SP_PROP_TEXT_DECORATION_STROKE, /* Misc */ SP_PROP_CLIP, diff --git a/src/style-enums.h b/src/style-enums.h index f52752018..f235b6699 100644 --- a/src/style-enums.h +++ b/src/style-enums.h @@ -72,6 +72,72 @@ enum SPCSSFontStretch { SP_CSS_FONT_STRETCH_WIDER }; +// Can select more than one +enum SPCSSFontVariantLigatures { + SP_CSS_FONT_VARIANT_LIGATURES_NORMAL, + SP_CSS_FONT_VARIANT_LIGATURES_NONE, + SP_CSS_FONT_VARIANT_LIGATURES_COMMON, + SP_CSS_FONT_VARIANT_LIGATURES_NO_COMMON, + SP_CSS_FONT_VARIANT_LIGATURES_DISCRETIONARY, + SP_CSS_FONT_VARIANT_LIGATURES_NO_DISCRETIONARY, + SP_CSS_FONT_VARIANT_LIGATURES_HISTORICAL, + SP_CSS_FONT_VARIANT_LIGATURES_NO_HISTORICAL, + SP_CSS_FONT_VARIANT_LIGATURES_CONTEXTUAL, + SP_CSS_FONT_VARIANT_LIGATURES_NO_CONTEXTUAL +}; + +enum SPCSSFontVariantPosition { + SP_CSS_FONT_VARIANT_POSITION_NORMAL, + SP_CSS_FONT_VARIANT_POSITION_SUB, + SP_CSS_FONT_VARIANT_POSITION_SUPER +}; + +enum SPCSSFontVariantCaps { + SP_CSS_FONT_VARIANT_CAPS_NORMAL, + SP_CSS_FONT_VARIANT_CAPS_SMALL, + SP_CSS_FONT_VARIANT_CAPS_ALL_SMALL, + SP_CSS_FONT_VARIANT_CAPS_PETITE, + SP_CSS_FONT_VARIANT_CAPS_ALL_PETITE, + SP_CSS_FONT_VARIANT_CAPS_UNICASE, + SP_CSS_FONT_VARIANT_CAPS_TITLING, +}; + +enum SPCSSFontVariantNumeric { + SP_CSS_FONT_VARIANT_NUMERIC_NORMAL, + SP_CSS_FONT_VARIANT_NUMERIC_LINING_NUMS, + SP_CSS_FONT_VARIANT_NUMERIC_OLDSTYLE_NUMS, + SP_CSS_FONT_VARIANT_NUMERIC_PROPORTIONAL_NUMS, + SP_CSS_FONT_VARIANT_NUMERIC_TABULAR_NUMS, + SP_CSS_FONT_VARIANT_NUMERIC_DIAGONAL_FRACTIONS, + SP_CSS_FONT_VARIANT_NUMERIC_STACKED_FRACTIONS, + SP_CSS_FONT_VARIANT_NUMERIC_ORDINAL, + SP_CSS_FONT_VARIANT_NUMERIC_SLASHED_ZERO +}; + +enum SPCSSFontVariantAlternates { + SP_CSS_FONT_VARIANT_ALTERNATES_NORMAL, + SP_CSS_FONT_VARIANT_ALTERNATES_HISTORICAL_FORMS, + SP_CSS_FONT_VARIANT_ALTERNATES_STYLISTIC, + SP_CSS_FONT_VARIANT_ALTERNATES_STYLESET, + SP_CSS_FONT_VARIANT_ALTERNATES_CHARACTER_VARIANT, + SP_CSS_FONT_VARIANT_ALTERNATES_SWASH, + SP_CSS_FONT_VARIANT_ALTERNATES_ORNAMENTS, + SP_CSS_FONT_VARIANT_ALTERNATES_ANNOTATION +}; + +enum SPCSSFontVariantEastAsian { + SP_CSS_FONT_VARIANT_EAST_ASIAN_NORMAL, + SP_CSS_FONT_VARIANT_EAST_ASIAN_JIS78, + SP_CSS_FONT_VARIANT_EAST_ASIAN_JIS83, + SP_CSS_FONT_VARIANT_EAST_ASIAN_JIS90, + SP_CSS_FONT_VARIANT_EAST_ASIAN_JIS04, + SP_CSS_FONT_VARIANT_EAST_ASIAN_SIMPLIFIED, + SP_CSS_FONT_VARIANT_EAST_ASIAN_TRADITIONAL, + SP_CSS_FONT_VARIANT_EAST_ASIAN_FULL_WIDTH, + SP_CSS_FONT_VARIANT_EAST_ASIAN_PROPORTIONAL_WIDTH, + SP_CSS_FONT_VARIANT_EAST_ASIAN_RUBY +}; + enum SPCSSTextAlign { SP_CSS_TEXT_ALIGN_START, SP_CSS_TEXT_ALIGN_END, @@ -309,6 +375,77 @@ static SPStyleEnum const enum_font_stretch[] = { {NULL, -1} }; +static SPStyleEnum const enum_font_variant_ligatures[] = { + {"normal", SP_CSS_FONT_VARIANT_LIGATURES_NORMAL}, + {"none", SP_CSS_FONT_VARIANT_LIGATURES_NONE}, + {"common-ligatures", SP_CSS_FONT_VARIANT_LIGATURES_COMMON}, + {"no-common-ligatures", SP_CSS_FONT_VARIANT_LIGATURES_NO_COMMON}, + {"discretionary-ligatures", SP_CSS_FONT_VARIANT_LIGATURES_DISCRETIONARY}, + {"no-discretionary-ligatures", SP_CSS_FONT_VARIANT_LIGATURES_NO_DISCRETIONARY}, + {"historical-ligatures", SP_CSS_FONT_VARIANT_LIGATURES_HISTORICAL}, + {"nohistorical-ligatures", SP_CSS_FONT_VARIANT_LIGATURES_NO_HISTORICAL}, + {"contextual", SP_CSS_FONT_VARIANT_LIGATURES_CONTEXTUAL}, + {"no-contextual", SP_CSS_FONT_VARIANT_LIGATURES_NO_CONTEXTUAL}, + {NULL, -1} +}; + +static SPStyleEnum const enum_font_variant_position[] = { + {"normal", SP_CSS_FONT_VARIANT_POSITION_NORMAL}, + {"sub", SP_CSS_FONT_VARIANT_POSITION_SUB}, + {"super", SP_CSS_FONT_VARIANT_POSITION_SUPER}, + {NULL, -1} +}; + +static SPStyleEnum const enum_font_variant_caps[] = { + {"normal", SP_CSS_FONT_VARIANT_CAPS_NORMAL}, + {"small-caps", SP_CSS_FONT_VARIANT_CAPS_SMALL}, + {"all-small-caps", SP_CSS_FONT_VARIANT_CAPS_ALL_SMALL}, + {"petite-caps", SP_CSS_FONT_VARIANT_CAPS_PETITE}, + {"all_petite-caps", SP_CSS_FONT_VARIANT_CAPS_ALL_PETITE}, + {"unicase", SP_CSS_FONT_VARIANT_CAPS_UNICASE}, + {"titling", SP_CSS_FONT_VARIANT_CAPS_TITLING}, + {NULL, -1} +}; + +static SPStyleEnum const enum_font_variant_numeric[] = { + {"normal", SP_CSS_FONT_VARIANT_NUMERIC_NORMAL}, + {"lining-nums", SP_CSS_FONT_VARIANT_NUMERIC_LINING_NUMS}, + {"oldstyle-nums", SP_CSS_FONT_VARIANT_NUMERIC_OLDSTYLE_NUMS}, + {"proportional-nums", SP_CSS_FONT_VARIANT_NUMERIC_PROPORTIONAL_NUMS}, + {"tabular-nums", SP_CSS_FONT_VARIANT_NUMERIC_TABULAR_NUMS}, + {"diagonal-fractions", SP_CSS_FONT_VARIANT_NUMERIC_DIAGONAL_FRACTIONS}, + {"stacked-fractions", SP_CSS_FONT_VARIANT_NUMERIC_STACKED_FRACTIONS}, + {"ordinal", SP_CSS_FONT_VARIANT_NUMERIC_ORDINAL}, + {"slashed-zero", SP_CSS_FONT_VARIANT_NUMERIC_SLASHED_ZERO}, + {NULL, -1} +}; + +static SPStyleEnum const enum_font_variant_alternates[] = { + {"normal", SP_CSS_FONT_VARIANT_ALTERNATES_NORMAL}, + {"historical-forms", SP_CSS_FONT_VARIANT_ALTERNATES_HISTORICAL_FORMS}, + {"stylistic", SP_CSS_FONT_VARIANT_ALTERNATES_STYLISTIC}, + {"styleset", SP_CSS_FONT_VARIANT_ALTERNATES_STYLESET}, + {"character_variant", SP_CSS_FONT_VARIANT_ALTERNATES_CHARACTER_VARIANT}, + {"swash", SP_CSS_FONT_VARIANT_ALTERNATES_SWASH}, + {"ornaments", SP_CSS_FONT_VARIANT_ALTERNATES_ORNAMENTS}, + {"annotation", SP_CSS_FONT_VARIANT_ALTERNATES_ANNOTATION}, + {NULL, -1} +}; + +static SPStyleEnum const enum_font_variant_east_asian[] = { + {"normal", SP_CSS_FONT_VARIANT_EAST_ASIAN_NORMAL}, + {"jis78", SP_CSS_FONT_VARIANT_EAST_ASIAN_JIS78}, + {"jis83", SP_CSS_FONT_VARIANT_EAST_ASIAN_JIS83}, + {"jis90", SP_CSS_FONT_VARIANT_EAST_ASIAN_JIS90}, + {"jis04", SP_CSS_FONT_VARIANT_EAST_ASIAN_JIS04}, + {"simplified", SP_CSS_FONT_VARIANT_EAST_ASIAN_SIMPLIFIED}, + {"traditional", SP_CSS_FONT_VARIANT_EAST_ASIAN_TRADITIONAL}, + {"full-width", SP_CSS_FONT_VARIANT_EAST_ASIAN_FULL_WIDTH}, + {"proportional-width", SP_CSS_FONT_VARIANT_EAST_ASIAN_PROPORTIONAL_WIDTH}, + {"ruby", SP_CSS_FONT_VARIANT_EAST_ASIAN_RUBY}, + {NULL, -1} +}; + static SPStyleEnum const enum_text_align[] = { {"start", SP_CSS_TEXT_ALIGN_START}, {"end", SP_CSS_TEXT_ALIGN_END}, diff --git a/src/style.cpp b/src/style.cpp index fa8aed68e..49a13604b 100644 --- a/src/style.cpp +++ b/src/style.cpp @@ -14,7 +14,7 @@ * Copyright (C) 2001 Ximian, Inc. * Copyright (C) 2005 Monash University * Copyright (C) 2012 Kris De Gussem - * Copyright (C) 2014 Tavmjong Bah + * Copyright (C) 2014-2015 Tavmjong Bah * * Released under GNU GPL, read the file 'COPYING' for more information */ @@ -118,6 +118,15 @@ SPStyle::SPStyle(SPDocument *document_in, SPObject *object_in) : font(), // SPIFont font_specification( "-inkscape-font-specification" ), // SPIString + // Font variants + font_variant_ligatures( "font-variant-ligatures", enum_font_variant_ligatures, SP_CSS_FONT_VARIANT_LIGATURES_NORMAL ), + font_variant_position( "font-variant-position", enum_font_variant_position, SP_CSS_FONT_VARIANT_POSITION_NORMAL ), + font_variant_caps( "font-variant-caps", enum_font_variant_caps, SP_CSS_FONT_VARIANT_CAPS_NORMAL ), + font_variant_numeric( "font-variant-numeric", enum_font_variant_numeric, SP_CSS_FONT_VARIANT_NUMERIC_NORMAL ), + font_variant_alternates("font-variant-alternates", enum_font_variant_alternates, SP_CSS_FONT_VARIANT_ALTERNATES_NORMAL ), + font_variant_east_asian("font-variant-east_asian", enum_font_variant_east_asian, SP_CSS_FONT_VARIANT_EAST_ASIAN_NORMAL ), + font_feature_settings( "font-feature-settings", "normal" ), + // Text related properties text_indent( "text-indent", 0.0 ), // SPILength text_align( "text-align", enum_text_align, SP_CSS_TEXT_ALIGN_START ), @@ -288,6 +297,15 @@ SPStyle::SPStyle(SPDocument *document_in, SPObject *object_in) : _properties.push_back( &font ); _properties.push_back( &font_specification ); + // Font variants + _properties.push_back( &font_variant_ligatures ); + _properties.push_back( &font_variant_position ); + _properties.push_back( &font_variant_caps ); + _properties.push_back( &font_variant_numeric ); + _properties.push_back( &font_variant_alternates ); + _properties.push_back( &font_variant_east_asian ); + _properties.push_back( &font_feature_settings ); + _properties.push_back( &text_indent ); _properties.push_back( &text_align ); @@ -374,6 +392,14 @@ SPStyle::SPStyle(SPDocument *document_in, SPObject *object_in) : // _propmap.insert( std::make_pair( font.name, reinterpret_cast(&SPStyle::font ) ) ); // _propmap.insert( std::make_pair( font_specification.name, reinterpret_cast(&SPStyle::font_specification ) ) ); + // font_variant_ligatures ); + // font_variant_position ); + // font_variant_caps ); + // font_variant_numeric ); + // font_variant_alternates ); + // font_variant_east_asian ); + // font_feature_settings ); + // _propmap.insert( std::make_pair( text_indent.name, reinterpret_cast(&SPStyle::text_indent ) ) ); // _propmap.insert( std::make_pair( text_align.name, reinterpret_cast(&SPStyle::text_align ) ) ); @@ -574,9 +600,9 @@ SPStyle::read( SPObject *object, Inkscape::XML::Node *repr ) { // std::cout << " MERGING PRESENTATION ATTRIBUTES" << std::endl; for(std::vector::size_type i = 0; i != _properties.size(); ++i) { - // Shorthands are not allowed as presentation properites. - // Note: text-decoration is converted to a shorthand in CSS 3 but can still be - // read as a non-shorthand so it should not be in this list. + // Shorthands are not allowed as presentation properites. Note: text-decoration and + // font-variant are converted to shorthands in CSS 3 but can still be read as a + // non-shorthand for compatability with older renders, so they should not be in this list. // We could add a flag to SPIBase to avoid string comparison. if( _properties[i]->name.compare( "font" ) != 0 && _properties[i]->name.compare( "marker" ) != 0 ) { @@ -694,6 +720,29 @@ SPStyle::readIfUnset( gint id, gchar const *val ) { font.readIfUnset( val ); break; + /* Font Variants CSS 3 */ + case SP_PROP_FONT_VARIANT_LIGATURES: + font_variant_ligatures.readIfUnset( val ); + break; + case SP_PROP_FONT_VARIANT_POSITION: + font_variant_position.readIfUnset( val ); + break; + case SP_PROP_FONT_VARIANT_CAPS: + font_variant_caps.readIfUnset( val ); + break; + case SP_PROP_FONT_VARIANT_NUMERIC: + font_variant_numeric.readIfUnset( val ); + break; + case SP_PROP_FONT_VARIANT_ALTERNATES: + font_variant_alternates.readIfUnset( val ); + break; + case SP_PROP_FONT_VARIANT_EAST_ASIAN: + font_variant_east_asian.readIfUnset( val ); + break; + case SP_PROP_FONT_FEATURE_SETTINGS: + font_feature_settings.readIfUnset( val ); + break; + /* Text */ case SP_PROP_TEXT_INDENT: text_indent.readIfUnset( val ); diff --git a/src/style.h b/src/style.h index ab34476b3..2618662f5 100644 --- a/src/style.h +++ b/src/style.h @@ -94,7 +94,7 @@ public: /** Font style */ SPIEnum font_style; - /** Which substyle of the font */ + /** Which substyle of the font (CSS 2. CSS 3 redefines as shorthand) */ SPIEnum font_variant; /** Weight of the font */ SPIEnum font_weight; @@ -111,6 +111,22 @@ public: /** Full font name, as font_factory::ConstructFontSpecification would give, for internal use. */ SPIString font_specification; + /* Font variants -------------------- */ + /** Font variant ligatures */ + SPIEnum font_variant_ligatures; + /** Font variant position (subscript/superscript) */ + SPIEnum font_variant_position; + /** Font variant caps (small caps) */ + SPIEnum font_variant_caps; + /** Font variant numeric (numerical formatting) */ + SPIEnum font_variant_numeric; + /** Font variant alternates (alternates/swatches) */ + SPIEnum font_variant_alternates; + /** Font variant East Asian */ + SPIEnum font_variant_east_asian; + /** Font feature settings (Low level access to TrueType tables) */ + SPIString font_feature_settings; + /* Text ----------------------------- */ /** First line indent of paragraphs (css2 16.1) */ -- cgit v1.2.3 From 9c2dcd93aa8c7e2975bda72f92603fcd0a343a95 Mon Sep 17 00:00:00 2001 From: Nicolas Dufour Date: Wed, 6 May 2015 17:21:03 +0200 Subject: UI. Fix for Bug #1450877 (GUI glitch in Object Properties) Fixed bugs: - https://launchpad.net/bugs/1450877 (bzr r14116) --- src/ui/dialog/object-properties.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/ui/dialog/object-properties.cpp b/src/ui/dialog/object-properties.cpp index dfe211e94..fc21a30d4 100644 --- a/src/ui/dialog/object-properties.cpp +++ b/src/ui/dialog/object-properties.cpp @@ -467,14 +467,14 @@ void ObjectProperties::_labelChanged() gchar *id = g_strdup(_entry_id.get_text().c_str()); g_strcanon(id, "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_.:", '_'); if (strcmp(id, item->getId()) == 0) { - _label_id.set_markup_with_mnemonic(_("_ID:")); + _label_id.set_markup_with_mnemonic(_("_ID:") + Glib::ustring(" ")); } else if (!*id || !isalnum (*id)) { _label_id.set_text(_("Id invalid! ")); } else if (SP_ACTIVE_DOCUMENT->getObjectById(id) != NULL) { _label_id.set_text(_("Id exists! ")); } else { SPException ex; - _label_id.set_markup_with_mnemonic(_("_ID:")); + _label_id.set_markup_with_mnemonic(_("_ID:") + Glib::ustring(" ")); SP_EXCEPTION_INIT(&ex); item->setAttribute("id", id, &ex); DocumentUndo::done(SP_ACTIVE_DOCUMENT, SP_VERB_DIALOG_ITEM, _("Set object ID")); -- cgit v1.2.3 From 8c3f982781088c386acb4105119b19d9c7160502 Mon Sep 17 00:00:00 2001 From: Marc Jeanmougin Date: Thu, 7 May 2015 00:10:23 +0200 Subject: fix crash due to logic error in Selection::_removeObjectDescendants (bzr r14117) --- src/selection.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/selection.cpp b/src/selection.cpp index 53772c381..f728f3381 100644 --- a/src/selection.cpp +++ b/src/selection.cpp @@ -481,17 +481,21 @@ std::vector Selection::getSnapPoints(SnapPreferenc } void Selection::_removeObjectDescendants(SPObject *obj) { + std::vector toremove; for ( std::list::const_iterator iter=_objs.begin();iter!=_objs.end();iter++ ) { SPObject *sel_obj= *iter; SPObject *parent = sel_obj->parent; while (parent) { if ( parent == obj ) { - _remove(sel_obj); + toremove.push_back(sel_obj); break; } parent = parent->parent; } } + for ( std::vector::const_iterator iter=toremove.begin();iter!=toremove.end();iter++ ) { + _remove(*iter); + } } void Selection::_removeObjectAncestors(SPObject *obj) { -- cgit v1.2.3 From fe6f8f1b7976197de20964be02e594d058aead84 Mon Sep 17 00:00:00 2001 From: Marc Jeanmougin Date: Thu, 7 May 2015 00:39:26 +0200 Subject: "select same..." no longer returns groups. (bzr r14118) --- src/selection-chemistry.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'src') diff --git a/src/selection-chemistry.cpp b/src/selection-chemistry.cpp index f444f4217..7a5c2c2d5 100644 --- a/src/selection-chemistry.cpp +++ b/src/selection-chemistry.cpp @@ -1837,6 +1837,15 @@ void sp_select_same_fill_stroke_style(SPDesktop *desktop, gboolean fill, gboolea Inkscape::Selection *selection = desktop->getSelection(); std::vector items = selection->itemList(); + + std::vector tmp; + for (std::vector::const_iterator iter=all_list.begin();iter!=all_list.end();iter++) { + if(!SP_IS_GROUP(*iter)){ + tmp.push_back(*iter); + } + } + all_list=tmp; + for (std::vector::const_iterator sel_iter=items.begin();sel_iter!=items.end();sel_iter++) { SPItem *sel = *sel_iter; std::vector matches = all_list; -- cgit v1.2.3 From c8aad8eba683cd12ddfde4acca3870e859216f21 Mon Sep 17 00:00:00 2001 From: Marc Jeanmougin Date: Thu, 7 May 2015 01:18:59 +0200 Subject: fix sorts (bzr r14119) --- src/selection-chemistry.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/selection-chemistry.cpp b/src/selection-chemistry.cpp index 7a5c2c2d5..8bc62d4b9 100644 --- a/src/selection-chemistry.cpp +++ b/src/selection-chemistry.cpp @@ -927,7 +927,7 @@ static SPObject *prev_sibling(SPObject *child) return prev; } -int sp_item_repr_compare_position_obj(SPObject const *first, SPObject const *second) +bool sp_item_repr_compare_position_bool(SPObject const *first, SPObject const *second) { return sp_repr_compare_position(((SPItem*)first)->getRepr(), ((SPItem*)second)->getRepr())<0; @@ -952,7 +952,7 @@ sp_selection_raise(Inkscape::Selection *selection, SPDesktop *desktop) /* Construct reverse-ordered list of selected children. */ std::vector rev(items); - sort(rev.begin(),rev.end(),sp_item_repr_compare_position); + sort(rev.begin(),rev.end(),sp_item_repr_compare_position_bool); // Determine the common bbox of the selected items. Geom::OptRect selected = enclose_items(items); @@ -1034,7 +1034,7 @@ void sp_selection_lower(Inkscape::Selection *selection, SPDesktop *desktop) /* Construct direct-ordered list of selected children. */ std::vector rev(items); - sort(rev.begin(),rev.end(),sp_item_repr_compare_position); + sort(rev.begin(),rev.end(),sp_item_repr_compare_position_bool); // Iterate over all objects in the selection (starting from top). if (selected) { @@ -3518,7 +3518,7 @@ void sp_selection_create_bitmap_copy(SPDesktop *desktop) std::vector items(selection->itemList()); // Sort items so that the topmost comes last - sort(items.begin(),items.end(),sp_item_repr_compare_position); + sort(items.begin(),items.end(),sp_item_repr_compare_position_bool); // Generate a random value from the current time (you may create bitmap from the same object(s) // multiple times, and this is done so that they don't clash) -- cgit v1.2.3 From a06c4852edb10e38fce19fd2df3833c03b6a15e4 Mon Sep 17 00:00:00 2001 From: Marc Jeanmougin Date: Fri, 8 May 2015 00:12:09 +0200 Subject: fix crash when converting a group of objects to path (bzr r14121) --- src/path-chemistry.cpp | 8 ++++++-- src/selection-chemistry.cpp | 16 ++++++++++++---- src/ui/tools/eraser-tool.cpp | 4 +++- 3 files changed, 21 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/path-chemistry.cpp b/src/path-chemistry.cpp index 8d2695b85..98148b916 100644 --- a/src/path-chemistry.cpp +++ b/src/path-chemistry.cpp @@ -388,7 +388,9 @@ sp_item_list_to_curves(const std::vector &items, std::vector& if (repr) { to_select.insert(to_select.begin(),repr); did = true; - selected.erase(find(selected.begin(),selected.end(),item)); + std::vector::iterator element=find(selected.begin(),selected.end(),item); + if(element != selected.end()) + selected.erase(find(selected.begin(),selected.end(),item)); } continue; @@ -413,7 +415,9 @@ sp_item_list_to_curves(const std::vector &items, std::vector& continue; did = true; - selected.erase(find(selected.begin(),selected.end(),item)); + std::vector::iterator element=find(selected.begin(),selected.end(),item); + if(element != selected.end()) + selected.erase(element); // remember the position of the item gint pos = item->getRepr()->position(); diff --git a/src/selection-chemistry.cpp b/src/selection-chemistry.cpp index 8bc62d4b9..3a68b03e5 100644 --- a/src/selection-chemistry.cpp +++ b/src/selection-chemistry.cpp @@ -3922,7 +3922,9 @@ void sp_selection_set_mask(SPDesktop *desktop, bool apply_clip_path, bool apply_ for (GSList *i = apply_to_items ; NULL != i ; i = i->next) { reprs_to_group.push_back(static_cast(i->data)->getRepr()); - items_to_select.erase(find(items_to_select.begin(),items_to_select.end(),static_cast(i->data))); + std::vector::iterator element = find(items_to_select.begin(),items_to_select.end(),static_cast(i->data)); + if(element != items_to_select.end()) + items_to_select.erase(element); } sp_selection_group_impl(reprs_to_group, group, xml_doc, doc); @@ -3972,7 +3974,9 @@ void sp_selection_set_mask(SPDesktop *desktop, bool apply_clip_path, bool apply_ Inkscape::XML::Node *spnew = current->duplicate(xml_doc); gint position = current->position(); - items_to_select.erase(find(items_to_select.begin(),items_to_select.end(),item)); + std::vector::iterator element = find(items_to_select.begin(),items_to_select.end(),item); + if(element != items_to_select.end()) + items_to_select.erase(element); current->parent()->appendChild(group); sp_repr_unparent(current); group->appendChild(spnew); @@ -3996,7 +4000,9 @@ void sp_selection_set_mask(SPDesktop *desktop, bool apply_clip_path, bool apply_ for (GSList *i = items_to_delete; NULL != i; i = i->next) { SPObject *item = reinterpret_cast(i->data); item->deleteObject(false); - items_to_select.erase(find(items_to_select.begin(),items_to_select.end(),item)); + std::vector::iterator element = find(items_to_select.begin(),items_to_select.end(),item); + if(element != items_to_select.end()) + items_to_select.erase(element); } g_slist_free(items_to_delete); @@ -4121,7 +4127,9 @@ void sp_selection_unset_mask(SPDesktop *desktop, bool apply_clip_path) { for (GSList *i = items_to_ungroup ; NULL != i ; i = i->next) { SPGroup *group = dynamic_cast(static_cast(i->data)); if (group) { - items_to_select.erase(find(items_to_select.begin(),items_to_select.end(),group)); + std::vector::iterator element = find(items_to_select.begin(),items_to_select.end(),group); + if(element != items_to_select.end()) + items_to_select.erase(element); std::vector children; sp_item_group_ungroup(group, children, false); items_to_select.insert(items_to_select.end(),children.rbegin(),children.rend()); diff --git a/src/ui/tools/eraser-tool.cpp b/src/ui/tools/eraser-tool.cpp index 01b75fdb4..0af347bef 100644 --- a/src/ui/tools/eraser-tool.cpp +++ b/src/ui/tools/eraser-tool.cpp @@ -674,7 +674,9 @@ void EraserTool::set_to_accumulated() { Inkscape::Rubberband *r = Inkscape::Rubberband::get(desktop); toWorkOn = desktop->getDocument()->getItemsAtPoints(desktop->dkey, r->getPoints()); } - toWorkOn.erase(find(toWorkOn.begin(),toWorkOn.end(),acid)); + std::vector::iterator element = find(toWorkOn.begin(),toWorkOn.end(),acid); + if(element != toWorkOn.end()) + toWorkOn.erase(element); } else { toWorkOn= selection->itemList(); wasSelection = true; -- cgit v1.2.3 From fbe59eb1913a779115d9c4769a4066d08e30ff44 Mon Sep 17 00:00:00 2001 From: Marc Jeanmougin Date: Fri, 8 May 2015 00:25:20 +0200 Subject: better fix, using std::remove instead of std::erase (bzr r14122) --- src/path-chemistry.cpp | 8 ++------ src/selection-chemistry.cpp | 16 ++++------------ src/ui/tools/eraser-tool.cpp | 4 +--- 3 files changed, 7 insertions(+), 21 deletions(-) (limited to 'src') diff --git a/src/path-chemistry.cpp b/src/path-chemistry.cpp index 98148b916..ff307cd66 100644 --- a/src/path-chemistry.cpp +++ b/src/path-chemistry.cpp @@ -388,9 +388,7 @@ sp_item_list_to_curves(const std::vector &items, std::vector& if (repr) { to_select.insert(to_select.begin(),repr); did = true; - std::vector::iterator element=find(selected.begin(),selected.end(),item); - if(element != selected.end()) - selected.erase(find(selected.begin(),selected.end(),item)); + remove(selected.begin(),selected.end(),item); } continue; @@ -415,9 +413,7 @@ sp_item_list_to_curves(const std::vector &items, std::vector& continue; did = true; - std::vector::iterator element=find(selected.begin(),selected.end(),item); - if(element != selected.end()) - selected.erase(element); + remove(selected.begin(),selected.end(),item); // remember the position of the item gint pos = item->getRepr()->position(); diff --git a/src/selection-chemistry.cpp b/src/selection-chemistry.cpp index 3a68b03e5..1e3afc6a8 100644 --- a/src/selection-chemistry.cpp +++ b/src/selection-chemistry.cpp @@ -3922,9 +3922,7 @@ void sp_selection_set_mask(SPDesktop *desktop, bool apply_clip_path, bool apply_ for (GSList *i = apply_to_items ; NULL != i ; i = i->next) { reprs_to_group.push_back(static_cast(i->data)->getRepr()); - std::vector::iterator element = find(items_to_select.begin(),items_to_select.end(),static_cast(i->data)); - if(element != items_to_select.end()) - items_to_select.erase(element); + remove(items_to_select.begin(),items_to_select.end(),static_cast(i->data)); } sp_selection_group_impl(reprs_to_group, group, xml_doc, doc); @@ -3974,9 +3972,7 @@ void sp_selection_set_mask(SPDesktop *desktop, bool apply_clip_path, bool apply_ Inkscape::XML::Node *spnew = current->duplicate(xml_doc); gint position = current->position(); - std::vector::iterator element = find(items_to_select.begin(),items_to_select.end(),item); - if(element != items_to_select.end()) - items_to_select.erase(element); + remove(items_to_select.begin(),items_to_select.end(),item); current->parent()->appendChild(group); sp_repr_unparent(current); group->appendChild(spnew); @@ -4000,9 +3996,7 @@ void sp_selection_set_mask(SPDesktop *desktop, bool apply_clip_path, bool apply_ for (GSList *i = items_to_delete; NULL != i; i = i->next) { SPObject *item = reinterpret_cast(i->data); item->deleteObject(false); - std::vector::iterator element = find(items_to_select.begin(),items_to_select.end(),item); - if(element != items_to_select.end()) - items_to_select.erase(element); + remove(items_to_select.begin(),items_to_select.end(),item); } g_slist_free(items_to_delete); @@ -4127,9 +4121,7 @@ void sp_selection_unset_mask(SPDesktop *desktop, bool apply_clip_path) { for (GSList *i = items_to_ungroup ; NULL != i ; i = i->next) { SPGroup *group = dynamic_cast(static_cast(i->data)); if (group) { - std::vector::iterator element = find(items_to_select.begin(),items_to_select.end(),group); - if(element != items_to_select.end()) - items_to_select.erase(element); + remove(items_to_select.begin(),items_to_select.end(),group); std::vector children; sp_item_group_ungroup(group, children, false); items_to_select.insert(items_to_select.end(),children.rbegin(),children.rend()); diff --git a/src/ui/tools/eraser-tool.cpp b/src/ui/tools/eraser-tool.cpp index 0af347bef..8a9db6c72 100644 --- a/src/ui/tools/eraser-tool.cpp +++ b/src/ui/tools/eraser-tool.cpp @@ -674,9 +674,7 @@ void EraserTool::set_to_accumulated() { Inkscape::Rubberband *r = Inkscape::Rubberband::get(desktop); toWorkOn = desktop->getDocument()->getItemsAtPoints(desktop->dkey, r->getPoints()); } - std::vector::iterator element = find(toWorkOn.begin(),toWorkOn.end(),acid); - if(element != toWorkOn.end()) - toWorkOn.erase(element); + std::remove(toWorkOn.begin(),toWorkOn.end(),acid); } else { toWorkOn= selection->itemList(); wasSelection = true; -- cgit v1.2.3 From 57808dd1abe86ae0088a74bd88041321f5df5fb8 Mon Sep 17 00:00:00 2001 From: Marc Jeanmougin Date: Fri, 8 May 2015 00:45:15 +0200 Subject: fix for stl "remove" (bzr r14123) --- src/path-chemistry.cpp | 4 ++-- src/selection-chemistry.cpp | 8 ++++---- src/ui/tools/eraser-tool.cpp | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/path-chemistry.cpp b/src/path-chemistry.cpp index ff307cd66..7bd5b6298 100644 --- a/src/path-chemistry.cpp +++ b/src/path-chemistry.cpp @@ -388,7 +388,7 @@ sp_item_list_to_curves(const std::vector &items, std::vector& if (repr) { to_select.insert(to_select.begin(),repr); did = true; - remove(selected.begin(),selected.end(),item); + selected.erase(remove(selected.begin(), selected.end(), item), selected.end()); } continue; @@ -413,7 +413,7 @@ sp_item_list_to_curves(const std::vector &items, std::vector& continue; did = true; - remove(selected.begin(),selected.end(),item); + selected.erase(remove(selected.begin(), selected.end(), item), selected.end()); // remember the position of the item gint pos = item->getRepr()->position(); diff --git a/src/selection-chemistry.cpp b/src/selection-chemistry.cpp index 1e3afc6a8..2cd4f6b4e 100644 --- a/src/selection-chemistry.cpp +++ b/src/selection-chemistry.cpp @@ -3922,7 +3922,7 @@ void sp_selection_set_mask(SPDesktop *desktop, bool apply_clip_path, bool apply_ for (GSList *i = apply_to_items ; NULL != i ; i = i->next) { reprs_to_group.push_back(static_cast(i->data)->getRepr()); - remove(items_to_select.begin(),items_to_select.end(),static_cast(i->data)); + items_to_select.erase(remove(items_to_select.begin(), items_to_select.end(), static_cast(i->data)), items_to_select.end()); } sp_selection_group_impl(reprs_to_group, group, xml_doc, doc); @@ -3972,7 +3972,7 @@ void sp_selection_set_mask(SPDesktop *desktop, bool apply_clip_path, bool apply_ Inkscape::XML::Node *spnew = current->duplicate(xml_doc); gint position = current->position(); - remove(items_to_select.begin(),items_to_select.end(),item); + items_to_select.erase(remove(items_to_select.begin(), items_to_select.end(), item), items_to_select.end()); current->parent()->appendChild(group); sp_repr_unparent(current); group->appendChild(spnew); @@ -3996,7 +3996,7 @@ void sp_selection_set_mask(SPDesktop *desktop, bool apply_clip_path, bool apply_ for (GSList *i = items_to_delete; NULL != i; i = i->next) { SPObject *item = reinterpret_cast(i->data); item->deleteObject(false); - remove(items_to_select.begin(),items_to_select.end(),item); + items_to_select.erase(remove(items_to_select.begin(), items_to_select.end(), item), items_to_select.end()); } g_slist_free(items_to_delete); @@ -4121,7 +4121,7 @@ void sp_selection_unset_mask(SPDesktop *desktop, bool apply_clip_path) { for (GSList *i = items_to_ungroup ; NULL != i ; i = i->next) { SPGroup *group = dynamic_cast(static_cast(i->data)); if (group) { - remove(items_to_select.begin(),items_to_select.end(),group); + items_to_select.erase(remove(items_to_select.begin(), items_to_select.end(), group), items_to_select.end()); std::vector children; sp_item_group_ungroup(group, children, false); items_to_select.insert(items_to_select.end(),children.rbegin(),children.rend()); diff --git a/src/ui/tools/eraser-tool.cpp b/src/ui/tools/eraser-tool.cpp index 8a9db6c72..10f8c8694 100644 --- a/src/ui/tools/eraser-tool.cpp +++ b/src/ui/tools/eraser-tool.cpp @@ -674,7 +674,7 @@ void EraserTool::set_to_accumulated() { Inkscape::Rubberband *r = Inkscape::Rubberband::get(desktop); toWorkOn = desktop->getDocument()->getItemsAtPoints(desktop->dkey, r->getPoints()); } - std::remove(toWorkOn.begin(),toWorkOn.end(),acid); + toWorkOn.erase(std::remove(toWorkOn.begin(), toWorkOn.end(), acid), toWorkOn.end()); } else { toWorkOn= selection->itemList(); wasSelection = true; -- cgit v1.2.3 From 0f23d91bdb4d8fca7be0c695e65a10b205fee1fc Mon Sep 17 00:00:00 2001 From: Marc Jeanmougin Date: Fri, 8 May 2015 02:49:43 +0200 Subject: Fixed the layer blends (bzr r14124) --- src/ui/widget/object-composite-settings.cpp | 4 ++-- src/ui/widget/style-subject.cpp | 24 ++++++++++++------------ src/ui/widget/style-subject.h | 10 +++------- 3 files changed, 17 insertions(+), 21 deletions(-) (limited to 'src') diff --git a/src/ui/widget/object-composite-settings.cpp b/src/ui/widget/object-composite-settings.cpp index 598a90e95..8acf083d0 100644 --- a/src/ui/widget/object-composite-settings.cpp +++ b/src/ui/widget/object-composite-settings.cpp @@ -125,8 +125,8 @@ ObjectCompositeSettings::_blendBlurValueChanged() const Glib::ustring blendmode = _fe_cb.get_blend_mode(); //apply created filter to every selected item - std::vector sel=_subject->getDesktop()->getSelection()->itemList(); - for (std::vector::const_iterator i = sel.begin() ; i != sel.end() ; ++i ) { + std::vector sel=_subject->list(); + for (std::vector::const_iterator i = sel.begin() ; i != sel.end() ; ++i ) { if (!SP_IS_ITEM(*i)) { continue; } diff --git a/src/ui/widget/style-subject.cpp b/src/ui/widget/style-subject.cpp index 95b89bf5f..da3bbcd20 100644 --- a/src/ui/widget/style-subject.cpp +++ b/src/ui/widget/style-subject.cpp @@ -54,15 +54,13 @@ Inkscape::Selection *StyleSubject::Selection::_getSelection() const { return NULL; } } -/* -StyleSubject::iterator StyleSubject::Selection::begin() { + +std::vector StyleSubject::Selection::list(){ Inkscape::Selection *selection = _getSelection(); - if (selection) { - return iterator(selection->list()); - } else { - return iterator(NULL); - } -}*/ + if(selection) + return selection->list(); + else return std::vector(); +} Geom::OptRect StyleSubject::Selection::getBounds(SPItem::BBoxType type) { Inkscape::Selection *selection = _getSelection(); @@ -133,10 +131,12 @@ SPObject *StyleSubject::CurrentLayer::_getLayerSList() const { return _element; } -/* -StyleSubject::iterator StyleSubject::CurrentLayer::begin() { - return iterator(_getLayerSList()); -}*/ + +std::vector StyleSubject::CurrentLayer::list(){ + std::vector list; + list.push_back(_element); + return list; +} Geom::OptRect StyleSubject::CurrentLayer::getBounds(SPItem::BBoxType type) { SPObject *layer = _getLayer(); diff --git a/src/ui/widget/style-subject.h b/src/ui/widget/style-subject.h index 60f979eb0..15a072f44 100644 --- a/src/ui/widget/style-subject.h +++ b/src/ui/widget/style-subject.h @@ -10,7 +10,6 @@ #ifndef SEEN_INKSCAPE_UI_WIDGET_STYLE_SUBJECT_H #define SEEN_INKSCAPE_UI_WIDGET_STYLE_SUBJECT_H -#include "util/glib-list-iterators.h" #include #include <2geom/rect.h> #include "sp-item.h" @@ -35,8 +34,6 @@ public: class Selection; class CurrentLayer; - //typedef Util::GSListConstIterator iterator; - typedef std::list::iterator iterator; StyleSubject(); virtual ~StyleSubject(); @@ -44,11 +41,10 @@ public: void setDesktop(SPDesktop *desktop); SPDesktop *getDesktop() const { return _desktop; } -// virtual iterator begin() = 0; -// virtual iterator end() { return iterator(NULL); } virtual Geom::OptRect getBounds(SPItem::BBoxType type) = 0; virtual int queryStyle(SPStyle *query, int property) = 0; virtual void setCSS(SPCSSAttr *css) = 0; + virtual std::vector list(){return std::vector();}; sigc::connection connectChanged(sigc::signal::slot_type slot) { return _changed_signal.connect(slot); @@ -68,10 +64,10 @@ public: Selection(); ~Selection(); -// virtual iterator begin(); virtual Geom::OptRect getBounds(SPItem::BBoxType type); virtual int queryStyle(SPStyle *query, int property); virtual void setCSS(SPCSSAttr *css); + virtual std::vector list(); protected: virtual void _afterDesktopSwitch(SPDesktop *desktop); @@ -89,10 +85,10 @@ public: CurrentLayer(); ~CurrentLayer(); -// virtual iterator begin(); virtual Geom::OptRect getBounds(SPItem::BBoxType type); virtual int queryStyle(SPStyle *query, int property); virtual void setCSS(SPCSSAttr *css); + virtual std::vector list(); protected: virtual void _afterDesktopSwitch(SPDesktop *desktop); -- cgit v1.2.3 From 9102ee49b968e55e93a7f6ccfb563c8571bf458c Mon Sep 17 00:00:00 2001 From: Marc Jeanmougin Date: Fri, 8 May 2015 03:22:12 +0200 Subject: forgotten dynamic cast (bzr r14125) --- src/extension/internal/latex-text-renderer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/extension/internal/latex-text-renderer.cpp b/src/extension/internal/latex-text-renderer.cpp index ab863f8b1..1026f51ad 100644 --- a/src/extension/internal/latex-text-renderer.cpp +++ b/src/extension/internal/latex-text-renderer.cpp @@ -230,7 +230,7 @@ void LaTeXTextRenderer::sp_group_render(SPGroup *group) { std::vector l = (group->childList(false)); for(std::vector::const_iterator x = l.begin(); x != l.end(); x++){ - SPItem *item = static_cast(*x); + SPItem *item = dynamic_cast(*x); if (item) { renderItem(item); } -- cgit v1.2.3 From e110371c4d69ea0a407d7500b156cf373109787b Mon Sep 17 00:00:00 2001 From: Krzysztof Kosi??ski Date: Fri, 8 May 2015 08:29:58 +0200 Subject: Fix node editing problems (bzr r14059.2.4) --- src/2geom/path-sink.h | 4 ++ src/2geom/pathvector.h | 3 +- src/2geom/svg-path-parser.cpp | 105 ++++++++++++++++++++++++--------------- src/2geom/svg-path-parser.h | 16 ++++++ src/svg/svg-path.cpp | 11 ++-- src/ui/tool/path-manipulator.cpp | 10 ++-- 6 files changed, 95 insertions(+), 54 deletions(-) (limited to 'src') diff --git a/src/2geom/path-sink.h b/src/2geom/path-sink.h index 5913593d2..d6806031d 100644 --- a/src/2geom/path-sink.h +++ b/src/2geom/path-sink.h @@ -212,7 +212,11 @@ class PathBuilder : public PathIteratorSink { private: PathVector _pathset; public: + /// Create a builder that outputs to an internal pathvector. PathBuilder() : PathIteratorSink(SubpathInserter(_pathset)) {} + /// Create a builder that outputs to pathvector given by reference. + PathBuilder(PathVector &pv) : PathIteratorSink(SubpathInserter(pv)) {} + /// Retrieve the path PathVector const &peek() const {return _pathset;} /// Clear the stored path vector diff --git a/src/2geom/pathvector.h b/src/2geom/pathvector.h index 375c4f0a0..955cd1d37 100644 --- a/src/2geom/pathvector.h +++ b/src/2geom/pathvector.h @@ -112,9 +112,8 @@ class PathVector , MultipliableNoncommutative< PathVector, HShear , MultipliableNoncommutative< PathVector, VShear , MultipliableNoncommutative< PathVector, Zoom - , boost::addable< PathVector , boost::equality_comparable< PathVector - > > > > > > > > > + > > > > > > > > { typedef std::vector Sequence; public: diff --git a/src/2geom/svg-path-parser.cpp b/src/2geom/svg-path-parser.cpp index 89a912695..2778795b3 100644 --- a/src/2geom/svg-path-parser.cpp +++ b/src/2geom/svg-path-parser.cpp @@ -1,5 +1,5 @@ -#line 1 "D:/lib2geom/trunk/src/2geom/svg-path-parser.rl" +#line 1 "/home/tweenk/src/lib2geom/src/2geom/svg-path-parser.rl" /** * \file * \brief parse SVG path specifications @@ -44,7 +44,7 @@ namespace Geom { -#line 48 "D:/lib2geom/trunk/src/2geom/svg-path-parser.cpp" +#line 48 "/home/tweenk/src/lib2geom/src/2geom/svg-path-parser.cpp" static const char _svg_path_actions[] = { 0, 1, 0, 1, 1, 1, 2, 1, 3, 1, 4, 1, 5, 1, 15, 2, @@ -1075,29 +1075,38 @@ static const int svg_path_first_final = 232; static const int svg_path_en_main = 232; -#line 47 "D:/lib2geom/trunk/src/2geom/svg-path-parser.rl" +#line 47 "/home/tweenk/src/lib2geom/src/2geom/svg-path-parser.rl" SVGPathParser::SVGPathParser(PathSink &sink) : _absolute(false) , _sink(sink) + , _z_snap_threshold(0) + , _curve(NULL) { reset(); } +SVGPathParser::~SVGPathParser() +{ + delete _curve; +} + void SVGPathParser::reset() { _absolute = false; _current = _initial = Point(0, 0); _quad_tangent = _cubic_tangent = Point(0, 0); _params.clear(); + delete _curve; + _curve = NULL; -#line 1096 "D:/lib2geom/trunk/src/2geom/svg-path-parser.cpp" +#line 1105 "/home/tweenk/src/lib2geom/src/2geom/svg-path-parser.cpp" { cs = svg_path_start; } -#line 64 "D:/lib2geom/trunk/src/2geom/svg-path-parser.rl" +#line 73 "/home/tweenk/src/lib2geom/src/2geom/svg-path-parser.rl" } @@ -1162,23 +1171,24 @@ Point SVGPathParser::_pop_point() { } void SVGPathParser::_moveTo(Point const &p) { + _pushCurve(NULL); // flush _sink.moveTo(p); _quad_tangent = _cubic_tangent = _current = _initial = p; } void SVGPathParser::_lineTo(Point const &p) { - _sink.lineTo(p); + _pushCurve(new LineSegment(_current, p)); _quad_tangent = _cubic_tangent = _current = p; } void SVGPathParser::_curveTo(Point const &c0, Point const &c1, Point const &p) { - _sink.curveTo(c0, c1, p); + _pushCurve(new CubicBezier(_current, c0, c1, p)); _quad_tangent = _current = p; _cubic_tangent = p + ( p - c1 ); } void SVGPathParser::_quadTo(Point const &c, Point const &p) { - _sink.quadTo(c, p); + _pushCurve(new QuadraticBezier(_current, c, p)); _cubic_tangent = _current = p; _quad_tangent = p + ( p - c ); } @@ -1186,19 +1196,31 @@ void SVGPathParser::_quadTo(Point const &c, Point const &p) { void SVGPathParser::_arcTo(Coord rx, Coord ry, Coord angle, bool large_arc, bool sweep, Point const &p) { - if (are_near(_current, p)) { + if (_current == p) { return; // ignore invalid (ambiguous) arc segments where start and end point are the same (per SVG spec) } - _sink.arcTo(rx, ry, angle, large_arc, sweep, p); + _pushCurve(new SVGEllipticalArc(_current, rx, ry, angle, large_arc, sweep, p)); _quad_tangent = _cubic_tangent = _current = p; } void SVGPathParser::_closePath() { + if (!_absolute && _curve && are_near(_initial, _current, _z_snap_threshold)) { + _curve->setFinal(_initial); + } + _pushCurve(NULL); // flush _sink.closePath(); _quad_tangent = _cubic_tangent = _current = _initial; } +void SVGPathParser::_pushCurve(Curve *c) { + if (_curve) { + _sink.feed(*_curve, false); + delete _curve; + } + _curve = c; +} + void SVGPathParser::_parse(char const *str, char const *strend, bool finish) { char const *p = str; @@ -1207,7 +1229,7 @@ void SVGPathParser::_parse(char const *str, char const *strend, bool finish) char const *start = NULL; -#line 1211 "D:/lib2geom/trunk/src/2geom/svg-path-parser.cpp" +#line 1233 "/home/tweenk/src/lib2geom/src/2geom/svg-path-parser.cpp" { int _klen; unsigned int _trans; @@ -1282,13 +1304,13 @@ _match: switch ( *_acts++ ) { case 0: -#line 173 "D:/lib2geom/trunk/src/2geom/svg-path-parser.rl" +#line 195 "/home/tweenk/src/lib2geom/src/2geom/svg-path-parser.rl" { start = p; } break; case 1: -#line 177 "D:/lib2geom/trunk/src/2geom/svg-path-parser.rl" +#line 199 "/home/tweenk/src/lib2geom/src/2geom/svg-path-parser.rl" { if (start) { std::string buf(start, p); @@ -1302,55 +1324,55 @@ _match: } break; case 2: -#line 189 "D:/lib2geom/trunk/src/2geom/svg-path-parser.rl" +#line 211 "/home/tweenk/src/lib2geom/src/2geom/svg-path-parser.rl" { _push(1.0); } break; case 3: -#line 193 "D:/lib2geom/trunk/src/2geom/svg-path-parser.rl" +#line 215 "/home/tweenk/src/lib2geom/src/2geom/svg-path-parser.rl" { _push(0.0); } break; case 4: -#line 197 "D:/lib2geom/trunk/src/2geom/svg-path-parser.rl" +#line 219 "/home/tweenk/src/lib2geom/src/2geom/svg-path-parser.rl" { _absolute = true; } break; case 5: -#line 201 "D:/lib2geom/trunk/src/2geom/svg-path-parser.rl" +#line 223 "/home/tweenk/src/lib2geom/src/2geom/svg-path-parser.rl" { _absolute = false; } break; case 6: -#line 205 "D:/lib2geom/trunk/src/2geom/svg-path-parser.rl" +#line 227 "/home/tweenk/src/lib2geom/src/2geom/svg-path-parser.rl" { _moveTo(_pop_point()); } break; case 7: -#line 209 "D:/lib2geom/trunk/src/2geom/svg-path-parser.rl" +#line 231 "/home/tweenk/src/lib2geom/src/2geom/svg-path-parser.rl" { _lineTo(_pop_point()); } break; case 8: -#line 213 "D:/lib2geom/trunk/src/2geom/svg-path-parser.rl" +#line 235 "/home/tweenk/src/lib2geom/src/2geom/svg-path-parser.rl" { _lineTo(Point(_pop_coord(X), _current[Y])); } break; case 9: -#line 217 "D:/lib2geom/trunk/src/2geom/svg-path-parser.rl" +#line 239 "/home/tweenk/src/lib2geom/src/2geom/svg-path-parser.rl" { _lineTo(Point(_current[X], _pop_coord(Y))); } break; case 10: -#line 221 "D:/lib2geom/trunk/src/2geom/svg-path-parser.rl" +#line 243 "/home/tweenk/src/lib2geom/src/2geom/svg-path-parser.rl" { Point p = _pop_point(); Point c1 = _pop_point(); @@ -1359,7 +1381,7 @@ _match: } break; case 11: -#line 228 "D:/lib2geom/trunk/src/2geom/svg-path-parser.rl" +#line 250 "/home/tweenk/src/lib2geom/src/2geom/svg-path-parser.rl" { Point p = _pop_point(); Point c1 = _pop_point(); @@ -1367,7 +1389,7 @@ _match: } break; case 12: -#line 234 "D:/lib2geom/trunk/src/2geom/svg-path-parser.rl" +#line 256 "/home/tweenk/src/lib2geom/src/2geom/svg-path-parser.rl" { Point p = _pop_point(); Point c = _pop_point(); @@ -1375,14 +1397,14 @@ _match: } break; case 13: -#line 240 "D:/lib2geom/trunk/src/2geom/svg-path-parser.rl" +#line 262 "/home/tweenk/src/lib2geom/src/2geom/svg-path-parser.rl" { Point p = _pop_point(); _quadTo(_quad_tangent, p); } break; case 14: -#line 245 "D:/lib2geom/trunk/src/2geom/svg-path-parser.rl" +#line 267 "/home/tweenk/src/lib2geom/src/2geom/svg-path-parser.rl" { Point point = _pop_point(); bool sweep = _pop_flag(); @@ -1395,12 +1417,12 @@ _match: } break; case 15: -#line 256 "D:/lib2geom/trunk/src/2geom/svg-path-parser.rl" +#line 278 "/home/tweenk/src/lib2geom/src/2geom/svg-path-parser.rl" { _closePath(); } break; -#line 1404 "D:/lib2geom/trunk/src/2geom/svg-path-parser.cpp" +#line 1426 "/home/tweenk/src/lib2geom/src/2geom/svg-path-parser.cpp" } } @@ -1417,7 +1439,7 @@ _again: while ( __nacts-- > 0 ) { switch ( *__acts++ ) { case 1: -#line 177 "D:/lib2geom/trunk/src/2geom/svg-path-parser.rl" +#line 199 "/home/tweenk/src/lib2geom/src/2geom/svg-path-parser.rl" { if (start) { std::string buf(start, p); @@ -1431,31 +1453,31 @@ _again: } break; case 6: -#line 205 "D:/lib2geom/trunk/src/2geom/svg-path-parser.rl" +#line 227 "/home/tweenk/src/lib2geom/src/2geom/svg-path-parser.rl" { _moveTo(_pop_point()); } break; case 7: -#line 209 "D:/lib2geom/trunk/src/2geom/svg-path-parser.rl" +#line 231 "/home/tweenk/src/lib2geom/src/2geom/svg-path-parser.rl" { _lineTo(_pop_point()); } break; case 8: -#line 213 "D:/lib2geom/trunk/src/2geom/svg-path-parser.rl" +#line 235 "/home/tweenk/src/lib2geom/src/2geom/svg-path-parser.rl" { _lineTo(Point(_pop_coord(X), _current[Y])); } break; case 9: -#line 217 "D:/lib2geom/trunk/src/2geom/svg-path-parser.rl" +#line 239 "/home/tweenk/src/lib2geom/src/2geom/svg-path-parser.rl" { _lineTo(Point(_current[X], _pop_coord(Y))); } break; case 10: -#line 221 "D:/lib2geom/trunk/src/2geom/svg-path-parser.rl" +#line 243 "/home/tweenk/src/lib2geom/src/2geom/svg-path-parser.rl" { Point p = _pop_point(); Point c1 = _pop_point(); @@ -1464,7 +1486,7 @@ _again: } break; case 11: -#line 228 "D:/lib2geom/trunk/src/2geom/svg-path-parser.rl" +#line 250 "/home/tweenk/src/lib2geom/src/2geom/svg-path-parser.rl" { Point p = _pop_point(); Point c1 = _pop_point(); @@ -1472,7 +1494,7 @@ _again: } break; case 12: -#line 234 "D:/lib2geom/trunk/src/2geom/svg-path-parser.rl" +#line 256 "/home/tweenk/src/lib2geom/src/2geom/svg-path-parser.rl" { Point p = _pop_point(); Point c = _pop_point(); @@ -1480,14 +1502,14 @@ _again: } break; case 13: -#line 240 "D:/lib2geom/trunk/src/2geom/svg-path-parser.rl" +#line 262 "/home/tweenk/src/lib2geom/src/2geom/svg-path-parser.rl" { Point p = _pop_point(); _quadTo(_quad_tangent, p); } break; case 14: -#line 245 "D:/lib2geom/trunk/src/2geom/svg-path-parser.rl" +#line 267 "/home/tweenk/src/lib2geom/src/2geom/svg-path-parser.rl" { Point point = _pop_point(); bool sweep = _pop_flag(); @@ -1500,12 +1522,12 @@ _again: } break; case 15: -#line 256 "D:/lib2geom/trunk/src/2geom/svg-path-parser.rl" +#line 278 "/home/tweenk/src/lib2geom/src/2geom/svg-path-parser.rl" { _closePath(); } break; -#line 1509 "D:/lib2geom/trunk/src/2geom/svg-path-parser.cpp" +#line 1531 "/home/tweenk/src/lib2geom/src/2geom/svg-path-parser.cpp" } } } @@ -1513,7 +1535,7 @@ _again: _out: {} } -#line 398 "D:/lib2geom/trunk/src/2geom/svg-path-parser.rl" +#line 420 "/home/tweenk/src/lib2geom/src/2geom/svg-path-parser.rl" if (finish) { @@ -1525,6 +1547,7 @@ _again: } if (finish) { + _pushCurve(NULL); _sink.flush(); reset(); } diff --git a/src/2geom/svg-path-parser.h b/src/2geom/svg-path-parser.h index 6478ba468..094ecd4da 100644 --- a/src/2geom/svg-path-parser.h +++ b/src/2geom/svg-path-parser.h @@ -40,6 +40,7 @@ #include <2geom/exception.h> #include <2geom/point.h> #include <2geom/path-sink.h> +#include <2geom/forward.h> namespace Geom { @@ -60,6 +61,7 @@ namespace Geom { class SVGPathParser { public: SVGPathParser(PathSink &sink); + ~SVGPathParser(); /** @brief Reset internal state. * Discards the internal state associated with partially parsed data, @@ -94,6 +96,17 @@ public: * You should not call this after parse(). */ void finish(); + /** @brief Set the threshold for considering the closing segment degenerate. + * When the current point was reached by a relative command, is closer + * to the initial point of the path than the specified threshold + * and a 'z' is encountered, the last segment will be adjusted instead so that + * the closing segment has exactly zero length. This is useful when reading + * SVG 1.1 paths that have non-linear final segments written in relative + * coordinates, which always suffer from some loss of precision. SVG 2 + * allows alternate placement of 'z' which does not have this problem. */ + void setZSnapThreshold(Coord threshold) { _z_snap_threshold = threshold; } + Coord zSnapThreshold() const { return _z_snap_threshold; } + private: bool _absolute; Point _current; @@ -102,6 +115,8 @@ private: Point _quad_tangent; std::vector _params; PathSink &_sink; + Coord _z_snap_threshold; + Curve *_curve; int cs; std::string _number_part; @@ -118,6 +133,7 @@ private: void _arcTo(double rx, double ry, double angle, bool large_arc, bool sweep, Point const &p); void _closePath(); + void _pushCurve(Curve *c); void _parse(char const *str, char const *strend, bool finish); }; diff --git a/src/svg/svg-path.cpp b/src/svg/svg-path.cpp index 8f839eca5..ab51a5537 100644 --- a/src/svg/svg-path.cpp +++ b/src/svg/svg-path.cpp @@ -43,16 +43,15 @@ Geom::PathVector sp_svg_read_pathv(char const * str) if (!str) return pathv; // return empty pathvector when str == NULL - - typedef std::back_insert_iterator Inserter; - Inserter iter(pathv); - Geom::PathIteratorSink generator(iter); + Geom::PathBuilder builder(pathv); + Geom::SVGPathParser parser(builder); + parser.setZSnapThreshold(Geom::EPSILON); try { - Geom::parse_svg_path(str, generator); + parser.parse(str); } catch (Geom::SVGPathParseError &e) { - generator.flush(); + builder.flush(); // This warning is extremely annoying when testing //g_warning("Malformed SVG path, truncated path up to where error was found.\n Input path=\"%s\"\n Parsed path=\"%s\"", str, sp_svg_write_path(pathv)); } diff --git a/src/ui/tool/path-manipulator.cpp b/src/ui/tool/path-manipulator.cpp index e54764216..bbedb8263 100644 --- a/src/ui/tool/path-manipulator.cpp +++ b/src/ui/tool/path-manipulator.cpp @@ -1148,15 +1148,15 @@ void PathManipulator::_createControlPointsFromGeometry() Node *previous_node = new Node(_multi_path_manipulator._path_data.node_data, pit->initialPoint()); subpath->push_back(previous_node); - Geom::Curve const &cseg = pit->back_closed(); - bool fuse_ends = pit->closed() - && Geom::are_near(cseg.initialPoint(), cseg.finalPoint()); - for (Geom::Path::iterator cit = pit->begin(); cit != pit->end_open(); ++cit) { + + bool closed = pit->closed(); + + for (Geom::Path::iterator cit = pit->begin(); cit != pit->end(); ++cit) { Geom::Point pos = cit->finalPoint(); Node *current_node; // if the closing segment is degenerate and the path is closed, we need to move // the handle of the first node instead of creating a new one - if (fuse_ends && cit == --(pit->end_open())) { + if (closed && cit == --(pit->end())) { current_node = subpath->begin().get_pointer(); } else { /* regardless of segment type, create a new node at the end -- cgit v1.2.3 From 7b7620b5dc7f3c57be46a5078f0bec2e3868f553 Mon Sep 17 00:00:00 2001 From: Krzysztof Kosi??ski Date: Fri, 8 May 2015 14:09:07 +0200 Subject: Fix ellipse problems (bzr r14059.2.5) --- .../!PLEASE DON'T MAKE CHANGES IN THESE FILES.README | 18 +++++++++++------- src/2geom/cairo-path-sink.cpp | 4 ++-- src/2geom/ellipse.cpp | 15 +++++++-------- src/2geom/path.h | 6 +++++- src/2geom/svg-path-writer.cpp | 2 +- 5 files changed, 26 insertions(+), 19 deletions(-) (limited to 'src') diff --git a/src/2geom/!PLEASE DON'T MAKE CHANGES IN THESE FILES.README b/src/2geom/!PLEASE DON'T MAKE CHANGES IN THESE FILES.README index 3ced704c7..074921de2 100644 --- a/src/2geom/!PLEASE DON'T MAKE CHANGES IN THESE FILES.README +++ b/src/2geom/!PLEASE DON'T MAKE CHANGES IN THESE FILES.README @@ -1,9 +1,13 @@ -All code files in this directory are *direct* copies of the files in 2geom's BZR repo. -If you want to change the code, please change it in 2geom, then copy the files here. -Otherwise, I will probably miss that you changed something in Inkscape's copy, and -destroy your changes by copying 2geom's files over it during the next time I update -Inkscape's copy of 2geom. - - Johan Engelen +This is an in-tree copy of lib2geom, a 2D geometry library started +by Inkscape developers. If you want to change code in 2Geom, you should +commit it first to upstream repository and then execute this command: + +rsync -r --existing /path/to/lib2geom/src/2geom /path/to/inkscape/src/2geom + +The command above will only update existing files. If you add new files +to 2Geom, you'll need to copy the new files manually. Same if you remove +some files. 2geom's BZR repo = lp:lib2geom -http://lib2geom.sourceforge.net \ No newline at end of file +http://lib2geom.sourceforge.net + diff --git a/src/2geom/cairo-path-sink.cpp b/src/2geom/cairo-path-sink.cpp index 244a08ba4..f327bf04d 100644 --- a/src/2geom/cairo-path-sink.cpp +++ b/src/2geom/cairo-path-sink.cpp @@ -31,7 +31,7 @@ #include #include <2geom/cairo-path-sink.h> -#include <2geom/elliptical-arc.h> +#include <2geom/svg-elliptical-arc.h> namespace Geom { @@ -71,7 +71,7 @@ void CairoPathSink::quadTo(Point const &p1, Point const &p2) void CairoPathSink::arcTo(double rx, double ry, double angle, bool large_arc, bool sweep, Point const &p) { - EllipticalArc arc(_current_point, rx, ry, angle, large_arc, sweep, p); + SVGEllipticalArc arc(_current_point, rx, ry, angle, large_arc, sweep, p); // Cairo only does circular arcs. // To do elliptical arcs, we must use a temporary transform. Affine uct = arc.unitCircleTransform(); diff --git a/src/2geom/ellipse.cpp b/src/2geom/ellipse.cpp index 9e927c9e8..f23c9b24e 100644 --- a/src/2geom/ellipse.cpp +++ b/src/2geom/ellipse.cpp @@ -180,7 +180,6 @@ Ellipse::arc(Point const &ip, Point const &inner, Point const &fp, // The arc is larger than half of the ellipse if the inner point // is on the same side of the line going from the initial // to the final point as the center of the ellipse - Line chord(ip, fp); Point versor = fp - ip; double sdist_c = cross(versor, _center - ip); double sdist_inner = cross(versor, inner - ip); @@ -225,9 +224,11 @@ Ellipse &Ellipse::operator*=(Rotate const &r) Ellipse &Ellipse::operator*=(Affine const& m) { - Rotate a(_angle); + Affine a = Scale(ray(X), ray(Y)) * Rotate(_angle); Affine mwot = m.withoutTranslation(); Affine am = a * mwot; + Point new_center = _center * m; + if (are_near(am.descrim(), 0)) { double angle; if (am[0] != 0) { @@ -237,13 +238,11 @@ Ellipse &Ellipse::operator*=(Affine const& m) } else { angle = M_PI/2; } - Point v; - sincos(angle, v[X], v[Y]); - v *= am; - _angle = atan2(v); - _center *= m; + Point v = Point::polar(angle) * am; + _center = new_center; _rays[X] = L2(v); _rays[Y] = 0; + _angle = atan2(v); return *this; } @@ -257,7 +256,7 @@ Ellipse &Ellipse::operator*=(Affine const& m) std::swap(invm[1], invm[2]); q *= invm; setCoefficients(q[0], 2*q[1], q[3], 0, 0, -1); - _center *= m; + _center = new_center; return *this; } diff --git a/src/2geom/path.h b/src/2geom/path.h index 6a6fa05ee..58afcfd8d 100644 --- a/src/2geom/path.h +++ b/src/2geom/path.h @@ -288,7 +288,11 @@ struct ShapeTraits { * - Iterating between @a begin() and @a end_closed() * will always iterate over a closed loop of segments. * - Iterating between @a begin() and @a end_open() will always skip - * the closing segment. + * the final linear closing segment. + * + * If the final point of the last "real" segment coincides exactly with the initial + * point of the first segment, the closing segment will be absent from both + * [begin(), end_open()) and [begin(), end_closed()). * * Normally, an exception will be thrown when you try to insert a curve * that makes the path non-continuous. If you are working with unsanitized diff --git a/src/2geom/svg-path-writer.cpp b/src/2geom/svg-path-writer.cpp index e8083a8d1..1c40ba64e 100644 --- a/src/2geom/svg-path-writer.cpp +++ b/src/2geom/svg-path-writer.cpp @@ -150,7 +150,7 @@ void SVGPathWriter::arcTo(double rx, double ry, double angle, _setCommand('A'); _current_pars.push_back(rx); _current_pars.push_back(ry); - _current_pars.push_back(angle); + _current_pars.push_back(rad_to_deg(angle)); _current_pars.push_back(large_arc ? 1. : 0.); _current_pars.push_back(sweep ? 1. : 0.); _current_pars.push_back(p[X]); -- cgit v1.2.3 From 6ae198bfe51ef5c850e2fc27f9f811f9f2acd655 Mon Sep 17 00:00:00 2001 From: Krzysztof Kosi??ski Date: Fri, 8 May 2015 14:41:06 +0200 Subject: Fix path conversion between 2Geom and Livarot (bzr r14059.2.6) --- src/livarot/PathCutting.cpp | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) (limited to 'src') diff --git a/src/livarot/PathCutting.cpp b/src/livarot/PathCutting.cpp index 12f2386b0..d6ad6c94a 100644 --- a/src/livarot/PathCutting.cpp +++ b/src/livarot/PathCutting.cpp @@ -434,17 +434,11 @@ void Path::LoadPath(Geom::Path const &path, Geom::Affine const &tr, bool doTran MoveTo( pathtr.initialPoint() ); - for(Geom::Path::const_iterator cit = pathtr.begin(); cit != pathtr.end_open(); ++cit) { + for(Geom::Path::const_iterator cit = pathtr.begin(); cit != pathtr.end(); ++cit) { AddCurve(*cit); } if (pathtr.closed()) { - // check if closing segment is empty before adding it - Geom::Curve const &crv = pathtr.back_closed(); - if ( !crv.isDegenerate() ) { - AddCurve(crv); - } - Close(); } } -- cgit v1.2.3 From 77dc53d662c518234ddc8d00f57c74838607bb30 Mon Sep 17 00:00:00 2001 From: Krzysztof Kosi??ski Date: Fri, 8 May 2015 15:11:29 +0200 Subject: Update to 2Geom r2358 - better z-snapping logic (bzr r14059.2.7) --- src/2geom/svg-path-parser.cpp | 102 ++++++++++++++++++++++++------------------ src/2geom/svg-path-parser.h | 1 + 2 files changed, 60 insertions(+), 43 deletions(-) (limited to 'src') diff --git a/src/2geom/svg-path-parser.cpp b/src/2geom/svg-path-parser.cpp index 2778795b3..6ee55171e 100644 --- a/src/2geom/svg-path-parser.cpp +++ b/src/2geom/svg-path-parser.cpp @@ -1142,21 +1142,25 @@ void SVGPathParser::finish() _parse(empty, empty, true); } -void SVGPathParser::_push(Coord value) { +void SVGPathParser::_push(Coord value) +{ _params.push_back(value); } -Coord SVGPathParser::_pop() { +Coord SVGPathParser::_pop() +{ Coord value = _params.back(); _params.pop_back(); return value; } -bool SVGPathParser::_pop_flag() { +bool SVGPathParser::_pop_flag() +{ return _pop() != 0.0; } -Coord SVGPathParser::_pop_coord(Dim2 axis) { +Coord SVGPathParser::_pop_coord(Dim2 axis) +{ if (_absolute) { return _pop(); } else { @@ -1164,30 +1168,35 @@ Coord SVGPathParser::_pop_coord(Dim2 axis) { } } -Point SVGPathParser::_pop_point() { +Point SVGPathParser::_pop_point() +{ Coord y = _pop_coord(Y); Coord x = _pop_coord(X); return Point(x, y); } -void SVGPathParser::_moveTo(Point const &p) { +void SVGPathParser::_moveTo(Point const &p) +{ _pushCurve(NULL); // flush _sink.moveTo(p); _quad_tangent = _cubic_tangent = _current = _initial = p; } -void SVGPathParser::_lineTo(Point const &p) { +void SVGPathParser::_lineTo(Point const &p) +{ _pushCurve(new LineSegment(_current, p)); _quad_tangent = _cubic_tangent = _current = p; } -void SVGPathParser::_curveTo(Point const &c0, Point const &c1, Point const &p) { +void SVGPathParser::_curveTo(Point const &c0, Point const &c1, Point const &p) +{ _pushCurve(new CubicBezier(_current, c0, c1, p)); _quad_tangent = _current = p; _cubic_tangent = p + ( p - c1 ); } -void SVGPathParser::_quadTo(Point const &c, Point const &p) { +void SVGPathParser::_quadTo(Point const &c, Point const &p) +{ _pushCurve(new QuadraticBezier(_current, c, p)); _cubic_tangent = _current = p; _quad_tangent = p + ( p - c ); @@ -1204,16 +1213,21 @@ void SVGPathParser::_arcTo(Coord rx, Coord ry, Coord angle, _quad_tangent = _cubic_tangent = _current = p; } -void SVGPathParser::_closePath() { - if (!_absolute && _curve && are_near(_initial, _current, _z_snap_threshold)) { +void SVGPathParser::_closePath() +{ + if (_curve && (!_absolute || !_moveto_was_absolute) && + are_near(_initial, _current, _z_snap_threshold)) + { _curve->setFinal(_initial); } + _pushCurve(NULL); // flush _sink.closePath(); _quad_tangent = _cubic_tangent = _current = _initial; } -void SVGPathParser::_pushCurve(Curve *c) { +void SVGPathParser::_pushCurve(Curve *c) +{ if (_curve) { _sink.feed(*_curve, false); delete _curve; @@ -1229,7 +1243,7 @@ void SVGPathParser::_parse(char const *str, char const *strend, bool finish) char const *start = NULL; -#line 1233 "/home/tweenk/src/lib2geom/src/2geom/svg-path-parser.cpp" +#line 1247 "/home/tweenk/src/lib2geom/src/2geom/svg-path-parser.cpp" { int _klen; unsigned int _trans; @@ -1304,13 +1318,13 @@ _match: switch ( *_acts++ ) { case 0: -#line 195 "/home/tweenk/src/lib2geom/src/2geom/svg-path-parser.rl" +#line 209 "/home/tweenk/src/lib2geom/src/2geom/svg-path-parser.rl" { start = p; } break; case 1: -#line 199 "/home/tweenk/src/lib2geom/src/2geom/svg-path-parser.rl" +#line 213 "/home/tweenk/src/lib2geom/src/2geom/svg-path-parser.rl" { if (start) { std::string buf(start, p); @@ -1324,55 +1338,56 @@ _match: } break; case 2: -#line 211 "/home/tweenk/src/lib2geom/src/2geom/svg-path-parser.rl" +#line 225 "/home/tweenk/src/lib2geom/src/2geom/svg-path-parser.rl" { _push(1.0); } break; case 3: -#line 215 "/home/tweenk/src/lib2geom/src/2geom/svg-path-parser.rl" +#line 229 "/home/tweenk/src/lib2geom/src/2geom/svg-path-parser.rl" { _push(0.0); } break; case 4: -#line 219 "/home/tweenk/src/lib2geom/src/2geom/svg-path-parser.rl" +#line 233 "/home/tweenk/src/lib2geom/src/2geom/svg-path-parser.rl" { _absolute = true; } break; case 5: -#line 223 "/home/tweenk/src/lib2geom/src/2geom/svg-path-parser.rl" +#line 237 "/home/tweenk/src/lib2geom/src/2geom/svg-path-parser.rl" { _absolute = false; } break; case 6: -#line 227 "/home/tweenk/src/lib2geom/src/2geom/svg-path-parser.rl" +#line 241 "/home/tweenk/src/lib2geom/src/2geom/svg-path-parser.rl" { + _moveto_was_absolute = _absolute; _moveTo(_pop_point()); } break; case 7: -#line 231 "/home/tweenk/src/lib2geom/src/2geom/svg-path-parser.rl" +#line 246 "/home/tweenk/src/lib2geom/src/2geom/svg-path-parser.rl" { _lineTo(_pop_point()); } break; case 8: -#line 235 "/home/tweenk/src/lib2geom/src/2geom/svg-path-parser.rl" +#line 250 "/home/tweenk/src/lib2geom/src/2geom/svg-path-parser.rl" { _lineTo(Point(_pop_coord(X), _current[Y])); } break; case 9: -#line 239 "/home/tweenk/src/lib2geom/src/2geom/svg-path-parser.rl" +#line 254 "/home/tweenk/src/lib2geom/src/2geom/svg-path-parser.rl" { _lineTo(Point(_current[X], _pop_coord(Y))); } break; case 10: -#line 243 "/home/tweenk/src/lib2geom/src/2geom/svg-path-parser.rl" +#line 258 "/home/tweenk/src/lib2geom/src/2geom/svg-path-parser.rl" { Point p = _pop_point(); Point c1 = _pop_point(); @@ -1381,7 +1396,7 @@ _match: } break; case 11: -#line 250 "/home/tweenk/src/lib2geom/src/2geom/svg-path-parser.rl" +#line 265 "/home/tweenk/src/lib2geom/src/2geom/svg-path-parser.rl" { Point p = _pop_point(); Point c1 = _pop_point(); @@ -1389,7 +1404,7 @@ _match: } break; case 12: -#line 256 "/home/tweenk/src/lib2geom/src/2geom/svg-path-parser.rl" +#line 271 "/home/tweenk/src/lib2geom/src/2geom/svg-path-parser.rl" { Point p = _pop_point(); Point c = _pop_point(); @@ -1397,14 +1412,14 @@ _match: } break; case 13: -#line 262 "/home/tweenk/src/lib2geom/src/2geom/svg-path-parser.rl" +#line 277 "/home/tweenk/src/lib2geom/src/2geom/svg-path-parser.rl" { Point p = _pop_point(); _quadTo(_quad_tangent, p); } break; case 14: -#line 267 "/home/tweenk/src/lib2geom/src/2geom/svg-path-parser.rl" +#line 282 "/home/tweenk/src/lib2geom/src/2geom/svg-path-parser.rl" { Point point = _pop_point(); bool sweep = _pop_flag(); @@ -1417,12 +1432,12 @@ _match: } break; case 15: -#line 278 "/home/tweenk/src/lib2geom/src/2geom/svg-path-parser.rl" +#line 293 "/home/tweenk/src/lib2geom/src/2geom/svg-path-parser.rl" { _closePath(); } break; -#line 1426 "/home/tweenk/src/lib2geom/src/2geom/svg-path-parser.cpp" +#line 1441 "/home/tweenk/src/lib2geom/src/2geom/svg-path-parser.cpp" } } @@ -1439,7 +1454,7 @@ _again: while ( __nacts-- > 0 ) { switch ( *__acts++ ) { case 1: -#line 199 "/home/tweenk/src/lib2geom/src/2geom/svg-path-parser.rl" +#line 213 "/home/tweenk/src/lib2geom/src/2geom/svg-path-parser.rl" { if (start) { std::string buf(start, p); @@ -1453,31 +1468,32 @@ _again: } break; case 6: -#line 227 "/home/tweenk/src/lib2geom/src/2geom/svg-path-parser.rl" +#line 241 "/home/tweenk/src/lib2geom/src/2geom/svg-path-parser.rl" { + _moveto_was_absolute = _absolute; _moveTo(_pop_point()); } break; case 7: -#line 231 "/home/tweenk/src/lib2geom/src/2geom/svg-path-parser.rl" +#line 246 "/home/tweenk/src/lib2geom/src/2geom/svg-path-parser.rl" { _lineTo(_pop_point()); } break; case 8: -#line 235 "/home/tweenk/src/lib2geom/src/2geom/svg-path-parser.rl" +#line 250 "/home/tweenk/src/lib2geom/src/2geom/svg-path-parser.rl" { _lineTo(Point(_pop_coord(X), _current[Y])); } break; case 9: -#line 239 "/home/tweenk/src/lib2geom/src/2geom/svg-path-parser.rl" +#line 254 "/home/tweenk/src/lib2geom/src/2geom/svg-path-parser.rl" { _lineTo(Point(_current[X], _pop_coord(Y))); } break; case 10: -#line 243 "/home/tweenk/src/lib2geom/src/2geom/svg-path-parser.rl" +#line 258 "/home/tweenk/src/lib2geom/src/2geom/svg-path-parser.rl" { Point p = _pop_point(); Point c1 = _pop_point(); @@ -1486,7 +1502,7 @@ _again: } break; case 11: -#line 250 "/home/tweenk/src/lib2geom/src/2geom/svg-path-parser.rl" +#line 265 "/home/tweenk/src/lib2geom/src/2geom/svg-path-parser.rl" { Point p = _pop_point(); Point c1 = _pop_point(); @@ -1494,7 +1510,7 @@ _again: } break; case 12: -#line 256 "/home/tweenk/src/lib2geom/src/2geom/svg-path-parser.rl" +#line 271 "/home/tweenk/src/lib2geom/src/2geom/svg-path-parser.rl" { Point p = _pop_point(); Point c = _pop_point(); @@ -1502,14 +1518,14 @@ _again: } break; case 13: -#line 262 "/home/tweenk/src/lib2geom/src/2geom/svg-path-parser.rl" +#line 277 "/home/tweenk/src/lib2geom/src/2geom/svg-path-parser.rl" { Point p = _pop_point(); _quadTo(_quad_tangent, p); } break; case 14: -#line 267 "/home/tweenk/src/lib2geom/src/2geom/svg-path-parser.rl" +#line 282 "/home/tweenk/src/lib2geom/src/2geom/svg-path-parser.rl" { Point point = _pop_point(); bool sweep = _pop_flag(); @@ -1522,12 +1538,12 @@ _again: } break; case 15: -#line 278 "/home/tweenk/src/lib2geom/src/2geom/svg-path-parser.rl" +#line 293 "/home/tweenk/src/lib2geom/src/2geom/svg-path-parser.rl" { _closePath(); } break; -#line 1531 "/home/tweenk/src/lib2geom/src/2geom/svg-path-parser.cpp" +#line 1547 "/home/tweenk/src/lib2geom/src/2geom/svg-path-parser.cpp" } } } @@ -1535,7 +1551,7 @@ _again: _out: {} } -#line 420 "/home/tweenk/src/lib2geom/src/2geom/svg-path-parser.rl" +#line 435 "/home/tweenk/src/lib2geom/src/2geom/svg-path-parser.rl" if (finish) { diff --git a/src/2geom/svg-path-parser.h b/src/2geom/svg-path-parser.h index 094ecd4da..9f304b9ed 100644 --- a/src/2geom/svg-path-parser.h +++ b/src/2geom/svg-path-parser.h @@ -109,6 +109,7 @@ public: private: bool _absolute; + bool _moveto_was_absolute; Point _current; Point _initial; Point _cubic_tangent; -- cgit v1.2.3 From 48e0423afcb02fe4a0f705d828a0dbdb3106b397 Mon Sep 17 00:00:00 2001 From: Marc Jeanmougin Date: Fri, 8 May 2015 15:46:25 +0200 Subject: fixes a few of jenkins warnings (bzr r14126) --- src/desktop.cpp | 1 - src/display/canvas-arena.cpp | 2 +- src/document.cpp | 2 +- src/extension/implementation/script.cpp | 16 ++++++++++------ src/extension/internal/cairo-render-context.cpp | 1 + src/extension/internal/wmf-inout.cpp | 6 ++---- src/file.cpp | 6 +++--- src/gradient-drag.cpp | 2 +- src/helper-fns.h | 2 +- src/helper/geom.cpp | 9 ++------- src/inkview.cpp | 2 +- src/libavoid/connector.cpp | 6 +----- src/libavoid/graph.cpp | 4 +++- src/libavoid/orthogonal.cpp | 1 - src/live_effects/lpe-gears.cpp | 2 +- src/live_effects/lpe-taperstroke.cpp | 4 ---- src/live_effects/parameter/filletchamferpointarray.cpp | 1 - src/selection.cpp | 3 ++- src/sp-item-transform.cpp | 6 +++--- src/trace/siox.cpp | 2 +- src/ui/dialog/document-properties.cpp | 4 ++-- src/ui/dialog/floating-behavior.cpp | 2 +- src/ui/dialog/grid-arrange-tab.cpp | 1 - src/ui/dialog/icon-preview.cpp | 2 +- src/ui/interface.cpp | 2 +- src/ui/tools/box3d-tool.cpp | 2 +- src/ui/tools/flood-tool.cpp | 2 +- src/ui/tools/pen-tool.cpp | 15 ++++----------- src/ui/tools/pencil-tool.cpp | 3 --- src/ui/tools/rect-tool.cpp | 1 - src/ui/tools/select-tool.cpp | 1 - src/util/ziptool.cpp | 2 +- src/widgets/desktop-widget.cpp | 4 +++- src/widgets/ege-adjustment-action.cpp | 2 +- src/widgets/gradient-vector.cpp | 1 + 35 files changed, 51 insertions(+), 71 deletions(-) (limited to 'src') diff --git a/src/desktop.cpp b/src/desktop.cpp index 5a1558b0f..02df50c6b 100644 --- a/src/desktop.cpp +++ b/src/desktop.cpp @@ -947,7 +947,6 @@ void SPDesktop::zoom_quick(bool enable) if (!zoomed) { zoom_relative(_quick_zoom_stored_area.midpoint()[Geom::X], _quick_zoom_stored_area.midpoint()[Geom::Y], 2.0); - zoomed = true; } } else { set_display_area(_quick_zoom_stored_area, false); diff --git a/src/display/canvas-arena.cpp b/src/display/canvas-arena.cpp index 8738b93e4..ec99eca9a 100644 --- a/src/display/canvas-arena.cpp +++ b/src/display/canvas-arena.cpp @@ -290,7 +290,7 @@ sp_canvas_arena_event (SPCanvasItem *item, GdkEvent *event) ret = sp_canvas_arena_send_event (arena, (GdkEvent *) &ec); } } - ret = sp_canvas_arena_send_event (arena, event); + ret = ret || sp_canvas_arena_send_event (arena, event); break; case GDK_SCROLL: { diff --git a/src/document.cpp b/src/document.cpp index f06953e34..741e7c812 100644 --- a/src/document.cpp +++ b/src/document.cpp @@ -1591,7 +1591,7 @@ static void vacuum_document_recursive(SPObject *obj) unsigned int SPDocument::vacuumDocument() { unsigned int start = objects_in_document(this); - unsigned int end = start; + unsigned int end; unsigned int newend = start; unsigned int iterations = 0; diff --git a/src/extension/implementation/script.cpp b/src/extension/implementation/script.cpp index 5cab3a2b2..e07a3963c 100644 --- a/src/extension/implementation/script.cpp +++ b/src/extension/implementation/script.cpp @@ -812,6 +812,12 @@ void Script::copy_doc (Inkscape::XML::Node * oldroot, Inkscape::XML::Node * newr } } + if(!oldroot_namedview) + { + g_warning("Error on copy_doc: No namedview on destination document."); + return; + } + // Unparent (delete) for (unsigned int i = 0; i < delete_list.size(); i++) { sp_repr_unparent(delete_list[i]); @@ -823,12 +829,10 @@ void Script::copy_doc (Inkscape::XML::Node * oldroot, Inkscape::XML::Node * newr child = child->next()) { if (!strcmp("sodipodi:namedview", child->name())) { newroot_namedview = child; - if (oldroot_namedview != NULL) { - for (Inkscape::XML::Node * newroot_namedview_child = child->firstChild(); - newroot_namedview_child != NULL; - newroot_namedview_child = newroot_namedview_child->next()) { - oldroot_namedview->appendChild(newroot_namedview_child->duplicate(oldroot->document())); - } + for (Inkscape::XML::Node * newroot_namedview_child = child->firstChild(); + newroot_namedview_child != NULL; + newroot_namedview_child = newroot_namedview_child->next()) { + oldroot_namedview->appendChild(newroot_namedview_child->duplicate(oldroot->document())); } } else { oldroot->appendChild(child->duplicate(oldroot->document())); diff --git a/src/extension/internal/cairo-render-context.cpp b/src/extension/internal/cairo-render-context.cpp index 2d6619e1e..27e34dbcf 100644 --- a/src/extension/internal/cairo-render-context.cpp +++ b/src/extension/internal/cairo-render-context.cpp @@ -1393,6 +1393,7 @@ CairoRenderContext::_setStrokeStyle(SPStyle const *style, Geom::OptRect const &p dashes[i] = style->stroke_dasharray.values[i]; } cairo_set_dash(_cr, dashes, ndashes, style->stroke_dashoffset.value); + free(dashes); } else { cairo_set_dash(_cr, NULL, 0, 0.0); // disable dashing } diff --git a/src/extension/internal/wmf-inout.cpp b/src/extension/internal/wmf-inout.cpp index 3ab7a4e89..f76fa16b4 100644 --- a/src/extension/internal/wmf-inout.cpp +++ b/src/extension/internal/wmf-inout.cpp @@ -95,7 +95,6 @@ Wmf::print_document_to_file(SPDocument *doc, const gchar *filename) SPPrintContext context; const gchar *oldconst; gchar *oldoutput; - unsigned int ret; doc->ensureUpToDate(); @@ -114,13 +113,12 @@ Wmf::print_document_to_file(SPDocument *doc, const gchar *filename) mod->root = mod->base->invoke_show(drawing, mod->dkey, SP_ITEM_SHOW_DISPLAY); drawing.setRoot(mod->root); /* Print document */ - ret = mod->begin(doc); - if (ret) { + if (mod->begin(doc)) { g_free(oldoutput); throw Inkscape::Extension::Output::save_failed(); } mod->base->invoke_print(&context); - ret = mod->finish(); + mod->finish(); /* Release arena */ mod->base->invoke_hide(mod->dkey); mod->base = NULL; diff --git a/src/file.cpp b/src/file.cpp index d1dd2bcd6..984bf7e08 100644 --- a/src/file.cpp +++ b/src/file.cpp @@ -769,7 +769,7 @@ file_save_remote(SPDocument */*doc*/, return false; } - result = gnome_vfs_create (&to_handle, uri_local, GNOME_VFS_OPEN_WRITE, FALSE, GNOME_VFS_PERM_USER_ALL); + gnome_vfs_create (&to_handle, uri_local, GNOME_VFS_OPEN_WRITE, FALSE, GNOME_VFS_PERM_USER_ALL); result = gnome_vfs_open (&to_handle, uri_local, GNOME_VFS_OPEN_WRITE); if (result != GNOME_VFS_OK) { @@ -782,8 +782,8 @@ file_save_remote(SPDocument */*doc*/, result = gnome_vfs_read (from_handle, buffer, 8192, &bytes_read); if ((result == GNOME_VFS_ERROR_EOF) &&(!bytes_read)){ - result = gnome_vfs_close (from_handle); - result = gnome_vfs_close (to_handle); + gnome_vfs_close (from_handle); + gnome_vfs_close (to_handle); return true; } diff --git a/src/gradient-drag.cpp b/src/gradient-drag.cpp index 169710114..b22714959 100644 --- a/src/gradient-drag.cpp +++ b/src/gradient-drag.cpp @@ -1155,7 +1155,7 @@ static void gr_knot_clicked_handler(SPKnot */*knot*/, guint state, gpointer data break; default: - break; + return; } diff --git a/src/helper-fns.h b/src/helper-fns.h index 2f1829c37..79771a001 100644 --- a/src/helper-fns.h +++ b/src/helper-fns.h @@ -78,7 +78,7 @@ inline std::vector helperfns_read_vector(const gchar* value){ g_warning("helper-fns::helperfns_read_vector() Unable to convert \"%s\" to number", beg); // We could leave this out, too. If strtod can't convert // anything, it will return zero. - ret = 0; + // ret = 0; break; } v.push_back(ret); diff --git a/src/helper/geom.cpp b/src/helper/geom.cpp index 91689375f..77cba4736 100644 --- a/src/helper/geom.cpp +++ b/src/helper/geom.cpp @@ -266,14 +266,13 @@ geom_cubic_bbox_wind_distance (Geom::Coord x000, Geom::Coord y000, Geom::Coord tolerance) { Geom::Coord x0, y0, x1, y1, len2; - int needdist, needwind, needline; + int needdist, needwind; const Geom::Coord Px = pt[X]; const Geom::Coord Py = pt[Y]; needdist = 0; needwind = 0; - needline = 0; if (bbox) cubic_bbox (x000, y000, x001, y001, x011, y011, x111, y111, *bbox); @@ -303,8 +302,6 @@ geom_cubic_bbox_wind_distance (Geom::Coord x000, Geom::Coord y000, /* fixme: (Lauris) */ if (((y1 - y0) > 5.0) || ((x1 - x0) > 5.0)) { needdist = 1; - } else { - needline = 1; } } } @@ -315,8 +312,6 @@ geom_cubic_bbox_wind_distance (Geom::Coord x000, Geom::Coord y000, /* fixme: (Lauris) */ if (((y1 - y0) > 5.0) || ((x1 - x0) > 5.0)) { needwind = 1; - } else { - needline = 1; } } } @@ -345,7 +340,7 @@ geom_cubic_bbox_wind_distance (Geom::Coord x000, Geom::Coord y000, geom_cubic_bbox_wind_distance (x000, y000, x00t, y00t, x0tt, y0tt, xttt, yttt, pt, NULL, wind, best, tolerance); geom_cubic_bbox_wind_distance (xttt, yttt, x1tt, y1tt, x11t, y11t, x111, y111, pt, NULL, wind, best, tolerance); - } else if (1 || needline) { + } else { geom_line_wind_distance (x000, y000, x111, y111, pt, wind, best); } } diff --git a/src/inkview.cpp b/src/inkview.cpp index 2c667237e..8b7492798 100644 --- a/src/inkview.cpp +++ b/src/inkview.cpp @@ -274,7 +274,7 @@ main (int argc, const char **argv) gchar *last_filename = jar_file_reader.get_last_filename(); if (ss.doc) { ss.slides[ss.length++] = strdup (last_filename); - (ss.doc)->setUri (strdup(last_filename)); + (ss.doc)->setUri (last_filename); } g_byte_array_free(gba, TRUE); g_free(last_filename); diff --git a/src/libavoid/connector.cpp b/src/libavoid/connector.cpp index 40ded7498..36892c668 100644 --- a/src/libavoid/connector.cpp +++ b/src/libavoid/connector.cpp @@ -1476,7 +1476,6 @@ CrossingsInfoPair countRealCrossings(Avoid::Polygon& poly, int prevTurnDir = -1; int startCornerSide = 1; int endCornerSide = 1; - bool reversed = false; if (!front_same) { // If there is a divergence at the beginning, @@ -1485,7 +1484,6 @@ CrossingsInfoPair countRealCrossings(Avoid::Polygon& poly, startCornerSide = Avoid::cornerSide(*c_path[0], *c_path[1], *c_path[2], *p_path[0]) * segDir(*c_path[1], *c_path[2]); - reversed = (startCornerSide != -prevTurnDir); } if (!back_same) { @@ -1497,7 +1495,6 @@ CrossingsInfoPair countRealCrossings(Avoid::Polygon& poly, *c_path[size - 2], *c_path[size - 1], *p_path[size - 1]) * segDir(*c_path[size - 3], *c_path[size - 2]); - reversed = (endCornerSide != -prevTurnDir); } else { @@ -1578,10 +1575,9 @@ CrossingsInfoPair countRealCrossings(Avoid::Polygon& poly, } } #endif - prevTurnDir = 0; if (pointOrders) { - reversed = false; + bool reversed = false; size_t startPt = (front_same) ? 0 : 1; // Orthogonal should always have at least one segment. diff --git a/src/libavoid/graph.cpp b/src/libavoid/graph.cpp index 728f8c085..5b617f123 100644 --- a/src/libavoid/graph.cpp +++ b/src/libavoid/graph.cpp @@ -129,7 +129,9 @@ static inline int orthogTurnOrder(const Point& a, const Point& b, // Note: This method assumes the two Edges that share a common point. bool EdgeInf::rotationLessThan(const VertInf *lastV, const EdgeInf *rhs) const { - if ((_v1 == rhs->_v1) && (_v2 == rhs->_v2)) + assert(_v1 == rhs->_v1 || _v1 == rhs->_v2 || _v2 == rhs->_v1 || _v2 == rhs->_v2 ); + + if ((_v1 == rhs->_v1) && (_v2 == rhs->_v2)) { // Effectively the same visibility edge, so they are equal. return false; diff --git a/src/libavoid/orthogonal.cpp b/src/libavoid/orthogonal.cpp index b5ef8d7e8..466d1dd58 100644 --- a/src/libavoid/orthogonal.cpp +++ b/src/libavoid/orthogonal.cpp @@ -1548,7 +1548,6 @@ extern void generateStaticOrthogonalVisGraph(Router *router) // Process the horizontal sweep thisPos = (totalEvents > 0) ? events[0]->pos : 0; posStartIndex = 0; - posFinishIndex = 0; for (unsigned i = 0; i <= totalEvents; ++i) { // If we have finished the current scanline or all events, then we diff --git a/src/live_effects/lpe-gears.cpp b/src/live_effects/lpe-gears.cpp index 003e22567..fafe143b5 100644 --- a/src/live_effects/lpe-gears.cpp +++ b/src/live_effects/lpe-gears.cpp @@ -168,7 +168,7 @@ Geom::Path Gear::path() { D2 root = _arc(cursor, cursor+root_advance, root_radius()); makeContinuous(root, prev); pb.append(SBasisCurve(root)); - cursor += root_advance; + //cursor += root_advance; prev = root.at1(); if (base_radius() > root_radius()) { diff --git a/src/live_effects/lpe-taperstroke.cpp b/src/live_effects/lpe-taperstroke.cpp index 2c74af6d6..451810d04 100644 --- a/src/live_effects/lpe-taperstroke.cpp +++ b/src/live_effects/lpe-taperstroke.cpp @@ -389,13 +389,9 @@ Piecewise > stretch_along(Piecewise > pwd2_in, Geom::Path x0 -= pattBndsX->min(); y0 -= pattBndsY->middle(); - double xspace = 0; double noffset = 0; double toffset = 0; // Prevent more than 90% overlap... - if (xspace < -pattBndsX->extent()*.9) { - xspace = -pattBndsX->extent()*.9; - } y0+=noffset; diff --git a/src/live_effects/parameter/filletchamferpointarray.cpp b/src/live_effects/parameter/filletchamferpointarray.cpp index e9d375b93..f05f401e4 100644 --- a/src/live_effects/parameter/filletchamferpointarray.cpp +++ b/src/live_effects/parameter/filletchamferpointarray.cpp @@ -506,7 +506,6 @@ std::vector FilletChamferPointArrayParam::get_times(int index, std::vect time_it1 = 0; } double resultLenght = 0; - time_it1_B = 1; if (subpaths[positions.first].closed() && last) { time_it2 = modf(to_time(index - positions.second , _vector[index - positions.second ][X]), &intpart); resultLenght = it1_length + to_len(index - positions.second, _vector[index - positions.second ][X]); diff --git a/src/selection.cpp b/src/selection.cpp index f728f3381..7979b5d61 100644 --- a/src/selection.cpp +++ b/src/selection.cpp @@ -178,6 +178,7 @@ void Selection::_add(SPObject *obj) { // (to prevent double-selection) _removeObjectDescendants(obj); _removeObjectAncestors(obj); + g_return_if_fail(SP_IS_OBJECT(obj)); _objs.push_front(obj); _objs_set.insert(obj); @@ -483,7 +484,7 @@ std::vector Selection::getSnapPoints(SnapPreferenc void Selection::_removeObjectDescendants(SPObject *obj) { std::vector toremove; for ( std::list::const_iterator iter=_objs.begin();iter!=_objs.end();iter++ ) { - SPObject *sel_obj= *iter; + SPObject *sel_obj= dynamic_cast(*iter); SPObject *parent = sel_obj->parent; while (parent) { if ( parent == obj ) { diff --git a/src/sp-item-transform.cpp b/src/sp-item-transform.cpp index 767f0ed91..f1c69cdf6 100644 --- a/src/sp-item-transform.cpp +++ b/src/sp-item-transform.cpp @@ -152,7 +152,7 @@ Geom::Affine get_scale_transform_for_uniform_stroke(Geom::Rect const &bbox_visua gdouble scale_x = 1; gdouble scale_y = 1; - gdouble r1 = r0; + gdouble r1; if ((fabs(w0 - stroke_x) < 1e-6) || w1 == 0) { // We have a vertical line at hand scale_y = h1/h0; @@ -310,8 +310,8 @@ Geom::Affine get_scale_transform_for_variable_stroke(Geom::Rect const &bbox_visu gdouble scale_x = 1; gdouble scale_y = 1; - gdouble r1h = r0h; - gdouble r1w = r0w; + gdouble r1h; + gdouble r1w; if ((fabs(w0 - r0w) < 1e-6) || w1 == 0) { // We have a vertical line at hand scale_y = h1/h0; diff --git a/src/trace/siox.cpp b/src/trace/siox.cpp index 065e891ed..9df4e561c 100644 --- a/src/trace/siox.cpp +++ b/src/trace/siox.cpp @@ -682,7 +682,7 @@ GdkPixbuf *SioxImage::getGdkPixbuf() } row += rowstride; } - + free(pixdata); return buf; } diff --git a/src/ui/dialog/document-properties.cpp b/src/ui/dialog/document-properties.cpp index c381ed755..b04e8ecc1 100644 --- a/src/ui/dialog/document-properties.cpp +++ b/src/ui/dialog/document-properties.cpp @@ -1672,10 +1672,10 @@ void DocumentProperties::onDocUnitChange() Inkscape::XML::Node *repr = getDesktop()->getNamedView()->getRepr(); - Inkscape::Util::Unit const *old_doc_unit = unit_table.getUnit("px"); + /*Inkscape::Util::Unit const *old_doc_unit = unit_table.getUnit("px"); if(repr->attribute("inkscape:document-units")) { old_doc_unit = unit_table.getUnit(repr->attribute("inkscape:document-units")); - } + }*/ Inkscape::Util::Unit const *doc_unit = _rum_deflt.getUnit(); // Set document unit diff --git a/src/ui/dialog/floating-behavior.cpp b/src/ui/dialog/floating-behavior.cpp index 740acd989..55ef0c5bb 100644 --- a/src/ui/dialog/floating-behavior.cpp +++ b/src/ui/dialog/floating-behavior.cpp @@ -112,7 +112,7 @@ bool FloatingBehavior::_trans_timer (void) { } float goal, current; - goal = current = _d->get_opacity(); + current = _d->get_opacity(); if (_dialog_active.get_value()) { goal = _trans_focus; diff --git a/src/ui/dialog/grid-arrange-tab.cpp b/src/ui/dialog/grid-arrange-tab.cpp index 4465d73a9..c44f66a4d 100644 --- a/src/ui/dialog/grid-arrange-tab.cpp +++ b/src/ui/dialog/grid-arrange-tab.cpp @@ -170,7 +170,6 @@ void GridArrangeTab::arrange() Inkscape::Selection *selection = desktop->getSelection(); const std::vector items = selection ? selection->itemList() : std::vector(); - cnt=0; for(std::vector::const_iterator i = items.begin();i!=items.end();i++){ SPItem *item = *i; Geom::OptRect b = item->documentVisualBounds(); diff --git a/src/ui/dialog/icon-preview.cpp b/src/ui/dialog/icon-preview.cpp index 7dc55c95c..77f120e1a 100644 --- a/src/ui/dialog/icon-preview.cpp +++ b/src/ui/dialog/icon-preview.cpp @@ -312,7 +312,7 @@ void IconPreviewPanel::setDesktop( SPDesktop* desktop ) if ( this->desktop ) { docReplacedConn = this->desktop->connectDocumentReplaced(sigc::hide<0>(sigc::mem_fun(this, &IconPreviewPanel::setDocument))); if ( this->desktop->selection && Inkscape::Preferences::get()->getBool("/iconpreview/autoRefresh", true) ) { - selChangedConn = desktop->selection->connectChanged(sigc::hide(sigc::mem_fun(this, &IconPreviewPanel::queueRefresh))); + selChangedConn = this->desktop->selection->connectChanged(sigc::hide(sigc::mem_fun(this, &IconPreviewPanel::queueRefresh))); } } } diff --git a/src/ui/interface.cpp b/src/ui/interface.cpp index 760d19e89..a129d4b92 100644 --- a/src/ui/interface.cpp +++ b/src/ui/interface.cpp @@ -439,7 +439,7 @@ sp_ui_dialog_title_string(Inkscape::Verb *verb, gchar *c) gchar* key = sp_shortcut_get_label(shortcut); s = g_stpcpy(s, " ("); s = g_stpcpy(s, key); - s = g_stpcpy(s, ")"); + g_stpcpy(s, ")"); g_free(key); } } diff --git a/src/ui/tools/box3d-tool.cpp b/src/ui/tools/box3d-tool.cpp index 538e0c7e2..27e755add 100644 --- a/src/ui/tools/box3d-tool.cpp +++ b/src/ui/tools/box3d-tool.cpp @@ -165,7 +165,7 @@ bool Box3dTool::item_handler(SPItem* item, GdkEvent* event) { case GDK_BUTTON_PRESS: if ( event->button.button == 1 && !this->space_panning) { Inkscape::setup_for_drag_start(desktop, this, event); - ret = TRUE; + //ret = TRUE; } break; // motion and release are always on root (why?) diff --git a/src/ui/tools/flood-tool.cpp b/src/ui/tools/flood-tool.cpp index ffd41d97d..748c82717 100644 --- a/src/ui/tools/flood-tool.cpp +++ b/src/ui/tools/flood-tool.cpp @@ -932,7 +932,7 @@ static void sp_flood_do_flood_fill(ToolBase *event_context, GdkEvent *event, boo std::deque::iterator start_sort = fill_queue.begin(); std::deque::iterator end_sort = fill_queue.begin(); unsigned int sort_y = (unsigned int)cp[Geom::Y]; - unsigned int current_y = sort_y; + unsigned int current_y; for (std::deque::iterator i = fill_queue.begin(); i != fill_queue.end(); ++i) { Geom::Point current = *i; diff --git a/src/ui/tools/pen-tool.cpp b/src/ui/tools/pen-tool.cpp index daffc7032..be6156fa2 100644 --- a/src/ui/tools/pen-tool.cpp +++ b/src/ui/tools/pen-tool.cpp @@ -762,14 +762,12 @@ bool PenTool::_handleButtonRelease(GdkEventButton const &revent) { } } this->state = PenTool::CONTROL; - ret = true; break; case PenTool::CONTROL: // End current segment this->_endpointSnap(p, revent.state); this->_finishSegment(p, revent.state); this->state = PenTool::POINT; - ret = true; break; case PenTool::CLOSE: // End current segment @@ -783,12 +781,10 @@ bool PenTool::_handleButtonRelease(GdkEventButton const &revent) { } this->_finish(true); this->state = PenTool::POINT; - ret = true; break; case PenTool::STOP: // This is allowed, if we just canceled curve this->state = PenTool::POINT; - ret = true; break; default: break; @@ -823,7 +819,6 @@ bool PenTool::_handleButtonRelease(GdkEventButton const &revent) { break; } this->state = PenTool::POINT; - ret = true; break; default: break; @@ -1432,8 +1427,7 @@ void PenTool::_bsplineSpiroStartAnchorOn() { using Geom::X; using Geom::Y; - SPCurve *tmp_curve = new SPCurve(); - tmp_curve = this->sa->curve->copy(); + SPCurve *tmp_curve = this->sa->curve->copy(); if(this->sa->start) tmp_curve = tmp_curve ->create_reverse(); Geom::CubicBezier const * cubic = dynamic_cast(&*tmp_curve ->last_segment()); @@ -1465,8 +1459,7 @@ void PenTool::_bsplineSpiroStartAnchorOn() void PenTool::_bsplineSpiroStartAnchorOff() { - SPCurve *tmp_curve = new SPCurve(); - tmp_curve = this->sa->curve->copy(); + SPCurve *tmp_curve = this->sa->curve->copy(); if(this->sa->start) tmp_curve = tmp_curve ->create_reverse(); Geom::CubicBezier const * cubic = dynamic_cast(&*tmp_curve ->last_segment()); @@ -1564,7 +1557,7 @@ void PenTool::_bsplineSpiroEndAnchorOn() using Geom::Y; this->p[2] = this->p[3] + (1./3)*(this->p[0] - this->p[3]); this->p[2] = Geom::Point(this->p[2][X] + HANDLE_CUBIC_GAP,this->p[2][Y] + HANDLE_CUBIC_GAP); - SPCurve *tmp_curve = new SPCurve(); + SPCurve *tmp_curve; SPCurve *last_segment = new SPCurve(); Geom::Point point_c(0,0); bool reverse = false; @@ -1621,7 +1614,7 @@ void PenTool::_bsplineSpiroEndAnchorOn() void PenTool::_bsplineSpiroEndAnchorOff() { - SPCurve *tmp_curve = new SPCurve(); + SPCurve *tmp_curve; SPCurve *last_segment = new SPCurve(); bool reverse = false; this->p[2] = this->p[3]; diff --git a/src/ui/tools/pencil-tool.cpp b/src/ui/tools/pencil-tool.cpp index 008804162..ba103fa8e 100644 --- a/src/ui/tools/pencil-tool.cpp +++ b/src/ui/tools/pencil-tool.cpp @@ -357,7 +357,6 @@ bool PencilTool::_handleButtonRelease(GdkEventButton const &revent) { // Ctrl+click creates a single point so only set context in ADDLINE mode when Ctrl isn't pressed this->state = SP_PENCIL_CONTEXT_ADDLINE; } - ret = true; break; case SP_PENCIL_CONTEXT_ADDLINE: /* Finish segment now */ @@ -371,7 +370,6 @@ bool PencilTool::_handleButtonRelease(GdkEventButton const &revent) { this->_finishEndpoint(); this->state = SP_PENCIL_CONTEXT_IDLE; sp_event_context_discard_delayed_snap_event(this); - ret = true; break; case SP_PENCIL_CONTEXT_FREEHAND: if (revent.state & GDK_MOD1_MASK) { @@ -413,7 +411,6 @@ bool PencilTool::_handleButtonRelease(GdkEventButton const &revent) { // reset sketch mode too this->sketch_n = 0; } - ret = true; break; case SP_PENCIL_CONTEXT_SKETCH: default: diff --git a/src/ui/tools/rect-tool.cpp b/src/ui/tools/rect-tool.cpp index 62a9006ea..844965c4d 100644 --- a/src/ui/tools/rect-tool.cpp +++ b/src/ui/tools/rect-tool.cpp @@ -143,7 +143,6 @@ bool RectTool::item_handler(SPItem* item, GdkEvent* event) { case GDK_BUTTON_PRESS: if ( event->button.button == 1 && !this->space_panning) { Inkscape::setup_for_drag_start(desktop, this, event); - ret = TRUE; } break; // motion and release are always on root (why?) diff --git a/src/ui/tools/select-tool.cpp b/src/ui/tools/select-tool.cpp index f8375a1bb..f06b03d91 100644 --- a/src/ui/tools/select-tool.cpp +++ b/src/ui/tools/select-tool.cpp @@ -777,7 +777,6 @@ bool SelectTool::root_handler(GdkEvent* event) { } rb_escaped = 0; - ret = TRUE; } } } diff --git a/src/util/ziptool.cpp b/src/util/ziptool.cpp index cf024008f..2eb516b2e 100644 --- a/src/util/ziptool.cpp +++ b/src/util/ziptool.cpp @@ -2605,7 +2605,7 @@ bool ZipFile::readFileData() if (gpBitFlag & 0x8)//bit 3 was set. means we dont know compressed size { unsigned char c1, c2, c3, c4; - c1 = c2 = c3 = c4 = 0; + c2 = c3 = c4 = 0; while (true) { unsigned char ch; diff --git a/src/widgets/desktop-widget.cpp b/src/widgets/desktop-widget.cpp index fd3756220..e19f56e48 100644 --- a/src/widgets/desktop-widget.cpp +++ b/src/widgets/desktop-widget.cpp @@ -1433,8 +1433,10 @@ sp_desktop_widget_maximize(SPDesktopWidget *dtw) if (!dtw->desktop->is_iconified() && !dtw->desktop->is_fullscreen()) { Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - gint w, h, x, y; + gint w = -1; + gint h, x, y; dtw->getWindowGeometry(x, y, w, h); + g_assert(w != -1); prefs->setInt("/desktop/geometry/width", w); prefs->setInt("/desktop/geometry/height", h); prefs->setInt("/desktop/geometry/x", x); diff --git a/src/widgets/ege-adjustment-action.cpp b/src/widgets/ege-adjustment-action.cpp index d89a6e3f1..a91149f4c 100644 --- a/src/widgets/ege-adjustment-action.cpp +++ b/src/widgets/ege-adjustment-action.cpp @@ -742,7 +742,7 @@ static GtkWidget* create_popup_number_menu( EgeAdjustmentAction* act ) if ( act->private_data->descriptions ) { gdouble value = ((EgeAdjustmentDescr*)act->private_data->descriptions->data)->value; - addOns = flush_explicit_items( addOns, G_CALLBACK(process_menu_action), BUMP_CUSTOM, menu, act, &single, &group, value ); + flush_explicit_items( addOns, G_CALLBACK(process_menu_action), BUMP_CUSTOM, menu, act, &single, &group, value ); } return menu; diff --git a/src/widgets/gradient-vector.cpp b/src/widgets/gradient-vector.cpp index d2c46ffec..10d1cc107 100644 --- a/src/widgets/gradient-vector.cpp +++ b/src/widgets/gradient-vector.cpp @@ -548,6 +548,7 @@ static void verify_grad(SPGradient *gradient) child->setAttribute("style", os.str().c_str()); gradient->getRepr()->addChild(child, NULL); Inkscape::GC::release(child); + return; } if (i < 2) { sp_repr_set_css_double(stop->getRepr(), "offset", 0.0); -- cgit v1.2.3 From 72d3556428cd68013cb604a708f27d3de0f60855 Mon Sep 17 00:00:00 2001 From: Marc Jeanmougin Date: Fri, 8 May 2015 17:19:23 +0200 Subject: fix for bug 1391374. apparently, libnrtype drastically misses unit tests. Fixed bugs: - https://launchpad.net/bugs/1391374 (bzr r14127) --- src/libnrtype/Layout-TNG-OutIter.cpp | 4 ++-- src/libnrtype/Layout-TNG.h | 6 +++++- 2 files changed, 7 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/libnrtype/Layout-TNG-OutIter.cpp b/src/libnrtype/Layout-TNG-OutIter.cpp index c9c318960..707897f50 100644 --- a/src/libnrtype/Layout-TNG-OutIter.cpp +++ b/src/libnrtype/Layout-TNG-OutIter.cpp @@ -788,12 +788,12 @@ bool Layout::iterator::prevLineCursor(int n) { if (!_cursor_moving_vertically) beginCursorUpDown(); - unsigned line_index; + int line_index; if (_char_index == _parent_layout->_characters.size()) line_index = _parent_layout->_lines.size() - 1; else line_index = _parent_layout->_characters[_char_index].chunk(_parent_layout).in_line; - if (line_index == 0) + if (line_index <= 0) return false; // nowhere to go else n = MIN (n, static_cast(line_index)); diff --git a/src/libnrtype/Layout-TNG.h b/src/libnrtype/Layout-TNG.h index e91c32ebe..26db1fad9 100644 --- a/src/libnrtype/Layout-TNG.h +++ b/src/libnrtype/Layout-TNG.h @@ -701,7 +701,11 @@ private: /** The overall block-progression of the whole flow. */ inline Direction _blockProgression() const - {return static_cast(_input_stream.front())->styleGetBlockProgression();} + { + if(!_input_stream.empty()) + return static_cast(_input_stream.front())->styleGetBlockProgression(); + return TOP_TO_BOTTOM; + } /** so that LEFT_TO_RIGHT == RIGHT_TO_LEFT but != TOP_TO_BOTTOM */ static bool _directions_are_orthogonal(Direction d1, Direction d2); -- cgit v1.2.3 From e5eda536f276f5042474ea65bba99a694afbeb71 Mon Sep 17 00:00:00 2001 From: Krzysztof Kosi??ski Date: Fri, 8 May 2015 17:35:07 +0200 Subject: Adjust CMakeLists for 2geom directory (bzr r14059.2.8) --- src/2geom/CMakeLists.txt | 4 ---- 1 file changed, 4 deletions(-) (limited to 'src') diff --git a/src/2geom/CMakeLists.txt b/src/2geom/CMakeLists.txt index 119c7aa71..eb25074ef 100644 --- a/src/2geom/CMakeLists.txt +++ b/src/2geom/CMakeLists.txt @@ -11,7 +11,6 @@ set(2geom_SRC circle.cpp # conic_section_clipper_impl.cpp # conicsec.cpp - conjugate_gradient.cpp convex-hull.cpp coord.cpp crossing.cpp @@ -34,7 +33,6 @@ set(2geom_SRC quadtree.cpp rect.cpp # recursive-bezier-intersection.cpp - region.cpp sbasis-2d.cpp sbasis-geometric.cpp sbasis-math.cpp @@ -42,7 +40,6 @@ set(2geom_SRC sbasis-roots.cpp sbasis-to-bezier.cpp sbasis.cpp - shape.cpp solve-bezier.cpp solve-bezier-one-d.cpp solve-bezier-parametric.cpp @@ -67,7 +64,6 @@ set(2geom_SRC bezier.h choose.h circle.h - circulator.h concepts.h conic_section_clipper.h conic_section_clipper_cr.h -- cgit v1.2.3 From 9d9699dd9cc0e86ac34a97f051ddf975bd004b8e Mon Sep 17 00:00:00 2001 From: Krzysztof Kosi??ski Date: Fri, 8 May 2015 17:37:07 +0200 Subject: Remove round_rectangle_outwards from helper/geom.h (bzr r14059.2.9) --- src/helper/geom.cpp | 12 ------------ src/helper/geom.h | 2 -- src/main.cpp | 2 +- 3 files changed, 1 insertion(+), 15 deletions(-) (limited to 'src') diff --git a/src/helper/geom.cpp b/src/helper/geom.cpp index daaf90ff2..0e97265d1 100644 --- a/src/helper/geom.cpp +++ b/src/helper/geom.cpp @@ -856,18 +856,6 @@ recursive_bezier4(const double x1, const double y1, } -/** - * rounds all corners of the rectangle 'outwards', i.e. x0 and y0 are floored, x1 and y1 are ceiled. - */ -void round_rectangle_outwards(Geom::Rect & rect) { - Geom::Interval ints[2]; - for (int i=0; i < 2; i++) { - ints[i] = Geom::Interval(std::floor(rect[i][0]), std::ceil(rect[i][1])); - } - rect = Geom::Rect(ints[0], ints[1]); -} - - namespace Geom { bool transform_equalp(Geom::Affine const &m0, Geom::Affine const &m1, Geom::Coord const epsilon) { diff --git a/src/helper/geom.h b/src/helper/geom.h index 3232d9fd5..22d770040 100644 --- a/src/helper/geom.h +++ b/src/helper/geom.h @@ -33,8 +33,6 @@ void recursive_bezier4(const double x1, const double y1, const double x2, const std::vector &pointlist, int level); -void round_rectangle_outwards(Geom::Rect & rect); - namespace Geom{ bool transform_equalp(Geom::Affine const &m0, Geom::Affine const &m1, Geom::Coord const epsilon); bool translate_equalp(Geom::Affine const &m0, Geom::Affine const &m1, Geom::Coord const epsilon); diff --git a/src/main.cpp b/src/main.cpp index 415118407..f72b6d121 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1545,7 +1545,7 @@ static int sp_do_export_png(SPDocument *doc) } if (sp_export_area_snap) { - round_rectangle_outwards(area); + area = area.roundOutwards(); } // default dpi -- cgit v1.2.3 From e18021588feee8f6872fd362b9f4ba5902ef1da9 Mon Sep 17 00:00:00 2001 From: Krzysztof Kosi??ski Date: Fri, 8 May 2015 17:40:38 +0200 Subject: More helper/geom.h pruning. Remove transform_equalp, translate_equalp and matrix_equalp. (bzr r14059.2.10) --- src/helper/geom.cpp | 23 ----------------------- src/helper/geom.h | 5 ----- src/sp-gradient-test.h | 14 +++++++------- 3 files changed, 7 insertions(+), 35 deletions(-) (limited to 'src') diff --git a/src/helper/geom.cpp b/src/helper/geom.cpp index 0e97265d1..42d1a3150 100644 --- a/src/helper/geom.cpp +++ b/src/helper/geom.cpp @@ -855,29 +855,6 @@ recursive_bezier4(const double x1, const double y1, recursive_bezier4(x1234, y1234, x234, y234, x34, y34, x4, y4, m_points, level + 1); } - -namespace Geom { - -bool transform_equalp(Geom::Affine const &m0, Geom::Affine const &m1, Geom::Coord const epsilon) { - return - Geom::are_near(m0[0], m1[0], epsilon) && - Geom::are_near(m0[1], m1[1], epsilon) && - Geom::are_near(m0[2], m1[2], epsilon) && - Geom::are_near(m0[3], m1[3], epsilon); -} - - -bool translate_equalp(Geom::Affine const &m0, Geom::Affine const &m1, Geom::Coord const epsilon) { - return Geom::are_near(m0[4], m1[4], epsilon) && Geom::are_near(m0[5], m1[5], epsilon); -} - - -bool matrix_equalp(Geom::Affine const &m0, Geom::Affine const &m1, Geom::Coord const epsilon) { - return transform_equalp(m0, m1, epsilon) && translate_equalp(m0, m1, epsilon); -} - -} //end namespace Geom - /* Local Variables: mode:c++ diff --git a/src/helper/geom.h b/src/helper/geom.h index 22d770040..d49e2070c 100644 --- a/src/helper/geom.h +++ b/src/helper/geom.h @@ -33,11 +33,6 @@ void recursive_bezier4(const double x1, const double y1, const double x2, const std::vector &pointlist, int level); -namespace Geom{ -bool transform_equalp(Geom::Affine const &m0, Geom::Affine const &m1, Geom::Coord const epsilon); -bool translate_equalp(Geom::Affine const &m0, Geom::Affine const &m1, Geom::Coord const epsilon); -bool matrix_equalp(Geom::Affine const &m0, Geom::Affine const &m1, Geom::Coord const epsilon); -} #endif // INKSCAPE_HELPER_GEOM_H /* diff --git a/src/sp-gradient-test.h b/src/sp-gradient-test.h index 696072929..578d0c5c0 100644 --- a/src/sp-gradient-test.h +++ b/src/sp-gradient-test.h @@ -102,10 +102,10 @@ public: Geom::Affine const g2d(sp_gradient_get_g2d_matrix(gr, Geom::identity(), unit_rect)); Geom::Affine const gs2d(sp_gradient_get_gs2d_matrix(gr, Geom::identity(), unit_rect)); TS_ASSERT_EQUALS( g2d, Geom::identity() ); - TS_ASSERT( Geom::matrix_equalp(gs2d, gr->gradientTransform * g2d, 1e-12) ); + TS_ASSERT( Geom::are_near(gs2d, gr->gradientTransform * g2d, 1e-12) ); sp_gradient_set_gs2d_matrix(gr, Geom::identity(), unit_rect, gs2d); - TS_ASSERT( Geom::matrix_equalp(gr->gradientTransform, grXform, 1e-12) ); + TS_ASSERT( Geom::are_near(gr->gradientTransform, grXform, 1e-12) ); } gr->gradientTransform = grXform; @@ -116,10 +116,10 @@ public: Geom::Affine const g2d(sp_gradient_get_g2d_matrix(gr, funny, unit_rect)); Geom::Affine const gs2d(sp_gradient_get_gs2d_matrix(gr, funny, unit_rect)); TS_ASSERT_EQUALS( g2d, funny ); - TS_ASSERT( Geom::matrix_equalp(gs2d, gr->gradientTransform * g2d, 1e-12) ); + TS_ASSERT( Geom::are_near(gs2d, gr->gradientTransform * g2d, 1e-12) ); sp_gradient_set_gs2d_matrix(gr, funny, unit_rect, gs2d); - TS_ASSERT( Geom::matrix_equalp(gr->gradientTransform, grXform, 1e-12) ); + TS_ASSERT( Geom::are_near(gr->gradientTransform, grXform, 1e-12) ); } gr->gradientTransform = grXform; @@ -130,16 +130,16 @@ public: TS_ASSERT_EQUALS( g2d, Geom::Affine(3, 0, 0, 4, 5, 6) * funny ); - TS_ASSERT( Geom::matrix_equalp(gs2d, gr->gradientTransform * g2d, 1e-12) ); + TS_ASSERT( Geom::are_near(gs2d, gr->gradientTransform * g2d, 1e-12) ); sp_gradient_set_gs2d_matrix(gr, funny, larger_rect, gs2d); - TS_ASSERT( Geom::matrix_equalp(gr->gradientTransform, grXform, 1e-12) ); + TS_ASSERT( Geom::are_near(gr->gradientTransform, grXform, 1e-12) ); SP_OBJECT(gr)->setKeyValue( SP_ATTR_GRADIENTUNITS, "userSpaceOnUse"); Geom::Affine const user_g2d(sp_gradient_get_g2d_matrix(gr, funny, larger_rect)); Geom::Affine const user_gs2d(sp_gradient_get_gs2d_matrix(gr, funny, larger_rect)); TS_ASSERT_EQUALS( user_g2d, funny ); - TS_ASSERT( Geom::matrix_equalp(user_gs2d, gr->gradientTransform * user_g2d, 1e-12) ); + TS_ASSERT( Geom::are_near(user_gs2d, gr->gradientTransform * user_g2d, 1e-12) ); } g_object_unref(gr); } -- cgit v1.2.3 From 1caee668eff9e8afe58a7592eb78908c96b530ba Mon Sep 17 00:00:00 2001 From: Marc Jeanmougin Date: Fri, 8 May 2015 19:16:19 +0200 Subject: fix for bug 168013 and its mask counterpart Fixed bugs: - https://launchpad.net/bugs/168013 (bzr r14129) --- src/sp-use.cpp | 62 +++++++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 59 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/sp-use.cpp b/src/sp-use.cpp index 239f487a4..c8a0830c1 100644 --- a/src/sp-use.cpp +++ b/src/sp-use.cpp @@ -22,6 +22,8 @@ #include "display/drawing-group.h" #include "attributes.h" #include "document.h" +#include "sp-clippath.h" +#include "sp-mask.h" #include "sp-factory.h" #include "sp-flowregion.h" #include "uri.h" @@ -426,16 +428,43 @@ void SPUse::move_compensate(Geom::Affine const *mp) { return; Geom::Affine m(*mp); + Geom::Affine t = this->get_parent_transform(); + Geom::Affine clone_move = t.inverse() * m * t; // this is not a simple move, do not try to compensate - if (!(m.isTranslation())) + if (!(m.isTranslation())){ + //BUT move clippaths accordingly. + //if clone has a clippath, move it accordingly + if(clip_ref->getObject()){ + SPObject *clip = clip_ref->getObject()->firstChild() ; + while(clip){ + SPItem *item = (SPItem*) clip; + if(item){ + item->transform *= m; + Geom::Affine identity; + item->doWriteTransform(clip->getRepr(),item->transform, &identity); + } + clip = clip->getNext(); + } + } + if(mask_ref->getObject()){ + SPObject *mask = mask_ref->getObject()->firstChild() ; + while(mask){ + SPItem *item = (SPItem*) mask; + if(item){ + item->transform *= m; + Geom::Affine identity; + item->doWriteTransform(mask->getRepr(),item->transform, &identity); + } + mask = mask->getNext(); + } + } return; + } // restore item->transform field from the repr, in case it was changed by seltrans this->readAttr ("transform"); - Geom::Affine t = this->get_parent_transform(); - Geom::Affine clone_move = t.inverse() * m * t; // calculate the compensation matrix and the advertized movement matrix Geom::Affine advertized_move; @@ -449,6 +478,33 @@ void SPUse::move_compensate(Geom::Affine const *mp) { g_assert_not_reached(); } + //if clone has a clippath, move it accordingly + if(clip_ref->getObject()){ + SPObject *clip = clip_ref->getObject()->firstChild() ; + while(clip){ + SPItem *item = (SPItem*) clip; + if(item){ + item->transform *= clone_move.inverse(); + Geom::Affine identity; + item->doWriteTransform(clip->getRepr(),item->transform, &identity); + } + clip = clip->getNext(); + } + } + if(mask_ref->getObject()){ + SPObject *mask = mask_ref->getObject()->firstChild() ; + while(mask){ + SPItem *item = (SPItem*) mask; + if(item){ + item->transform *= clone_move.inverse(); + Geom::Affine identity; + item->doWriteTransform(mask->getRepr(),item->transform, &identity); + } + mask = mask->getNext(); + } + } + + // commit the compensation this->transform *= clone_move; this->doWriteTransform(this->getRepr(), this->transform, &advertized_move); -- cgit v1.2.3 From 76268cdf97916d0de571586ff1111b90c1a65286 Mon Sep 17 00:00:00 2001 From: Marc Jeanmougin Date: Sat, 9 May 2015 00:04:46 +0200 Subject: fixes various bugs with clipping and masking Fixed bugs: - https://launchpad.net/bugs/569281 - https://launchpad.net/bugs/1319171 - https://launchpad.net/bugs/1177650 (bzr r14130) --- src/selection-chemistry.cpp | 34 ++++++++++++++++------------------ src/sp-clippath.cpp | 3 +-- src/sp-mask.cpp | 3 +-- 3 files changed, 18 insertions(+), 22 deletions(-) (limited to 'src') diff --git a/src/selection-chemistry.cpp b/src/selection-chemistry.cpp index 2cd4f6b4e..f72bd1259 100644 --- a/src/selection-chemistry.cpp +++ b/src/selection-chemistry.cpp @@ -3893,14 +3893,17 @@ void sp_selection_set_mask(SPDesktop *desktop, bool apply_clip_path, bool apply_ items_to_select.push_back(*i); } } else { - SPItem *i = NULL; - for (std::vector::const_iterator j=items.begin();j!=items.end();j++) { - i=*j; + SPItem *i = items.front(); + for (std::vector::const_iterator j=items.begin();(j+1)!=items.end();j++) { apply_to_items = g_slist_prepend(apply_to_items, i); items_to_select.push_back(i); + i=*(j+1); } - + Geom::Affine oldtr=i->transform; + i->doWriteTransform(i->getRepr(), i->i2doc_affine()); Inkscape::XML::Node *dup = SP_OBJECT(i)->getRepr()->duplicate(xml_doc); + i->doWriteTransform(i->getRepr(), oldtr); + mask_items = g_slist_prepend(mask_items, dup); if (remove_original) { @@ -3922,8 +3925,9 @@ void sp_selection_set_mask(SPDesktop *desktop, bool apply_clip_path, bool apply_ for (GSList *i = apply_to_items ; NULL != i ; i = i->next) { reprs_to_group.push_back(static_cast(i->data)->getRepr()); - items_to_select.erase(remove(items_to_select.begin(), items_to_select.end(), static_cast(i->data)), items_to_select.end()); + //items_to_select.erase(remove(items_to_select.begin(), items_to_select.end(), static_cast(i->data)), items_to_select.end()); } + items_to_select.clear(); sp_selection_group_impl(reprs_to_group, group, xml_doc, doc); @@ -3936,30 +3940,25 @@ void sp_selection_set_mask(SPDesktop *desktop, bool apply_clip_path, bool apply_ Inkscape::GC::release(group); } + if (grouping == PREFS_MASKOBJECT_GROUPING_SEPARATE) { + items_to_select.clear(); + } + gchar const *attributeName = apply_clip_path ? "clip-path" : "mask"; for (GSList *i = apply_to_items; NULL != i; i = i->next) { SPItem *item = reinterpret_cast(i->data); // inverted object transform should be applied to a mask object, // as mask is calculated in user space (after applying transform) - Geom::Affine maskTransform(item->transform.inverse()); - - GSList *mask_items_dup = NULL; - for (GSList *mask_item = mask_items; NULL != mask_item; mask_item = mask_item->next) { - Inkscape::XML::Node *dup = reinterpret_cast(mask_item->data)->duplicate(xml_doc); - mask_items_dup = g_slist_prepend(mask_items_dup, dup); - } + Geom::Affine maskTransform(item->i2doc_affine().inverse()); gchar const *mask_id = NULL; if (apply_clip_path) { - mask_id = SPClipPath::create(mask_items_dup, doc, &maskTransform); + mask_id = SPClipPath::create(mask_items, doc, &maskTransform); } else { - mask_id = sp_mask_create(mask_items_dup, doc, &maskTransform); + mask_id = sp_mask_create(mask_items, doc, &maskTransform); } - g_slist_free(mask_items_dup); - mask_items_dup = NULL; - Inkscape::XML::Node *current = SP_OBJECT(i->data)->getRepr(); // Node to apply mask to Inkscape::XML::Node *apply_mask_to = current; @@ -3972,7 +3971,6 @@ void sp_selection_set_mask(SPDesktop *desktop, bool apply_clip_path, bool apply_ Inkscape::XML::Node *spnew = current->duplicate(xml_doc); gint position = current->position(); - items_to_select.erase(remove(items_to_select.begin(), items_to_select.end(), item), items_to_select.end()); current->parent()->appendChild(group); sp_repr_unparent(current); group->appendChild(spnew); diff --git a/src/sp-clippath.cpp b/src/sp-clippath.cpp index 3c6167438..0c13ca80d 100644 --- a/src/sp-clippath.cpp +++ b/src/sp-clippath.cpp @@ -313,8 +313,7 @@ const gchar *SPClipPath::create (GSList *reprs, SPDocument *document, Geom::Affi SPItem *item = SP_ITEM(clip_path_object->appendChildRepr(node)); if (NULL != applyTransform) { - Geom::Affine transform (item->transform); - transform *= (*applyTransform); + Geom::Affine transform (item->transform * (*applyTransform)); item->doWriteTransform(item->getRepr(), transform); } } diff --git a/src/sp-mask.cpp b/src/sp-mask.cpp index d60473e1d..c36c3c005 100644 --- a/src/sp-mask.cpp +++ b/src/sp-mask.cpp @@ -226,8 +226,7 @@ sp_mask_create (GSList *reprs, SPDocument *document, Geom::Affine const* applyTr SPItem *item = SP_ITEM(mask_object->appendChildRepr(node)); if (NULL != applyTransform) { - Geom::Affine transform (item->transform); - transform *= (*applyTransform); + Geom::Affine transform (item->transform * (*applyTransform)); item->doWriteTransform(item->getRepr(), transform); } } -- cgit v1.2.3 From 7cb183695ed9eec9fb3e08045e4a265d10eca76e Mon Sep 17 00:00:00 2001 From: Marc Jeanmougin Date: Sat, 9 May 2015 01:05:06 +0200 Subject: refactor sp_selection_set_mask (bzr r14131) --- src/selection-chemistry.cpp | 94 +++++++++++++++------------------------------ src/sp-clippath.cpp | 6 +-- src/sp-clippath.h | 2 +- src/sp-mask.cpp | 6 +-- src/sp-mask.h | 2 +- 5 files changed, 40 insertions(+), 70 deletions(-) (limited to 'src') diff --git a/src/selection-chemistry.cpp b/src/selection-chemistry.cpp index f72bd1259..7be1e3ec0 100644 --- a/src/selection-chemistry.cpp +++ b/src/selection-chemistry.cpp @@ -3787,13 +3787,11 @@ void sp_selection_set_clipgroup(SPDesktop *desktop) clone->setAttribute("inkscape:transform-center-y", inner->attribute("inkscape:transform-center-y"), false); const Geom::Affine maskTransform(Geom::Affine::identity()); - GSList *templist = NULL; - - templist = g_slist_append(templist, clone); + std::vector templist; + templist.push_back(clone); // add the new clone to the top of the original's parent gchar const *mask_id = SPClipPath::create(templist, doc, &maskTransform); - g_slist_free(templist); outer->setAttribute("clip-path", g_strdup_printf("url(#%s)", mask_id)); @@ -3851,9 +3849,9 @@ void sp_selection_set_mask(SPDesktop *desktop, bool apply_clip_path, bool apply_ selection->clear(); // create a list of duplicates - GSList *mask_items = NULL; - GSList *apply_to_items = NULL; - GSList *items_to_delete = NULL; + std::vector mask_items; + std::vector apply_to_items; + std::vector items_to_delete; std::vector items_to_select; Inkscape::Preferences *prefs = Inkscape::Preferences::get(); @@ -3863,57 +3861,36 @@ void sp_selection_set_mask(SPDesktop *desktop, bool apply_clip_path, bool apply_ if (apply_to_layer) { // all selected items are used for mask, which is applied to a layer - apply_to_items = g_slist_prepend(apply_to_items, desktop->currentLayer()); + apply_to_items.push_back(SP_ITEM(desktop->currentLayer())); + } + + for (std::vector::const_iterator i=items.begin();i!=items.end();i++) { + if((!topmost && !apply_to_layer && *i == items.front()) + || (topmost && !apply_to_layer && *i == items.back()) + || apply_to_layer){ - for (std::vector::const_iterator i=items.begin();i!=items.end();i++) { + Geom::Affine oldtr=(*i)->transform; + (*i)->doWriteTransform((*i)->getRepr(), (*i)->i2doc_affine()); Inkscape::XML::Node *dup = (*i)->getRepr()->duplicate(xml_doc); - mask_items = g_slist_prepend(mask_items, dup); + (*i)->doWriteTransform((*i)->getRepr(), oldtr); + mask_items.push_back(dup); - SPObject *item = *i; if (remove_original) { - items_to_delete = g_slist_prepend(items_to_delete, item); + items_to_delete.push_back(*i); } else { - items_to_select.push_back((SPItem*)item); + items_to_select.push_back(*i); } - } - } else if (!topmost) { - // topmost item is used as a mask, which is applied to other items in a selection - Inkscape::XML::Node *dup = items[0]->getRepr()->duplicate(xml_doc); - mask_items = g_slist_prepend(mask_items, dup); - - if (remove_original) { - SPObject *item = items.front(); - items_to_delete = g_slist_prepend(items_to_delete, item); - } - - for (std::vector::const_iterator i=items.begin();i!=items.end();i++) { - if(i==items.begin())continue; - apply_to_items = g_slist_prepend(apply_to_items, *i); + continue; + }else{ + apply_to_items.push_back(*i); items_to_select.push_back(*i); } - } else { - SPItem *i = items.front(); - for (std::vector::const_iterator j=items.begin();(j+1)!=items.end();j++) { - apply_to_items = g_slist_prepend(apply_to_items, i); - items_to_select.push_back(i); - i=*(j+1); - } - Geom::Affine oldtr=i->transform; - i->doWriteTransform(i->getRepr(), i->i2doc_affine()); - Inkscape::XML::Node *dup = SP_OBJECT(i)->getRepr()->duplicate(xml_doc); - i->doWriteTransform(i->getRepr(), oldtr); - - mask_items = g_slist_prepend(mask_items, dup); - - if (remove_original) { - SPObject *item = reinterpret_cast(i); - items_to_delete = g_slist_prepend(items_to_delete, item); - } } + items.clear(); - if (apply_to_items && grouping == PREFS_MASKOBJECT_GROUPING_ALL) { + if (grouping == PREFS_MASKOBJECT_GROUPING_ALL) { // group all those objects into one group // and apply mask to that Inkscape::XML::Node *group = xml_doc->createElement("svg:g"); @@ -3922,19 +3899,16 @@ void sp_selection_set_mask(SPDesktop *desktop, bool apply_clip_path, bool apply_ group->setAttribute("inkscape:groupmode", "maskhelper"); std::vector reprs_to_group; - - for (GSList *i = apply_to_items ; NULL != i ; i = i->next) { - reprs_to_group.push_back(static_cast(i->data)->getRepr()); - //items_to_select.erase(remove(items_to_select.begin(), items_to_select.end(), static_cast(i->data)), items_to_select.end()); + for (std::vector::const_iterator i = apply_to_items.begin(); i != apply_to_items.end(); i++) { + reprs_to_group.push_back(static_cast(*i)->getRepr()); } items_to_select.clear(); sp_selection_group_impl(reprs_to_group, group, xml_doc, doc); // apply clip/mask only to newly created group - g_slist_free(apply_to_items); - apply_to_items = NULL; - apply_to_items = g_slist_prepend(apply_to_items, doc->getObjectByRepr(group)); + apply_to_items.clear(); + apply_to_items.push_back(dynamic_cast(doc->getObjectByRepr(group))); items_to_select.push_back((SPItem*)(doc->getObjectByRepr(group))); @@ -3946,8 +3920,8 @@ void sp_selection_set_mask(SPDesktop *desktop, bool apply_clip_path, bool apply_ gchar const *attributeName = apply_clip_path ? "clip-path" : "mask"; - for (GSList *i = apply_to_items; NULL != i; i = i->next) { - SPItem *item = reinterpret_cast(i->data); + for (std::vector::const_reverse_iterator i = apply_to_items.rbegin(); i != apply_to_items.rend(); i++) { + SPItem *item = reinterpret_cast(*i); // inverted object transform should be applied to a mask object, // as mask is calculated in user space (after applying transform) Geom::Affine maskTransform(item->i2doc_affine().inverse()); @@ -3959,7 +3933,7 @@ void sp_selection_set_mask(SPDesktop *desktop, bool apply_clip_path, bool apply_ mask_id = sp_mask_create(mask_items, doc, &maskTransform); } - Inkscape::XML::Node *current = SP_OBJECT(i->data)->getRepr(); + Inkscape::XML::Node *current = SP_OBJECT(*i)->getRepr(); // Node to apply mask to Inkscape::XML::Node *apply_mask_to = current; @@ -3988,15 +3962,11 @@ void sp_selection_set_mask(SPDesktop *desktop, bool apply_clip_path, bool apply_ } - g_slist_free(mask_items); - g_slist_free(apply_to_items); - - for (GSList *i = items_to_delete; NULL != i; i = i->next) { - SPObject *item = reinterpret_cast(i->data); + for (std::vector::const_iterator i = items_to_delete.begin(); i != items_to_delete.end(); i++) { + SPObject *item = reinterpret_cast(*i); item->deleteObject(false); items_to_select.erase(remove(items_to_select.begin(), items_to_select.end(), item), items_to_select.end()); } - g_slist_free(items_to_delete); selection->addList(items_to_select); diff --git a/src/sp-clippath.cpp b/src/sp-clippath.cpp index 0c13ca80d..d66508eae 100644 --- a/src/sp-clippath.cpp +++ b/src/sp-clippath.cpp @@ -296,7 +296,7 @@ sp_clippath_view_list_remove(SPClipPathView *list, SPClipPathView *view) } // Create a mask element (using passed elements), add it to -const gchar *SPClipPath::create (GSList *reprs, SPDocument *document, Geom::Affine const* applyTransform) +const gchar *SPClipPath::create (std::vector &reprs, SPDocument *document, Geom::Affine const* applyTransform) { Inkscape::XML::Node *defsrepr = document->getDefs()->getRepr(); @@ -308,8 +308,8 @@ const gchar *SPClipPath::create (GSList *reprs, SPDocument *document, Geom::Affi const gchar *id = repr->attribute("id"); SPObject *clip_path_object = document->getObjectById(id); - for (GSList *it = reprs; it != NULL; it = it->next) { - Inkscape::XML::Node *node = (Inkscape::XML::Node *)(it->data); + for (std::vector::const_iterator it = reprs.begin(); it != reprs.end(); it++) { + Inkscape::XML::Node *node = (*it); SPItem *item = SP_ITEM(clip_path_object->appendChildRepr(node)); if (NULL != applyTransform) { diff --git a/src/sp-clippath.h b/src/sp-clippath.h index eb8b14174..91dcfd625 100644 --- a/src/sp-clippath.h +++ b/src/sp-clippath.h @@ -45,7 +45,7 @@ public: unsigned int clipPathUnits : 1; SPClipPathView *display; - static char const *create(GSList *reprs, SPDocument *document, Geom::Affine const* applyTransform); + static char const *create(std::vector &reprs, SPDocument *document, Geom::Affine const* applyTransform); //static GType sp_clippath_get_type(void); Inkscape::DrawingItem *show(Inkscape::Drawing &drawing, unsigned int key); diff --git a/src/sp-mask.cpp b/src/sp-mask.cpp index c36c3c005..f8fb7aff4 100644 --- a/src/sp-mask.cpp +++ b/src/sp-mask.cpp @@ -209,7 +209,7 @@ Inkscape::XML::Node* SPMask::write(Inkscape::XML::Document* xml_doc, Inkscape::X // Create a mask element (using passed elements), add it to const gchar * -sp_mask_create (GSList *reprs, SPDocument *document, Geom::Affine const* applyTransform) +sp_mask_create (std::vector &reprs, SPDocument *document, Geom::Affine const* applyTransform) { Inkscape::XML::Node *defsrepr = document->getDefs()->getRepr(); @@ -221,8 +221,8 @@ sp_mask_create (GSList *reprs, SPDocument *document, Geom::Affine const* applyTr const gchar *mask_id = repr->attribute("id"); SPObject *mask_object = document->getObjectById(mask_id); - for (GSList *it = reprs; it != NULL; it = it->next) { - Inkscape::XML::Node *node = (Inkscape::XML::Node *)(it->data); + for (std::vector::const_iterator it = reprs.begin(); it != reprs.end(); it++) { + Inkscape::XML::Node *node = (*it); SPItem *item = SP_ITEM(mask_object->appendChildRepr(node)); if (NULL != applyTransform) { diff --git a/src/sp-mask.h b/src/sp-mask.h index e991fedb6..3559483bb 100644 --- a/src/sp-mask.h +++ b/src/sp-mask.h @@ -108,6 +108,6 @@ protected: } }; -const char *sp_mask_create (GSList *reprs, SPDocument *document, Geom::Affine const* applyTransform); +const char *sp_mask_create (std::vector &reprs, SPDocument *document, Geom::Affine const* applyTransform); #endif // SEEN_SP_MASK_H -- cgit v1.2.3 From 31c3977006f63720ca6aa473585760da7d59a833 Mon Sep 17 00:00:00 2001 From: Marc Jeanmougin Date: Sat, 9 May 2015 01:50:13 +0200 Subject: fixed logic error in earlier fix (bzr r14132) --- src/selection-chemistry.cpp | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) (limited to 'src') diff --git a/src/selection-chemistry.cpp b/src/selection-chemistry.cpp index 7be1e3ec0..4352878d6 100644 --- a/src/selection-chemistry.cpp +++ b/src/selection-chemistry.cpp @@ -3924,15 +3924,6 @@ void sp_selection_set_mask(SPDesktop *desktop, bool apply_clip_path, bool apply_ SPItem *item = reinterpret_cast(*i); // inverted object transform should be applied to a mask object, // as mask is calculated in user space (after applying transform) - Geom::Affine maskTransform(item->i2doc_affine().inverse()); - - gchar const *mask_id = NULL; - if (apply_clip_path) { - mask_id = SPClipPath::create(mask_items, doc, &maskTransform); - } else { - mask_id = sp_mask_create(mask_items, doc, &maskTransform); - } - Inkscape::XML::Node *current = SP_OBJECT(*i)->getRepr(); // Node to apply mask to Inkscape::XML::Node *apply_mask_to = current; @@ -3953,11 +3944,22 @@ void sp_selection_set_mask(SPDesktop *desktop, bool apply_clip_path, bool apply_ // Apply clip/mask to group instead apply_mask_to = group; - items_to_select.push_back((SPItem*)(doc->getObjectByRepr(group))); + items_to_select.push_back(item = (SPItem*)(doc->getObjectByRepr(group))); Inkscape::GC::release(spnew); Inkscape::GC::release(group); } + + + Geom::Affine maskTransform(item->i2doc_affine().inverse()); + + gchar const *mask_id = NULL; + if (apply_clip_path) { + mask_id = SPClipPath::create(mask_items, doc, &maskTransform); + } else { + mask_id = sp_mask_create(mask_items, doc, &maskTransform); + } + apply_mask_to->setAttribute(attributeName, Glib::ustring("url(#") + mask_id + ')'); } -- cgit v1.2.3 From 13fc1db22c959600f7b179abf1a70ca42ab587de Mon Sep 17 00:00:00 2001 From: Marc Jeanmougin Date: Sat, 9 May 2015 02:57:05 +0200 Subject: fix crash introduces by recent rev when clipping (bzr r14133) --- src/selection-chemistry.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/selection-chemistry.cpp b/src/selection-chemistry.cpp index 4352878d6..a21a82983 100644 --- a/src/selection-chemistry.cpp +++ b/src/selection-chemistry.cpp @@ -3924,6 +3924,9 @@ void sp_selection_set_mask(SPDesktop *desktop, bool apply_clip_path, bool apply_ SPItem *item = reinterpret_cast(*i); // inverted object transform should be applied to a mask object, // as mask is calculated in user space (after applying transform) + std::vector mask_items_dup; + for(std::vector::const_iterator it=mask_items.begin();it!=mask_items.end();it++) + mask_items_dup.push_back((*it)->duplicate(xml_doc)); Inkscape::XML::Node *current = SP_OBJECT(*i)->getRepr(); // Node to apply mask to Inkscape::XML::Node *apply_mask_to = current; @@ -3949,15 +3952,13 @@ void sp_selection_set_mask(SPDesktop *desktop, bool apply_clip_path, bool apply_ Inkscape::GC::release(group); } - - Geom::Affine maskTransform(item->i2doc_affine().inverse()); gchar const *mask_id = NULL; if (apply_clip_path) { - mask_id = SPClipPath::create(mask_items, doc, &maskTransform); + mask_id = SPClipPath::create(mask_items_dup, doc, &maskTransform); } else { - mask_id = sp_mask_create(mask_items, doc, &maskTransform); + mask_id = sp_mask_create(mask_items_dup, doc, &maskTransform); } apply_mask_to->setAttribute(attributeName, Glib::ustring("url(#") + mask_id + ')'); -- cgit v1.2.3 From ae5fc6f7c5d78bca051dcc308d3344c65fb802cb Mon Sep 17 00:00:00 2001 From: Tomasz Boczkowski Date: Sat, 9 May 2015 13:41:17 +0200 Subject: Using MODE_SOLID_COLOR in paint selector instead of duplicated MODE_COLOR_RGB and MODE_COLOR_CMYK (bzr r14059.1.22) --- src/widgets/fill-style.cpp | 6 ++---- src/widgets/paint-selector.cpp | 14 ++++++-------- src/widgets/paint-selector.h | 3 +-- 3 files changed, 9 insertions(+), 14 deletions(-) (limited to 'src') diff --git a/src/widgets/fill-style.cpp b/src/widgets/fill-style.cpp index 264ebff5a..fa5eabab4 100644 --- a/src/widgets/fill-style.cpp +++ b/src/widgets/fill-style.cpp @@ -431,8 +431,7 @@ void FillNStroke::dragFromPaint() update = true; switch (psel->mode) { - case SPPaintSelector::MODE_COLOR_RGB: - case SPPaintSelector::MODE_COLOR_CMYK: + case SPPaintSelector::MODE_SOLID_COLOR: { // local change, do not update from selection dragId = g_timeout_add_full(G_PRIORITY_DEFAULT, 100, dragDelayCB, this, 0); @@ -505,8 +504,7 @@ void FillNStroke::updateFromPaint() break; } - case SPPaintSelector::MODE_COLOR_RGB: - case SPPaintSelector::MODE_COLOR_CMYK: + case SPPaintSelector::MODE_SOLID_COLOR: { if (kind == FILL) { // FIXME: fix for GTK breakage, see comment in SelectedStyle::on_opacity_changed; here it results in losing release events diff --git a/src/widgets/paint-selector.cpp b/src/widgets/paint-selector.cpp index 3b191b2f3..8dd309260 100644 --- a/src/widgets/paint-selector.cpp +++ b/src/widgets/paint-selector.cpp @@ -95,8 +95,7 @@ static gchar const* modeStrings[] = { "MODE_EMPTY", "MODE_MULTIPLE", "MODE_NONE", - "MODE_COLOR_RGB", - "MODE_COLOR_CMYK", + "MODE_SOLID_COLOR", "MODE_GRADIENT_LINEAR", "MODE_GRADIENT_RADIAL", "MODE_PATTERN", @@ -219,7 +218,7 @@ sp_paint_selector_init(SPPaintSelector *psel) psel->none = sp_paint_selector_style_button_add(psel, INKSCAPE_ICON("paint-none"), SPPaintSelector::MODE_NONE, _("No paint")); psel->solid = sp_paint_selector_style_button_add(psel, INKSCAPE_ICON("paint-solid"), - SPPaintSelector::MODE_COLOR_RGB, _("Flat color")); + SPPaintSelector::MODE_SOLID_COLOR, _("Flat color")); psel->gradient = sp_paint_selector_style_button_add(psel, INKSCAPE_ICON("paint-gradient-linear"), SPPaintSelector::MODE_GRADIENT_LINEAR, _("Linear gradient")); psel->radial = sp_paint_selector_style_button_add(psel, INKSCAPE_ICON("paint-gradient-radial"), @@ -407,8 +406,7 @@ void SPPaintSelector::setMode(Mode mode) case MODE_NONE: sp_paint_selector_set_mode_none(this); break; - case MODE_COLOR_RGB: - case MODE_COLOR_CMYK: + case MODE_SOLID_COLOR: sp_paint_selector_set_mode_color(this, mode); break; case MODE_GRADIENT_LINEAR: @@ -465,7 +463,7 @@ void SPPaintSelector::setColorAlpha(SPColor const &color, float alpha) #ifdef SP_PS_VERBOSE g_print("PaintSelector set RGBA\n"); #endif - setMode(MODE_COLOR_RGB); + setMode(MODE_SOLID_COLOR); } updating_color = true; @@ -681,7 +679,7 @@ static void sp_paint_selector_set_mode_color(SPPaintSelector *psel, SPPaintSelec sp_paint_selector_set_style_buttons(psel, psel->solid); gtk_widget_set_sensitive(psel->style, TRUE); - if ((psel->mode == SPPaintSelector::MODE_COLOR_RGB) || (psel->mode == SPPaintSelector::MODE_COLOR_CMYK)) { + if ((psel->mode == SPPaintSelector::MODE_SOLID_COLOR)) { /* Already have color selector */ // Do nothing } else { @@ -1262,7 +1260,7 @@ SPPaintSelector::Mode SPPaintSelector::getModeForStyle(SPStyle const & style, Fi } } else if ( target.isColor() ) { // TODO this is no longer a valid assertion: - mode = MODE_COLOR_RGB; // so far only rgb can be read from svg + mode = MODE_SOLID_COLOR; // so far only rgb can be read from svg } else if ( target.isNone() ) { mode = MODE_NONE; } else { diff --git a/src/widgets/paint-selector.h b/src/widgets/paint-selector.h index 55f0e8ec9..23c2dd456 100644 --- a/src/widgets/paint-selector.h +++ b/src/widgets/paint-selector.h @@ -50,8 +50,7 @@ struct SPPaintSelector { MODE_EMPTY, MODE_MULTIPLE, MODE_NONE, - MODE_COLOR_RGB, - MODE_COLOR_CMYK, + MODE_SOLID_COLOR, MODE_GRADIENT_LINEAR, MODE_GRADIENT_RADIAL, #ifdef WITH_MESH -- cgit v1.2.3 From cd9885ddc7dfbf7769f902dd7ee043892a2c8ee9 Mon Sep 17 00:00:00 2001 From: Tomasz Boczkowski Date: Sat, 9 May 2015 14:53:54 +0200 Subject: fixed crash in paint selector when changing from gradient to solid color (bzr r14059.1.23) --- src/ui/selected-color.cpp | 17 ++++++++++------- src/ui/selected-color.h | 2 +- src/ui/widget/color-scales.cpp | 11 +++-------- src/widgets/paint-selector.cpp | 18 ++++++++++++++---- 4 files changed, 28 insertions(+), 20 deletions(-) (limited to 'src') diff --git a/src/ui/selected-color.cpp b/src/ui/selected-color.cpp index 7652e5acf..6573129d3 100644 --- a/src/ui/selected-color.cpp +++ b/src/ui/selected-color.cpp @@ -72,7 +72,7 @@ guint32 SelectedColor::value() const return color().toRGBA32(_alpha); } -void SelectedColor::setColorAlpha(SPColor const &color, gfloat alpha) +void SelectedColor::setColorAlpha(SPColor const &color, gfloat alpha, bool emit_signal) { #ifdef DUMP_CHANGE_INFO g_message("SelectedColor::setColorAlpha( this=%p, %f, %f, %f, %s, %f, %s) in %s", this, color.v.c[0], color.v.c[1], color.v.c[2], (color.icc?color.icc->colorProfile.c_str():""), alpha, (emit?"YES":"no"), FOO_NAME(_csel)); @@ -100,13 +100,16 @@ void SelectedColor::setColorAlpha(SPColor const &color, gfloat alpha) _color = color; _alpha = alpha; - _updating = true; - if (_held) { - signal_dragged.emit(); - } else { - signal_changed.emit(); + if (emit_signal) + { + _updating = true; + if (_held) { + signal_dragged.emit(); + } else { + signal_changed.emit(); + } + _updating = false; } - _updating = false; #ifdef DUMP_CHANGE_INFO } else { diff --git a/src/ui/selected-color.h b/src/ui/selected-color.h index 168099c82..e9e702d43 100644 --- a/src/ui/selected-color.h +++ b/src/ui/selected-color.h @@ -38,7 +38,7 @@ public: void setValue(guint32 value); guint32 value() const; - void setColorAlpha(SPColor const &color, gfloat alpha); + void setColorAlpha(SPColor const &color, gfloat alpha, bool emit_signal = true); void colorAlpha(SPColor &color, gfloat &alpha) const; void setHeld(bool held); diff --git a/src/ui/widget/color-scales.cpp b/src/ui/widget/color-scales.cpp index 5fa5af902..ead636406 100644 --- a/src/ui/widget/color-scales.cpp +++ b/src/ui/widget/color-scales.cpp @@ -376,8 +376,8 @@ void ColorScales::setMode(SPColorScalesMode mode) setScaled(_a[1], rgba[1]); setScaled(_a[2], rgba[2]); setScaled(_a[3], rgba[3]); - _updating = FALSE; _updateSliders(CSC_CHANNELS_ALL); + _updating = FALSE; break; case SP_COLOR_SCALES_MODE_HSV: _setRangeLimit(255.0); @@ -404,8 +404,8 @@ void ColorScales::setMode(SPColorScalesMode mode) setScaled(_a[1], c[1]); setScaled(_a[2], c[2]); setScaled(_a[3], rgba[3]); - _updating = FALSE; _updateSliders(CSC_CHANNELS_ALL); + _updating = FALSE; break; case SP_COLOR_SCALES_MODE_CMYK: _setRangeLimit(100.0); @@ -437,8 +437,8 @@ void ColorScales::setMode(SPColorScalesMode mode) setScaled(_a[3], c[3]); setScaled(_a[4], rgba[3]); - _updating = FALSE; _updateSliders(CSC_CHANNELS_ALL); + _updating = FALSE; break; default: g_warning("file %s: line %d: Illegal color selector mode", __FILE__, __LINE__); @@ -607,11 +607,6 @@ void ColorScales::_updateSliders(guint channels) break; } - // Force the internal color to be updated - if (!_updating) { - _recalcColor(); - } - #ifdef SPCS_PREVIEW rgba = sp_color_scales_get_rgba32(cs); sp_color_preview_set_rgba32(SP_COLOR_PREVIEW(_p), rgba); diff --git a/src/widgets/paint-selector.cpp b/src/widgets/paint-selector.cpp index 8dd309260..f9a537f41 100644 --- a/src/widgets/paint-selector.cpp +++ b/src/widgets/paint-selector.cpp @@ -657,7 +657,12 @@ void SPPaintSelector::onSelectedColorChanged() { if (updating_color) { return; } - g_signal_emit(G_OBJECT(this), psel_signals[CHANGED], 0); + + if (mode == MODE_SOLID_COLOR) { + g_signal_emit(G_OBJECT(this), psel_signals[CHANGED], 0); + } else { + g_warning("SPPaintSelector::onSelectedColorChanged(): selected color changed while not in color selection mode"); + } } static void sp_paint_selector_set_mode_color(SPPaintSelector *psel, SPPaintSelector::Mode /*mode*/) @@ -670,9 +675,14 @@ static void sp_paint_selector_set_mode_color(SPPaintSelector *psel, SPPaintSelec SPGradientSelector *gsel = getGradientFromData(psel); if (gsel) { SPGradient *gradient = gsel->getVector(); - SPColor color = gradient->getFirstStop()->specified_color; - float alpha = gradient->getFirstStop()->opacity; - psel->selected_color->setColorAlpha(color, alpha); + + // Gradient can be null if object paint is changed externally (ie. with a color picker tool) + if (gradient) + { + SPColor color = gradient->getFirstStop()->specified_color; + float alpha = gradient->getFirstStop()->opacity; + psel->selected_color->setColorAlpha(color, alpha, false); + } } } -- cgit v1.2.3 From 9b1d6715ff2a56c9f1b94c0f8474c3e4efd48539 Mon Sep 17 00:00:00 2001 From: Marc Jeanmougin Date: Sat, 9 May 2015 14:59:00 +0200 Subject: duplicating layers now respect prefs for clone relinking Fixed bugs: - https://launchpad.net/bugs/267565 (bzr r14134) --- src/selection-chemistry.cpp | 25 ++++++++++++++++++++----- src/selection-chemistry.h | 2 +- src/verbs.cpp | 36 +++--------------------------------- 3 files changed, 24 insertions(+), 39 deletions(-) (limited to 'src') diff --git a/src/selection-chemistry.cpp b/src/selection-chemistry.cpp index a21a82983..d6e9a1e32 100644 --- a/src/selection-chemistry.cpp +++ b/src/selection-chemistry.cpp @@ -107,6 +107,7 @@ SPCycleType SP_CYCLING = SP_CYCLE_FOCUS; #include "live_effects/effect.h" #include "live_effects/effect-enum.h" #include "live_effects/parameter/originalpath.h" +#include "layer-manager.h" #include "enums.h" #include "sp-item-group.h" @@ -438,7 +439,7 @@ static void add_ids_recursive(std::vector &ids, SPObject *obj) } } -void sp_selection_duplicate(SPDesktop *desktop, bool suppressDone) +void sp_selection_duplicate(SPDesktop *desktop, bool suppressDone, bool duplicateLayer) { if (desktop == NULL) { return; @@ -449,12 +450,17 @@ void sp_selection_duplicate(SPDesktop *desktop, bool suppressDone) Inkscape::Selection *selection = desktop->getSelection(); // check if something is selected - if (selection->isEmpty()) { + if (selection->isEmpty() && !duplicateLayer) { desktop->messageStack()->flash(Inkscape::WARNING_MESSAGE, _("Select object(s) to duplicate.")); return; } std::vector reprs(selection->reprList()); + if(duplicateLayer){ + reprs.clear(); + reprs.push_back(desktop->currentLayer()->getRepr()); + } + selection->clear(); // sorting items from different parents sorts each parent's subset without possibly mixing @@ -474,7 +480,10 @@ void sp_selection_duplicate(SPDesktop *desktop, bool suppressDone) Inkscape::XML::Node *parent = old_repr->parent(); Inkscape::XML::Node *copy = old_repr->duplicate(xml_doc); - parent->appendChild(copy); + if(! duplicateLayer) + parent->appendChild(copy); + else + parent->addChild(copy, old_repr); if (relink_clones) { SPObject *old_obj = doc->getObjectByRepr(old_repr); @@ -535,8 +544,14 @@ void sp_selection_duplicate(SPDesktop *desktop, bool suppressDone) DocumentUndo::done(desktop->getDocument(), SP_VERB_EDIT_DUPLICATE, _("Duplicate")); } - - selection->setReprList(newsel); + if(!duplicateLayer) + selection->setReprList(newsel); + else{ + SPObject* new_layer = doc->getObjectByRepr(newsel[0]); + gchar* name = g_strdup_printf(_("%s copy"), new_layer->label()); + desktop->layer_manager->renameLayer( new_layer, name, TRUE ); + g_free(name); + } } void sp_edit_clear_all(Inkscape::Selection *selection) diff --git a/src/selection-chemistry.h b/src/selection-chemistry.h index 8bcab664b..5bcc5b1ea 100644 --- a/src/selection-chemistry.h +++ b/src/selection-chemistry.h @@ -52,7 +52,7 @@ namespace LivePathEffect { } // namespace Inkscape void sp_selection_delete(SPDesktop *desktop); -void sp_selection_duplicate(SPDesktop *desktop, bool suppressDone = false); +void sp_selection_duplicate(SPDesktop *desktop, bool suppressDone = false, bool duplicateLayer = false); void sp_edit_clear_all(Inkscape::Selection *selection); void sp_edit_select_all(SPDesktop *desktop); diff --git a/src/verbs.cpp b/src/verbs.cpp index ea2c06dcf..e0ef27b0d 100644 --- a/src/verbs.cpp +++ b/src/verbs.cpp @@ -1350,39 +1350,9 @@ void LayerVerb::perform(SPAction *action, void *data) } case SP_VERB_LAYER_DUPLICATE: { if ( dt->currentLayer() != dt->currentRoot() ) { - // Note with either approach: - // Any clone masters are duplicated, their clones use the *original*, - // but the duplicated master is not linked up as master nor clone of the original. -#if 0 - // Only copies selectable things, honoring locks, visibility, avoids sublayers. - SPObject *new_layer = Inkscape::create_layer(dt->currentRoot(), dt->currentLayer(), LPOS_BELOW); - if ( dt->currentLayer()->label() ) { - gchar* name = g_strdup_printf(_("%s copy"), dt->currentLayer()->label()); - dt->layer_manager->renameLayer( new_layer, name, TRUE ); - g_free(name); - } - sp_edit_select_all(dt); - sp_selection_duplicate(dt, true); - sp_selection_to_prev_layer(dt, true); - dt->setCurrentLayer(new_layer); - sp_edit_select_all(dt); -#else - // Copies everything, regardless of locks, visibility, sublayers. - //XML Tree being directly used here while it shouldn't be. - Inkscape::XML::Node *selected = dt->currentLayer()->getRepr(); - Inkscape::XML::Node *parent = selected->parent(); - Inkscape::XML::Node *dup = selected->duplicate(parent->document()); - parent->addChild(dup, selected); - SPObject *new_layer = dt->currentLayer()->next; - if (new_layer) { - if (new_layer->label()) { - gchar* name = g_strdup_printf(_("%s copy"), new_layer->label()); - dt->layer_manager->renameLayer( new_layer, name, TRUE ); - g_free(name); - } - dt->setCurrentLayer(new_layer); - } -#endif + + sp_selection_duplicate(dt, true, true); + DocumentUndo::done(dt->getDocument(), SP_VERB_LAYER_DUPLICATE, _("Duplicate layer")); -- cgit v1.2.3 From 6d9c35c80d9cabfe44682ecfa724bd0d517c56f4 Mon Sep 17 00:00:00 2001 From: Krzysztof Kosi??ski Date: Sat, 9 May 2015 17:23:25 +0200 Subject: Fix eraser tool (bzr r14059.2.12) --- src/2geom/CMakeLists.txt | 316 +++++++++++++++++++++++++------------------ src/2geom/path.cpp | 18 ++- src/2geom/path.h | 3 + src/display/curve.cpp | 14 +- src/ui/tools/eraser-tool.cpp | 24 +++- 5 files changed, 222 insertions(+), 153 deletions(-) (limited to 'src') diff --git a/src/2geom/CMakeLists.txt b/src/2geom/CMakeLists.txt index eb25074ef..38f39ab40 100644 --- a/src/2geom/CMakeLists.txt +++ b/src/2geom/CMakeLists.txt @@ -1,136 +1,186 @@ +#generate parser file with ragel +SET(SVG_PARSER_CPP "${CMAKE_CURRENT_SOURCE_DIR}/svg-path-parser.cpp") +SET(SVG_PARSER_TMP "${CMAKE_CURRENT_SOURCE_DIR}/svg-path-parser.tmp") +SET(SVG_PARSER_RL "${CMAKE_CURRENT_SOURCE_DIR}/svg-path-parser.rl") +SET(GENERATE_SVG_PARSER NOT EXISTS "${SVG_PARSER_CPP}") +SET(REGENERATE_SVG_PARSER "${SVG_PARSER_CPP}" IS_NEWER_THAN "${SVG_PARSER_RL}") +find_program(RAGEL_PROGRAM + NAMES ragel + ragel.exe + DOC "Find ragel program" + HINTS /usr/bin + /usr/local/bin + ${RAGEL_BIN} + ${MINGW_BIN} +) +IF( RAGEL_PROGRAM ) +IF(GENERATE_SVG_PARSER OR REGENERATE_SVG_PARSER) + ADD_CUSTOM_COMMAND(OUTPUT "${SVG_PARSER_CPP}" + COMMAND ${RAGEL_PROGRAM} -C -T0 -o "${SVG_PARSER_CPP}" "${SVG_PARSER_RL}" + DEPENDS "${SVG_PARSER_RL}" + WORKING_DIRECTORY "${CURRENT_SOURCE_DIR}" + COMMENT "Generating svg_path_parser.cpp with ragel" + ) +ENDIF(GENERATE_SVG_PARSER OR REGENERATE_SVG_PARSER) +ENDIF( RAGEL_PROGRAM ) + +SET(2GEOM_SRC + +affine.cpp +affine.h +angle.h + +basic-intersection.cpp +basic-intersection.h +bezier.cpp +bezier.h +bezier-clipping.cpp +bezier-curve.cpp +bezier-curve.h +bezier-to-sbasis.h +bezier-utils.cpp +bezier-utils.h + +cairo-path-sink.h +cairo-path-sink.cpp +choose.h +circle.cpp +circle.h +concepts.cpp +concepts.h +conicsec.cpp +conicsec.h +conic_section_clipper.h +conic_section_clipper_cr.h +conic_section_clipper_impl.cpp +conic_section_clipper_impl.h +convex-hull.cpp +convex-hull.h +coord.cpp +coord.h +crossing.cpp +crossing.h +curve.cpp +curve.h +curves.h + +d2-sbasis.cpp +d2-sbasis.h +d2.h + +ellipse.cpp +ellipse.h +elliptical-arc.cpp +elliptical-arc.h +exception.h + +forward.h + +geom.cpp +geom.h + +intersection.h +intersection-graph.cpp +intersection-graph.h + +line.cpp +line.h +linear.h + +math-utils.h + +nearest-time.cpp +nearest-time.h + +numeric/matrix.cpp -set(2geom_SRC - affine.cpp - basic-intersection.cpp - bezier.cpp - bezier-clipping.cpp - bezier-curve.cpp - bezier-utils.cpp - cairo-path-sink.cpp - circle-circle.cpp - circle.cpp - # conic_section_clipper_impl.cpp - # conicsec.cpp - convex-hull.cpp - coord.cpp - crossing.cpp - curve.cpp - d2-sbasis.cpp - ellipse.cpp - elliptical-arc.cpp - geom.cpp - intersection-graph.cpp - line.cpp - nearest-time.cpp - numeric/matrix.cpp - path-intersection.cpp - path-sink.cpp - path.cpp - pathvector.cpp - piecewise.cpp - point.cpp - poly.cpp - quadtree.cpp - rect.cpp - # recursive-bezier-intersection.cpp - sbasis-2d.cpp - sbasis-geometric.cpp - sbasis-math.cpp - sbasis-poly.cpp - sbasis-roots.cpp - sbasis-to-bezier.cpp - sbasis.cpp - solve-bezier.cpp - solve-bezier-one-d.cpp - solve-bezier-parametric.cpp - svg-elliptical-arc.cpp - svg-path-parser.cpp - sweep.cpp - toposweep.cpp - transforms.cpp - utils.cpp - viewbox.cpp - - - # ------- - 2geom.h - # Headers - affine.h - angle.h - basic-intersection.h - bezier-curve.h - bezier-to-sbasis.h - bezier-utils.h - bezier.h - choose.h - circle.h - concepts.h - conic_section_clipper.h - conic_section_clipper_cr.h - conic_section_clipper_impl.h - conicsec.h - conjugate_gradient.h - convex-cover.h - coord.h - crossing.h - curve.h - curves.h - d2-sbasis.h - d2.h - ellipse.h - elliptical-arc.h - exception.h - forward.h - generic-interval.h - generic-rect.h - geom.h - hvlinesegment.h - int-interval.h - int-point.h - int-rect.h - interval.h - line.h - linear.h - math-utils.h - nearest-point.h - ord.h - path-intersection.h - path-sink.h - path.h - pathvector.h - piecewise.h - point-ops.h - point.h - poly.h - quadtree.h - ray.h - rect.h - region.h - sbasis-2d.h - sbasis-curve.h - sbasis-geometric.h - sbasis-math.h - sbasis-poly.h - sbasis-to-bezier.h - sbasis.h - shape.h - solver.h - svg-elliptical-arc.h - svg-path-parser.h - sweep.h - toposweep.h - transforms.h - utils.h - - numeric/fitting-model.h - numeric/fitting-tool.h - numeric/linear_system.h - numeric/matrix.h - numeric/symmetric-matrix-fs-operation.h - numeric/symmetric-matrix-fs-trace.h - numeric/symmetric-matrix-fs.h - numeric/vector.h +ord.h + +path-intersection.cpp +path-intersection.h +path-sink.cpp +path-sink.h +path.cpp +path.h +pathvector.cpp +pathvector.h +piecewise.cpp +piecewise.h +point.cpp +point.h +poly.cpp +poly.h + +quadtree.cpp +quadtree.h + +ray.h +rect.h +rect.cpp +recursive-bezier-intersection.cpp + +sbasis-2d.cpp +sbasis-2d.h +sbasis-curve.h +sbasis-geometric.cpp +sbasis-geometric.h +sbasis-math.cpp +sbasis-math.h +sbasis-poly.cpp +sbasis-poly.h +sbasis-roots.cpp +sbasis-to-bezier.cpp +sbasis-to-bezier.h +sbasis.cpp +sbasis.h +solve-bezier.cpp +solve-bezier-one-d.cpp +solve-bezier-parametric.cpp +solver.h +svg-elliptical-arc.cpp +svg-elliptical-arc.h +svg-path-parser.cpp +svg-path-parser.h +svg-path-writer.cpp +svg-path-writer.h +sweep.cpp +sweep.h + +toposweep.cpp +toposweep.h +transforms.cpp +transforms.h + +utils.cpp +utils.h + +viewbox.cpp +viewbox.h ) -# make lib for 2geom_LIB -add_inkscape_lib(2geom_LIB "${2geom_SRC}") +# make lib for 2geom +ADD_LIBRARY(2geom ${LIB_TYPE} ${2GEOM_SRC}) +TARGET_LINK_LIBRARIES(2geom "${LINK_GSL} ${GTK2_LINK_FLAGS}") +SET_TARGET_PROPERTIES(2geom PROPERTIES SOVERSION "${2GEOM_ABI_VERSION}") +INSTALL(TARGETS 2geom + RUNTIME DESTINATION bin + LIBRARY DESTINATION lib + ARCHIVE DESTINATION lib +) +FILE(GLOB files "${CMAKE_CURRENT_SOURCE_DIR}/*.h") +INSTALL(FILES ${files} DESTINATION include/2geom-${2GEOM_VERSION}/2geom) +FILE(GLOB files "${CMAKE_CURRENT_SOURCE_DIR}/numeric/*.h") +INSTALL(FILES ${files} DESTINATION include/2geom-${2GEOM_VERSION}/2geom/numeric) + +CONFIGURE_FILE( ${CMAKE_SOURCE_DIR}/2geom.pc.in + ${CMAKE_BINARY_DIR}/2geom.pc @ONLY IMMEDIATE ) +INSTALL(FILES "${CMAKE_BINARY_DIR}/2geom.pc" DESTINATION lib/pkgconfig) +ADD_SUBDIRECTORY (toys) +ADD_SUBDIRECTORY (tests) +ADD_SUBDIRECTORY (py2geom) +ADD_SUBDIRECTORY (performance-tests) + + +add_subdirectory(cython-bindings) + + diff --git a/src/2geom/path.cpp b/src/2geom/path.cpp index 71b7b25bb..e38835776 100644 --- a/src/2geom/path.cpp +++ b/src/2geom/path.cpp @@ -215,6 +215,18 @@ PathInterval PathInterval::from_direction(PathTime const &from, PathTime const & } +Path::Path(Rect const &r) + : _curves(new Sequence()) + , _closing_seg(new ClosingSegment(r.corner(3), r.corner(0))) + , _closed(true) + , _exception_on_stitch(true) +{ + for (unsigned i = 0; i < 3; ++i) { + _curves->push_back(new LineSegment(r.corner(i), r.corner(i+1))); + } + _curves->push_back(_closing_seg); +} + Path::Path(ConvexHull const &ch) : _curves(new Sequence()) , _closing_seg(new ClosingSegment(Point(), Point())) @@ -678,12 +690,12 @@ Path Path::reversed() const typedef std::reverse_iterator RIter; Path ret; - ret._curves->pop_back(); - RIter iter(_curves->end()), rend(_curves->begin()); + ret._curves->pop_back(); // this also deletes the closing segment + RIter iter(_curves->end() - 1), rend(_curves->begin()); for (; iter != rend; ++iter) { ret._curves->push_back(iter->reverse()); } - ret._closing_seg = static_cast(ret._closing_seg->reverse()); + ret._closing_seg = static_cast(_closing_seg->reverse()); ret._curves->push_back(ret._closing_seg); return ret; } diff --git a/src/2geom/path.h b/src/2geom/path.h index 58afcfd8d..5a172f598 100644 --- a/src/2geom/path.h +++ b/src/2geom/path.h @@ -371,6 +371,9 @@ public: _curves->push_back(_closing_seg); } + /// Construct a path from a rectangle. + Path(Rect const &r); + /// Construct a path from a convex hull. Path(ConvexHull const &); diff --git a/src/display/curve.cpp b/src/display/curve.cpp index 6cc7121dc..d236d81cf 100644 --- a/src/display/curve.cpp +++ b/src/display/curve.cpp @@ -31,14 +31,12 @@ SPCurve::SPCurve() : _refcount(1), _pathv() -{ -} +{} SPCurve::SPCurve(Geom::PathVector const& pathv) : _refcount(1), _pathv(pathv) -{ -} +{} SPCurve * SPCurve::new_from_rect(Geom::Rect const &rect, bool all_four_sides) @@ -90,13 +88,7 @@ SPCurve::get_pathvector() const size_t SPCurve::get_segment_count() const { - size_t nr = 0; - for(Geom::PathVector::const_iterator it = _pathv.begin(); it != _pathv.end(); ++it) { - nr += (*it).size(); - - if (it->closed()) nr += 1; - } - return nr; + return _pathv.curveCount(); } /** diff --git a/src/ui/tools/eraser-tool.cpp b/src/ui/tools/eraser-tool.cpp index 10f8c8694..e416fd7ef 100644 --- a/src/ui/tools/eraser-tool.cpp +++ b/src/ui/tools/eraser-tool.cpp @@ -789,6 +789,8 @@ add_cap(SPCurve *curve, } void EraserTool::accumulate() { + // construct a crude outline of the eraser's path. + // this desperately needs to be rewritten to use the path outliner... if ( !this->cal1->is_empty() && !this->cal2->is_empty() ) { this->accumulated->reset(); /* Is this required ?? */ SPCurve *rev_cal2 = this->cal2->create_reverse(); @@ -798,10 +800,10 @@ void EraserTool::accumulate() { g_assert( ! this->cal1->first_path()->closed() ); g_assert( ! rev_cal2->first_path()->closed() ); - Geom::CubicBezier const * dc_cal1_firstseg = dynamic_cast( this->cal1->first_segment() ); - Geom::CubicBezier const * rev_cal2_firstseg = dynamic_cast( rev_cal2->first_segment() ); - Geom::CubicBezier const * dc_cal1_lastseg = dynamic_cast( this->cal1->last_segment() ); - Geom::CubicBezier const * rev_cal2_lastseg = dynamic_cast( rev_cal2->last_segment() ); + Geom::BezierCurve const * dc_cal1_firstseg = dynamic_cast( this->cal1->first_segment() ); + Geom::BezierCurve const * rev_cal2_firstseg = dynamic_cast( rev_cal2->first_segment() ); + Geom::BezierCurve const * dc_cal1_lastseg = dynamic_cast( this->cal1->last_segment() ); + Geom::BezierCurve const * rev_cal2_lastseg = dynamic_cast( rev_cal2->last_segment() ); g_assert( dc_cal1_firstseg ); g_assert( rev_cal2_firstseg ); @@ -810,11 +812,21 @@ void EraserTool::accumulate() { this->accumulated->append(this->cal1, FALSE); - add_cap(this->accumulated, (*dc_cal1_lastseg)[2], (*dc_cal1_lastseg)[3], (*rev_cal2_firstseg)[0], (*rev_cal2_firstseg)[1], this->cap_rounding); + add_cap(this->accumulated, + dc_cal1_lastseg->finalPoint() - dc_cal1_lastseg->unitTangentAt(1), + dc_cal1_lastseg->finalPoint(), + rev_cal2_firstseg->initialPoint(), + rev_cal2_firstseg->initialPoint() + rev_cal2_firstseg->unitTangentAt(0), + this->cap_rounding); this->accumulated->append(rev_cal2, TRUE); - add_cap(this->accumulated, (*rev_cal2_lastseg)[2], (*rev_cal2_lastseg)[3], (*dc_cal1_firstseg)[0], (*dc_cal1_firstseg)[1], this->cap_rounding); + add_cap(this->accumulated, + rev_cal2_lastseg->finalPoint() - rev_cal2_lastseg->unitTangentAt(1), + rev_cal2_lastseg->finalPoint(), + dc_cal1_firstseg->initialPoint(), + dc_cal1_firstseg->initialPoint() + dc_cal1_firstseg->unitTangentAt(0), + this->cap_rounding); this->accumulated->closepath(); -- cgit v1.2.3 From 5e862e0de5ba75615a722fff471008a3cedb3212 Mon Sep 17 00:00:00 2001 From: Krzysztof Kosi??ski Date: Sat, 9 May 2015 17:39:31 +0200 Subject: Fix potential crash in FontLister (bzr r14135) --- src/libnrtype/font-lister.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/libnrtype/font-lister.cpp b/src/libnrtype/font-lister.cpp index a6ab3b239..70374864a 100644 --- a/src/libnrtype/font-lister.cpp +++ b/src/libnrtype/font-lister.cpp @@ -335,7 +335,7 @@ Glib::ustring FontLister::system_fontspec(Glib::ustring fontspec) PangoFontDescription *descr = pango_font_description_from_string(fontspec.c_str()); font_instance *res = (font_factory::Default())->Face(descr); - if (res->pFont) { + if (res && res->pFont) { PangoFontDescription *nFaceDesc = pango_font_describe(res->pFont); out = sp_font_description_get_family(nFaceDesc); } -- cgit v1.2.3 From 78cee203a59243dcabbf67499682ce720be6d1d6 Mon Sep 17 00:00:00 2001 From: Jabier Arraiza Cenoz Date: Sat, 9 May 2015 17:50:08 +0200 Subject: Remove documentUnits from live_effect/effect.cpp/h Remove units from fillet-chamfer and roughen (bzr r14136) --- src/live_effects/effect.cpp | 3 --- src/live_effects/effect.h | 1 - src/live_effects/lpe-fillet-chamfer.cpp | 7 +------ src/live_effects/lpe-fillet-chamfer.h | 1 - src/live_effects/lpe-roughen.cpp | 22 +++------------------- src/live_effects/lpe-roughen.h | 2 -- .../parameter/filletchamferpointarray.cpp | 12 +----------- .../parameter/filletchamferpointarray.h | 4 ---- src/ui/dialog/lpe-fillet-chamfer-properties.cpp | 22 ++-------------------- src/ui/dialog/lpe-fillet-chamfer-properties.h | 8 +------- 10 files changed, 8 insertions(+), 74 deletions(-) (limited to 'src') diff --git a/src/live_effects/effect.cpp b/src/live_effects/effect.cpp index 1da364580..53097171b 100644 --- a/src/live_effects/effect.cpp +++ b/src/live_effects/effect.cpp @@ -364,7 +364,6 @@ Effect::Effect(LivePathEffectObject *lpeobject) lpeobj(lpeobject), concatenate_before_pwd2(false), sp_lpe_item(NULL), - defaultUnit("px"), current_zoom(1), sp_curve(NULL), provides_own_flash_paths(true), // is automatically set to false if providesOwnFlashPaths() is not overridden @@ -454,7 +453,6 @@ void Effect::doOnRemove (SPLPEItem const* /*lpeitem*/) void Effect::doOnApply_impl(SPLPEItem const* lpeitem) { sp_lpe_item = const_cast(lpeitem); - defaultUnit = sp_lpe_item->document->getDisplayUnit()->abbr; /*sp_curve = SP_SHAPE(sp_lpe_item)->getCurve(); pathvector_before_effect = sp_curve->get_pathvector();*/ doOnApply(lpeitem); @@ -463,7 +461,6 @@ void Effect::doOnApply_impl(SPLPEItem const* lpeitem) void Effect::doBeforeEffect_impl(SPLPEItem const* lpeitem) { sp_lpe_item = const_cast(lpeitem); - defaultUnit = sp_lpe_item->document->getDisplayUnit()->abbr; //printf("(SPLPEITEM*) %p\n", sp_lpe_item); SPShape * shape = dynamic_cast(sp_lpe_item); if(shape){ diff --git a/src/live_effects/effect.h b/src/live_effects/effect.h index ac1f0b8dc..a6b5a13ea 100644 --- a/src/live_effects/effect.h +++ b/src/live_effects/effect.h @@ -159,7 +159,6 @@ protected: bool concatenate_before_pwd2; SPLPEItem * sp_lpe_item; // these get stored in doBeforeEffect_impl, and derived classes may do as they please with them. - Glib::ustring defaultUnit; // these get stored in doBeforeEffect_impl, and derived classes may do as they please with them. double current_zoom; std::vector selectedNodesPoints; SPCurve * sp_curve; diff --git a/src/live_effects/lpe-fillet-chamfer.cpp b/src/live_effects/lpe-fillet-chamfer.cpp index c8458b8cb..ca87c7be1 100644 --- a/src/live_effects/lpe-fillet-chamfer.cpp +++ b/src/live_effects/lpe-fillet-chamfer.cpp @@ -29,7 +29,6 @@ // for programmatically updating knots #include "ui/tools-switch.h" -#include // TODO due to internal breakage in glibmm headers, this must be last: #include @@ -57,7 +56,6 @@ LPEFilletChamfer::LPEFilletChamfer(LivePathEffectObject *lpeobject) : only_selected(_("Change only selected nodes"), _("Change only selected nodes"), "only_selected", &wr, this, false), flexible(_("Flexible radius size (%)"), _("Flexible radius size (%)"), "flexible", &wr, this, false), use_knot_distance(_("Use knots distance instead radius"), _("Use knots distance instead radius"), "use_knot_distance", &wr, this, false), - unit(_("Unit:"), _("Unit"), "unit", &wr, this), method(_("Method:"), _("Fillets methods"), "method", FMConverter, &wr, this, FM_AUTO), radius(_("Radius (unit or %):"), _("Radius, in unit or %"), "radius", &wr, this, 0.), chamfer_steps(_("Chamfer steps:"), _("Chamfer steps"), "chamfer_steps", &wr, this, 0), @@ -65,7 +63,6 @@ LPEFilletChamfer::LPEFilletChamfer(LivePathEffectObject *lpeobject) : helper_size(_("Helper size with direction:"), _("Helper size with direction"), "helper_size", &wr, this, 0) { registerParameter(&fillet_chamfer_values); - registerParameter(&unit); registerParameter(&method); registerParameter(&radius); registerParameter(&chamfer_steps); @@ -223,7 +220,7 @@ void LPEFilletChamfer::updateFillet() { double power = 0; if (!flexible) { - power = Inkscape::Util::Quantity::convert(radius, unit.get_abbreviation(), defaultUnit) * -1; + power = radius * -1; } else { power = radius; } @@ -444,9 +441,7 @@ void LPEFilletChamfer::doBeforeEffect(SPLPEItem const *lpeItem) } else { fillet_chamfer_values.set_helper_size(helper_size); } - fillet_chamfer_values.set_document_unit(defaultUnit); fillet_chamfer_values.set_use_distance(use_knot_distance); - fillet_chamfer_values.set_unit(unit.get_abbreviation()); SPCurve *c = SP_IS_PATH(lpeItem) ? static_cast(lpeItem) ->get_original_curve() : SP_SHAPE(lpeItem)->getCurve(); diff --git a/src/live_effects/lpe-fillet-chamfer.h b/src/live_effects/lpe-fillet-chamfer.h index fb06e804c..f8e03a399 100644 --- a/src/live_effects/lpe-fillet-chamfer.h +++ b/src/live_effects/lpe-fillet-chamfer.h @@ -66,7 +66,6 @@ private: BoolParam only_selected; BoolParam flexible; BoolParam use_knot_distance; - UnitParam unit; EnumParam method; ScalarParam radius; ScalarParam chamfer_steps; diff --git a/src/live_effects/lpe-roughen.cpp b/src/live_effects/lpe-roughen.cpp index 9d1c3152b..c5e002351 100644 --- a/src/live_effects/lpe-roughen.cpp +++ b/src/live_effects/lpe-roughen.cpp @@ -20,7 +20,6 @@ #include "live_effects/parameter/parameter.h" #include "helper/geom.h" #include -#include #include namespace Inkscape { @@ -36,7 +35,6 @@ DMConverter(DivisionMethodData, DM_END); LPERoughen::LPERoughen(LivePathEffectObject *lpeobject) : Effect(lpeobject), // initialise your parameters here: - unit(_("Unit"), _("Unit"), "unit", &wr, this), method(_("Method"), _("Division method"), "method", DMConverter, &wr, this, DM_SEGMENTS), max_segment_size(_("Max. segment size"), _("Max. segment size"), @@ -54,7 +52,6 @@ LPERoughen::LPERoughen(LivePathEffectObject *lpeobject) shift_node_handles(_("Shift node handles"), _("Shift node handles"), "shift_node_handles", &wr, this, true) { - registerParameter(&unit); registerParameter(&method); registerParameter(&max_segment_size); registerParameter(&segments); @@ -98,14 +95,6 @@ Gtk::Widget *LPERoughen::newWidget() if ((*it)->widget_is_visible) { Parameter *param = *it; Gtk::Widget *widg = dynamic_cast(param->param_newWidget()); - if (param->param_key == "unit") { - Gtk::Label *unit_label = Gtk::manage(new Gtk::Label( - Glib::ustring(_("Roughen unit")), Gtk::ALIGN_START)); - unit_label->set_use_markup(true); - vbox->pack_start(*unit_label, false, false, 2); - vbox->pack_start(*Gtk::manage(new Gtk::HSeparator()), - Gtk::PACK_EXPAND_WIDGET); - } if (param->param_key == "method") { Gtk::Label *method_label = Gtk::manage(new Gtk::Label( Glib::ustring(_("Add nodes Subdivide each segment")), @@ -160,11 +149,8 @@ double LPERoughen::sign(double random_number) Geom::Point LPERoughen::randomize() { - Inkscape::Util::Unit const *svg_units = SP_ACTIVE_DESKTOP->namedview->svg_units; - double displace_x_parsed = Inkscape::Util::Quantity::convert( - displace_x * global_randomize, unit.get_abbreviation(), svg_units->abbr); - double displace_y_parsed = Inkscape::Util::Quantity::convert( - displace_y * global_randomize, unit.get_abbreviation(), svg_units->abbr); + double displace_x_parsed = displace_x * global_randomize; + double displace_y_parsed = displace_y * global_randomize; Geom::Point output = Geom::Point(sign(displace_x_parsed), sign(displace_y_parsed)); return output; @@ -175,7 +161,6 @@ void LPERoughen::doEffect(SPCurve *curve) Geom::PathVector const original_pathv = pathv_to_linear_and_cubic_beziers(curve->get_pathvector()); curve->reset(); - Inkscape::Util::Unit const *svg_units = SP_ACTIVE_DESKTOP->namedview->svg_units; for (Geom::PathVector::const_iterator path_it = original_pathv.begin(); path_it != original_pathv.end(); ++path_it) { if (path_it->empty()) @@ -220,8 +205,7 @@ void LPERoughen::doEffect(SPCurve *curve) } else { nCurve->lineto(point3); } - double length = Inkscape::Util::Quantity::convert( - curve_it1->length(0.001), svg_units->abbr, unit.get_abbreviation()); + double length = curve_it1->length(0.001); std::size_t splits = 0; if (method == DM_SEGMENTS) { splits = segments; diff --git a/src/live_effects/lpe-roughen.h b/src/live_effects/lpe-roughen.h index ed9f06cf7..2b285cd40 100644 --- a/src/live_effects/lpe-roughen.h +++ b/src/live_effects/lpe-roughen.h @@ -17,7 +17,6 @@ #include "live_effects/parameter/parameter.h" #include "live_effects/parameter/path.h" #include "live_effects/parameter/bool.h" -#include "live_effects/parameter/unit.h" #include "live_effects/parameter/random.h" namespace Inkscape { @@ -45,7 +44,6 @@ public: virtual Gtk::Widget *newWidget(); private: - UnitParam unit; EnumParam method; ScalarParam max_segment_size; ScalarParam segments; diff --git a/src/live_effects/parameter/filletchamferpointarray.cpp b/src/live_effects/parameter/filletchamferpointarray.cpp index f05f401e4..10ded4d9f 100644 --- a/src/live_effects/parameter/filletchamferpointarray.cpp +++ b/src/live_effects/parameter/filletchamferpointarray.cpp @@ -354,11 +354,6 @@ void FilletChamferPointArrayParam::set_pwd2( last_pwd2_normal = pwd2_normal_in; } -void FilletChamferPointArrayParam::set_document_unit(Glib::ustring value_document_unit) -{ - documentUnit = value_document_unit; -} - void FilletChamferPointArrayParam::set_helper_size(int hs) { helper_size = hs; @@ -374,11 +369,6 @@ void FilletChamferPointArrayParam::set_use_distance(bool use_knot_distance ) use_distance = use_knot_distance; } -void FilletChamferPointArrayParam::set_unit(const gchar *abbr) -{ - unit = abbr; -} - void FilletChamferPointArrayParam::updateCanvasIndicators() { std::vector ts = data(); @@ -812,7 +802,7 @@ void FilletChamferPointArrayParamKnotHolderEntity::knot_click(guint state) bool aprox = (A[0].degreesOfFreedom() != 2 || B[0].degreesOfFreedom() != 2) && !_pparam->use_distance?true:false; Geom::Point offset = Geom::Point(xModified, _pparam->_vector.at(_index).y()); Inkscape::UI::Dialogs::FilletChamferPropertiesDialog::showDialog( - this->desktop, offset, this, _pparam->unit, _pparam->use_distance, aprox, _pparam->documentUnit); + this->desktop, offset, this, _pparam->use_distance, aprox); } } diff --git a/src/live_effects/parameter/filletchamferpointarray.h b/src/live_effects/parameter/filletchamferpointarray.h index 7849d5afb..9bfd86b41 100644 --- a/src/live_effects/parameter/filletchamferpointarray.h +++ b/src/live_effects/parameter/filletchamferpointarray.h @@ -53,8 +53,6 @@ public: virtual void set_helper_size(int hs); virtual void set_use_distance(bool use_knot_distance); virtual void set_chamfer_steps(int value_chamfer_steps); - virtual void set_document_unit(Glib::ustring value_document_unit); - virtual void set_unit(const gchar *abbr); virtual void addCanvasIndicators(SPLPEItem const *lpeitem, std::vector &hp_vec); virtual bool providesKnotHolderEntities() const { @@ -89,8 +87,6 @@ private: int helper_size; int chamfer_steps; bool use_distance; - const gchar *unit; - Glib::ustring documentUnit; Geom::PathVector hp; Geom::Piecewise > last_pwd2; diff --git a/src/ui/dialog/lpe-fillet-chamfer-properties.cpp b/src/ui/dialog/lpe-fillet-chamfer-properties.cpp index f63b19e86..061055feb 100644 --- a/src/ui/dialog/lpe-fillet-chamfer-properties.cpp +++ b/src/ui/dialog/lpe-fillet-chamfer-properties.cpp @@ -27,7 +27,6 @@ #include "selection-chemistry.h" #include "ui/icon-names.h" #include "ui/widget/imagetoggler.h" -#include "util/units.h" #include //#include "event-context.h" @@ -122,18 +121,14 @@ void FilletChamferPropertiesDialog::showDialog( SPDesktop *desktop, Geom::Point knotpoint, const Inkscape::LivePathEffect:: FilletChamferPointArrayParamKnotHolderEntity *pt, - const gchar *unit, bool use_distance, - bool aprox_radius, - Glib::ustring documentUnit) + bool aprox_radius) { FilletChamferPropertiesDialog *dialog = new FilletChamferPropertiesDialog(); dialog->_set_desktop(desktop); - dialog->_set_unit(unit); dialog->_set_use_distance(use_distance); dialog->_set_aprox(aprox_radius); - dialog->_set_document_unit(documentUnit); dialog->_set_knot_point(knotpoint); dialog->_set_pt(pt); @@ -168,7 +163,6 @@ void FilletChamferPropertiesDialog::_apply() } d_pos = _index + (d_pos / 100); } else { - d_pos = Inkscape::Util::Quantity::convert(d_pos, unit, document_unit); d_pos = d_pos * -1; } _knotpoint->knot_set_offset(Geom::Point(d_pos, d_width)); @@ -218,11 +212,9 @@ void FilletChamferPropertiesDialog::_set_knot_point(Geom::Point knotpoint) _fillet_chamfer_position_label.set_label(_("Position (%):")); } else { _flexible = false; - std::string posConcat = Glib::ustring::compose (_("%1 (%2):"), distance_or_radius, unit); + std::string posConcat = Glib::ustring::compose (_("%1:"), distance_or_radius); _fillet_chamfer_position_label.set_label(_(posConcat.c_str())); position = knotpoint[Geom::X] * -1; - - position = Inkscape::Util::Quantity::convert(position, document_unit, unit); } _fillet_chamfer_position_numeric.set_value(position); if (knotpoint.y() == 1) { @@ -247,16 +239,6 @@ void FilletChamferPropertiesDialog::_set_pt( pt); } -void FilletChamferPropertiesDialog::_set_unit(const gchar *abbr) -{ - unit = abbr; -} - -void FilletChamferPropertiesDialog::_set_document_unit(Glib::ustring abbr) -{ - document_unit = abbr; -} - void FilletChamferPropertiesDialog::_set_use_distance(bool use_knot_distance) { use_distance = use_knot_distance; diff --git a/src/ui/dialog/lpe-fillet-chamfer-properties.h b/src/ui/dialog/lpe-fillet-chamfer-properties.h index 870a1734f..99494bd63 100644 --- a/src/ui/dialog/lpe-fillet-chamfer-properties.h +++ b/src/ui/dialog/lpe-fillet-chamfer-properties.h @@ -30,10 +30,8 @@ public: static void showDialog(SPDesktop *desktop, Geom::Point knotpoint, const Inkscape::LivePathEffect:: FilletChamferPointArrayParamKnotHolderEntity *pt, - const gchar *unit, bool use_distance, - bool aprox_radius, - Glib::ustring documentUnit); + bool aprox_radius); protected: @@ -68,15 +66,11 @@ protected: void _set_desktop(SPDesktop *desktop); void _set_pt(const Inkscape::LivePathEffect:: FilletChamferPointArrayParamKnotHolderEntity *pt); - void _set_unit(const gchar *abbr); - void _set_document_unit(Glib::ustring abbr); void _set_use_distance(bool use_knot_distance); void _set_aprox(bool aprox_radius); void _apply(); void _close(); bool _flexible; - const gchar *unit; - Glib::ustring document_unit; bool use_distance; bool aprox; void _set_knot_point(Geom::Point knotpoint); -- cgit v1.2.3 From b80ece09a1c8045cec3597f9c61b417323399290 Mon Sep 17 00:00:00 2001 From: su_v Date: Sat, 9 May 2015 19:20:42 +0200 Subject: cmake: refactor SRC lists for optional input formats (cdr, vsd, wpg) (bzr r14139) --- src/extension/CMakeLists.txt | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/extension/CMakeLists.txt b/src/extension/CMakeLists.txt index d1104f3cc..21e652563 100644 --- a/src/extension/CMakeLists.txt +++ b/src/extension/CMakeLists.txt @@ -36,7 +36,6 @@ set(extension_SRC internal/cairo-render-context.cpp internal/cairo-renderer.cpp internal/cairo-renderer-pdf-out.cpp - internal/cdr-input.cpp internal/emf-inout.cpp internal/emf-print.cpp internal/gdkpixbuf-input.cpp @@ -54,10 +53,8 @@ set(extension_SRC internal/svg.cpp internal/svgz.cpp internal/text_reassemble.c - internal/vsd-input.cpp internal/wmf-inout.cpp internal/wmf-print.cpp - internal/wpg-input.cpp internal/filter/filter-all.cpp internal/filter/filter-file.cpp @@ -104,7 +101,6 @@ set(extension_SRC internal/cairo-render-context.h internal/cairo-renderer-pdf-out.h internal/cairo-renderer.h - internal/cdr-input.h internal/clear-n_.h internal/emf-inout.h internal/emf-print.h @@ -140,10 +136,8 @@ set(extension_SRC internal/svg.h internal/svgz.h internal/text_reassemble.h - internal/vsd-input.h internal/wmf-inout.h internal/wmf-print.h - internal/wpg-input.h ) if(WIN32) @@ -151,6 +145,20 @@ if(WIN32) ) endif() +if(WITH_LIBCDR) + list(APPEND extension_SRC + internal/cdr-input.cpp + internal/cdr-input.h + ) +endif() + +if(WITH_LIBVISIO) + list(APPEND extension_SRC + internal/vsd-input.cpp + internal/vsd-input.h + ) +endif() + if(WITH_LIBWPG) list(APPEND extension_SRC internal/wpg-input.cpp @@ -158,7 +166,7 @@ if(WITH_LIBWPG) ) endif() -if(ImageMagick_FOUND) +if(WITH_IMAGE_MAGICK) list(APPEND extension_SRC internal/bitmap/adaptiveThreshold.cpp internal/bitmap/adaptiveThreshold.h -- cgit v1.2.3 From 2fd30724472ab97df99c329e66310395a5c3bfa9 Mon Sep 17 00:00:00 2001 From: Krzysztof Kosi??ski Date: Sat, 9 May 2015 19:57:41 +0200 Subject: Update to 2Geom r2360. Fixes taper stroke LPE. (bzr r14059.2.13) --- src/2geom/path.cpp | 40 ++++++++++++++++++++++++++++++++++++---- src/2geom/path.h | 11 ++++++++++- 2 files changed, 46 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/2geom/path.cpp b/src/2geom/path.cpp index e38835776..8cba316f5 100644 --- a/src/2geom/path.cpp +++ b/src/2geom/path.cpp @@ -36,6 +36,7 @@ #include <2geom/pathvector.h> #include <2geom/transforms.h> #include <2geom/convex-hull.h> +#include <2geom/svg-path-writer.h> #include #include @@ -689,14 +690,37 @@ Path Path::reversed() const { typedef std::reverse_iterator RIter; - Path ret; - ret._curves->pop_back(); // this also deletes the closing segment - RIter iter(_curves->end() - 1), rend(_curves->begin()); + Path ret(finalPoint()); + if (empty()) return ret; + + ret._curves->pop_back(); // this also deletes the closing segment from ret + + RIter iter(_includesClosingSegment() ? _curves->end() : _curves->end() - 1); + RIter rend(_curves->begin()); + + if (_closed) { + // when the path is closed, there are two cases: + BezierCurve const *iseg = dynamic_cast(&front()); + if (iseg && iseg->size() == 2) { + // 1. initial segment is linear: it becomes the new closing segment. + rend = RIter(_curves->begin() + 1); + ret._closing_seg = new ClosingSegment(iseg->finalPoint(), iseg->initialPoint()); + } else { + // 2. initial segment is not linear: the closing segment becomes degenerate. + // However, skip it if it's already degenerate. + Point fp = finalPoint(); + ret._closing_seg = new ClosingSegment(fp, fp); + } + } else { + // when the path is open, we reverse all real curves, and add a reversed closing segment. + ret._closing_seg = static_cast(_closing_seg->reverse()); + } + for (; iter != rend; ++iter) { ret._curves->push_back(iter->reverse()); } - ret._closing_seg = static_cast(_closing_seg->reverse()); ret._curves->push_back(ret._closing_seg); + ret._closed = _closed; return ret; } @@ -906,6 +930,14 @@ Piecewise > paths_to_pw(PathVector const &paths) return ret; } +std::ostream &operator<<(std::ostream &out, Path const &path) +{ + SVGPathWriter pw; + pw.feed(path); + out << pw.str(); + return out; +} + } // end namespace Geom /* diff --git a/src/2geom/path.h b/src/2geom/path.h index 5a172f598..5340df0c5 100644 --- a/src/2geom/path.h +++ b/src/2geom/path.h @@ -402,6 +402,8 @@ public: * Since the curve always contains at least a degenerate closing segment, * it is always safe to use this method. */ Curve const &front() const { return _curves->front(); } + /// Alias for front(). + Curve const &initialCurve() const { return _curves->front(); } /** @brief Access the last curve in the path. */ Curve const &back() const { return back_default(); } Curve const &back_open() const { @@ -413,7 +415,12 @@ public: ? (*_curves)[_curves->size() - 2] : (*_curves)[_curves->size() - 1]; } - Curve const &back_default() const { return (_closed ? back_closed() : back_open()); } + Curve const &back_default() const { + return _includesClosingSegment() + ? back_closed() + : back_open(); + } + Curve const &finalCurve() const { return back_default(); } const_iterator begin() const { return const_iterator(*this, 0); } const_iterator end() const { return end_default(); } @@ -812,6 +819,8 @@ inline Coord nearest_time(Point const &p, Path const &c) { return pt.curve_index + pt.t; } +std::ostream &operator<<(std::ostream &out, Path const &path); + } // end namespace Geom -- cgit v1.2.3 From 58e8b8eadfe0862aa9edeb53d35714629d56fd40 Mon Sep 17 00:00:00 2001 From: Krzysztof Kosi??ski Date: Sat, 9 May 2015 20:12:39 +0200 Subject: Undo changes to CMakeLists.txt in 2geom directory after syncs (bzr r14059.2.14) --- src/2geom/CMakeLists.txt | 316 ++++++++++++++++++++--------------------------- 1 file changed, 133 insertions(+), 183 deletions(-) (limited to 'src') diff --git a/src/2geom/CMakeLists.txt b/src/2geom/CMakeLists.txt index 38f39ab40..eb25074ef 100644 --- a/src/2geom/CMakeLists.txt +++ b/src/2geom/CMakeLists.txt @@ -1,186 +1,136 @@ -#generate parser file with ragel -SET(SVG_PARSER_CPP "${CMAKE_CURRENT_SOURCE_DIR}/svg-path-parser.cpp") -SET(SVG_PARSER_TMP "${CMAKE_CURRENT_SOURCE_DIR}/svg-path-parser.tmp") -SET(SVG_PARSER_RL "${CMAKE_CURRENT_SOURCE_DIR}/svg-path-parser.rl") -SET(GENERATE_SVG_PARSER NOT EXISTS "${SVG_PARSER_CPP}") -SET(REGENERATE_SVG_PARSER "${SVG_PARSER_CPP}" IS_NEWER_THAN "${SVG_PARSER_RL}") -find_program(RAGEL_PROGRAM - NAMES ragel - ragel.exe - DOC "Find ragel program" - HINTS /usr/bin - /usr/local/bin - ${RAGEL_BIN} - ${MINGW_BIN} -) -IF( RAGEL_PROGRAM ) -IF(GENERATE_SVG_PARSER OR REGENERATE_SVG_PARSER) - ADD_CUSTOM_COMMAND(OUTPUT "${SVG_PARSER_CPP}" - COMMAND ${RAGEL_PROGRAM} -C -T0 -o "${SVG_PARSER_CPP}" "${SVG_PARSER_RL}" - DEPENDS "${SVG_PARSER_RL}" - WORKING_DIRECTORY "${CURRENT_SOURCE_DIR}" - COMMENT "Generating svg_path_parser.cpp with ragel" - ) -ENDIF(GENERATE_SVG_PARSER OR REGENERATE_SVG_PARSER) -ENDIF( RAGEL_PROGRAM ) - -SET(2GEOM_SRC - -affine.cpp -affine.h -angle.h - -basic-intersection.cpp -basic-intersection.h -bezier.cpp -bezier.h -bezier-clipping.cpp -bezier-curve.cpp -bezier-curve.h -bezier-to-sbasis.h -bezier-utils.cpp -bezier-utils.h - -cairo-path-sink.h -cairo-path-sink.cpp -choose.h -circle.cpp -circle.h -concepts.cpp -concepts.h -conicsec.cpp -conicsec.h -conic_section_clipper.h -conic_section_clipper_cr.h -conic_section_clipper_impl.cpp -conic_section_clipper_impl.h -convex-hull.cpp -convex-hull.h -coord.cpp -coord.h -crossing.cpp -crossing.h -curve.cpp -curve.h -curves.h - -d2-sbasis.cpp -d2-sbasis.h -d2.h - -ellipse.cpp -ellipse.h -elliptical-arc.cpp -elliptical-arc.h -exception.h - -forward.h - -geom.cpp -geom.h - -intersection.h -intersection-graph.cpp -intersection-graph.h - -line.cpp -line.h -linear.h - -math-utils.h - -nearest-time.cpp -nearest-time.h - -numeric/matrix.cpp -ord.h - -path-intersection.cpp -path-intersection.h -path-sink.cpp -path-sink.h -path.cpp -path.h -pathvector.cpp -pathvector.h -piecewise.cpp -piecewise.h -point.cpp -point.h -poly.cpp -poly.h - -quadtree.cpp -quadtree.h - -ray.h -rect.h -rect.cpp -recursive-bezier-intersection.cpp - -sbasis-2d.cpp -sbasis-2d.h -sbasis-curve.h -sbasis-geometric.cpp -sbasis-geometric.h -sbasis-math.cpp -sbasis-math.h -sbasis-poly.cpp -sbasis-poly.h -sbasis-roots.cpp -sbasis-to-bezier.cpp -sbasis-to-bezier.h -sbasis.cpp -sbasis.h -solve-bezier.cpp -solve-bezier-one-d.cpp -solve-bezier-parametric.cpp -solver.h -svg-elliptical-arc.cpp -svg-elliptical-arc.h -svg-path-parser.cpp -svg-path-parser.h -svg-path-writer.cpp -svg-path-writer.h -sweep.cpp -sweep.h - -toposweep.cpp -toposweep.h -transforms.cpp -transforms.h - -utils.cpp -utils.h - -viewbox.cpp -viewbox.h +set(2geom_SRC + affine.cpp + basic-intersection.cpp + bezier.cpp + bezier-clipping.cpp + bezier-curve.cpp + bezier-utils.cpp + cairo-path-sink.cpp + circle-circle.cpp + circle.cpp + # conic_section_clipper_impl.cpp + # conicsec.cpp + convex-hull.cpp + coord.cpp + crossing.cpp + curve.cpp + d2-sbasis.cpp + ellipse.cpp + elliptical-arc.cpp + geom.cpp + intersection-graph.cpp + line.cpp + nearest-time.cpp + numeric/matrix.cpp + path-intersection.cpp + path-sink.cpp + path.cpp + pathvector.cpp + piecewise.cpp + point.cpp + poly.cpp + quadtree.cpp + rect.cpp + # recursive-bezier-intersection.cpp + sbasis-2d.cpp + sbasis-geometric.cpp + sbasis-math.cpp + sbasis-poly.cpp + sbasis-roots.cpp + sbasis-to-bezier.cpp + sbasis.cpp + solve-bezier.cpp + solve-bezier-one-d.cpp + solve-bezier-parametric.cpp + svg-elliptical-arc.cpp + svg-path-parser.cpp + sweep.cpp + toposweep.cpp + transforms.cpp + utils.cpp + viewbox.cpp + + + # ------- + 2geom.h + # Headers + affine.h + angle.h + basic-intersection.h + bezier-curve.h + bezier-to-sbasis.h + bezier-utils.h + bezier.h + choose.h + circle.h + concepts.h + conic_section_clipper.h + conic_section_clipper_cr.h + conic_section_clipper_impl.h + conicsec.h + conjugate_gradient.h + convex-cover.h + coord.h + crossing.h + curve.h + curves.h + d2-sbasis.h + d2.h + ellipse.h + elliptical-arc.h + exception.h + forward.h + generic-interval.h + generic-rect.h + geom.h + hvlinesegment.h + int-interval.h + int-point.h + int-rect.h + interval.h + line.h + linear.h + math-utils.h + nearest-point.h + ord.h + path-intersection.h + path-sink.h + path.h + pathvector.h + piecewise.h + point-ops.h + point.h + poly.h + quadtree.h + ray.h + rect.h + region.h + sbasis-2d.h + sbasis-curve.h + sbasis-geometric.h + sbasis-math.h + sbasis-poly.h + sbasis-to-bezier.h + sbasis.h + shape.h + solver.h + svg-elliptical-arc.h + svg-path-parser.h + sweep.h + toposweep.h + transforms.h + utils.h + + numeric/fitting-model.h + numeric/fitting-tool.h + numeric/linear_system.h + numeric/matrix.h + numeric/symmetric-matrix-fs-operation.h + numeric/symmetric-matrix-fs-trace.h + numeric/symmetric-matrix-fs.h + numeric/vector.h ) -# make lib for 2geom -ADD_LIBRARY(2geom ${LIB_TYPE} ${2GEOM_SRC}) -TARGET_LINK_LIBRARIES(2geom "${LINK_GSL} ${GTK2_LINK_FLAGS}") -SET_TARGET_PROPERTIES(2geom PROPERTIES SOVERSION "${2GEOM_ABI_VERSION}") -INSTALL(TARGETS 2geom - RUNTIME DESTINATION bin - LIBRARY DESTINATION lib - ARCHIVE DESTINATION lib -) -FILE(GLOB files "${CMAKE_CURRENT_SOURCE_DIR}/*.h") -INSTALL(FILES ${files} DESTINATION include/2geom-${2GEOM_VERSION}/2geom) -FILE(GLOB files "${CMAKE_CURRENT_SOURCE_DIR}/numeric/*.h") -INSTALL(FILES ${files} DESTINATION include/2geom-${2GEOM_VERSION}/2geom/numeric) - -CONFIGURE_FILE( ${CMAKE_SOURCE_DIR}/2geom.pc.in - ${CMAKE_BINARY_DIR}/2geom.pc @ONLY IMMEDIATE ) -INSTALL(FILES "${CMAKE_BINARY_DIR}/2geom.pc" DESTINATION lib/pkgconfig) -ADD_SUBDIRECTORY (toys) -ADD_SUBDIRECTORY (tests) -ADD_SUBDIRECTORY (py2geom) -ADD_SUBDIRECTORY (performance-tests) - - -add_subdirectory(cython-bindings) - - +# make lib for 2geom_LIB +add_inkscape_lib(2geom_LIB "${2geom_SRC}") -- cgit v1.2.3 From 3b8c4f31de73bd83057bffb8105498ae62be1984 Mon Sep 17 00:00:00 2001 From: Marc Jeanmougin Date: Sun, 10 May 2015 23:55:55 +0200 Subject: Fix for bug 1194091 Fixed bugs: - https://launchpad.net/bugs/1194091 (bzr r14142) --- src/sp-item.cpp | 40 ++++++++++++++-------------------------- src/ui/dialog/layers.cpp | 12 ++++++++++-- 2 files changed, 24 insertions(+), 28 deletions(-) (limited to 'src') diff --git a/src/sp-item.cpp b/src/sp-item.cpp index 8c99e9bcf..5445be947 100644 --- a/src/sp-item.cpp +++ b/src/sp-item.cpp @@ -349,17 +349,11 @@ void SPItem::lowerToBottom() { using Inkscape::Util::MutableList; using Inkscape::Util::reverse_list; - MutableList bottom=find_last_if( - reverse_list( - parent->firstChild(), this - ), - MutableList(), - &is_item - ); + SPObject * bottom=parent->firstChild(); + while(dynamic_cast(bottom) && dynamic_cast(bottom->next) && bottom!=this && !is_item(*(bottom->next))) bottom=bottom->next; if (bottom) { - ++bottom; Inkscape::XML::Node *ref = ( bottom ? bottom->getRepr() : NULL ); - getRepr()->parent()->changeOrder(getRepr(), ref); + parent->getRepr()->changeOrder(getRepr(), ref); } } @@ -367,20 +361,20 @@ void SPItem::moveTo(SPItem *target, bool intoafter) { Inkscape::XML::Node *target_ref = ( target ? target->getRepr() : NULL ); Inkscape::XML::Node *our_ref = getRepr(); - gboolean first = FALSE; - - if (target_ref == our_ref) { - // Move to ourself ignore - return; - } if (!target_ref) { // Assume move to the "first" in the top node, find the top node - target_ref = our_ref; - while (target_ref->parent() != target_ref->root()) { - target_ref = target_ref->parent(); + intoafter = false; + SPObject* bottom = this->document->getObjectByRepr(our_ref->root())->firstChild(); + while(!dynamic_cast(bottom->next)){ + bottom=bottom->next; } - first = TRUE; + target_ref = bottom->getRepr(); + } + + if (target_ref == our_ref) { + // Move to ourself ignore + return; } if (intoafter) { @@ -391,16 +385,10 @@ void SPItem::moveTo(SPItem *target, bool intoafter) { // Change in parent, need to remove and add our_ref->parent()->removeChild(our_ref); target_ref->parent()->addChild(our_ref, target_ref); - } else if (!first) { + } else { // Same parent, just move our_ref->parent()->changeOrder(our_ref, target_ref); } - - if (first && parent) { - // If "first" ensure it appears after the defs etc - lowerToBottom(); - return; - } } void SPItem::build(SPDocument *document, Inkscape::XML::Node *repr) { diff --git a/src/ui/dialog/layers.cpp b/src/ui/dialog/layers.cpp index 65351cb68..c6888386f 100644 --- a/src/ui/dialog/layers.cpp +++ b/src/ui/dialog/layers.cpp @@ -713,13 +713,21 @@ bool LayersPanel::_handleDragDrop(const Glib::RefPtr& /*contex */ void LayersPanel::_doTreeMove( ) { - if (_dnd_source ) { + if (_dnd_source && _dnd_source->getRepr() ) { + if(!_dnd_target){ + _dnd_source->doWriteTransform(_dnd_source->getRepr(), _dnd_source->document->getRoot()->i2doc_affine().inverse() * _dnd_source->i2doc_affine()); + }else{ + SPItem* parent = _dnd_into ? _dnd_target : dynamic_cast(_dnd_target->parent); + if(parent){ + Geom::Affine move = parent->i2doc_affine().inverse() * _dnd_source->i2doc_affine(); + _dnd_source->doWriteTransform(_dnd_source->getRepr(), move); + } + } _dnd_source->moveTo(_dnd_target, _dnd_into); _selectLayer(_dnd_source); _dnd_source = NULL; DocumentUndo::done( _desktop->doc() , SP_VERB_NONE, _("Moved layer")); - } } -- cgit v1.2.3 From 1d290ae90c78f35b67f474d34eef6f8fbeaa248c Mon Sep 17 00:00:00 2001 From: Nicolas Dufour Date: Mon, 11 May 2015 17:56:55 +0200 Subject: Metadata. Fix for Bug #1452266 (Outdated Creative Commons licenses). Fixed bugs: - https://launchpad.net/bugs/1452266 (bzr r14143) --- src/rdf.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/rdf.cpp b/src/rdf.cpp index 16344e520..938dc60c6 100644 --- a/src/rdf.cpp +++ b/src/rdf.cpp @@ -39,7 +39,7 @@ - @@ -173,32 +173,32 @@ struct rdf_double_t rdf_license_ofl [] = { struct rdf_license_t rdf_licenses [] = { { N_("CC Attribution"), - "http://creativecommons.org/licenses/by/3.0/", + "http://creativecommons.org/licenses/by/4.0/", rdf_license_cc_a, }, { N_("CC Attribution-ShareAlike"), - "http://creativecommons.org/licenses/by-sa/3.0/", + "http://creativecommons.org/licenses/by-sa/4.0/", rdf_license_cc_a_sa, }, { N_("CC Attribution-NoDerivs"), - "http://creativecommons.org/licenses/by-nd/3.0/", + "http://creativecommons.org/licenses/by-nd/4.0/", rdf_license_cc_a_nd, }, { N_("CC Attribution-NonCommercial"), - "http://creativecommons.org/licenses/by-nc/3.0/", + "http://creativecommons.org/licenses/by-nc/4.0/", rdf_license_cc_a_nc, }, { N_("CC Attribution-NonCommercial-ShareAlike"), - "http://creativecommons.org/licenses/by-nc-sa/3.0/", + "http://creativecommons.org/licenses/by-nc-sa/4.0/", rdf_license_cc_a_nc_sa, }, { N_("CC Attribution-NonCommercial-NoDerivs"), - "http://creativecommons.org/licenses/by-nc-nd/3.0/", + "http://creativecommons.org/licenses/by-nc-nd/4.0/", rdf_license_cc_a_nc_nd, }, -- cgit v1.2.3 From f7bd98a01dce9cb5a1532ab983c0b39b4d14d8f5 Mon Sep 17 00:00:00 2001 From: Nicolas Dufour Date: Mon, 11 May 2015 17:58:35 +0200 Subject: UI. Fix for Bug #1450875 (A change of the Image quality for an embedded/linked image can't be saved in some circumstances.). Fixed bugs: - https://launchpad.net/bugs/1450875 (bzr r14144) --- src/ui/dialog/object-properties.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/ui/dialog/object-properties.cpp b/src/ui/dialog/object-properties.cpp index fc21a30d4..75430ed44 100644 --- a/src/ui/dialog/object-properties.cpp +++ b/src/ui/dialog/object-properties.cpp @@ -529,10 +529,12 @@ void ObjectProperties::_imageRenderingChanged() SPCSSAttr *css = sp_repr_css_attr_new(); sp_repr_css_set_property(css, "image-rendering", scale.c_str()); Inkscape::XML::Node *image_node = item->getRepr(); - if( image_node ) { + if (image_node) { sp_repr_css_change(image_node, css, "style"); + DocumentUndo::done(SP_ACTIVE_DOCUMENT, SP_VERB_DIALOG_ITEM, + _("Set image rendering option")); } - sp_repr_css_attr_unref( css ); + sp_repr_css_attr_unref(css); _blocked = false; } -- cgit v1.2.3 From 7d5213c328e56fcb23169dd6b1633853ab04bf88 Mon Sep 17 00:00:00 2001 From: Yuri Chornoivan <> Date: Mon, 11 May 2015 18:07:41 +0200 Subject: Translations. Fix typo in the Color blindness filter and Ukrainian translation update. Fixed bugs: - https://launchpad.net/bugs/1407331 (bzr r14145) --- src/extension/internal/filter/color.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/extension/internal/filter/color.h b/src/extension/internal/filter/color.h index c3c26bf8b..b9c76615c 100644 --- a/src/extension/internal/filter/color.h +++ b/src/extension/internal/filter/color.h @@ -258,7 +258,7 @@ public: "\n" "<_item value=\"0.618 0.32 0.062 0 0 0.163 0.775 0.062 0 0 0.163 0.32 0.516 0 0 0 0 0 1 0 \">" N_("Rod monochromacy (atypical achromatopsia)") "\n" "<_item value=\"0.299 0.587 0.114 0 0 0.299 0.587 0.114 0 0 0.299 0.587 0.114 0 0 0 0 0 1 0 \">" N_("Cone monochromacy (typical achromatopsia)") "\n" - "<_item value=\"0.8 0.2 0 0 0 0.2583 0.74167 0 0 0 0 0.14167 0.85833 0 0 0 0 0 1 0 \">" N_("Geen weak (deuteranomaly)") "\n" + "<_item value=\"0.8 0.2 0 0 0 0.2583 0.74167 0 0 0 0 0.14167 0.85833 0 0 0 0 0 1 0 \">" N_("Green weak (deuteranomaly)") "\n" "<_item value=\"0.625 0.375 0 0 0 0.7 0.3 0 0 0 0 0.3 0.7 0 0 0 0 0 1 0 \">" N_("Green blind (deuteranopia)") "\n" "<_item value=\"0.8166 0.1833 0 0 0 0.333 0.666 0 0 0 0 0.125 0.875 0 0 0 0 0 1 0 \">" N_("Red weak (protanomaly)") "\n" "<_item value=\"0.566 0.43333 0 0 0 0.55833 0.4416 0 0 0 0 0.24167 0.75833 0 0 0 0 0 1 0 \">" N_("Red blind (protanopia)") "\n" -- cgit v1.2.3 From fbff05fb816454688444dd23169a70092f1252bc Mon Sep 17 00:00:00 2001 From: Tomasz Boczkowski Date: Tue, 12 May 2015 00:28:20 +0200 Subject: fixed color selector not remembering it's last open tab (bzr r14059.1.25) --- src/ui/widget/color-notebook.cpp | 2 +- src/widgets/paint-selector.cpp | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/ui/widget/color-notebook.cpp b/src/ui/widget/color-notebook.cpp index 0150f2ca2..60abf43bf 100644 --- a/src/ui/widget/color-notebook.cpp +++ b/src/ui/widget/color-notebook.cpp @@ -275,7 +275,7 @@ void ColorNotebook::_onSelectedColorChanged() { _updateICCButtons(); } void ColorNotebook::_onPageSwitched(GtkNotebook *notebook, GtkWidget *page, guint page_num, ColorNotebook *colorbook) { - if (colorbook) { + if (colorbook->get_visible()) { // remember the page we switched to Inkscape::Preferences *prefs = Inkscape::Preferences::get(); prefs->setInt("/colorselector/page", page_num); diff --git a/src/widgets/paint-selector.cpp b/src/widgets/paint-selector.cpp index f9a537f41..846ded511 100644 --- a/src/widgets/paint-selector.cpp +++ b/src/widgets/paint-selector.cpp @@ -586,6 +586,9 @@ sp_paint_selector_clear_frame(SPPaintSelector *psel) if (psel->selector) { + //This is a hack to work around GtkNotebook bug in ColorSelector. Is sends signal switch-page on destroy + //The widget is hidden firts so it can recognize that it should not process signals from notebook child + gtk_widget_set_visible(psel->selector, false); gtk_widget_destroy(psel->selector); psel->selector = NULL; } -- cgit v1.2.3 From c1b1d511b45348d8bccc5d22cd3471bb540cde12 Mon Sep 17 00:00:00 2001 From: Tavmjong Bah Date: Tue, 12 May 2015 21:43:24 +0200 Subject: GUI for font-variant-xxx, parse 'font-variant-ligatures'. This is a work in progress. (bzr r14148) --- src/desktop-style.cpp | 60 ++++++++++ src/desktop-style.h | 2 + src/style-enums.h | 39 ++++--- src/style-internal.cpp | 131 +++++++++++++++++++++ src/style-internal.h | 49 ++++++++ src/style-test.h | 11 ++ src/style.cpp | 2 +- src/style.h | 2 +- src/ui/dialog/text-edit.cpp | 9 +- src/ui/dialog/text-edit.h | 4 + src/ui/widget/Makefile_insert | 6 +- src/ui/widget/font-variants.cpp | 246 ++++++++++++++++++++++++++++++++++++++++ src/ui/widget/font-variants.h | 119 +++++++++++++++++++ 13 files changed, 655 insertions(+), 25 deletions(-) create mode 100644 src/ui/widget/font-variants.cpp create mode 100644 src/ui/widget/font-variants.h (limited to 'src') diff --git a/src/desktop-style.cpp b/src/desktop-style.cpp index afdc3064a..118f983bb 100644 --- a/src/desktop-style.cpp +++ b/src/desktop-style.cpp @@ -1168,6 +1168,63 @@ objects_query_fontstyle (const std::vector &objects, SPStyle *style_res } } +int +objects_query_fontvariants (const std::vector &objects, SPStyle *style_res) +{ + bool set = false; + + int texts = 0; + + SPILigatures* ligatures_res = &(style_res->font_variant_ligatures); + ligatures_res->computed = + SP_CSS_FONT_VARIANT_LIGATURES_COMMON | + SP_CSS_FONT_VARIANT_LIGATURES_CONTEXTUAL; + ligatures_res->value = 0; + for (std::vector::const_iterator i = objects.begin(); i != objects.end(); i++) { + SPObject *obj = *i; + + if (!isTextualItem(obj)) { + continue; + } + + SPStyle *style = obj->style; + if (!style) { + continue; + } + + texts ++; + + SPILigatures* ligatures_in = &(style->font_variant_ligatures); + // computed stores which bits are on/off, only valid if same between all selected objects. + // value stores which bits are different between objects. This is a bit of an abuse of + // the values but then we don't need to add new variables to class. + if (set) { + ligatures_res->value |= (ligatures_res->computed ^ ligatures_in->computed ); + ligatures_res->computed &= ligatures_in->computed; + } else { + set = true; + ligatures_res->computed = ligatures_in->computed; + } + } + + bool different = (style_res->font_variant_position.value != + style_res->font_variant_position.computed ); + + if (texts == 0 || !set) + return QUERY_STYLE_NOTHING; + + if (texts > 1) { + if (different) { + return QUERY_STYLE_MULTIPLE_DIFFERENT; + } else { + return QUERY_STYLE_MULTIPLE_SAME; + } + } else { + return QUERY_STYLE_SINGLE; + } +} + + /** * Write to style_res the baseline numbers. */ @@ -1577,6 +1634,8 @@ sp_desktop_query_style_from_list (const std::vector &list, SPStyle *sty return objects_query_fontfamily (list, style); } else if (property == QUERY_STYLE_PROPERTY_FONTSTYLE) { return objects_query_fontstyle (list, style); + } else if (property == QUERY_STYLE_PROPERTY_FONTVARIANTS) { + return objects_query_fontvariants (list, style); } else if (property == QUERY_STYLE_PROPERTY_FONTNUMBERS) { return objects_query_fontnumbers (list, style); } else if (property == QUERY_STYLE_PROPERTY_BASELINES) { @@ -1598,6 +1657,7 @@ sp_desktop_query_style_from_list (const std::vector &list, SPStyle *sty int sp_desktop_query_style(SPDesktop *desktop, SPStyle *style, int property) { + // Used by text tool and in gradient dragging int ret = desktop->_query_style_signal.emit(style, property); if (ret != QUERY_STYLE_NOTHING) diff --git a/src/desktop-style.h b/src/desktop-style.h index a72f49776..e5fe50440 100644 --- a/src/desktop-style.h +++ b/src/desktop-style.h @@ -47,6 +47,7 @@ enum { // which property was queried (add when you need more) QUERY_STYLE_PROPERTY_FONT_SPECIFICATION, //-inkscape-font-specification QUERY_STYLE_PROPERTY_FONTFAMILY, // font-family QUERY_STYLE_PROPERTY_FONTSTYLE, // font style + QUERY_STYLE_PROPERTY_FONTVARIANTS, // font variants (OpenType features) QUERY_STYLE_PROPERTY_FONTNUMBERS, // size, spacings QUERY_STYLE_PROPERTY_BASELINES, // baseline-shift QUERY_STYLE_PROPERTY_MASTEROPACITY, // opacity @@ -71,6 +72,7 @@ int objects_query_fillstroke (const std::vector &objects, SPStyle *styl int objects_query_fontnumbers (const std::vector &objects, SPStyle *style_res); int objects_query_fontstyle (const std::vector &objects, SPStyle *style_res); int objects_query_fontfamily (const std::vector &objects, SPStyle *style_res); +int objects_query_fontvariants (const std::vector &objects, SPStyle *style_res); int objects_query_opacity (const std::vector &objects, SPStyle *style_res); int objects_query_strokewidth (const std::vector &objects, SPStyle *style_res); int objects_query_miterlimit (const std::vector &objects, SPStyle *style_res); diff --git a/src/style-enums.h b/src/style-enums.h index f235b6699..36eab216d 100644 --- a/src/style-enums.h +++ b/src/style-enums.h @@ -74,16 +74,15 @@ enum SPCSSFontStretch { // Can select more than one enum SPCSSFontVariantLigatures { - SP_CSS_FONT_VARIANT_LIGATURES_NORMAL, - SP_CSS_FONT_VARIANT_LIGATURES_NONE, - SP_CSS_FONT_VARIANT_LIGATURES_COMMON, - SP_CSS_FONT_VARIANT_LIGATURES_NO_COMMON, - SP_CSS_FONT_VARIANT_LIGATURES_DISCRETIONARY, - SP_CSS_FONT_VARIANT_LIGATURES_NO_DISCRETIONARY, - SP_CSS_FONT_VARIANT_LIGATURES_HISTORICAL, - SP_CSS_FONT_VARIANT_LIGATURES_NO_HISTORICAL, - SP_CSS_FONT_VARIANT_LIGATURES_CONTEXTUAL, - SP_CSS_FONT_VARIANT_LIGATURES_NO_CONTEXTUAL + SP_CSS_FONT_VARIANT_LIGATURES_NONE = 0, + SP_CSS_FONT_VARIANT_LIGATURES_COMMON = 1, + SP_CSS_FONT_VARIANT_LIGATURES_DISCRETIONARY = 2, + SP_CSS_FONT_VARIANT_LIGATURES_HISTORICAL = 4, + SP_CSS_FONT_VARIANT_LIGATURES_CONTEXTUAL = 8, + SP_CSS_FONT_VARIANT_LIGATURES_NOCOMMON = 16, + SP_CSS_FONT_VARIANT_LIGATURES_NODISCRETIONARY = 32, + SP_CSS_FONT_VARIANT_LIGATURES_NOHISTORICAL = 64, + SP_CSS_FONT_VARIANT_LIGATURES_NOCONTEXTUAL = 128 }; enum SPCSSFontVariantPosition { @@ -102,6 +101,7 @@ enum SPCSSFontVariantCaps { SP_CSS_FONT_VARIANT_CAPS_TITLING, }; +// Can select more than one (see spec) enum SPCSSFontVariantNumeric { SP_CSS_FONT_VARIANT_NUMERIC_NORMAL, SP_CSS_FONT_VARIANT_NUMERIC_LINING_NUMS, @@ -376,16 +376,15 @@ static SPStyleEnum const enum_font_stretch[] = { }; static SPStyleEnum const enum_font_variant_ligatures[] = { - {"normal", SP_CSS_FONT_VARIANT_LIGATURES_NORMAL}, - {"none", SP_CSS_FONT_VARIANT_LIGATURES_NONE}, - {"common-ligatures", SP_CSS_FONT_VARIANT_LIGATURES_COMMON}, - {"no-common-ligatures", SP_CSS_FONT_VARIANT_LIGATURES_NO_COMMON}, - {"discretionary-ligatures", SP_CSS_FONT_VARIANT_LIGATURES_DISCRETIONARY}, - {"no-discretionary-ligatures", SP_CSS_FONT_VARIANT_LIGATURES_NO_DISCRETIONARY}, - {"historical-ligatures", SP_CSS_FONT_VARIANT_LIGATURES_HISTORICAL}, - {"nohistorical-ligatures", SP_CSS_FONT_VARIANT_LIGATURES_NO_HISTORICAL}, - {"contextual", SP_CSS_FONT_VARIANT_LIGATURES_CONTEXTUAL}, - {"no-contextual", SP_CSS_FONT_VARIANT_LIGATURES_NO_CONTEXTUAL}, + {"none", SP_CSS_FONT_VARIANT_LIGATURES_NONE}, + {"common-ligatures", SP_CSS_FONT_VARIANT_LIGATURES_COMMON}, + {"discretionary-ligatures", SP_CSS_FONT_VARIANT_LIGATURES_DISCRETIONARY}, + {"historical-ligatures", SP_CSS_FONT_VARIANT_LIGATURES_HISTORICAL}, + {"contextual", SP_CSS_FONT_VARIANT_LIGATURES_CONTEXTUAL}, + {"no-common-ligatures", SP_CSS_FONT_VARIANT_LIGATURES_NOCOMMON}, + {"no-discretionary-ligatures", SP_CSS_FONT_VARIANT_LIGATURES_NODISCRETIONARY}, + {"no-historical-ligatures", SP_CSS_FONT_VARIANT_LIGATURES_NOHISTORICAL}, + {"no-contextual", SP_CSS_FONT_VARIANT_LIGATURES_NOCONTEXTUAL}, {NULL, -1} }; diff --git a/src/style-internal.cpp b/src/style-internal.cpp index 915282301..7f6f6400d 100644 --- a/src/style-internal.cpp +++ b/src/style-internal.cpp @@ -45,6 +45,8 @@ #include #include +#include + // TODO REMOVE OR MAKE MEMBER FUNCTIONS void sp_style_fill_paint_server_ref_changed( SPObject *old_ref, SPObject *ref, SPStyle *style); void sp_style_stroke_paint_server_ref_changed(SPObject *old_ref, SPObject *ref, SPStyle *style); @@ -664,6 +666,135 @@ SPIEnum::operator==(const SPIBase& rhs) { } +// SPIEnumBits ---------------------------------------------------------- +// Used for 'font-variant-xxx' +void +SPIEnumBits::read( gchar const *str ) { + + if( !str ) return; + std::cout << "SPIEnumBits: " << name << ": " << str << std::endl; + if( !strcmp(str, "inherit") ) { + set = true; + inherit = true; + } else { + for (unsigned i = 0; enums[i].key; i++) { + if (!strcmp(str, enums[i].key)) { + std::cout << " found: " << enums[i].key << std::endl; + set = true; + inherit = false; + value += enums[i].value; + /* Save copying for values not needing it */ + computed = value; + } + } + } +} + +const Glib::ustring +SPIEnumBits::write( guint const flags, SPIBase const *const base) const { + + SPIEnum const *const my_base = dynamic_cast(base); + if ( (flags & SP_STYLE_FLAG_ALWAYS) || + ((flags & SP_STYLE_FLAG_IFSET) && this->set) || + ((flags & SP_STYLE_FLAG_IFDIFF) && this->set + && (!my_base->set || this != my_base ))) + { + if (this->inherit) { + return (name + ":inherit;"); + } + if (this->value == 0 ) { + return (name + ":normal"); + } + Glib::ustring return_string = name + ":"; + unsigned j = 1; + for (unsigned i = 0; enums[i].key; ++i) { + if (j & this->value ) { + return_string += enums[i].value + " "; + } + j *= 2; + } + return return_string; + } + return Glib::ustring(""); +} + + +// SPILigatures ----------------------------------------------------- +// Used for 'font-variant-ligatures' +void +SPILigatures::read( gchar const *str ) { + + if( !str ) return; + + value = SP_CSS_FONT_VARIANT_LIGATURES_COMMON | SP_CSS_FONT_VARIANT_LIGATURES_CONTEXTUAL; + if( !strcmp(str, "inherit") ) { + set = true; + inherit = true; + } else if (!strcmp(str, "normal" )) { + // Defaults for TrueType + inherit = false; + set = true; + } else if (!strcmp(str, "none" )) { + value = SP_CSS_FONT_VARIANT_LIGATURES_NONE; + inherit = false; + set = true; + } else { + // We need to parse in order + std::vector tokens = Glib::Regex::split_simple("\\s+", str ); + for( unsigned i = 0; i < tokens.size(); ++i ) { + for (unsigned j = 0; enums[j].key; ++j ) { + if (tokens[i].compare( enums[j].key ) == 0 ) { + set = true; + inherit = false; + if( enums[j].value < SP_CSS_FONT_VARIANT_LIGATURES_NOCOMMON ) { + // Turn on + value |= enums[j].value; + } else { + // Turn off + value &= ~(enums[j].value >> 4); + } + } + } + } + } + computed = value; +} + +const Glib::ustring +SPILigatures::write( guint const flags, SPIBase const *const base) const { + + SPIEnum const *const my_base = dynamic_cast(base); + if ( (flags & SP_STYLE_FLAG_ALWAYS) || + ((flags & SP_STYLE_FLAG_IFSET) && this->set) || + ((flags & SP_STYLE_FLAG_IFDIFF) && this->set + && (!my_base->set || this != my_base ))) + { + if (this->inherit) { + return (name + ":inherit;"); + } + if (value == SP_CSS_FONT_VARIANT_LIGATURES_NONE ) { + return (name + ":none;"); + } + if (value == (SP_CSS_FONT_VARIANT_LIGATURES_COMMON + + SP_CSS_FONT_VARIANT_LIGATURES_CONTEXTUAL) ) { + return (name + ":normal;"); + } + + Glib::ustring return_string = name + ":"; + if ( !(value & SP_CSS_FONT_VARIANT_LIGATURES_COMMON) ) + return_string += "no-common-ligatures "; + if ( value & SP_CSS_FONT_VARIANT_LIGATURES_DISCRETIONARY ) + return_string += "discretionary-ligatures "; + if ( value & SP_CSS_FONT_VARIANT_LIGATURES_HISTORICAL ) + return_string += "historical-ligatures "; + if ( !(value & SP_CSS_FONT_VARIANT_LIGATURES_CONTEXTUAL) ) + return_string += "no-contextual "; + return_string.erase( return_string.size() - 1 ); + return_string += ";"; + return return_string; + } + return Glib::ustring(""); +} // SPIString ------------------------------------------------------------ diff --git a/src/style-internal.h b/src/style-internal.h index a8f0c5096..ea966866a 100644 --- a/src/style-internal.h +++ b/src/style-internal.h @@ -510,6 +510,55 @@ private: }; +/// SPIEnum w/ bits, allows values with multiple key words. +class SPIEnumBits : public SPIEnum +{ + +public: + SPIEnumBits() : + SPIEnum( "anonymous_enumbits", NULL ) + {} + + SPIEnumBits( Glib::ustring const &name, SPStyleEnum const *enums, unsigned value = 0, bool inherits = true ) : + SPIEnum( name, enums, value, inherit ) + {} + + virtual ~SPIEnumBits() + {} + + virtual void read( gchar const *str ); + virtual const Glib::ustring write( guint const flags = SP_STYLE_FLAG_IFSET, + SPIBase const *const base = NULL ) const; + +}; + + +/// SPIEnum w/ extra bits. The 'font-variants-ligatures' property is a complete mess that needs +/// special handling. For OpenType fonts the values 'common-ligatures', 'contextual', +/// 'no-discretionary-ligatures', and 'no-historical-ligatures' are not useful but we still must be +/// able to parse them. +class SPILigatures : public SPIEnum +{ + +public: + SPILigatures() : + SPIEnum( "anonymous_enumligatures", NULL ) + {} + + SPILigatures( Glib::ustring const &name, SPStyleEnum const *enums) : + SPIEnum( name, enums, + SP_CSS_FONT_VARIANT_LIGATURES_COMMON | SP_CSS_FONT_VARIANT_LIGATURES_CONTEXTUAL) + {} + + virtual ~SPILigatures() + {} + + virtual void read( gchar const *str ); + virtual const Glib::ustring write( guint const flags = SP_STYLE_FLAG_IFSET, + SPIBase const *const base = NULL ) const; +}; + + /// String type internal to SPStyle. // Used for 'marker', ..., 'font', 'font-family', 'inkscape-font-specification' class SPIString : public SPIBase diff --git a/src/style-test.h b/src/style-test.h index cd6769b24..fec0da0f8 100644 --- a/src/style-test.h +++ b/src/style-test.h @@ -137,6 +137,17 @@ public: TestCase("font-weight:bolder"), TestCase("font-stretch:condensed"), // SPIEnum + TestCase("font-variant-ligatures:none"), // SPILigatures + TestCase("font-variant-ligatures:normal"), + TestCase("font-variant-ligatures:no-common-ligatures"), + TestCase("font-variant-ligatures:discretionary-ligatures"), + TestCase("font-variant-ligatures:historical-ligatures"), + TestCase("font-variant-ligatures:no-contextual"), + TestCase("font-variant-ligatures:common-ligatures", "font-variant-ligatures:normal"), + TestCase("font-variant-ligatures:contextual", "font-variant-ligatures:normal"), + TestCase("font-variant-ligatures:no-common-ligatures historical-ligatures"), + TestCase("font-variant-ligatures:historical-ligatures no-contextual"), + // Should be moved down TestCase("text-indent:12em"), // SPILength? TestCase("text-align:center"), // SPIEnum diff --git a/src/style.cpp b/src/style.cpp index 49a13604b..4d93841eb 100644 --- a/src/style.cpp +++ b/src/style.cpp @@ -119,7 +119,7 @@ SPStyle::SPStyle(SPDocument *document_in, SPObject *object_in) : font_specification( "-inkscape-font-specification" ), // SPIString // Font variants - font_variant_ligatures( "font-variant-ligatures", enum_font_variant_ligatures, SP_CSS_FONT_VARIANT_LIGATURES_NORMAL ), + font_variant_ligatures( "font-variant-ligatures", enum_font_variant_ligatures ), font_variant_position( "font-variant-position", enum_font_variant_position, SP_CSS_FONT_VARIANT_POSITION_NORMAL ), font_variant_caps( "font-variant-caps", enum_font_variant_caps, SP_CSS_FONT_VARIANT_CAPS_NORMAL ), font_variant_numeric( "font-variant-numeric", enum_font_variant_numeric, SP_CSS_FONT_VARIANT_NUMERIC_NORMAL ), diff --git a/src/style.h b/src/style.h index 2618662f5..f82fad9b0 100644 --- a/src/style.h +++ b/src/style.h @@ -113,7 +113,7 @@ public: /* Font variants -------------------- */ /** Font variant ligatures */ - SPIEnum font_variant_ligatures; + SPILigatures font_variant_ligatures; /** Font variant position (subscript/superscript) */ SPIEnum font_variant_position; /** Font variant caps (small caps) */ diff --git a/src/ui/dialog/text-edit.cpp b/src/ui/dialog/text-edit.cpp index 815aa12ef..98ea7f9f7 100644 --- a/src/ui/dialog/text-edit.cpp +++ b/src/ui/dialog/text-edit.cpp @@ -69,6 +69,7 @@ TextEdit::TextEdit() font_label(_("_Font"), true), layout_frame(), text_label(_("_Text"), true), + vari_label(_("_Variants"), true), setasdefault_button(_("Set as _default")), close_button(Gtk::Stock::CLOSE), apply_button(Gtk::Stock::APPLY), @@ -195,7 +196,8 @@ TextEdit::TextEdit() notebook.append_page(font_vbox, font_label); notebook.append_page(text_vbox, text_label); - + notebook.append_page(vari_vbox, vari_label); + /* Buttons */ setasdefault_button.set_use_underline(true); apply_button.set_can_default(); @@ -384,6 +386,11 @@ void TextEdit::onReadSelection ( gboolean dostyle, gboolean /*docontent*/ ) gtk_entry_set_text ((GtkEntry *) gtk_bin_get_child ((GtkBin *) spacing_combo), sstr); g_free(sstr); + // Update font variant widget + //int result_variants = + sp_desktop_query_style (SP_ACTIVE_DESKTOP, &query, QUERY_STYLE_PROPERTY_FONTVARIANTS); + vari_vbox.update( query.font_variant_ligatures.computed, query.font_variant_ligatures.value ); + } blocked = false; } diff --git a/src/ui/dialog/text-edit.h b/src/ui/dialog/text-edit.h index 117ad2e28..f088fd337 100644 --- a/src/ui/dialog/text-edit.h +++ b/src/ui/dialog/text-edit.h @@ -32,6 +32,7 @@ #include "ui/widget/panel.h" #include "ui/widget/frame.h" #include "ui/dialog/desktop-tracker.h" +#include "ui/widget/font-variants.h" class SPItem; struct SPFontSelector; @@ -213,6 +214,9 @@ private: GtkWidget *text_view; // TODO - Convert this to a Gtk::TextView, but GtkSpell doesn't seem to work with it GtkTextBuffer *text_buffer; + Inkscape::UI::Widget::FontVariants vari_vbox; + Gtk::Label vari_label; + Gtk::HBox button_row; Gtk::Button setasdefault_button; Gtk::Button close_button; diff --git a/src/ui/widget/Makefile_insert b/src/ui/widget/Makefile_insert index e18b790bd..305076a9d 100644 --- a/src/ui/widget/Makefile_insert +++ b/src/ui/widget/Makefile_insert @@ -21,8 +21,10 @@ ink_common_sources += \ ui/widget/entry.h \ ui/widget/filter-effect-chooser.h \ ui/widget/filter-effect-chooser.cpp \ - ui/widget/gimpspinscale.c \ - ui/widget/gimpspinscale.h \ + ui/widget/font-variants.h \ + ui/widget/font-variants.cpp \ + ui/widget/gimpspinscale.c \ + ui/widget/gimpspinscale.h \ ui/widget/gimpcolorwheel.c \ ui/widget/gimpcolorwheel.h \ ui/widget/frame.cpp \ diff --git a/src/ui/widget/font-variants.cpp b/src/ui/widget/font-variants.cpp new file mode 100644 index 000000000..46fbc2aa4 --- /dev/null +++ b/src/ui/widget/font-variants.cpp @@ -0,0 +1,246 @@ +/* + * Author: + * Tavmjong Bah + * + * Copyright (C) 2015 Tavmong Bah + * + * Released under GNU GPL. Read the file 'COPYING' for more information. + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include + +#include + +#include "font-variants.h" + +// For updating from selection +#include "desktop.h" +#include "selection.h" +#include "style.h" +#include "sp-text.h" +#include "sp-tspan.h" +#include "sp-tref.h" +#include "sp-textpath.h" +#include "sp-item-group.h" + +namespace Inkscape { +namespace UI { +namespace Widget { + + FontVariants::FontVariants () : + Gtk::VBox (), + _ligatures_frame ( Glib::ustring(_("Ligatures" )) ), + _ligatures_common ( Glib::ustring(_("Common" )) ), + _ligatures_discretionary ( Glib::ustring(_("Discretionary")) ), + _ligatures_historical ( Glib::ustring(_("Historical" )) ), + _ligatures_contextual ( Glib::ustring(_("Contextual" )) ), + + _position_frame ( Glib::ustring(_("Position" )) ), + _position_normal ( Glib::ustring(_("Normal" )) ), + _position_sub ( Glib::ustring(_("Subscript" )) ), + _position_super ( Glib::ustring(_("Superscript" )) ), + + _caps_frame ( Glib::ustring(_("Capitals" )) ), + _caps_normal ( Glib::ustring(_("Normal" )) ), + _caps_small ( Glib::ustring(_("Small" )) ), + _caps_all_small ( Glib::ustring(_("All small" )) ), + _caps_petite ( Glib::ustring(_("Petite" )) ), + _caps_all_petite ( Glib::ustring(_("All petite" )) ), + _caps_unicase ( Glib::ustring(_("Unicase" )) ), + _caps_titling ( Glib::ustring(_("Titling" )) ), + + _numeric_frame ( Glib::ustring(_("Numeric" )) ), + _numeric_lining ( Glib::ustring(_("Lining" )) ), + _numeric_old_style ( Glib::ustring(_("Old Style" )) ), + _numeric_default_style ( Glib::ustring(_("Default Style")) ), + _numeric_proportional ( Glib::ustring(_("Proportional" )) ), + _numeric_tabular ( Glib::ustring(_("Tabular" )) ), + _numeric_default_width ( Glib::ustring(_("Default Width")) ), + _numeric_diagonal ( Glib::ustring(_("Diagonal" )) ), + _numeric_stacked ( Glib::ustring(_("Stacked" )) ), + _numeric_default_fractions( Glib::ustring(_("Default Fractions")) ), + _numeric_ordinal ( Glib::ustring(_("Ordinal" )) ), + _numeric_slashed_zero ( Glib::ustring(_("Slashed Zero" )) ) + + + { + + // Ligatures -------------------------- + _ligatures_common.set_tooltip_text( + _("Common ligatures. On by default. OpenType tables: 'liga', 'clig'")); + _ligatures_discretionary.set_tooltip_text( + _("Discretionary ligatures. Off by default. OpenType table: 'dlig'")); + _ligatures_historical.set_tooltip_text( + _("Historical ligatures. Off by default. OpenType table: 'hlig'")); + _ligatures_contextual.set_tooltip_text( + _("Contextual forms. On by default. OpenType table: 'calt'")); + + + _ligatures_common.signal_clicked().connect ( sigc::mem_fun(*this, &FontVariants::ligatures_callback) ); + _ligatures_discretionary.signal_clicked().connect ( sigc::mem_fun(*this, &FontVariants::ligatures_callback) ); + _ligatures_historical.signal_clicked().connect ( sigc::mem_fun(*this, &FontVariants::ligatures_callback) ); + _ligatures_contextual.signal_clicked().connect ( sigc::mem_fun(*this, &FontVariants::ligatures_callback) ); + _ligatures_vbox.add( _ligatures_common ); + _ligatures_vbox.add( _ligatures_discretionary ); + _ligatures_vbox.add( _ligatures_historical ); + _ligatures_vbox.add( _ligatures_contextual ); + _ligatures_frame.add( _ligatures_vbox ); + add( _ligatures_frame ); + + ligatures_init(); + + // Position ---------------------------------- + _position_vbox.add( _position_normal ); + _position_vbox.add( _position_sub ); + _position_vbox.add( _position_super ); + _position_frame.add( _position_vbox ); + add( _position_frame ); + + // Group buttons + Gtk::RadioButton::Group position_group = _position_normal.get_group(); + _position_sub.set_group(position_group); + _position_super.set_group(position_group); + _position_normal.signal_pressed().connect ( sigc::mem_fun(*this, &FontVariants::position_callback) ); + _position_sub.signal_pressed().connect ( sigc::mem_fun(*this, &FontVariants::position_callback) ); + _position_super.signal_pressed().connect ( sigc::mem_fun(*this, &FontVariants::position_callback) ); + + position_init(); + + // Caps ---------------------------------- + _caps_vbox.add( _caps_normal ); + _caps_vbox.add( _caps_small ); + _caps_vbox.add( _caps_all_small ); + _caps_vbox.add( _caps_petite ); + _caps_vbox.add( _caps_all_petite ); + _caps_vbox.add( _caps_unicase ); + _caps_vbox.add( _caps_titling ); + _caps_frame.add( _caps_vbox ); + add( _caps_frame ); + + // Group buttons + Gtk::RadioButton::Group caps_group = _caps_normal.get_group(); + _caps_small.set_group(caps_group); + _caps_all_small.set_group(caps_group); + _caps_petite.set_group(caps_group); + _caps_all_petite.set_group(caps_group); + _caps_unicase.set_group(caps_group); + _caps_titling.set_group(caps_group); + _caps_normal.signal_clicked().connect ( sigc::mem_fun(*this, &FontVariants::caps_callback) ); + _caps_small.signal_clicked().connect ( sigc::mem_fun(*this, &FontVariants::caps_callback) ); + _caps_all_small.signal_clicked().connect ( sigc::mem_fun(*this, &FontVariants::caps_callback) ); + _caps_petite.signal_clicked().connect ( sigc::mem_fun(*this, &FontVariants::caps_callback) ); + _caps_all_petite.signal_clicked().connect ( sigc::mem_fun(*this, &FontVariants::caps_callback) ); + _caps_unicase.signal_clicked().connect ( sigc::mem_fun(*this, &FontVariants::caps_callback) ); + _caps_titling.signal_clicked().connect ( sigc::mem_fun(*this, &FontVariants::caps_callback) ); + + caps_init(); + + // Numeric ------------------------------ + _numeric_stylebox.add( _numeric_default_style ); + _numeric_stylebox.add( _numeric_lining ); + _numeric_stylebox.add( _numeric_old_style ); + _numeric_vbox.add( _numeric_stylebox ); + _numeric_widthbox.add( _numeric_default_width ); + _numeric_widthbox.add( _numeric_proportional ); + _numeric_widthbox.add( _numeric_tabular ); + _numeric_vbox.add( _numeric_widthbox ); + _numeric_fractionbox.add( _numeric_default_fractions ); + _numeric_fractionbox.add( _numeric_diagonal ); + _numeric_fractionbox.add( _numeric_stacked ); + _numeric_vbox.add( _numeric_fractionbox ); + _numeric_vbox.add( _numeric_ordinal ); + _numeric_vbox.add( _numeric_slashed_zero ); + _numeric_frame.add( _numeric_vbox ); + add( _numeric_frame ); + + // Group buttons + Gtk::RadioButton::Group style_group = _numeric_default_style.get_group(); + _numeric_lining.set_group(style_group); + _numeric_old_style.set_group(style_group); + + Gtk::RadioButton::Group width_group = _numeric_default_width.get_group(); + _numeric_proportional.set_group(width_group); + _numeric_tabular.set_group(width_group); + + Gtk::RadioButton::Group fraction_group = _numeric_default_fractions.get_group(); + _numeric_diagonal.set_group(fraction_group); + _numeric_stacked.set_group(fraction_group); + + show_all_children(); + } + + void + FontVariants::ligatures_init() { + // std::cout << "FontVariants::ligatures_init()" << std::endl; + } + + void + FontVariants::ligatures_callback() { + // std::cout << "FontVariants::ligatures_callback()" << std::endl; + } + + void + FontVariants::position_init() { + // std::cout << "FontVariants::position_init()" << std::endl; + } + + void + FontVariants::position_callback() { + // std::cout << "FontVariants::position_callback()" << std::endl; + } + + void + FontVariants::caps_init() { + // std::cout << "FontVariants::caps_init()" << std::endl; + } + + void + FontVariants::caps_callback() { + // std::cout << "FontVariants::caps_callback()" << std::endl; + } + + void + FontVariants::numeric_init() { + std::cout << "FontVariants::numeric_init()" << std::endl; + // _numeric_tabular.set_inconsistent(); + } + + void + FontVariants::numeric_callback() { + // std::cout << "FontVariants::numeric_callback()" << std::endl; + } + + void + FontVariants::update( unsigned all, unsigned mix ) { + // std::cout << "FontVariants::update" << std::endl; + + _ligatures_common.set_active( all & SP_CSS_FONT_VARIANT_LIGATURES_COMMON ); + _ligatures_discretionary.set_active( all & SP_CSS_FONT_VARIANT_LIGATURES_DISCRETIONARY ); + _ligatures_historical.set_active( all & SP_CSS_FONT_VARIANT_LIGATURES_HISTORICAL ); + _ligatures_contextual.set_active( all & SP_CSS_FONT_VARIANT_LIGATURES_CONTEXTUAL ); + + _ligatures_common.set_inconsistent( mix & SP_CSS_FONT_VARIANT_LIGATURES_COMMON ); + _ligatures_discretionary.set_inconsistent( mix & SP_CSS_FONT_VARIANT_LIGATURES_DISCRETIONARY ); + _ligatures_historical.set_inconsistent( mix & SP_CSS_FONT_VARIANT_LIGATURES_HISTORICAL ); + _ligatures_contextual.set_inconsistent( mix & SP_CSS_FONT_VARIANT_LIGATURES_CONTEXTUAL ); + } + +} // namespace Widget +} // namespace UI +} // namespace Inkscape + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 : diff --git a/src/ui/widget/font-variants.h b/src/ui/widget/font-variants.h new file mode 100644 index 000000000..bef14c4bd --- /dev/null +++ b/src/ui/widget/font-variants.h @@ -0,0 +1,119 @@ +/* + * Author: + * Tavmjong Bah + * + * Copyright (C) 2015 Tavmong Bah + * + * Released under GNU GPL. Read the file 'COPYING' for more information. + */ + +#ifndef INKSCAPE_UI_WIDGET_FONT_VARIANT_H +#define INKSCAPE_UI_WIDGET_FONT_VARIANT_H + +// Temp: both frame and expander +#include +#include +#include +#include + +class SPDesktop; +class SPObject; + +namespace Inkscape { +namespace UI { +namespace Widget { + +/** + * A container for selecting font variants (OpenType Features). + */ +class FontVariants : public Gtk::VBox +{ + +public: + + /** + * Constructor + */ + FontVariants(); + +protected: + // To start, use four check buttons. + Gtk::Expander _ligatures_frame; + Gtk::VBox _ligatures_vbox; + Gtk::CheckButton _ligatures_common; + Gtk::CheckButton _ligatures_discretionary; + Gtk::CheckButton _ligatures_historical; + Gtk::CheckButton _ligatures_contextual; + + // Exclusive options + Gtk::Expander _position_frame; + Gtk::VBox _position_vbox; + Gtk::RadioButton _position_normal; + Gtk::RadioButton _position_sub; + Gtk::RadioButton _position_super; + + // Exclusive options (maybe a dropdown menu to save space?) + Gtk::Expander _caps_frame; + Gtk::VBox _caps_vbox; + Gtk::RadioButton _caps_normal; + Gtk::RadioButton _caps_small; + Gtk::RadioButton _caps_all_small; + Gtk::RadioButton _caps_petite; + Gtk::RadioButton _caps_all_petite; + Gtk::RadioButton _caps_unicase; + Gtk::RadioButton _caps_titling; + + // Complicated! + Gtk::Expander _numeric_frame; + Gtk::VBox _numeric_vbox; + Gtk::HBox _numeric_stylebox; + Gtk::RadioButton _numeric_lining; + Gtk::RadioButton _numeric_old_style; + Gtk::RadioButton _numeric_default_style; + Gtk::HBox _numeric_widthbox; + Gtk::RadioButton _numeric_proportional; + Gtk::RadioButton _numeric_tabular; + Gtk::RadioButton _numeric_default_width; + Gtk::HBox _numeric_fractionbox; + Gtk::RadioButton _numeric_diagonal; + Gtk::RadioButton _numeric_stacked; + Gtk::RadioButton _numeric_default_fractions; + Gtk::CheckButton _numeric_ordinal; + Gtk::CheckButton _numeric_slashed_zero; + +private: + void ligatures_init(); + void ligatures_callback(); + + void position_init(); + void position_callback(); + + void caps_init(); + void caps_callback(); + + void numeric_init(); + void numeric_callback(); + +public: + void update_recursive( SPObject *object ); + void update( unsigned all, unsigned mix ); + +}; + + +} // namespace Widget +} // namespace UI +} // namespace Inkscape + +#endif // INKSCAPE_UI_WIDGET_FONT_VARIANT_H + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 : -- cgit v1.2.3 From 5f3d8bb9fbfefd83502fed2c8a7b2a2909a92059 Mon Sep 17 00:00:00 2001 From: su_v Date: Tue, 12 May 2015 22:23:05 +0200 Subject: cmake: fix build with new GUI for font-variant-xxx (r14148) (bzr r14149) --- src/ui/CMakeLists.txt | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src') diff --git a/src/ui/CMakeLists.txt b/src/ui/CMakeLists.txt index 991d11feb..164d74156 100644 --- a/src/ui/CMakeLists.txt +++ b/src/ui/CMakeLists.txt @@ -122,6 +122,7 @@ set(ui_SRC widget/entity-entry.cpp widget/entry.cpp widget/filter-effect-chooser.cpp + widget/font-variants.cpp widget/frame.cpp widget/gimpcolorwheel.c widget/gimpspinscale.c @@ -295,6 +296,7 @@ set(ui_SRC widget/entity-entry.h widget/entry.h widget/filter-effect-chooser.h + widget/font-variants.h widget/frame.h widget/gimpspinscale.h widget/gimpcolorwheel.h -- cgit v1.2.3 From 4bd53e1e365fe78a674ee6ee0232f4a1d9b38dbf Mon Sep 17 00:00:00 2001 From: Marc Jeanmougin Date: Wed, 13 May 2015 00:12:43 +0200 Subject: forgot a line; had weird consequences on filters (bzr r14150) --- src/selection.cpp | 1 + 1 file changed, 1 insertion(+) (limited to 'src') diff --git a/src/selection.cpp b/src/selection.cpp index 7979b5d61..77a507eec 100644 --- a/src/selection.cpp +++ b/src/selection.cpp @@ -125,6 +125,7 @@ Selection::_releaseContext(SPObject *obj) void Selection::_invalidateCachedLists() { _items.clear(); _reprs.clear(); + _objs_vector.clear(); } void Selection::_clear() { -- cgit v1.2.3 From ffd7534dc2d5d718dbc0720c17dda56f57fcd7ed Mon Sep 17 00:00:00 2001 From: Tavmjong Bah Date: Thu, 14 May 2015 07:24:57 +0200 Subject: Enable setting of 'font-variant-ligatures' (rendering waits on new Pango library). (bzr r14152) --- src/ui/dialog/text-edit.cpp | 5 ++++- src/ui/widget/font-variants.cpp | 28 ++++++++++++++++++++++++++++ src/ui/widget/font-variants.h | 3 ++- 3 files changed, 34 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/ui/dialog/text-edit.cpp b/src/ui/dialog/text-edit.cpp index 98ea7f9f7..2726d979c 100644 --- a/src/ui/dialog/text-edit.cpp +++ b/src/ui/dialog/text-edit.cpp @@ -517,12 +517,15 @@ SPCSSAttr *TextEdit::fillTextStyle () sp_repr_css_set_property (css, "writing-mode", "tb"); } - // Note that CSS 1.1 does not support line-height; we set it for consistency, but also set + // Note that SVG 1.1 does not support line-height; we set it for consistency, but also set // sodipodi:linespacing for backwards compatibility; in 1.2 we use line-height for flowtext const gchar *sstr = gtk_combo_box_text_get_active_text ((GtkComboBoxText *) spacing_combo); sp_repr_css_set_property (css, "line-height", sstr); + // Font variants + vari_vbox.fill_css( css ); + return css; } diff --git a/src/ui/widget/font-variants.cpp b/src/ui/widget/font-variants.cpp index 46fbc2aa4..7da7662e2 100644 --- a/src/ui/widget/font-variants.cpp +++ b/src/ui/widget/font-variants.cpp @@ -27,6 +27,7 @@ #include "sp-tref.h" #include "sp-textpath.h" #include "sp-item-group.h" +#include "xml/repr.h" namespace Inkscape { namespace UI { @@ -230,6 +231,33 @@ namespace Widget { _ligatures_contextual.set_inconsistent( mix & SP_CSS_FONT_VARIANT_LIGATURES_CONTEXTUAL ); } + void + FontVariants::fill_css( SPCSSAttr *css ) { + + // Ligatures + bool common = _ligatures_common.get_active(); + bool discretionary = _ligatures_discretionary.get_active(); + bool historical = _ligatures_historical.get_active(); + bool contextual = _ligatures_contextual.get_active(); + + if( !common && !discretionary && !historical && !contextual ) { + sp_repr_css_set_property(css, "font-variant-ligatures", "none" ); + } else if ( common && !discretionary && !historical && contextual ) { + sp_repr_css_set_property(css, "font-variant-ligatures", "normal" ); + } else { + Glib::ustring css_string; + if ( !common ) + css_string += "no-common-ligatures "; + if ( discretionary ) + css_string += "discretionary-ligatures "; + if ( historical ) + css_string += "historical-ligatures "; + if ( !contextual ) + css_string += "no-contextual "; + sp_repr_css_set_property(css, "font-variant-ligatures", css_string.c_str() ); + } + } + } // namespace Widget } // namespace UI } // namespace Inkscape diff --git a/src/ui/widget/font-variants.h b/src/ui/widget/font-variants.h index bef14c4bd..f58b80f34 100644 --- a/src/ui/widget/font-variants.h +++ b/src/ui/widget/font-variants.h @@ -18,6 +18,7 @@ class SPDesktop; class SPObject; +class SPCSSAttr; namespace Inkscape { namespace UI { @@ -95,9 +96,9 @@ private: void numeric_callback(); public: - void update_recursive( SPObject *object ); void update( unsigned all, unsigned mix ); + void fill_css( SPCSSAttr* css ); }; -- cgit v1.2.3 From ddf9853ed86846c5cc4e22a1ede31dafcda5c99d Mon Sep 17 00:00:00 2001 From: Tavmjong Bah Date: Sat, 16 May 2015 14:50:10 +0200 Subject: Enable setting of 'font-variant-position' and 'font-variant-caps'. Rendering awaits Pango update. (bzr r14155) --- src/desktop-style.cpp | 37 ++++++++++-- src/style-enums.h | 24 ++++---- src/style-internal.cpp | 5 +- src/style-test.h | 8 ++- src/ui/dialog/text-edit.cpp | 2 +- src/ui/widget/font-variants.cpp | 121 ++++++++++++++++++++++++++++++++++++---- src/ui/widget/font-variants.h | 19 ++++++- 7 files changed, 183 insertions(+), 33 deletions(-) (limited to 'src') diff --git a/src/desktop-style.cpp b/src/desktop-style.cpp index 118f983bb..f25ce8fa8 100644 --- a/src/desktop-style.cpp +++ b/src/desktop-style.cpp @@ -1176,10 +1176,19 @@ objects_query_fontvariants (const std::vector &objects, SPStyle *style_ int texts = 0; SPILigatures* ligatures_res = &(style_res->font_variant_ligatures); - ligatures_res->computed = - SP_CSS_FONT_VARIANT_LIGATURES_COMMON | - SP_CSS_FONT_VARIANT_LIGATURES_CONTEXTUAL; + SPIEnum* position_res = &(style_res->font_variant_position); + SPIEnum* caps_res = &(style_res->font_variant_caps); + + // Stores 'and' of all values + ligatures_res->computed = SP_CSS_FONT_VARIANT_LIGATURES_NORMAL; + position_res->computed = SP_CSS_FONT_VARIANT_POSITION_NORMAL; + caps_res->computed = SP_CSS_FONT_VARIANT_CAPS_NORMAL; + + // Stores only differences ligatures_res->value = 0; + position_res->value = 0; + caps_res->value = 0; + for (std::vector::const_iterator i = objects.begin(); i != objects.end(); i++) { SPObject *obj = *i; @@ -1195,20 +1204,36 @@ objects_query_fontvariants (const std::vector &objects, SPStyle *style_ texts ++; SPILigatures* ligatures_in = &(style->font_variant_ligatures); + SPIEnum* position_in = &(style->font_variant_position); + SPIEnum* caps_in = &(style->font_variant_caps); // computed stores which bits are on/off, only valid if same between all selected objects. // value stores which bits are different between objects. This is a bit of an abuse of // the values but then we don't need to add new variables to class. if (set) { ligatures_res->value |= (ligatures_res->computed ^ ligatures_in->computed ); ligatures_res->computed &= ligatures_in->computed; + + position_res->value |= (position_res->computed ^ position_in->computed ); + position_res->computed &= position_in->computed; + + caps_res->value |= (caps_res->computed ^ caps_in->computed ); + caps_res->computed &= caps_in->computed; + } else { - set = true; ligatures_res->computed = ligatures_in->computed; + position_res->computed = position_in->computed; + caps_res->computed = caps_in->computed; } + + set = true; } - bool different = (style_res->font_variant_position.value != - style_res->font_variant_position.computed ); + bool different = (style_res->font_variant_ligatures.value != + style_res->font_variant_ligatures.computed || + style_res->font_variant_position.value != + style_res->font_variant_position.computed || + style_res->font_variant_caps.value != + style_res->font_variant_caps.computed ); if (texts == 0 || !set) return QUERY_STYLE_NOTHING; diff --git a/src/style-enums.h b/src/style-enums.h index 36eab216d..dca7e246d 100644 --- a/src/style-enums.h +++ b/src/style-enums.h @@ -79,6 +79,7 @@ enum SPCSSFontVariantLigatures { SP_CSS_FONT_VARIANT_LIGATURES_DISCRETIONARY = 2, SP_CSS_FONT_VARIANT_LIGATURES_HISTORICAL = 4, SP_CSS_FONT_VARIANT_LIGATURES_CONTEXTUAL = 8, + SP_CSS_FONT_VARIANT_LIGATURES_NORMAL = 9, // Special case SP_CSS_FONT_VARIANT_LIGATURES_NOCOMMON = 16, SP_CSS_FONT_VARIANT_LIGATURES_NODISCRETIONARY = 32, SP_CSS_FONT_VARIANT_LIGATURES_NOHISTORICAL = 64, @@ -86,19 +87,19 @@ enum SPCSSFontVariantLigatures { }; enum SPCSSFontVariantPosition { - SP_CSS_FONT_VARIANT_POSITION_NORMAL, - SP_CSS_FONT_VARIANT_POSITION_SUB, - SP_CSS_FONT_VARIANT_POSITION_SUPER + SP_CSS_FONT_VARIANT_POSITION_NORMAL = 1, + SP_CSS_FONT_VARIANT_POSITION_SUB = 2, + SP_CSS_FONT_VARIANT_POSITION_SUPER = 4 }; enum SPCSSFontVariantCaps { - SP_CSS_FONT_VARIANT_CAPS_NORMAL, - SP_CSS_FONT_VARIANT_CAPS_SMALL, - SP_CSS_FONT_VARIANT_CAPS_ALL_SMALL, - SP_CSS_FONT_VARIANT_CAPS_PETITE, - SP_CSS_FONT_VARIANT_CAPS_ALL_PETITE, - SP_CSS_FONT_VARIANT_CAPS_UNICASE, - SP_CSS_FONT_VARIANT_CAPS_TITLING, + SP_CSS_FONT_VARIANT_CAPS_NORMAL = 1, + SP_CSS_FONT_VARIANT_CAPS_SMALL = 2, + SP_CSS_FONT_VARIANT_CAPS_ALL_SMALL = 4, + SP_CSS_FONT_VARIANT_CAPS_PETITE = 8, + SP_CSS_FONT_VARIANT_CAPS_ALL_PETITE = 16, + SP_CSS_FONT_VARIANT_CAPS_UNICASE = 32, + SP_CSS_FONT_VARIANT_CAPS_TITLING = 64 }; // Can select more than one (see spec) @@ -381,6 +382,7 @@ static SPStyleEnum const enum_font_variant_ligatures[] = { {"discretionary-ligatures", SP_CSS_FONT_VARIANT_LIGATURES_DISCRETIONARY}, {"historical-ligatures", SP_CSS_FONT_VARIANT_LIGATURES_HISTORICAL}, {"contextual", SP_CSS_FONT_VARIANT_LIGATURES_CONTEXTUAL}, + {"normal", SP_CSS_FONT_VARIANT_LIGATURES_NORMAL}, {"no-common-ligatures", SP_CSS_FONT_VARIANT_LIGATURES_NOCOMMON}, {"no-discretionary-ligatures", SP_CSS_FONT_VARIANT_LIGATURES_NODISCRETIONARY}, {"no-historical-ligatures", SP_CSS_FONT_VARIANT_LIGATURES_NOHISTORICAL}, @@ -400,7 +402,7 @@ static SPStyleEnum const enum_font_variant_caps[] = { {"small-caps", SP_CSS_FONT_VARIANT_CAPS_SMALL}, {"all-small-caps", SP_CSS_FONT_VARIANT_CAPS_ALL_SMALL}, {"petite-caps", SP_CSS_FONT_VARIANT_CAPS_PETITE}, - {"all_petite-caps", SP_CSS_FONT_VARIANT_CAPS_ALL_PETITE}, + {"all-petite-caps", SP_CSS_FONT_VARIANT_CAPS_ALL_PETITE}, {"unicase", SP_CSS_FONT_VARIANT_CAPS_UNICASE}, {"titling", SP_CSS_FONT_VARIANT_CAPS_TITLING}, {NULL, -1} diff --git a/src/style-internal.cpp b/src/style-internal.cpp index 7f6f6400d..3b76e5ab1 100644 --- a/src/style-internal.cpp +++ b/src/style-internal.cpp @@ -726,7 +726,7 @@ SPILigatures::read( gchar const *str ) { if( !str ) return; - value = SP_CSS_FONT_VARIANT_LIGATURES_COMMON | SP_CSS_FONT_VARIANT_LIGATURES_CONTEXTUAL; + value = SP_CSS_FONT_VARIANT_LIGATURES_NORMAL; if( !strcmp(str, "inherit") ) { set = true; inherit = true; @@ -775,8 +775,7 @@ SPILigatures::write( guint const flags, SPIBase const *const base) const { if (value == SP_CSS_FONT_VARIANT_LIGATURES_NONE ) { return (name + ":none;"); } - if (value == (SP_CSS_FONT_VARIANT_LIGATURES_COMMON + - SP_CSS_FONT_VARIANT_LIGATURES_CONTEXTUAL) ) { + if (value == SP_CSS_FONT_VARIANT_LIGATURES_NORMAL ) { return (name + ":normal;"); } diff --git a/src/style-test.h b/src/style-test.h index fec0da0f8..1d821312b 100644 --- a/src/style-test.h +++ b/src/style-test.h @@ -147,7 +147,13 @@ public: TestCase("font-variant-ligatures:contextual", "font-variant-ligatures:normal"), TestCase("font-variant-ligatures:no-common-ligatures historical-ligatures"), TestCase("font-variant-ligatures:historical-ligatures no-contextual"), - + TestCase("font-variant-position:normal"), + TestCase("font-variant-position:sub"), + TestCase("font-variant-position:super"), + TestCase("font-variant-caps:normal"), + TestCase("font-variant-caps:small-caps"), + TestCase("font-variant-caps:all-small-caps"), + // Should be moved down TestCase("text-indent:12em"), // SPILength? TestCase("text-align:center"), // SPIEnum diff --git a/src/ui/dialog/text-edit.cpp b/src/ui/dialog/text-edit.cpp index 2726d979c..4fd227f01 100644 --- a/src/ui/dialog/text-edit.cpp +++ b/src/ui/dialog/text-edit.cpp @@ -389,7 +389,7 @@ void TextEdit::onReadSelection ( gboolean dostyle, gboolean /*docontent*/ ) // Update font variant widget //int result_variants = sp_desktop_query_style (SP_ACTIVE_DESKTOP, &query, QUERY_STYLE_PROPERTY_FONTVARIANTS); - vari_vbox.update( query.font_variant_ligatures.computed, query.font_variant_ligatures.value ); + vari_vbox.update( &query ); } blocked = false; diff --git a/src/ui/widget/font-variants.cpp b/src/ui/widget/font-variants.cpp index 7da7662e2..8ca926d8f 100644 --- a/src/ui/widget/font-variants.cpp +++ b/src/ui/widget/font-variants.cpp @@ -66,8 +66,12 @@ namespace Widget { _numeric_stacked ( Glib::ustring(_("Stacked" )) ), _numeric_default_fractions( Glib::ustring(_("Default Fractions")) ), _numeric_ordinal ( Glib::ustring(_("Ordinal" )) ), - _numeric_slashed_zero ( Glib::ustring(_("Slashed Zero" )) ) + _numeric_slashed_zero ( Glib::ustring(_("Slashed Zero" )) ), + _ligatures_changed( false ), + _position_changed( false ), + _caps_changed( false ), + _numeric_changed( false ) { @@ -183,6 +187,7 @@ namespace Widget { void FontVariants::ligatures_callback() { // std::cout << "FontVariants::ligatures_callback()" << std::endl; + _ligatures_changed = true; } void @@ -193,6 +198,7 @@ namespace Widget { void FontVariants::position_callback() { // std::cout << "FontVariants::position_callback()" << std::endl; + _position_changed = true; } void @@ -203,6 +209,7 @@ namespace Widget { void FontVariants::caps_callback() { // std::cout << "FontVariants::caps_callback()" << std::endl; + _caps_changed = true; } void @@ -214,21 +221,61 @@ namespace Widget { void FontVariants::numeric_callback() { // std::cout << "FontVariants::numeric_callback()" << std::endl; + _numeric_changed = true; } + // Update GUI based on query. void - FontVariants::update( unsigned all, unsigned mix ) { + FontVariants::update( SPStyle const *query ) { // std::cout << "FontVariants::update" << std::endl; - _ligatures_common.set_active( all & SP_CSS_FONT_VARIANT_LIGATURES_COMMON ); - _ligatures_discretionary.set_active( all & SP_CSS_FONT_VARIANT_LIGATURES_DISCRETIONARY ); - _ligatures_historical.set_active( all & SP_CSS_FONT_VARIANT_LIGATURES_HISTORICAL ); - _ligatures_contextual.set_active( all & SP_CSS_FONT_VARIANT_LIGATURES_CONTEXTUAL ); + _ligatures_all = query->font_variant_ligatures.computed; + _ligatures_mix = query->font_variant_ligatures.value; + + _ligatures_common.set_active( _ligatures_all & SP_CSS_FONT_VARIANT_LIGATURES_COMMON ); + _ligatures_discretionary.set_active(_ligatures_all & SP_CSS_FONT_VARIANT_LIGATURES_DISCRETIONARY ); + _ligatures_historical.set_active( _ligatures_all & SP_CSS_FONT_VARIANT_LIGATURES_HISTORICAL ); + _ligatures_contextual.set_active( _ligatures_all & SP_CSS_FONT_VARIANT_LIGATURES_CONTEXTUAL ); + + _ligatures_common.set_inconsistent( _ligatures_mix & SP_CSS_FONT_VARIANT_LIGATURES_COMMON ); + _ligatures_discretionary.set_inconsistent( _ligatures_mix & SP_CSS_FONT_VARIANT_LIGATURES_DISCRETIONARY ); + _ligatures_historical.set_inconsistent( _ligatures_mix & SP_CSS_FONT_VARIANT_LIGATURES_HISTORICAL ); + _ligatures_contextual.set_inconsistent( _ligatures_mix & SP_CSS_FONT_VARIANT_LIGATURES_CONTEXTUAL ); + + _position_all = query->font_variant_position.computed; + _position_mix = query->font_variant_position.value; - _ligatures_common.set_inconsistent( mix & SP_CSS_FONT_VARIANT_LIGATURES_COMMON ); - _ligatures_discretionary.set_inconsistent( mix & SP_CSS_FONT_VARIANT_LIGATURES_DISCRETIONARY ); - _ligatures_historical.set_inconsistent( mix & SP_CSS_FONT_VARIANT_LIGATURES_HISTORICAL ); - _ligatures_contextual.set_inconsistent( mix & SP_CSS_FONT_VARIANT_LIGATURES_CONTEXTUAL ); + _position_normal.set_active( _position_all & SP_CSS_FONT_VARIANT_POSITION_NORMAL ); + _position_sub.set_active( _position_all & SP_CSS_FONT_VARIANT_POSITION_SUB ); + _position_super.set_active( _position_all & SP_CSS_FONT_VARIANT_POSITION_SUPER ); + + _position_normal.set_inconsistent( _position_mix & SP_CSS_FONT_VARIANT_POSITION_NORMAL ); + _position_sub.set_inconsistent( _position_mix & SP_CSS_FONT_VARIANT_POSITION_SUB ); + _position_super.set_inconsistent( _position_mix & SP_CSS_FONT_VARIANT_POSITION_SUPER ); + + unsigned _caps_all = query->font_variant_caps.computed; + unsigned _caps_mix = query->font_variant_caps.value; + + _caps_normal.set_active( _caps_all & SP_CSS_FONT_VARIANT_CAPS_NORMAL ); + _caps_small.set_active( _caps_all & SP_CSS_FONT_VARIANT_CAPS_SMALL ); + _caps_all_small.set_active( _caps_all & SP_CSS_FONT_VARIANT_CAPS_ALL_SMALL ); + _caps_petite.set_active( _caps_all & SP_CSS_FONT_VARIANT_CAPS_PETITE ); + _caps_all_petite.set_active( _caps_all & SP_CSS_FONT_VARIANT_CAPS_ALL_PETITE ); + _caps_unicase.set_active( _caps_all & SP_CSS_FONT_VARIANT_CAPS_UNICASE ); + _caps_titling.set_active( _caps_all & SP_CSS_FONT_VARIANT_CAPS_TITLING ); + + _caps_normal.set_inconsistent( _caps_mix & SP_CSS_FONT_VARIANT_CAPS_NORMAL ); + _caps_small.set_inconsistent( _caps_mix & SP_CSS_FONT_VARIANT_CAPS_SMALL ); + _caps_all_small.set_inconsistent( _caps_mix & SP_CSS_FONT_VARIANT_CAPS_ALL_SMALL ); + _caps_petite.set_inconsistent( _caps_mix & SP_CSS_FONT_VARIANT_CAPS_PETITE ); + _caps_all_petite.set_inconsistent( _caps_mix & SP_CSS_FONT_VARIANT_CAPS_ALL_PETITE ); + _caps_unicase.set_inconsistent( _caps_mix & SP_CSS_FONT_VARIANT_CAPS_UNICASE ); + _caps_titling.set_inconsistent( _caps_mix & SP_CSS_FONT_VARIANT_CAPS_TITLING ); + + _ligatures_changed = false; + _position_changed = false; + _caps_changed = false; + _numeric_changed = false; } void @@ -256,6 +303,60 @@ namespace Widget { css_string += "no-contextual "; sp_repr_css_set_property(css, "font-variant-ligatures", css_string.c_str() ); } + + // Position + { + unsigned position_new = SP_CSS_FONT_VARIANT_POSITION_NORMAL; + Glib::ustring css_string; + if( _position_normal.get_active() ) { + css_string = "normal"; + } else if( _position_sub.get_active() ) { + css_string = "sub"; + position_new = SP_CSS_FONT_VARIANT_POSITION_SUB; + } else if( _position_super.get_active() ) { + css_string = "super"; + position_new = SP_CSS_FONT_VARIANT_POSITION_SUPER; + } + + // 'if' may not be necessary... need to test. + if( (_position_all != position_new) || ((_position_mix != 0) && _position_changed) ) { + sp_repr_css_set_property(css, "font-variant-position", css_string.c_str() ); + } + } + + // Caps + { + unsigned caps_new = SP_CSS_FONT_VARIANT_CAPS_NORMAL; + Glib::ustring css_string; + if( _caps_normal.get_active() ) { + css_string = "normal"; + caps_new = SP_CSS_FONT_VARIANT_CAPS_NORMAL; + } else if( _caps_small.get_active() ) { + css_string = "small-caps"; + caps_new = SP_CSS_FONT_VARIANT_CAPS_SMALL; + } else if( _caps_all_small.get_active() ) { + css_string = "all-small-caps"; + caps_new = SP_CSS_FONT_VARIANT_CAPS_ALL_SMALL; + } else if( _caps_all_petite.get_active() ) { + css_string = "petite"; + caps_new = SP_CSS_FONT_VARIANT_CAPS_PETITE; + } else if( _caps_all_petite.get_active() ) { + css_string = "all-petite"; + caps_new = SP_CSS_FONT_VARIANT_CAPS_ALL_PETITE; + } else if( _caps_unicase.get_active() ) { + css_string = "unicase"; + caps_new = SP_CSS_FONT_VARIANT_CAPS_UNICASE; + } else if( _caps_titling.get_active() ) { + css_string = "titling"; + caps_new = SP_CSS_FONT_VARIANT_CAPS_TITLING; + } + + // May not be necessary... need to test. + //if( (_caps_all != caps_new) || ((_caps_mix != 0) && _caps_changed) ) { + sp_repr_css_set_property(css, "font-variant-caps", css_string.c_str() ); + //} + } + } } // namespace Widget diff --git a/src/ui/widget/font-variants.h b/src/ui/widget/font-variants.h index f58b80f34..04c05d3c6 100644 --- a/src/ui/widget/font-variants.h +++ b/src/ui/widget/font-variants.h @@ -18,6 +18,7 @@ class SPDesktop; class SPObject; +class SPStyle; class SPCSSAttr; namespace Inkscape { @@ -95,8 +96,24 @@ private: void numeric_init(); void numeric_callback(); + // To determine if we need to write out property (may not be necessary) + unsigned _ligatures_all; + unsigned _position_all; + unsigned _caps_all; + unsigned _numeric_all; + + unsigned _ligatures_mix; + unsigned _position_mix; + unsigned _caps_mix; + unsigned _numeric_mix; + + bool _ligatures_changed; + bool _position_changed; + bool _caps_changed; + bool _numeric_changed; + public: - void update( unsigned all, unsigned mix ); + void update( SPStyle const *query ); void fill_css( SPCSSAttr* css ); }; -- cgit v1.2.3 From defc4244715d81258f9d91123ee36dce353c0230 Mon Sep 17 00:00:00 2001 From: Tavmjong Bah Date: Sat, 16 May 2015 15:18:06 +0200 Subject: Potential fix for 384688 (A linked offset to a text object is malformed...) Basically flip a flag to use a slower but more accurate offset method. (bzr r14156) --- src/sp-offset.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/sp-offset.cpp b/src/sp-offset.cpp index 15d3821c7..e8aa09952 100644 --- a/src/sp-offset.cpp +++ b/src/sp-offset.cpp @@ -83,7 +83,7 @@ static void sp_offset_source_modified (SPObject *iSource, guint flags, SPItem *i // fast is not mathematically correct, because computing the offset of a single // cubic bezier patch is not trivial; in particular, there are problems with holes // reappearing in offset when the radius becomes too large -static bool use_slow_but_correct_offset_method=false; +static bool use_slow_but_correct_offset_method=true; SPOffset::SPOffset() : SPShape() { this->rad = 1.0; -- cgit v1.2.3 From 10b301c126354d9b1d4f0f220fec1d6eb75925ee Mon Sep 17 00:00:00 2001 From: Tavmjong Bah Date: Sun, 17 May 2015 10:33:41 +0200 Subject: Fix attributes unit test. (bzr r14158) --- src/attributes-test.h | 34 +++++++++++++++++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/attributes-test.h b/src/attributes-test.h index 7379e4e85..411304ec3 100644 --- a/src/attributes-test.h +++ b/src/attributes-test.h @@ -40,6 +40,10 @@ public: I've added these manually. SVG 2: white-space, shape-inside, shape-outside, shape-padding, shape-margin + SVG 2: text-decoration-fill, text-decoration-stroke + SVG 2: solid-color, solid-opacity + SVG 2: Hatches and Meshes + CSS 3: font-variant-xxx, font-feature-settings */ struct {char const *attr; bool supported;} const all_attrs[] = { {"attributeName", true}, @@ -124,11 +128,18 @@ struct {char const *attr; bool supported;} const all_attrs[] = { {"flood-color", true}, {"flood-opacity", true}, {"font-family", true}, + {"font-feature-settings", true}, {"font-size", true}, {"font-size-adjust", true}, {"font-stretch", true}, {"font-style", true}, {"font-variant", true}, + {"font-variant-ligatures", true}, + {"font-variant-position", true}, + {"font-variant-caps", true}, + {"font-variant-numeric", true}, + {"font-variant-east-asian", true}, + {"font-variant-alternates", true}, {"font-weight", true}, {"format", false}, {"from", true}, @@ -288,6 +299,8 @@ struct {char const *attr; bool supported;} const all_attrs[] = { {"text-decoration-line", true}, {"text-decoration-style", true}, {"text-decoration-color", true}, + {"text-decoration-fill", true}, + {"text-decoration-stroke", true}, {"text-indent", true}, {"text-rendering", true}, {"text-transform", true}, @@ -381,8 +394,11 @@ struct {char const *attr; bool supported;} const all_attrs[] = { {"inkscape:pageopacity", true}, {"inkscape:pageshadow", true}, {"inkscape:path-effect", true}, + // SPItem {"inkscape:transform-center-x", true}, {"inkscape:transform-center-y", true}, + {"inkscape:highlight-color", true}, + // Namedview {"inkscape:zoom", true}, {"inkscape:cx", true}, {"inkscape:cy", true}, @@ -392,6 +408,7 @@ struct {char const *attr; bool supported;} const all_attrs[] = { {"inkscape:window-y", true}, {"inkscape:window-maximized", true}, {"inkscape:current-layer", true}, + // Connector tool {"inkscape:connector-type", true}, {"inkscape:connection-start", true}, {"inkscape:connection-end", true}, @@ -401,10 +418,12 @@ struct {char const *attr; bool supported;} const all_attrs[] = { {"inkscape:connector-curvature", true}, {"inkscape:connector-avoid", true}, {"inkscape:connector-spacing", true}, + // Ellipse, Spiral, Star {"sodipodi:cx", true}, {"sodipodi:cy", true}, {"sodipodi:rx", true}, {"sodipodi:ry", true}, + // Box tool {"inkscape:perspectiveID", true}, {"inkscape:corner0", true}, {"inkscape:corner7", true}, @@ -414,6 +433,7 @@ struct {char const *attr; bool supported;} const all_attrs[] = { {"inkscape:vp_y", true}, {"inkscape:vp_z", true}, {"inkscape:persp3d-origin", true}, + // Star tool {"sodipodi:start", true}, {"sodipodi:end", true}, {"sodipodi:open", true}, @@ -446,9 +466,19 @@ struct {char const *attr; bool supported;} const all_attrs[] = { {"inkscape:layoutOptions", true}, {"osb:paint", true}, + /* SPSolidColor" */ + {"solid-color", true}, + {"solid-opacity", true}, + /* SPMeshPatch */ {"tensor", true}, + /* SPHash */ + {"hatchUnits", true}, + {"hatchContentUnits", true}, + {"hatchTransform", true}, + {"pitch", true}, + /* SPNamedView */ {"fit-margin-top", true}, {"fit-margin-left", true}, @@ -485,8 +515,10 @@ struct {char const *attr; bool supported;} const all_attrs[] = { {"pagecolor", true}, /* SPGuide */ - {"position", true} + {"position", true}, + /* SPTag */ + {"inkscape:expanded", true} }; -- cgit v1.2.3 From a1a3b4c11831f2a81201863556058fefcb741f4d Mon Sep 17 00:00:00 2001 From: Tomasz Boczkowski Date: Sun, 17 May 2015 12:10:12 +0200 Subject: fixed: color scales - extra row in RGB mode (bzr r14059.1.28) --- src/ui/widget/color-scales.cpp | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'src') diff --git a/src/ui/widget/color-scales.cpp b/src/ui/widget/color-scales.cpp index ead636406..b940acbc7 100644 --- a/src/ui/widget/color-scales.cpp +++ b/src/ui/widget/color-scales.cpp @@ -165,6 +165,11 @@ void ColorScales::_initUI(SPColorScalesMode mode) _s[i]->signal_value_changed.connect(sigc::mem_fun(this, &ColorScales::_sliderAnyChanged)); } + //Prevent 5th bar from being shown by PanelDialog::show_all_children + gtk_widget_set_no_show_all(_l[4], TRUE); + _s[4]->set_no_show_all(true); + gtk_widget_set_no_show_all(_b[4], TRUE); + /* Initial mode is none, so it works */ setMode(mode); } -- cgit v1.2.3 From 279bb517e59386cc3a5b299cafb78c0eb81cbedd Mon Sep 17 00:00:00 2001 From: Tomasz Boczkowski Date: Sun, 17 May 2015 13:33:31 +0200 Subject: fixed: color scales - updating color when switched from undefined (bzr r14059.1.29) --- src/ui/selected-color.cpp | 13 +++---- src/ui/widget/color-icc-selector.cpp | 19 ++++++++-- src/ui/widget/color-icc-selector.h | 2 + src/ui/widget/color-scales.cpp | 69 +++++++++++++++++++++------------- src/ui/widget/color-scales.h | 2 + src/ui/widget/color-wheel-selector.cpp | 57 +++++++++++++++++----------- src/ui/widget/color-wheel-selector.h | 4 +- 7 files changed, 107 insertions(+), 59 deletions(-) (limited to 'src') diff --git a/src/ui/selected-color.cpp b/src/ui/selected-color.cpp index 6573129d3..8c37ee7e0 100644 --- a/src/ui/selected-color.cpp +++ b/src/ui/selected-color.cpp @@ -75,7 +75,7 @@ guint32 SelectedColor::value() const void SelectedColor::setColorAlpha(SPColor const &color, gfloat alpha, bool emit_signal) { #ifdef DUMP_CHANGE_INFO - g_message("SelectedColor::setColorAlpha( this=%p, %f, %f, %f, %s, %f, %s) in %s", this, color.v.c[0], color.v.c[1], color.v.c[2], (color.icc?color.icc->colorProfile.c_str():""), alpha, (emit?"YES":"no"), FOO_NAME(_csel)); + g_message("SelectedColor::setColorAlpha( this=%p, %f, %f, %f, %s, %f, %s)", this, color.v.c[0], color.v.c[1], color.v.c[2], (color.icc?color.icc->colorProfile.c_str():""), alpha, (emit_signal?"YES":"no")); #endif g_return_if_fail( ( 0.0 <= alpha ) && ( alpha <= 1.0 ) ); @@ -84,11 +84,10 @@ void SelectedColor::setColorAlpha(SPColor const &color, gfloat alpha, bool emit_ } #ifdef DUMP_CHANGE_INFO - g_message("---- SelectedColor::setColorAlpha virgin:%s !close:%s alpha is:%s in %s", + g_message("---- SelectedColor::setColorAlpha virgin:%s !close:%s alpha is:%s", (_virgin?"YES":"no"), - (!color.isClose( _color, _epsilon )?"YES":"no"), - ((fabs((_alpha) - (alpha)) >= _epsilon )?"YES":"no"), - FOO_NAME(_csel) + (!color.isClose( _color, _EPSILON )?"YES":"no"), + ((fabs((_alpha) - (alpha)) >= _EPSILON )?"YES":"no") ); #endif @@ -113,8 +112,8 @@ void SelectedColor::setColorAlpha(SPColor const &color, gfloat alpha, bool emit_ #ifdef DUMP_CHANGE_INFO } else { - g_message("++++ SelectedColor::setColorAlpha color:%08x ==> _color:%08X isClose:%s in %s", color.toRGBA32(alpha), _color.toRGBA32(_alpha), - (color.isClose( _color, _epsilon )?"YES":"no"), FOO_NAME(_csel)); + g_message("++++ SelectedColor::setColorAlpha color:%08x ==> _color:%08X isClose:%s", color.toRGBA32(alpha), _color.toRGBA32(_alpha), + (color.isClose( _color, _EPSILON )?"YES":"no")); #endif } } diff --git a/src/ui/widget/color-icc-selector.cpp b/src/ui/widget/color-icc-selector.cpp index a7e75bfc5..2c00ba081 100644 --- a/src/ui/widget/color-icc-selector.cpp +++ b/src/ui/widget/color-icc-selector.cpp @@ -366,8 +366,6 @@ void ColorICCSelector::init() GtkWidget *t = GTK_WIDGET(gobj()); - gtk_widget_show(t); - _impl->_compUI.clear(); // Create components @@ -523,6 +521,8 @@ void ColorICCSelector::init() _impl->_slider->signal_grabbed.connect(sigc::mem_fun(_impl, &ColorICCSelectorImpl::_sliderGrabbed)); _impl->_slider->signal_released.connect(sigc::mem_fun(_impl, &ColorICCSelectorImpl::_sliderReleased)); _impl->_slider->signal_value_changed.connect(sigc::mem_fun(_impl, &ColorICCSelectorImpl::_sliderChanged)); + + gtk_widget_show(t); } void ColorICCSelectorImpl::_fixupHit(GtkWidget * /*src*/, gpointer data) @@ -696,6 +696,16 @@ void ColorICCSelectorImpl::_profilesChanged(std::string const &name) void ColorICCSelectorImpl::_profilesChanged(std::string const & /*name*/) {} #endif // defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) +void ColorICCSelector::on_show() +{ +#if GTK_CHECK_VERSION(3, 0, 0) + Gtk::Grid::on_show(); +#else + Gtk::Table::on_show(); +#endif + _colorChanged(); +} + // Helpers for setting color value void ColorICCSelector::_colorChanged() @@ -894,7 +904,10 @@ void ColorICCSelectorImpl::_updateSliders(gint ignore) cmsHTRANSFORM trans = _prof->getTransfToSRGB8(); if (trans) { cmsDoTransform(trans, scratch, _compUI[i]._map, 1024); - _compUI[i]._slider->setMap(_compUI[i]._map); + if (_compUI[i]._slider) + { + _compUI[i]._slider->setMap(_compUI[i]._map); + } } } } diff --git a/src/ui/widget/color-icc-selector.h b/src/ui/widget/color-icc-selector.h index 37201de3b..1bcb0a540 100644 --- a/src/ui/widget/color-icc-selector.h +++ b/src/ui/widget/color-icc-selector.h @@ -39,6 +39,8 @@ class ColorICCSelector virtual void init(); protected: + void on_show(); + virtual void _colorChanged(); void _recalcColor(gboolean changing); diff --git a/src/ui/widget/color-scales.cpp b/src/ui/widget/color-scales.cpp index b940acbc7..170f83887 100644 --- a/src/ui/widget/color-scales.cpp +++ b/src/ui/widget/color-scales.cpp @@ -205,34 +205,8 @@ void ColorScales::_recalcColor() _color.setColorAlpha(color, alpha); } -/* Helpers for setting color value */ -gfloat ColorScales::getScaled(const GtkAdjustment *a) -{ - gfloat val = gtk_adjustment_get_value(const_cast(a)) / - gtk_adjustment_get_upper(const_cast(a)); - return val; -} - -void ColorScales::setScaled(GtkAdjustment *a, gfloat v) -{ - gfloat val = v * gtk_adjustment_get_upper(a); - gtk_adjustment_set_value(a, val); -} - -void ColorScales::_setRangeLimit(gdouble upper) -{ - _rangeLimit = upper; - for (gint i = 0; i < static_cast(G_N_ELEMENTS(_a)); i++) { - gtk_adjustment_set_upper(_a[i], upper); - gtk_adjustment_changed(_a[i]); - } -} - -void ColorScales::_onColorChanged() +void ColorScales::_updateDisplay() { - if (!get_visible()) { - return; - } #ifdef DUMP_CHANGE_INFO g_message("ColorScales::_onColorChanged( this=%p, %f, %f, %f, %f)", this, _color.color().v.c[0], _color.color().v.c[1], _color.color().v.c[2], _color.alpha()); @@ -273,6 +247,47 @@ void ColorScales::_onColorChanged() _updating = FALSE; } +/* Helpers for setting color value */ +gfloat ColorScales::getScaled(const GtkAdjustment *a) +{ + gfloat val = gtk_adjustment_get_value(const_cast(a)) / + gtk_adjustment_get_upper(const_cast(a)); + return val; +} + +void ColorScales::setScaled(GtkAdjustment *a, gfloat v) +{ + gfloat val = v * gtk_adjustment_get_upper(a); + gtk_adjustment_set_value(a, val); +} + +void ColorScales::_setRangeLimit(gdouble upper) +{ + _rangeLimit = upper; + for (gint i = 0; i < static_cast(G_N_ELEMENTS(_a)); i++) { + gtk_adjustment_set_upper(_a[i], upper); + gtk_adjustment_changed(_a[i]); + } +} + +void ColorScales::_onColorChanged() +{ + if (!get_visible()) { + return; + } + _updateDisplay(); +} + +void ColorScales::on_show() +{ +#if GTK_CHECK_VERSION(3, 0, 0) + Gtk::Grid::on_show(); +#else + Gtk::Table::on_show(); +#endif + _updateDisplay(); +} + void ColorScales::_getRgbaFloatv(gfloat *rgba) { g_return_if_fail(rgba != NULL); diff --git a/src/ui/widget/color-scales.h b/src/ui/widget/color-scales.h index 025f92e2d..aeacfbcc1 100644 --- a/src/ui/widget/color-scales.h +++ b/src/ui/widget/color-scales.h @@ -49,6 +49,7 @@ public: protected: void _onColorChanged(); + void on_show(); static void _adjustmentAnyChanged(GtkAdjustment *adjustment, ColorScales *cs); void _sliderAnyGrabbed(); @@ -61,6 +62,7 @@ protected: guint32 _getRgba32(); void _updateSliders(guint channels); void _recalcColor(); + void _updateDisplay(); void _setRangeLimit(gdouble upper); diff --git a/src/ui/widget/color-wheel-selector.cpp b/src/ui/widget/color-wheel-selector.cpp index 8c6402d90..ed3400bb5 100644 --- a/src/ui/widget/color-wheel-selector.cpp +++ b/src/ui/widget/color-wheel-selector.cpp @@ -170,30 +170,19 @@ void ColorWheelSelector::_initUI() g_signal_connect(G_OBJECT(_wheel), "changed", G_CALLBACK(_wheelChanged), this); } -void ColorWheelSelector::_colorChanged() +void ColorWheelSelector::on_show() { -#ifdef DUMP_CHANGE_INFO - g_message("ColorWheelSelector::_colorChanged( this=%p, %f, %f, %f, %f)", this, _color.color().v.c[0], - _color.color().v.c[1], _color.color().v.c[2], alpha); +#if GTK_CHECK_VERSION(3, 0, 0) + Gtk::Grid::on_show(); +#else + Gtk::Table::on_show(); #endif + _updateDisplay(); +} - bool oldval = _updating; - _updating = true; - { - float hsv[3] = { 0, 0, 0 }; - sp_color_rgb_to_hsv_floatv(hsv, _color.color().v.c[0], _color.color().v.c[1], _color.color().v.c[2]); - gimp_color_wheel_set_color(GIMP_COLOR_WHEEL(_wheel), hsv[0], hsv[1], hsv[2]); - } - - guint32 start = _color.color().toRGBA32(0x00); - guint32 mid = _color.color().toRGBA32(0x7f); - guint32 end = _color.color().toRGBA32(0xff); - - _slider->setColors(start, mid, end); - - ColorScales::setScaled(_alpha_adjustment->gobj(), _color.alpha()); - - _updating = oldval; +void ColorWheelSelector::_colorChanged() +{ + _updateDisplay(); } void ColorWheelSelector::_adjustmentChanged() @@ -264,6 +253,32 @@ void ColorWheelSelector::_wheelChanged(GimpColorWheel *wheel, ColorWheelSelector wheelSelector->_color.setColor(color); } +void ColorWheelSelector::_updateDisplay() +{ +#ifdef DUMP_CHANGE_INFO + g_message("ColorWheelSelector::_colorChanged( this=%p, %f, %f, %f, %f)", this, _color.color().v.c[0], + _color.color().v.c[1], _color.color().v.c[2], alpha); +#endif + + bool oldval = _updating; + _updating = true; + { + float hsv[3] = { 0, 0, 0 }; + sp_color_rgb_to_hsv_floatv(hsv, _color.color().v.c[0], _color.color().v.c[1], _color.color().v.c[2]); + gimp_color_wheel_set_color(GIMP_COLOR_WHEEL(_wheel), hsv[0], hsv[1], hsv[2]); + } + + guint32 start = _color.color().toRGBA32(0x00); + guint32 mid = _color.color().toRGBA32(0x7f); + guint32 end = _color.color().toRGBA32(0xff); + + _slider->setColors(start, mid, end); + + ColorScales::setScaled(_alpha_adjustment->gobj(), _color.alpha()); + + _updating = oldval; +} + Gtk::Widget *ColorWheelSelectorFactory::createWidget(Inkscape::UI::SelectedColor &color) const { diff --git a/src/ui/widget/color-wheel-selector.h b/src/ui/widget/color-wheel-selector.h index f97f70f6a..5711d417c 100644 --- a/src/ui/widget/color-wheel-selector.h +++ b/src/ui/widget/color-wheel-selector.h @@ -48,6 +48,8 @@ public: protected: void _initUI(); + void on_show(); + void _colorChanged(); void _adjustmentChanged(); void _sliderGrabbed(); @@ -55,7 +57,7 @@ protected: void _sliderChanged(); static void _wheelChanged(GimpColorWheel *wheel, ColorWheelSelector *cs); - void _recalcColor(gboolean changing); + void _updateDisplay(); SelectedColor &_color; bool _updating; -- cgit v1.2.3 From e6770f0bb8829e60c6a8babddeb7104dcc50fea8 Mon Sep 17 00:00:00 2001 From: Tomasz Boczkowski Date: Sun, 17 May 2015 13:43:24 +0200 Subject: fixed: color icc selector - extra rows on startup (bzr r14059.1.30) --- src/ui/widget/color-icc-selector.cpp | 3 +++ 1 file changed, 3 insertions(+) (limited to 'src') diff --git a/src/ui/widget/color-icc-selector.cpp b/src/ui/widget/color-icc-selector.cpp index 2c00ba081..1c31ae33a 100644 --- a/src/ui/widget/color-icc-selector.cpp +++ b/src/ui/widget/color-icc-selector.cpp @@ -433,6 +433,7 @@ void ColorICCSelector::init() _impl->_compUI[i]._label = gtk_label_new_with_mnemonic(labelStr.c_str()); gtk_misc_set_alignment(GTK_MISC(_impl->_compUI[i]._label), 1.0, 0.5); gtk_widget_show(_impl->_compUI[i]._label); + gtk_widget_set_no_show_all(_impl->_compUI[i]._label, TRUE); attachToGridOrTable(t, _impl->_compUI[i]._label, 0, row, 1, 1); @@ -452,6 +453,7 @@ void ColorICCSelector::init() _impl->_compUI[i]._slider->set_tooltip_text("."); #endif // defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) _impl->_compUI[i]._slider->show(); + _impl->_compUI[i]._slider->set_no_show_all(); attachToGridOrTable(t, _impl->_compUI[i]._slider->gobj(), 1, row, 1, 1, true); @@ -464,6 +466,7 @@ void ColorICCSelector::init() sp_dialog_defocus_on_enter(_impl->_compUI[i]._btn); gtk_label_set_mnemonic_widget(GTK_LABEL(_impl->_compUI[i]._label), _impl->_compUI[i]._btn); gtk_widget_show(_impl->_compUI[i]._btn); + gtk_widget_set_no_show_all(_impl->_compUI[i]._btn, TRUE); attachToGridOrTable(t, _impl->_compUI[i]._btn, 2, row, 1, 1, false, true); -- cgit v1.2.3 From b59c753a013f60192a6d4528fbd4b011d69b313f Mon Sep 17 00:00:00 2001 From: Alvin Penner Date: Mon, 18 May 2015 11:03:15 -0400 Subject: sbasis-to-bezier. avoid ill-conditioned behavior for anti-symmetric case. (Bug 1428267) Fixed bugs: - https://launchpad.net/bugs/1428267 (bzr r14161) --- src/2geom/sbasis-to-bezier.cpp | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'src') diff --git a/src/2geom/sbasis-to-bezier.cpp b/src/2geom/sbasis-to-bezier.cpp index a2e4253d2..98c400197 100644 --- a/src/2geom/sbasis-to-bezier.cpp +++ b/src/2geom/sbasis-to-bezier.cpp @@ -245,6 +245,8 @@ void sbasis_to_cubic_bezier (std::vector & bz, D2 const& sb) midx = 8*midx - 4*bz[0][X] - 4*bz[3][X]; // re-define relative to center midy = 8*midy - 4*bz[0][Y] - 4*bz[3][Y]; + if ((std::abs(midx) < EPSILON) && (std::abs(midy) < EPSILON)) + return; if ((std::abs(xprime[0]) < EPSILON) && (std::abs(yprime[0]) < EPSILON) && ((std::abs(xprime[1]) > EPSILON) || (std::abs(yprime[1]) > EPSILON))) { // degenerate handle at 0 : use distance of closest approach @@ -264,6 +266,10 @@ void sbasis_to_cubic_bezier (std::vector & bz, D2 const& sb) dely[1] = 0; } else if (std::abs(xprime[1]*yprime[0] - yprime[1]*xprime[0]) > // general case : fit mid fxn value 0.002 * std::abs(xprime[1]*xprime[0] + yprime[1]*yprime[0])) { // approx. 0.1 degree of angle + double test1 = (bz[1][Y] - bz[0][Y])*(bz[3][X] - bz[0][X]) - (bz[1][X] - bz[0][X])*(bz[3][Y] - bz[0][Y]); + double test2 = (bz[2][Y] - bz[0][Y])*(bz[3][X] - bz[0][X]) - (bz[2][X] - bz[0][X])*(bz[3][Y] - bz[0][Y]); + if (test1*test2 < 0) // reject anti-symmetric case, LP Bug 1428267 & Bug 1428683 + return; denom = xprime[1]*yprime[0] - yprime[1]*xprime[0]; for (int i = 0; i < 2; ++i) { numer = xprime[1 - i]*midy - yprime[1 - i]*midx; -- cgit v1.2.3 From 7c7e740dd76054367ceae7f545ac27f0d7cdc7f0 Mon Sep 17 00:00:00 2001 From: Tavmjong Bah Date: Mon, 18 May 2015 21:50:54 +0200 Subject: Enable setting of 'font-variant-ligatures' (rendering waits on new Pango library). (bzr r14162) --- src/desktop-style.cpp | 30 ++++++----- src/style-enums.h | 18 +++---- src/style-internal.cpp | 107 ++++++++++++++++++++++++++++++++++++++++ src/style-internal.h | 26 +++++++++- src/style-test.h | 17 +++++-- src/style.cpp | 2 +- src/style.h | 2 +- src/ui/widget/font-variants.cpp | 87 ++++++++++++++++++++++++++++++-- 8 files changed, 256 insertions(+), 33 deletions(-) (limited to 'src') diff --git a/src/desktop-style.cpp b/src/desktop-style.cpp index 3bb0ce71a..d2109c03c 100644 --- a/src/desktop-style.cpp +++ b/src/desktop-style.cpp @@ -1178,17 +1178,20 @@ objects_query_fontvariants (const std::vector &objects, SPStyle *style_ SPILigatures* ligatures_res = &(style_res->font_variant_ligatures); SPIEnum* position_res = &(style_res->font_variant_position); SPIEnum* caps_res = &(style_res->font_variant_caps); - + SPINumeric* numeric_res = &(style_res->font_variant_numeric); + // Stores 'and' of all values ligatures_res->computed = SP_CSS_FONT_VARIANT_LIGATURES_NORMAL; position_res->computed = SP_CSS_FONT_VARIANT_POSITION_NORMAL; caps_res->computed = SP_CSS_FONT_VARIANT_CAPS_NORMAL; + numeric_res->computed = SP_CSS_FONT_VARIANT_NUMERIC_NORMAL; // Stores only differences ligatures_res->value = 0; position_res->value = 0; caps_res->value = 0; - + numeric_res->value = 0; + for (std::vector::const_iterator i = objects.begin(); i != objects.end(); i++) { SPObject *obj = *i; @@ -1204,8 +1207,9 @@ objects_query_fontvariants (const std::vector &objects, SPStyle *style_ texts ++; SPILigatures* ligatures_in = &(style->font_variant_ligatures); - SPIEnum* position_in = &(style->font_variant_position); - SPIEnum* caps_in = &(style->font_variant_caps); + SPIEnum* position_in = &(style->font_variant_position); + SPIEnum* caps_in = &(style->font_variant_caps); + SPINumeric* numeric_in = &(style->font_variant_numeric); // computed stores which bits are on/off, only valid if same between all selected objects. // value stores which bits are different between objects. This is a bit of an abuse of // the values but then we don't need to add new variables to class. @@ -1219,21 +1223,23 @@ objects_query_fontvariants (const std::vector &objects, SPStyle *style_ caps_res->value |= (caps_res->computed ^ caps_in->computed ); caps_res->computed &= caps_in->computed; + numeric_res->value |= (numeric_res->computed ^ numeric_in->computed ); + numeric_res->computed &= numeric_in->computed; + } else { ligatures_res->computed = ligatures_in->computed; - position_res->computed = position_in->computed; - caps_res->computed = caps_in->computed; + position_res->computed = position_in->computed; + caps_res->computed = caps_in->computed; + numeric_res->computed = numeric_in->computed; } set = true; } - bool different = (style_res->font_variant_ligatures.value != - style_res->font_variant_ligatures.computed || - style_res->font_variant_position.value != - style_res->font_variant_position.computed || - style_res->font_variant_caps.value != - style_res->font_variant_caps.computed ); + bool different = (style_res->font_variant_ligatures.value != 0 || + style_res->font_variant_position.value != 0 || + style_res->font_variant_caps.value != 0 || + style_res->font_variant_numeric.value != 0 ); if (texts == 0 || !set) return QUERY_STYLE_NOTHING; diff --git a/src/style-enums.h b/src/style-enums.h index dca7e246d..29b8e2130 100644 --- a/src/style-enums.h +++ b/src/style-enums.h @@ -104,15 +104,15 @@ enum SPCSSFontVariantCaps { // Can select more than one (see spec) enum SPCSSFontVariantNumeric { - SP_CSS_FONT_VARIANT_NUMERIC_NORMAL, - SP_CSS_FONT_VARIANT_NUMERIC_LINING_NUMS, - SP_CSS_FONT_VARIANT_NUMERIC_OLDSTYLE_NUMS, - SP_CSS_FONT_VARIANT_NUMERIC_PROPORTIONAL_NUMS, - SP_CSS_FONT_VARIANT_NUMERIC_TABULAR_NUMS, - SP_CSS_FONT_VARIANT_NUMERIC_DIAGONAL_FRACTIONS, - SP_CSS_FONT_VARIANT_NUMERIC_STACKED_FRACTIONS, - SP_CSS_FONT_VARIANT_NUMERIC_ORDINAL, - SP_CSS_FONT_VARIANT_NUMERIC_SLASHED_ZERO + SP_CSS_FONT_VARIANT_NUMERIC_NORMAL = 0, + SP_CSS_FONT_VARIANT_NUMERIC_LINING_NUMS = 1, + SP_CSS_FONT_VARIANT_NUMERIC_OLDSTYLE_NUMS = 2, + SP_CSS_FONT_VARIANT_NUMERIC_PROPORTIONAL_NUMS = 4, + SP_CSS_FONT_VARIANT_NUMERIC_TABULAR_NUMS = 8, + SP_CSS_FONT_VARIANT_NUMERIC_DIAGONAL_FRACTIONS = 16, + SP_CSS_FONT_VARIANT_NUMERIC_STACKED_FRACTIONS = 32, + SP_CSS_FONT_VARIANT_NUMERIC_ORDINAL = 64, + SP_CSS_FONT_VARIANT_NUMERIC_SLASHED_ZERO = 128 }; enum SPCSSFontVariantAlternates { diff --git a/src/style-internal.cpp b/src/style-internal.cpp index 3b76e5ab1..0e53da0d3 100644 --- a/src/style-internal.cpp +++ b/src/style-internal.cpp @@ -795,6 +795,113 @@ SPILigatures::write( guint const flags, SPIBase const *const base) const { return Glib::ustring(""); } + +// SPINumeric ----------------------------------------------------- +// Used for 'font-variant-numeric' +void +SPINumeric::read( gchar const *str ) { + + if( !str ) return; + + value = SP_CSS_FONT_VARIANT_NUMERIC_NORMAL; + if( !strcmp(str, "inherit") ) { + set = true; + inherit = true; + } else if (!strcmp(str, "normal" )) { + // Defaults for TrueType + inherit = false; + set = true; + } else { + // We need to parse in order + std::vector tokens = Glib::Regex::split_simple("\\s+", str ); + for( unsigned i = 0; i < tokens.size(); ++i ) { + for (unsigned j = 0; enums[j].key; ++j ) { + if (tokens[i].compare( enums[j].key ) == 0 ) { + set = true; + inherit = false; + value |= enums[j].value; + + // Must switch off incompatible value + switch (enums[j].value ) { + case SP_CSS_FONT_VARIANT_NUMERIC_LINING_NUMS: + value &= ~SP_CSS_FONT_VARIANT_NUMERIC_OLDSTYLE_NUMS; + break; + case SP_CSS_FONT_VARIANT_NUMERIC_OLDSTYLE_NUMS: + value &= ~SP_CSS_FONT_VARIANT_NUMERIC_LINING_NUMS; + break; + + case SP_CSS_FONT_VARIANT_NUMERIC_PROPORTIONAL_NUMS: + value &= ~SP_CSS_FONT_VARIANT_NUMERIC_TABULAR_NUMS; + break; + case SP_CSS_FONT_VARIANT_NUMERIC_TABULAR_NUMS: + value &= ~SP_CSS_FONT_VARIANT_NUMERIC_PROPORTIONAL_NUMS; + break; + + case SP_CSS_FONT_VARIANT_NUMERIC_DIAGONAL_FRACTIONS: + value &= ~SP_CSS_FONT_VARIANT_NUMERIC_STACKED_FRACTIONS; + break; + case SP_CSS_FONT_VARIANT_NUMERIC_STACKED_FRACTIONS: + value &= ~SP_CSS_FONT_VARIANT_NUMERIC_DIAGONAL_FRACTIONS; + break; + + case SP_CSS_FONT_VARIANT_NUMERIC_NORMAL: + case SP_CSS_FONT_VARIANT_NUMERIC_ORDINAL: + case SP_CSS_FONT_VARIANT_NUMERIC_SLASHED_ZERO: + // Do nothing + break; + + default: + std::cerr << "SPINumeric::read(): Invalid value." << std::endl; + break; + } + } + } + } + } + computed = value; +} + +const Glib::ustring +SPINumeric::write( guint const flags, SPIBase const *const base) const { + + SPIEnum const *const my_base = dynamic_cast(base); + if ( (flags & SP_STYLE_FLAG_ALWAYS) || + ((flags & SP_STYLE_FLAG_IFSET) && this->set) || + ((flags & SP_STYLE_FLAG_IFDIFF) && this->set + && (!my_base->set || this != my_base ))) + { + if (this->inherit) { + return (name + ":inherit;"); + } + if (value == SP_CSS_FONT_VARIANT_NUMERIC_NORMAL ) { + return (name + ":normal;"); + } + + Glib::ustring return_string = name + ":"; + if ( value & SP_CSS_FONT_VARIANT_NUMERIC_LINING_NUMS ) + return_string += "lining-nums "; + if ( value & SP_CSS_FONT_VARIANT_NUMERIC_OLDSTYLE_NUMS ) + return_string += "oldstyle-nums "; + if ( value & SP_CSS_FONT_VARIANT_NUMERIC_PROPORTIONAL_NUMS ) + return_string += "proportional-nums "; + if ( value & SP_CSS_FONT_VARIANT_NUMERIC_TABULAR_NUMS ) + return_string += "tabular-nums "; + if ( value & SP_CSS_FONT_VARIANT_NUMERIC_DIAGONAL_FRACTIONS ) + return_string += "diagonal-fractions "; + if ( value & SP_CSS_FONT_VARIANT_NUMERIC_STACKED_FRACTIONS ) + return_string += "stacked-fractions "; + if ( value & SP_CSS_FONT_VARIANT_NUMERIC_ORDINAL ) + return_string += "ordinal "; + if ( value & SP_CSS_FONT_VARIANT_NUMERIC_SLASHED_ZERO ) + return_string += "slashed-zero "; + return_string.erase( return_string.size() - 1 ); + return_string += ";"; + return return_string; + } + return Glib::ustring(""); +} + + // SPIString ------------------------------------------------------------ void diff --git a/src/style-internal.h b/src/style-internal.h index ea966866a..bd2a92c8c 100644 --- a/src/style-internal.h +++ b/src/style-internal.h @@ -546,8 +546,7 @@ public: {} SPILigatures( Glib::ustring const &name, SPStyleEnum const *enums) : - SPIEnum( name, enums, - SP_CSS_FONT_VARIANT_LIGATURES_COMMON | SP_CSS_FONT_VARIANT_LIGATURES_CONTEXTUAL) + SPIEnum( name, enums, SP_CSS_FONT_VARIANT_NORMAL ) {} virtual ~SPILigatures() @@ -559,6 +558,29 @@ public: }; +/// SPIEnum w/ extra bits. The 'font-variants-numeric' property is a complete mess that needs +/// special handling. Multiple key words can be specified, some exclusive of others. +class SPINumeric : public SPIEnum +{ + +public: + SPINumeric() : + SPIEnum( "anonymous_enumnumeric", NULL ) + {} + + SPINumeric( Glib::ustring const &name, SPStyleEnum const *enums) : + SPIEnum( name, enums, SP_CSS_FONT_VARIANT_NUMERIC_NORMAL ) + {} + + virtual ~SPINumeric() + {} + + virtual void read( gchar const *str ); + virtual const Glib::ustring write( guint const flags = SP_STYLE_FLAG_IFSET, + SPIBase const *const base = NULL ) const; +}; + + /// String type internal to SPStyle. // Used for 'marker', ..., 'font', 'font-family', 'inkscape-font-specification' class SPIString : public SPIBase diff --git a/src/style-test.h b/src/style-test.h index 1d821312b..c6bb665e0 100644 --- a/src/style-test.h +++ b/src/style-test.h @@ -109,13 +109,13 @@ public: TestCase("font: 12pt/15pt sans-serif", "font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:16px;line-height:15pt;font-family:sans-serif"), TestCase("font: 80% sans-serif", - "font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:80.00000119%;line-height:normal;font-family:sans-serif"), + "font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:80%;line-height:normal;font-family:sans-serif"), TestCase("font: x-large/110% 'new century schoolbook', serif", - "font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:x-large;line-height:110.00000238%;font-family:\'new century schoolbook\', serif"), + "font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:x-large;line-height:110%;font-family:\'new century schoolbook\', serif"), TestCase("font: bold italic large Palatino, serif", "font-style:italic;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:large;line-height:normal;font-family:Palatino, serif"), TestCase("font: normal small-caps 120%/120% fantasy", - "font-style:normal;font-variant:small-caps;font-weight:normal;font-stretch:normal;font-size:120.00000477%;line-height:120.00000477%;font-family:fantasy"), + "font-style:normal;font-variant:small-caps;font-weight:normal;font-stretch:normal;font-size:120%;line-height:120%;font-family:fantasy"), TestCase("font: condensed oblique 12pt 'Helvetica Neue', serif;", "font-style:oblique;font-variant:normal;font-weight:normal;font-stretch:condensed;font-size:16px;line-height:normal;font-family:\'Helvetica Neue\', serif"), @@ -153,6 +153,17 @@ public: TestCase("font-variant-caps:normal"), TestCase("font-variant-caps:small-caps"), TestCase("font-variant-caps:all-small-caps"), + TestCase("font-variant-numeric:normal"), + TestCase("font-variant-numeric:lining-nums"), + TestCase("font-variant-numeric:oldstyle-nums"), + TestCase("font-variant-numeric:proportional-nums"), + TestCase("font-variant-numeric:tabular-nums"), + TestCase("font-variant-numeric:diagonal-fractions"), + TestCase("font-variant-numeric:stacked-fractions"), + TestCase("font-variant-numeric:ordinal"), + TestCase("font-variant-numeric:slashed-zero"), + TestCase("font-variant-numeric:tabular-nums slashed-zero"), + TestCase("font-variant-numeric:tabular-nums proportional-nums", "font-variant-numeric:proportional-nums"), // Should be moved down TestCase("text-indent:12em"), // SPILength? diff --git a/src/style.cpp b/src/style.cpp index 4d93841eb..b218f4e4d 100644 --- a/src/style.cpp +++ b/src/style.cpp @@ -122,7 +122,7 @@ SPStyle::SPStyle(SPDocument *document_in, SPObject *object_in) : font_variant_ligatures( "font-variant-ligatures", enum_font_variant_ligatures ), font_variant_position( "font-variant-position", enum_font_variant_position, SP_CSS_FONT_VARIANT_POSITION_NORMAL ), font_variant_caps( "font-variant-caps", enum_font_variant_caps, SP_CSS_FONT_VARIANT_CAPS_NORMAL ), - font_variant_numeric( "font-variant-numeric", enum_font_variant_numeric, SP_CSS_FONT_VARIANT_NUMERIC_NORMAL ), + font_variant_numeric( "font-variant-numeric", enum_font_variant_numeric ), font_variant_alternates("font-variant-alternates", enum_font_variant_alternates, SP_CSS_FONT_VARIANT_ALTERNATES_NORMAL ), font_variant_east_asian("font-variant-east_asian", enum_font_variant_east_asian, SP_CSS_FONT_VARIANT_EAST_ASIAN_NORMAL ), font_feature_settings( "font-feature-settings", "normal" ), diff --git a/src/style.h b/src/style.h index f82fad9b0..8e22b3121 100644 --- a/src/style.h +++ b/src/style.h @@ -119,7 +119,7 @@ public: /** Font variant caps (small caps) */ SPIEnum font_variant_caps; /** Font variant numeric (numerical formatting) */ - SPIEnum font_variant_numeric; + SPINumeric font_variant_numeric; /** Font variant alternates (alternates/swatches) */ SPIEnum font_variant_alternates; /** Font variant East Asian */ diff --git a/src/ui/widget/font-variants.cpp b/src/ui/widget/font-variants.cpp index 8ca926d8f..56c24ea6f 100644 --- a/src/ui/widget/font-variants.cpp +++ b/src/ui/widget/font-variants.cpp @@ -214,8 +214,7 @@ namespace Widget { void FontVariants::numeric_init() { - std::cout << "FontVariants::numeric_init()" << std::endl; - // _numeric_tabular.set_inconsistent(); + // std::cout << "FontVariants::numeric_init()" << std::endl; } void @@ -227,7 +226,6 @@ namespace Widget { // Update GUI based on query. void FontVariants::update( SPStyle const *query ) { - // std::cout << "FontVariants::update" << std::endl; _ligatures_all = query->font_variant_ligatures.computed; _ligatures_mix = query->font_variant_ligatures.value; @@ -253,8 +251,8 @@ namespace Widget { _position_sub.set_inconsistent( _position_mix & SP_CSS_FONT_VARIANT_POSITION_SUB ); _position_super.set_inconsistent( _position_mix & SP_CSS_FONT_VARIANT_POSITION_SUPER ); - unsigned _caps_all = query->font_variant_caps.computed; - unsigned _caps_mix = query->font_variant_caps.value; + _caps_all = query->font_variant_caps.computed; + _caps_mix = query->font_variant_caps.value; _caps_normal.set_active( _caps_all & SP_CSS_FONT_VARIANT_CAPS_NORMAL ); _caps_small.set_active( _caps_all & SP_CSS_FONT_VARIANT_CAPS_SMALL ); @@ -272,6 +270,46 @@ namespace Widget { _caps_unicase.set_inconsistent( _caps_mix & SP_CSS_FONT_VARIANT_CAPS_UNICASE ); _caps_titling.set_inconsistent( _caps_mix & SP_CSS_FONT_VARIANT_CAPS_TITLING ); + _numeric_all = query->font_variant_numeric.computed; + _numeric_mix = query->font_variant_numeric.value; + + if (_numeric_all & SP_CSS_FONT_VARIANT_NUMERIC_LINING_NUMS) { + _numeric_lining.set_active(); + } else if (_numeric_all & SP_CSS_FONT_VARIANT_NUMERIC_OLDSTYLE_NUMS) { + _numeric_old_style.set_active(); + } else { + _numeric_default_style.set_active(); + } + + if (_numeric_all & SP_CSS_FONT_VARIANT_NUMERIC_PROPORTIONAL_NUMS) { + _numeric_proportional.set_active(); + } else if (_numeric_all & SP_CSS_FONT_VARIANT_NUMERIC_TABULAR_NUMS) { + _numeric_tabular.set_active(); + } else { + _numeric_default_width.set_active(); + } + + if (_numeric_all & SP_CSS_FONT_VARIANT_NUMERIC_DIAGONAL_FRACTIONS) { + _numeric_diagonal.set_active(); + } else if (_numeric_all & SP_CSS_FONT_VARIANT_NUMERIC_STACKED_FRACTIONS) { + _numeric_stacked.set_active(); + } else { + _numeric_default_fractions.set_active(); + } + + _numeric_ordinal.set_active( _numeric_all & SP_CSS_FONT_VARIANT_NUMERIC_ORDINAL ); + _numeric_slashed_zero.set_active( _numeric_all & SP_CSS_FONT_VARIANT_NUMERIC_SLASHED_ZERO ); + + + _numeric_lining.set_inconsistent( _numeric_mix & SP_CSS_FONT_VARIANT_NUMERIC_LINING_NUMS ); + _numeric_old_style.set_inconsistent( _numeric_mix & SP_CSS_FONT_VARIANT_NUMERIC_OLDSTYLE_NUMS ); + _numeric_proportional.set_inconsistent( _numeric_mix & SP_CSS_FONT_VARIANT_NUMERIC_PROPORTIONAL_NUMS ); + _numeric_tabular.set_inconsistent( _numeric_mix & SP_CSS_FONT_VARIANT_NUMERIC_TABULAR_NUMS ); + _numeric_diagonal.set_inconsistent( _numeric_mix & SP_CSS_FONT_VARIANT_NUMERIC_DIAGONAL_FRACTIONS ); + _numeric_stacked.set_inconsistent( _numeric_mix & SP_CSS_FONT_VARIANT_NUMERIC_STACKED_FRACTIONS ); + _numeric_ordinal.set_inconsistent( _numeric_mix & SP_CSS_FONT_VARIANT_NUMERIC_ORDINAL ); + _numeric_slashed_zero.set_inconsistent( _numeric_mix & SP_CSS_FONT_VARIANT_NUMERIC_SLASHED_ZERO ); + _ligatures_changed = false; _position_changed = false; _caps_changed = false; @@ -357,6 +395,45 @@ namespace Widget { //} } + // Numeric + bool default_style = _numeric_default_style.get_active(); + bool lining = _numeric_lining.get_active(); + bool old_style = _numeric_old_style.get_active(); + + bool default_width = _numeric_default_width.get_active(); + bool proportional = _numeric_proportional.get_active(); + bool tabular = _numeric_tabular.get_active(); + + bool default_fractions = _numeric_default_fractions.get_active(); + bool diagonal = _numeric_diagonal.get_active(); + bool stacked = _numeric_stacked.get_active(); + + bool ordinal = _numeric_ordinal.get_active(); + bool slashed_zero = _numeric_slashed_zero.get_active(); + + if (default_style & default_width & default_fractions & !ordinal & !slashed_zero) { + sp_repr_css_set_property(css, "font-variant-numeric", "normal"); + } else { + Glib::ustring css_string; + if ( lining ) + css_string += "lining-nums "; + if ( old_style ) + css_string += "oldstyle-nums "; + if ( proportional ) + css_string += "proportional-nums "; + if ( tabular ) + css_string += "tabular-nums "; + if ( diagonal ) + css_string += "diagonal-fractions "; + if ( stacked ) + css_string += "stacked-fractions "; + if ( ordinal ) + css_string += "ordinal "; + if ( slashed_zero ) + css_string += "slashed-zero "; + sp_repr_css_set_property(css, "font-variant-numeric", css_string.c_str() ); + } + } } // namespace Widget -- cgit v1.2.3 From 421d13903f4ae30d1b536788e9b48b69398bf139 Mon Sep 17 00:00:00 2001 From: Tavmjong Bah Date: Wed, 20 May 2015 10:53:59 +0200 Subject: Font-variants widget: Enable 'Apply' button. Add more tooltips. (bzr r14163) --- src/ui/dialog/text-edit.cpp | 15 ++++++ src/ui/dialog/text-edit.h | 13 +++++ src/ui/widget/font-variants.cpp | 114 ++++++++++++++++++++++++++++++---------- src/ui/widget/font-variants.h | 19 ++++++- 4 files changed, 132 insertions(+), 29 deletions(-) (limited to 'src') diff --git a/src/ui/dialog/text-edit.cpp b/src/ui/dialog/text-edit.cpp index 4fd227f01..1a696c820 100644 --- a/src/ui/dialog/text-edit.cpp +++ b/src/ui/dialog/text-edit.cpp @@ -218,6 +218,7 @@ TextEdit::TextEdit() setasdefault_button.signal_clicked().connect(sigc::mem_fun(*this, &TextEdit::onSetDefault)); apply_button.signal_clicked().connect(sigc::mem_fun(*this, &TextEdit::onApply)); close_button.signal_clicked().connect(sigc::bind(_signal_response.make_slot(), GTK_RESPONSE_CLOSE)); + fontVariantChangedConn = vari_vbox.connectChanged(sigc::bind(sigc::ptr_fun(&onFontVariantChange), this)); desktopChangeConn = deskTrack.connectDesktopChanged( sigc::mem_fun(*this, &TextEdit::setTargetDesktop) ); deskTrack.connect(GTK_WIDGET(gobj())); @@ -232,6 +233,7 @@ TextEdit::~TextEdit() selectChangedConn.disconnect(); desktopChangeConn.disconnect(); deskTrack.disconnect(); + fontVariantChangedConn.disconnect(); } void TextEdit::styleButton(Gtk::RadioButton *button, gchar const *tooltip, gchar const *icon_name, Gtk::RadioButton *group_button ) @@ -656,6 +658,19 @@ void TextEdit::onFontChange(SPFontSelector * /*fontsel*/, gchar* fontspec, TextE } +void TextEdit::onFontVariantChange(TextEdit *self) +{ + if( self->blocked ) + return; + + SPItem *text = self->getSelectedTextItem (); + + if (text) { + self->apply_button.set_sensitive ( true ); + } + self->setasdefault_button.set_sensitive ( true ); +} + void TextEdit::onStartOffsetChange(GtkTextBuffer * /*text_buffer*/, TextEdit *self) { SPItem *text = self->getSelectedTextItem(); diff --git a/src/ui/dialog/text-edit.h b/src/ui/dialog/text-edit.h index f088fd337..41f89b3e7 100644 --- a/src/ui/dialog/text-edit.h +++ b/src/ui/dialog/text-edit.h @@ -36,6 +36,7 @@ class SPItem; struct SPFontSelector; +class FontVariants; class font_instance; class SPCSSAttr; @@ -111,6 +112,17 @@ protected: */ static void onFontChange (SPFontSelector *fontsel, gchar* fontspec, TextEdit *self); + /** + * Callback invoked when the user modifies the font variant through the dialog. + * + * onFontChange updates the dialog UI. The subfunction setPreviewText updates the preview label. + * + * @param fontsel pointer to FontVariant (currently not used). + * @param fontspec for the text to be previewed. + * @param self pointer to the current instance of the dialog. + */ + static void onFontVariantChange (TextEdit *self); + /** * Callback invoked when the user modifies the startOffset of text on a path. * @@ -228,6 +240,7 @@ private: sigc::connection selectChangedConn; sigc::connection subselChangedConn; sigc::connection selectModifiedConn; + sigc::connection fontVariantChangedConn; bool blocked; const Glib::ustring samplephrase; diff --git a/src/ui/widget/font-variants.cpp b/src/ui/widget/font-variants.cpp index 56c24ea6f..637631fda 100644 --- a/src/ui/widget/font-variants.cpp +++ b/src/ui/widget/font-variants.cpp @@ -76,6 +76,8 @@ namespace Widget { { // Ligatures -------------------------- + + // Add tooltips _ligatures_common.set_tooltip_text( _("Common ligatures. On by default. OpenType tables: 'liga', 'clig'")); _ligatures_discretionary.set_tooltip_text( @@ -85,11 +87,13 @@ namespace Widget { _ligatures_contextual.set_tooltip_text( _("Contextual forms. On by default. OpenType table: 'calt'")); - + // Add signals _ligatures_common.signal_clicked().connect ( sigc::mem_fun(*this, &FontVariants::ligatures_callback) ); _ligatures_discretionary.signal_clicked().connect ( sigc::mem_fun(*this, &FontVariants::ligatures_callback) ); _ligatures_historical.signal_clicked().connect ( sigc::mem_fun(*this, &FontVariants::ligatures_callback) ); _ligatures_contextual.signal_clicked().connect ( sigc::mem_fun(*this, &FontVariants::ligatures_callback) ); + + // Add to frame _ligatures_vbox.add( _ligatures_common ); _ligatures_vbox.add( _ligatures_discretionary ); _ligatures_vbox.add( _ligatures_historical ); @@ -100,32 +104,41 @@ namespace Widget { ligatures_init(); // Position ---------------------------------- - _position_vbox.add( _position_normal ); - _position_vbox.add( _position_sub ); - _position_vbox.add( _position_super ); - _position_frame.add( _position_vbox ); - add( _position_frame ); + + // Add tooltips + _position_normal.set_tooltip_text( _("Normal position.")); + _position_sub.set_tooltip_text( _("Subscript. OpenType table: 'subs'") ); + _position_super.set_tooltip_text( _("Superscript. OpenType table: 'sups'") ); // Group buttons Gtk::RadioButton::Group position_group = _position_normal.get_group(); _position_sub.set_group(position_group); _position_super.set_group(position_group); + + // Add signals _position_normal.signal_pressed().connect ( sigc::mem_fun(*this, &FontVariants::position_callback) ); _position_sub.signal_pressed().connect ( sigc::mem_fun(*this, &FontVariants::position_callback) ); _position_super.signal_pressed().connect ( sigc::mem_fun(*this, &FontVariants::position_callback) ); + // Add to frame + _position_vbox.add( _position_normal ); + _position_vbox.add( _position_sub ); + _position_vbox.add( _position_super ); + _position_frame.add( _position_vbox ); + add( _position_frame ); + position_init(); // Caps ---------------------------------- - _caps_vbox.add( _caps_normal ); - _caps_vbox.add( _caps_small ); - _caps_vbox.add( _caps_all_small ); - _caps_vbox.add( _caps_petite ); - _caps_vbox.add( _caps_all_petite ); - _caps_vbox.add( _caps_unicase ); - _caps_vbox.add( _caps_titling ); - _caps_frame.add( _caps_vbox ); - add( _caps_frame ); + + // Add tooltips + _caps_normal.set_tooltip_text( _("Normal capitalization.")); + _caps_small.set_tooltip_text( _("Small-caps (lowercase). OpenType table: 'smcp'")); + _caps_all_small.set_tooltip_text( _("All small-caps (uppercase and lowercase). OpenType tables: 'c2sc' and 'smcp'")); + _caps_petite.set_tooltip_text( _("Petite-caps (lowercase). OpenType table: 'pcap'")); + _caps_all_petite.set_tooltip_text( _("All petite-caps (uppercase and lowercase). OpenType tables: 'c2sc' and 'pcap'")); + _caps_unicase.set_tooltip_text( _("Unicase (small caps for uppercase, normal for lowercase). OpenType table: 'unic'")); + _caps_titling.set_tooltip_text( _("Titling caps (lighter-weight uppercase for use in titles). OpenType table: 'titl'")); // Group buttons Gtk::RadioButton::Group caps_group = _caps_normal.get_group(); @@ -135,6 +148,8 @@ namespace Widget { _caps_all_petite.set_group(caps_group); _caps_unicase.set_group(caps_group); _caps_titling.set_group(caps_group); + + // Add signals _caps_normal.signal_clicked().connect ( sigc::mem_fun(*this, &FontVariants::caps_callback) ); _caps_small.signal_clicked().connect ( sigc::mem_fun(*this, &FontVariants::caps_callback) ); _caps_all_small.signal_clicked().connect ( sigc::mem_fun(*this, &FontVariants::caps_callback) ); @@ -143,9 +158,61 @@ namespace Widget { _caps_unicase.signal_clicked().connect ( sigc::mem_fun(*this, &FontVariants::caps_callback) ); _caps_titling.signal_clicked().connect ( sigc::mem_fun(*this, &FontVariants::caps_callback) ); + // Add to frame + _caps_vbox.add( _caps_normal ); + _caps_vbox.add( _caps_small ); + _caps_vbox.add( _caps_all_small ); + _caps_vbox.add( _caps_petite ); + _caps_vbox.add( _caps_all_petite ); + _caps_vbox.add( _caps_unicase ); + _caps_vbox.add( _caps_titling ); + _caps_frame.add( _caps_vbox ); + add( _caps_frame ); + caps_init(); // Numeric ------------------------------ + + // Add tooltips + _numeric_default_style.set_tooltip_text( _("Normal style.")); + _numeric_lining.set_tooltip_text( _("Lining numerals. OpenType table: 'lnum'")); + _numeric_old_style.set_tooltip_text( _("Old style numerals. OpenType table: 'onum'")); + _numeric_default_width.set_tooltip_text( _("Normal widths.")); + _numeric_proportional.set_tooltip_text( _("Proportional width numerals. OpenType table: 'pnum'")); + _numeric_tabular.set_tooltip_text( _("Same width numerals. OpenType table: 'tnum'")); + _numeric_default_fractions.set_tooltip_text( _("Normal fractions.")); + _numeric_diagonal.set_tooltip_text( _("Diagonal fractions. OpenType table: 'frac'")); + _numeric_stacked.set_tooltip_text( _("Stacked fractions. OpenType table: 'afrc'")); + _numeric_ordinal.set_tooltip_text( _("Ordinals (raised 'th', etc.). OpenType table: 'ordn'")); + _numeric_slashed_zero.set_tooltip_text( _("Slashed zeros. OpenType table: 'zero'")); + + // Group buttons + Gtk::RadioButton::Group style_group = _numeric_default_style.get_group(); + _numeric_lining.set_group(style_group); + _numeric_old_style.set_group(style_group); + + Gtk::RadioButton::Group width_group = _numeric_default_width.get_group(); + _numeric_proportional.set_group(width_group); + _numeric_tabular.set_group(width_group); + + Gtk::RadioButton::Group fraction_group = _numeric_default_fractions.get_group(); + _numeric_diagonal.set_group(fraction_group); + _numeric_stacked.set_group(fraction_group); + + // Add signals + _numeric_default_style.signal_clicked().connect ( sigc::mem_fun(*this, &FontVariants::numeric_callback) ); + _numeric_lining.signal_clicked().connect ( sigc::mem_fun(*this, &FontVariants::numeric_callback) ); + _numeric_old_style.signal_clicked().connect ( sigc::mem_fun(*this, &FontVariants::numeric_callback) ); + _numeric_default_width.signal_clicked().connect ( sigc::mem_fun(*this, &FontVariants::numeric_callback) ); + _numeric_proportional.signal_clicked().connect ( sigc::mem_fun(*this, &FontVariants::numeric_callback) ); + _numeric_tabular.signal_clicked().connect ( sigc::mem_fun(*this, &FontVariants::numeric_callback) ); + _numeric_default_fractions.signal_clicked().connect ( sigc::mem_fun(*this, &FontVariants::numeric_callback) ); + _numeric_diagonal.signal_clicked().connect ( sigc::mem_fun(*this, &FontVariants::numeric_callback) ); + _numeric_stacked.signal_clicked().connect ( sigc::mem_fun(*this, &FontVariants::numeric_callback) ); + _numeric_ordinal.signal_clicked().connect ( sigc::mem_fun(*this, &FontVariants::numeric_callback) ); + _numeric_slashed_zero.signal_clicked().connect ( sigc::mem_fun(*this, &FontVariants::numeric_callback) ); + + // Add to frame _numeric_stylebox.add( _numeric_default_style ); _numeric_stylebox.add( _numeric_lining ); _numeric_stylebox.add( _numeric_old_style ); @@ -163,20 +230,9 @@ namespace Widget { _numeric_frame.add( _numeric_vbox ); add( _numeric_frame ); - // Group buttons - Gtk::RadioButton::Group style_group = _numeric_default_style.get_group(); - _numeric_lining.set_group(style_group); - _numeric_old_style.set_group(style_group); - - Gtk::RadioButton::Group width_group = _numeric_default_width.get_group(); - _numeric_proportional.set_group(width_group); - _numeric_tabular.set_group(width_group); - - Gtk::RadioButton::Group fraction_group = _numeric_default_fractions.get_group(); - _numeric_diagonal.set_group(fraction_group); - _numeric_stacked.set_group(fraction_group); show_all_children(); + } void @@ -188,6 +244,7 @@ namespace Widget { FontVariants::ligatures_callback() { // std::cout << "FontVariants::ligatures_callback()" << std::endl; _ligatures_changed = true; + _changed_signal.emit(); } void @@ -199,6 +256,7 @@ namespace Widget { FontVariants::position_callback() { // std::cout << "FontVariants::position_callback()" << std::endl; _position_changed = true; + _changed_signal.emit(); } void @@ -210,6 +268,7 @@ namespace Widget { FontVariants::caps_callback() { // std::cout << "FontVariants::caps_callback()" << std::endl; _caps_changed = true; + _changed_signal.emit(); } void @@ -221,6 +280,7 @@ namespace Widget { FontVariants::numeric_callback() { // std::cout << "FontVariants::numeric_callback()" << std::endl; _numeric_changed = true; + _changed_signal.emit(); } // Update GUI based on query. diff --git a/src/ui/widget/font-variants.h b/src/ui/widget/font-variants.h index 04c05d3c6..e6a9dd68b 100644 --- a/src/ui/widget/font-variants.h +++ b/src/ui/widget/font-variants.h @@ -10,8 +10,6 @@ #ifndef INKSCAPE_UI_WIDGET_FONT_VARIANT_H #define INKSCAPE_UI_WIDGET_FONT_VARIANT_H -// Temp: both frame and expander -#include #include #include #include @@ -112,10 +110,27 @@ private: bool _caps_changed; bool _numeric_changed; + sigc::signal _changed_signal; + public: + + /** + * Update GUI based on query results. + */ void update( SPStyle const *query ); + /** + * Fill SPCSSAttr based on settings of buttons. + */ void fill_css( SPCSSAttr* css ); + + /** + * Let others know that user has changed GUI settings. + * (Used to enable 'Apply' and 'Default' buttons.) + */ + sigc::connection connectChanged(sigc::slot slot) { + return _changed_signal.connect(slot); + } }; -- cgit v1.2.3 From 2645ecd8d21e66346238d3f75a844499c94ca328 Mon Sep 17 00:00:00 2001 From: Ben Scholzen 'DASPRiD Date: Wed, 20 May 2015 15:35:51 +0200 Subject: Fix locale number handling on powerstroke dialog (bzr r14163.1.1) --- src/ui/dialog/lpe-powerstroke-properties.cpp | 19 +++++++++++-------- src/ui/dialog/lpe-powerstroke-properties.h | 14 +++----------- 2 files changed, 14 insertions(+), 19 deletions(-) (limited to 'src') diff --git a/src/ui/dialog/lpe-powerstroke-properties.cpp b/src/ui/dialog/lpe-powerstroke-properties.cpp index 0cf3e9706..aa2b3cb72 100644 --- a/src/ui/dialog/lpe-powerstroke-properties.cpp +++ b/src/ui/dialog/lpe-powerstroke-properties.cpp @@ -52,10 +52,16 @@ PowerstrokePropertiesDialog::PowerstrokePropertiesDialog() // Layer name widgets _powerstroke_position_entry.set_activates_default(true); + _powerstroke_position_entry.set_digits(4); + _powerstroke_position_entry.set_increments(1,1); + _powerstroke_position_entry.set_range(-999999999999999999., 999999999999999999.); _powerstroke_position_label.set_label(_("Position:")); _powerstroke_position_label.set_alignment(1.0, 0.5); _powerstroke_width_entry.set_activates_default(true); + _powerstroke_width_entry.set_digits(4); + _powerstroke_width_entry.set_increments(1,1); + _powerstroke_width_entry.set_range(-999999999999999999., 999999999999999999.); _powerstroke_width_label.set_label(_("Width:")); _powerstroke_width_label.set_alignment(1.0, 0.5); @@ -126,12 +132,9 @@ void PowerstrokePropertiesDialog::showDialog(SPDesktop *desktop, Geom::Point kno void PowerstrokePropertiesDialog::_apply() { - std::istringstream i_pos(_powerstroke_position_entry.get_text()); - std::istringstream i_width(_powerstroke_width_entry.get_text()); - double d_pos, d_width; - if ((i_pos >> d_pos) && i_width >> d_width) { - _knotpoint->knot_set_offset(Geom::Point(d_pos, d_width)); - } + double d_pos = _powerstroke_position_entry.get_value(); + double d_width = _powerstroke_width_entry.get_value(); + _knotpoint->knot_set_offset(Geom::Point(d_pos, d_width)); _close(); } @@ -171,8 +174,8 @@ void PowerstrokePropertiesDialog::_handleButtonEvent(GdkEventButton* event) void PowerstrokePropertiesDialog::_setKnotPoint(Geom::Point knotpoint) { - _powerstroke_position_entry.set_text(boost::lexical_cast(knotpoint.x())); - _powerstroke_width_entry.set_text(boost::lexical_cast(knotpoint.y())); + _powerstroke_position_entry.set_value(knotpoint.x()); + _powerstroke_width_entry.set_value(knotpoint.y()); } void PowerstrokePropertiesDialog::_setPt(const Inkscape::LivePathEffect::PowerStrokePointArrayParamKnotHolderEntity *pt) diff --git a/src/ui/dialog/lpe-powerstroke-properties.h b/src/ui/dialog/lpe-powerstroke-properties.h index c53eac0d9..1e4c1df5b 100644 --- a/src/ui/dialog/lpe-powerstroke-properties.h +++ b/src/ui/dialog/lpe-powerstroke-properties.h @@ -13,15 +13,7 @@ #define INKSCAPE_DIALOG_POWERSTROKE_PROPERTIES_H #include <2geom/point.h> -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include #include "live_effects/parameter/powerstrokepointarray.h" class SPDesktop; @@ -45,9 +37,9 @@ protected: Inkscape::LivePathEffect::PowerStrokePointArrayParamKnotHolderEntity *_knotpoint; Gtk::Label _powerstroke_position_label; - Gtk::Entry _powerstroke_position_entry; + Gtk::SpinButton _powerstroke_position_entry; Gtk::Label _powerstroke_width_label; - Gtk::Entry _powerstroke_width_entry; + Gtk::SpinButton _powerstroke_width_entry; Gtk::Table _layout_table; bool _position_visible; -- cgit v1.2.3 From cb0c46c9678889ce05dedae3ad2569435c7bb969 Mon Sep 17 00:00:00 2001 From: Ben Scholzen 'DASPRiD Date: Wed, 20 May 2015 17:51:48 +0200 Subject: Use sane constant for min and max values in LPE dialogs (bzr r14163.1.2) --- src/live_effects/parameter/parameter.cpp | 7 ------- src/live_effects/parameter/parameter.h | 7 +++++++ src/ui/dialog/lpe-fillet-chamfer-properties.cpp | 5 +++-- src/ui/dialog/lpe-powerstroke-properties.cpp | 5 +++-- 4 files changed, 13 insertions(+), 11 deletions(-) (limited to 'src') diff --git a/src/live_effects/parameter/parameter.cpp b/src/live_effects/parameter/parameter.cpp index beb750404..527bc06fe 100644 --- a/src/live_effects/parameter/parameter.cpp +++ b/src/live_effects/parameter/parameter.cpp @@ -42,13 +42,6 @@ Parameter::param_write_to_repr(const char * svgd) param_effect->getRepr()->setAttribute(param_key.c_str(), svgd); } -// In gtk2, this wasn't an issue; we could toss around -// G_MAXDOUBLE and not worry about size allocations. But -// in gtk3, it is an issue: it allocates widget size for the maxmium -// value you pass to it, leading to some insane lengths. -// If you need this to be more, please be conservative about it. -const double SCALARPARAM_G_MAXDOUBLE = 10000000000.0; // TODO fixme: using an arbitrary large number as a magic value seems fragile. - void Parameter::write_to_SVG(void) { gchar * str = param_getSVGValue(); diff --git a/src/live_effects/parameter/parameter.h b/src/live_effects/parameter/parameter.h index 2e6cae49f..cc2c4f3d6 100644 --- a/src/live_effects/parameter/parameter.h +++ b/src/live_effects/parameter/parameter.h @@ -13,6 +13,13 @@ #include <2geom/forward.h> #include <2geom/pathvector.h> +// In gtk2, this wasn't an issue; we could toss around +// G_MAXDOUBLE and not worry about size allocations. But +// in gtk3, it is an issue: it allocates widget size for the maxmium +// value you pass to it, leading to some insane lengths. +// If you need this to be more, please be conservative about it. +const double SCALARPARAM_G_MAXDOUBLE = 10000000000.0; // TODO fixme: using an arbitrary large number as a magic value seems fragile. + class KnotHolder; class SPLPEItem; class SPDesktop; diff --git a/src/ui/dialog/lpe-fillet-chamfer-properties.cpp b/src/ui/dialog/lpe-fillet-chamfer-properties.cpp index 061055feb..5ccee103c 100644 --- a/src/ui/dialog/lpe-fillet-chamfer-properties.cpp +++ b/src/ui/dialog/lpe-fillet-chamfer-properties.cpp @@ -27,6 +27,7 @@ #include "selection-chemistry.h" #include "ui/icon-names.h" #include "ui/widget/imagetoggler.h" +#include "live_effects/parameter/parameter.h" #include //#include "event-context.h" @@ -47,7 +48,7 @@ FilletChamferPropertiesDialog::FilletChamferPropertiesDialog() _fillet_chamfer_position_numeric.set_digits(4); _fillet_chamfer_position_numeric.set_increments(1,1); //todo: get tha max aloable infinity freeze the widget - _fillet_chamfer_position_numeric.set_range(0., 999999999999999999.); + _fillet_chamfer_position_numeric.set_range(0., SCALARPARAM_G_MAXDOUBLE); _fillet_chamfer_position_label.set_label(_("Radius (pixels):")); _fillet_chamfer_position_label.set_alignment(1.0, 0.5); @@ -59,7 +60,7 @@ FilletChamferPropertiesDialog::FilletChamferPropertiesDialog() _fillet_chamfer_chamfer_subdivisions.set_digits(0); _fillet_chamfer_chamfer_subdivisions.set_increments(1,1); //todo: get tha max aloable infinity freeze the widget - _fillet_chamfer_chamfer_subdivisions.set_range(0, 999999999999999999.0); + _fillet_chamfer_chamfer_subdivisions.set_range(0, SCALARPARAM_G_MAXDOUBLE); _fillet_chamfer_chamfer_subdivisions_label.set_label(_("Chamfer subdivisions:")); _fillet_chamfer_chamfer_subdivisions_label.set_alignment(1.0, 0.5); diff --git a/src/ui/dialog/lpe-powerstroke-properties.cpp b/src/ui/dialog/lpe-powerstroke-properties.cpp index aa2b3cb72..cfc972547 100644 --- a/src/ui/dialog/lpe-powerstroke-properties.cpp +++ b/src/ui/dialog/lpe-powerstroke-properties.cpp @@ -36,6 +36,7 @@ #include "selection-chemistry.h" #include "ui/icon-names.h" #include "ui/widget/imagetoggler.h" +#include "live_effects/parameter/parameter.h" //#include "event-context.h" namespace Inkscape { @@ -54,14 +55,14 @@ PowerstrokePropertiesDialog::PowerstrokePropertiesDialog() _powerstroke_position_entry.set_activates_default(true); _powerstroke_position_entry.set_digits(4); _powerstroke_position_entry.set_increments(1,1); - _powerstroke_position_entry.set_range(-999999999999999999., 999999999999999999.); + _powerstroke_position_entry.set_range(-SCALARPARAM_G_MAXDOUBLE, SCALARPARAM_G_MAXDOUBLE); _powerstroke_position_label.set_label(_("Position:")); _powerstroke_position_label.set_alignment(1.0, 0.5); _powerstroke_width_entry.set_activates_default(true); _powerstroke_width_entry.set_digits(4); _powerstroke_width_entry.set_increments(1,1); - _powerstroke_width_entry.set_range(-999999999999999999., 999999999999999999.); + _powerstroke_width_entry.set_range(-SCALARPARAM_G_MAXDOUBLE, SCALARPARAM_G_MAXDOUBLE); _powerstroke_width_label.set_label(_("Width:")); _powerstroke_width_label.set_alignment(1.0, 0.5); -- cgit v1.2.3 From da59adbf4c5d970a899919d37a22a31865f9c540 Mon Sep 17 00:00:00 2001 From: Tavmjong Bah Date: Thu, 21 May 2015 10:09:24 +0200 Subject: Don't fill entry box with zeros while typing. Bug introduced with r14160. (bzr r14166) --- src/ui/widget/color-entry.cpp | 10 ++++++++++ src/ui/widget/color-entry.h | 1 + 2 files changed, 11 insertions(+) (limited to 'src') diff --git a/src/ui/widget/color-entry.cpp b/src/ui/widget/color-entry.cpp index 473d7de65..f5658c3a6 100644 --- a/src/ui/widget/color-entry.cpp +++ b/src/ui/widget/color-entry.cpp @@ -20,6 +20,7 @@ namespace Widget { ColorEntry::ColorEntry(SelectedColor &color) : _color(color) , _updating(false) + , _updatingrgba(false) { _color_changed_connection = color.signal_changed.connect(sigc::mem_fun(this, &ColorEntry::_onColorChanged)); _color_dragged_connection = color.signal_dragged.connect(sigc::mem_fun(this, &ColorEntry::_onColorChanged)); @@ -41,6 +42,9 @@ void ColorEntry::on_changed() if (_updating) { return; } + if (_updatingrgba) { + return; // Typing text into entry box + } Glib::ustring text = get_text(); bool changed = false; @@ -64,11 +68,13 @@ void ColorEntry::on_changed() if (len < 8) { rgba = rgba << (4 * (8 - len)); } + _updatingrgba = true; if (changed) { set_text(str); } SPColor color(rgba); _color.setColorAlpha(color, SP_RGBA32_A_F(rgba)); + _updatingrgba = false; } g_free(str); } @@ -76,6 +82,10 @@ void ColorEntry::on_changed() void ColorEntry::_onColorChanged() { + if (_updatingrgba) { + return; + } + SPColor color = _color.color(); gdouble alpha = _color.alpha(); diff --git a/src/ui/widget/color-entry.h b/src/ui/widget/color-entry.h index cd7d6164a..edabe1980 100644 --- a/src/ui/widget/color-entry.h +++ b/src/ui/widget/color-entry.h @@ -34,6 +34,7 @@ private: sigc::connection _color_changed_connection; sigc::connection _color_dragged_connection; bool _updating; + bool _updatingrgba; }; } -- cgit v1.2.3 From 9f1c113eb98e7898f14502c69d8e3f7c35664c11 Mon Sep 17 00:00:00 2001 From: mathog <> Date: Thu, 21 May 2015 10:23:01 -0700 Subject: patch bug 1294784 (bzr r14167) --- src/display/drawing-text.cpp | 3 ++- src/style-internal.cpp | 15 +++++++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/display/drawing-text.cpp b/src/display/drawing-text.cpp index e20a7ff2a..3928ad796 100644 --- a/src/display/drawing-text.cpp +++ b/src/display/drawing-text.cpp @@ -367,7 +367,7 @@ void DrawingText::decorateStyle(DrawingContext &dc, double vextent, double xphas /* returns scaled line thickness */ void DrawingText::decorateItem(DrawingContext &dc, double phase_length, bool under) { - if (_nrstyle.font_size < 1.0e-32)return; // would cause a divide by zero and nothing would be visible anyway + if ( _nrstyle.font_size <= 1.0e-32 )return; // might cause a divide by zero or overflow and nothing would be visible anyway double tsp_width_adj = _nrstyle.tspan_width / _nrstyle.font_size; double tsp_asc_adj = _nrstyle.ascender / _nrstyle.font_size; double tsp_size_adj = (_nrstyle.ascender + _nrstyle.descender) / _nrstyle.font_size; @@ -381,6 +381,7 @@ void DrawingText::decorateItem(DrawingContext &dc, double phase_length, bool und Geom::Point p2; // All lines must be the same thickness, in combinations, line_through trumps underline double thickness = final_underline_thickness; + if ( thickness <= 1.0e-32 )return; // might cause a divide by zero or overflow and nothing would be visible anyway dc.setTolerance(0.5); // Is this really necessary... could effect dots. if( under ) { diff --git a/src/style-internal.cpp b/src/style-internal.cpp index 0e53da0d3..c117a97f9 100644 --- a/src/style-internal.cpp +++ b/src/style-internal.cpp @@ -1931,6 +1931,11 @@ SPIFontSize::read( gchar const *str ) { unit = length.unit; value = length.value; computed = length.computed; + /* Set a minimum font size to something much smaller than should ever (ever!) be encountered in a real file. + If a bad SVG file is encountered and this is zero odd things + might happen because the inverse is used in some scaling actions. + */ + if ( computed <= 1.0e-32 ) { computed = 1.0e-32; } if( unit == SP_CSS_UNIT_PERCENT ) { type = SP_FONT_SIZE_PERCENTAGE; } else { @@ -2011,6 +2016,11 @@ SPIFontSize::cascade( const SPIBase* const parent ) { break; } } + /* Set a minimum font size to something much smaller than should ever (ever!) be encountered in a real file. + If a bad SVG file is encountered and this is zero odd things + might happen because the inverse is used in some scaling actions. + */ + if ( computed <= 1.0e-32 ) { computed = 1.0e-32; } } else { std::cerr << "SPIFontSize::cascade(): Incorrect parent type" << std::endl; } @@ -2099,6 +2109,11 @@ SPIFontSize::merge( const SPIBase* const parent ) { } } } // Relative size + /* Set a minimum font size to something much smaller than should ever (ever!) be encountered in a real file. + If a bad SVG file is encountered and this is zero odd things + might happen because the inverse is used in some scaling actions. + */ + if ( computed <= 1.0e-32 ) { computed = 1.0e-32; } } // Parent set and not inherit } else { std::cerr << "SPIFontSize::merge(): Incorrect parent type" << std::endl; -- cgit v1.2.3 From e091cbbea4228bf243b1c040e774ad884683da8f Mon Sep 17 00:00:00 2001 From: mathog <> Date: Thu, 21 May 2015 11:40:38 -0700 Subject: patch for bug 1457612 (bzr r14168) --- src/extension/internal/text_reassemble.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/extension/internal/text_reassemble.c b/src/extension/internal/text_reassemble.c index d3aafef12..fa983b83d 100644 --- a/src/extension/internal/text_reassemble.c +++ b/src/extension/internal/text_reassemble.c @@ -67,8 +67,8 @@ Optional compiler switches for development: File: text_reassemble.c -Version: 0.0.16 -Date: 25-FEB-2015 +Version: 0.0.17 +Date: 21-MAY-2015 Author: David Mathog, Biology Division, Caltech email: mathog@caltech.edu Copyright: 2015 David Mathog and California Institute of Technology (Caltech) @@ -2204,10 +2204,10 @@ void TR_layout_2_svg(TR_INFO *tri){ sprintf(obuf,"text-decoration:"); /* multiple text decoration styles may be set */ utmp = tsp->decoration & TXTDECOR_TMASK; - if(utmp & TXTDECOR_UNDER ){ strcat(obuf,"underline"); } - if(utmp & TXTDECOR_OVER ){ strcat(obuf,"overline"); } - if(utmp & TXTDECOR_BLINK ){ strcat(obuf,"blink"); } - if(utmp & TXTDECOR_STRIKE){ strcat(obuf,"line-through");} + if(utmp & TXTDECOR_UNDER ){ strcat(obuf," underline"); } + if(utmp & TXTDECOR_OVER ){ strcat(obuf," overline"); } + if(utmp & TXTDECOR_BLINK ){ strcat(obuf," blink"); } + if(utmp & TXTDECOR_STRIKE){ strcat(obuf," line-through");} if(*obuf){ /* only a single text decoration line type may be set */ switch(tsp->decoration & TXTDECOR_LMASK){ -- cgit v1.2.3 From 252d594b8f4e0f8b340a62a242795f0583c57a25 Mon Sep 17 00:00:00 2001 From: mathog <> Date: Thu, 21 May 2015 16:06:06 -0700 Subject: minor tweaks to libUEMF and related code (bzr r14169) --- src/extension/internal/wmf-inout.cpp | 6 +++-- src/libuemf/uemf.h | 11 ++++++--- src/libuemf/uemf_print.c | 48 +++++++++++++++++++++++++++++++++--- src/libuemf/uemf_print.h | 7 ++++-- src/libuemf/upmf.c | 12 +++++---- src/libuemf/upmf_print.c | 21 ++++++++++------ src/libuemf/upmf_print.h | 6 ++--- src/libuemf/uwmf.c | 42 +++++++++++++++++-------------- src/libuemf/uwmf.h | 10 ++++---- src/libuemf/uwmf_endian.c | 20 +++++++++------ src/libuemf/uwmf_endian.h | 8 +++--- src/libuemf/uwmf_print.c | 25 ++++++++++++------- 12 files changed, 145 insertions(+), 71 deletions(-) (limited to 'src') diff --git a/src/extension/internal/wmf-inout.cpp b/src/extension/internal/wmf-inout.cpp index f76fa16b4..d17180d91 100644 --- a/src/extension/internal/wmf-inout.cpp +++ b/src/extension/internal/wmf-inout.cpp @@ -449,7 +449,8 @@ uint32_t Wmf::add_dib_image(PWMF_CALLBACK_DATA d, const char *dib, uint32_t iUsa char *rgba_px = NULL; // RGBA pixels const char *px = NULL; // DIB pixels const U_RGBQUAD *ct = NULL; // DIB color table - int32_t width, height, colortype, numCt, invert; // if needed these values will be set by wget_DIB_params + uint32_t numCt; + int32_t width, height, colortype, invert; // if needed these values will be set by wget_DIB_params if(iUsage == U_DIB_RGB_COLORS){ // next call returns pointers and values, but allocates no memory dibparams = wget_DIB_params(dib, &px, &ct, &numCt, &width, &height, &colortype, &invert); @@ -1318,7 +1319,8 @@ void Wmf::common_dib_to_image(PWMF_CALLBACK_DATA d, const char *dib, char *sub_px = NULL; // RGBA pixels, subarray const char *px = NULL; // DIB pixels const U_RGBQUAD *ct = NULL; // color table - int32_t width, height, colortype, numCt, invert; // if needed these values will be set in wget_DIB_params + uint32_t numCt; + int32_t width, height, colortype, invert; // if needed these values will be set in wget_DIB_params if(iUsage == U_DIB_RGB_COLORS){ // next call returns pointers and values, but allocates no memory dibparams = wget_DIB_params(dib, &px, &ct, &numCt, &width, &height, &colortype, &invert); diff --git a/src/libuemf/uemf.h b/src/libuemf/uemf.h index 53426cb55..f6ed7da03 100644 --- a/src/libuemf/uemf.h +++ b/src/libuemf/uemf.h @@ -95,8 +95,8 @@ these WMF enumerations is by referencing the following table: /* File: uemf.h -Version: 0.0.31 -Date: 23-APR-2015 +Version: 0.0.32 +Date: 28-APR-2015 Author: David Mathog, Biology Division, Caltech email: mathog@caltech.edu Copyright: 2015 David Mathog and California Institute of Technology (Caltech) @@ -168,7 +168,12 @@ extern "C" { #define U_ROUND(A) ( (A) > 0 ? floor((A)+0.5) : ( (A) < 0 ? -floor(-(A)+0.5) : (A) ) ) #define MAKE_MIN_PTR(A,B) ( A < B ? A : B) -#define IS_MEM_UNSAFE(A,B,C) ( (int8_t *)(A) > (int8_t *)(C) ? 1 : ((int8_t *)(C) - (int8_t *)(A) >= (int)(B) ? 0 : 1 )) //!< Return 1 when a region of memory starting at A of B bytes extends beyond pointer C +/* This is tricky. The next one can be called with a size which is either an int or an unsigned int. + The former can be negative, which is obviously wrong, but testing for that means that the size cannot + be more than INT_MAX/2. Accept that limitation since no reasonable EMF record or file should ever be that large. + B must be an INT or size_t. + If a uint16_t is used gcc complains about the first test. Force B to be at least as big as int (at run time) */ +#define IS_MEM_UNSAFE(A,B,C) ( (sizeof(B) < sizeof(int) || (int)(B)) < 0 ? 1 : ((int8_t *)(A) > (int8_t *)(C) ? 1 : ((int8_t *)(C) - (int8_t *)(A) >= (int)(B) ? 0 : 1 ))) //!< Return 1 when a region of memory starting at A of B bytes extends beyond pointer C /** @} */ diff --git a/src/libuemf/uemf_print.c b/src/libuemf/uemf_print.c index adcf54c0f..4bc9f0206 100644 --- a/src/libuemf/uemf_print.c +++ b/src/libuemf/uemf_print.c @@ -6,8 +6,8 @@ /* File: uemf_print.c -Version: 0.0.18 -Date: 25-MAR-2015 +Version: 0.0.20 +Date: 21-MAY-2015 Author: David Mathog, Biology Division, Caltech email: mathog@caltech.edu Copyright: 2015 David Mathog and California Institute of Technology (Caltech) @@ -34,6 +34,31 @@ extern "C" { void U_swap4(void *ul, unsigned int count); //! \endcond +/** + \brief calculate a CRC32 value for record + \returns CRC32 value calculated for record + \param record pointer to the first byte + \param Size number of bytes in the record + +Code based on example crc32b here: + http://www.hackersdelight.org/hdcodetxt/crc.c.txt +*/ +uint32_t lu_crc32(const char *record, uint32_t Size){ + const unsigned char *message = record; + uint32_t i, j; + uint32_t crc, mask; + + crc = 0xFFFFFFFF; + for(i=0;i> 1) ^ (0xEDB88320 & mask); + } + } + return ~crc; +} + /** \brief Print some number of hex bytes \param buf pointer to the first byte @@ -45,6 +70,7 @@ void hexbytes_print(uint8_t *buf,unsigned int num){ } } + /* ********************************************************************************************** These functions print standard objects used in the EMR records. The low level ones do not append EOL. @@ -2505,7 +2531,7 @@ int U_emf_onerec_print(const char *contents, const char *blimit, int recnum, siz uint32_t nSize; uint32_t iType; const char *record = contents + off; - + if(record < contents)return(-1); // offset wrapped /* Check that COMMON data in record can be touched without an access violation. If it cannot be @@ -2514,7 +2540,21 @@ int U_emf_onerec_print(const char *contents, const char *blimit, int recnum, siz */ if(!U_emf_record_sizeok(record, blimit, &nSize, &iType, 1))return(-1); - printf("%-30srecord:%5d type:%-4d offset:%8d rsize:%8d\n",U_emr_names(iType),recnum,iType,(int) off,nSize); + uint32_t crc; +#if U_BYTE_SWAP + //This is a Big Endian machine, EMF crc values must be calculated on Little Endian form + char *swapbuf=malloc(nSize); + if(!swapbuf)return(-1); + memcpy(swapbuf,record,nSize); + U_emf_endian(swapbuf,nSize,1); // BE to LE + crc=lu_crc32(swapbuf,nSize); + free(swapbuf); +#else + crc=lu_crc32(record,nSize); +#endif + printf("%-30srecord:%5d type:%-4d offset:%8d rsize:%8d crc32:%8.8X\n", + U_emr_names(iType),recnum,iType,(int) off,nSize,crc); + fflush(stdout); /* print the record header before checking further. diff --git a/src/libuemf/uemf_print.h b/src/libuemf/uemf_print.h index 6568b4cfa..088a8a302 100644 --- a/src/libuemf/uemf_print.h +++ b/src/libuemf/uemf_print.h @@ -6,8 +6,8 @@ /* File: uemf_print.h -Version: 0.0.7 -Date: 24-MAR-2015 +Version: 0.0.9 +Date: 21-MAY-2015 Author: David Mathog, Biology Division, Caltech email: mathog@caltech.edu Copyright: 2015 David Mathog and California Institute of Technology (Caltech) @@ -21,6 +21,9 @@ extern "C" { #endif //! \cond +/* prototypes for miscellaneous */ +uint32_t lu_crc32(const char *record, uint32_t Size); + /* prototypes for objects used in EMR records */ void hexbytes_print(uint8_t *buf,unsigned int num); void colorref_print(U_COLORREF color); diff --git a/src/libuemf/upmf.c b/src/libuemf/upmf.c index 7d6349185..2ba818fa4 100644 --- a/src/libuemf/upmf.c +++ b/src/libuemf/upmf.c @@ -21,8 +21,8 @@ /* File: upmf.c -Version: 0.0.9 -Date: 25-MAR-2015 +Version: 0.0.10 +Date: 27-APR-2015 Author: David Mathog, Biology Division, Caltech email: mathog@caltech.edu Copyright: 2015 David Mathog and California Institute of Technology (Caltech) @@ -6575,15 +6575,17 @@ int U_PMF_VARPOINTS_get(const char *contents, uint16_t Flags, int Elements, U_PM } } else if(Flags & U_PPF_C){ - for(XFS = YFS = 0.0; Elements; Elements--, pts++){ + for(XF = YF = 0.0; Elements; Elements--, pts++){ if(!U_PMF_POINT_get(&contents, &XF, &XF, blimit))break; /* this should never happen */ pts->X = XF; pts->Y = YF; } } else { - for(XFS = YFS = 0.0; Elements; Elements--, pts++){ - (void) U_PMF_POINTF_get(&contents, &(pts->X), &(pts->Y), blimit); + for(XF = YF = 0.0; Elements; Elements--, pts++){ + (void) U_PMF_POINTF_get(&contents, &XF, &YF, blimit); + pts->X = XF; + pts->Y = YF; } } if(Elements){ /* some error in the preceding */ diff --git a/src/libuemf/upmf_print.c b/src/libuemf/upmf_print.c index 7d9598b0d..58ff4edd0 100644 --- a/src/libuemf/upmf_print.c +++ b/src/libuemf/upmf_print.c @@ -6,8 +6,8 @@ /* File: upmf_print.c -Version: 0.0.5 -Date: 24-MAR-2015 +Version: 0.0.7 +Date: 21-MAY-2015 Author: David Mathog, Biology Division, Caltech email: mathog@caltech.edu Copyright: 2015 David Mathog and California Institute of Technology (Caltech) @@ -142,7 +142,7 @@ int U_pmf_onerec_print(const char *contents, const char *blimit, int recnum, int int type = Header.Type & U_PMR_TYPE_MASK; /* strip the U_PMR_RECFLAG bit, leaving the indexable part */ if(type < U_PMR_MIN || type > U_PMR_MAX)return(-1); /* unknown EMF+ record type */ - status = U_PMF_CMN_HDR_print(Header, recnum, off); /* EMF+ part */ + status = U_PMF_CMN_HDR_print(contents, Header, recnum, off); /* EMF+ part */ /* Buggy EMF+ can set the continue bit and then do something else. In that case, force out the pending Object. Side effect - clears the pending object. */ @@ -222,14 +222,16 @@ int U_pmf_onerec_print(const char *contents, const char *blimit, int recnum, int /** \brief Print data from a U_PMF_CMN_HDR object \return number of bytes in record, 0 on error + \param contents pointer to a buffer holding this EMF+ record \param Header Header of the record \param precnum EMF+ record number in file. \param off Offset in file to the start of this EMF+ record. common structure present at the beginning of all(*) EMF+ records */ -int U_PMF_CMN_HDR_print(U_PMF_CMN_HDR Header, int precnum, int off){ - printf(" %-29srec+:%5d type:%X offset:%8d rsize:%8u dsize:%8u flags:%4.4X\n", - U_pmr_names(Header.Type &U_PMR_TYPE_MASK),precnum, Header.Type,off,Header.Size,Header.DataSize,Header.Flags); +int U_PMF_CMN_HDR_print(const char *contents, U_PMF_CMN_HDR Header, int precnum, int off){ + printf(" %-29srec+:%5d type:%X offset:%8d rsize:%8u dsize:%8u flags:%4.4X crc32:%8.8X\n", + U_pmr_names(Header.Type &U_PMR_TYPE_MASK),precnum, Header.Type,off,Header.Size,Header.DataSize,Header.Flags, + lu_crc32(contents,Header.Size)); return((int) Header.Size); } @@ -1852,7 +1854,12 @@ int U_PMF_TRANSFORMMATRIX_print(const char *contents, const char *blimit){ EMF+ manual 2.2.2.47, Microsoft name: EmfPlusTransformMatrix Object */ int U_PMF_TRANSFORMMATRIX2_print(U_PMF_TRANSFORMMATRIX *Tm){ - printf(" Matrix:{%f,%f,%f,%f,%f,%f}", Tm->m11, Tm->m12, Tm->m21, Tm->m22, Tm->dX, Tm->dY); + if(Tm){ + printf(" Matrix:{%f,%f,%f,%f,%f,%f}", Tm->m11, Tm->m12, Tm->m21, Tm->m22, Tm->dX, Tm->dY); + } + else { + printf(" Matrix:(None)"); + } return(1); } diff --git a/src/libuemf/upmf_print.h b/src/libuemf/upmf_print.h index fe1c57d60..a25374487 100644 --- a/src/libuemf/upmf_print.h +++ b/src/libuemf/upmf_print.h @@ -6,8 +6,8 @@ /* File: upmf_print.h -Version: 0.0.4 -Date: 24-MAR-2015 +Version: 0.0.5 +Date: 28-APR-2015 Author: David Mathog, Biology Division, Caltech email: mathog@caltech.edu Copyright: 2015 David Mathog and California Institute of Technology (Caltech) @@ -23,7 +23,7 @@ extern "C" { #include "upmf.h" /* includes uemf.h */ /* prototypes for simple types and enums used in PMR records */ -int U_PMF_CMN_HDR_print(U_PMF_CMN_HDR Header, int precnum, int off); +int U_PMF_CMN_HDR_print(const char *contents, U_PMF_CMN_HDR Header, int precnum, int off); int U_PMF_UINT8_ARRAY_print(const char *Start, const uint8_t *Array, int Elements, char *End); int U_PMF_BRUSHTYPEENUMERATION_print(int otype); int U_PMF_HATCHSTYLEENUMERATION_print(int hstype); diff --git a/src/libuemf/uwmf.c b/src/libuemf/uwmf.c index 35d38f69a..62e3d3c06 100644 --- a/src/libuemf/uwmf.c +++ b/src/libuemf/uwmf.c @@ -19,8 +19,8 @@ /* File: uwmf.c -Version: 0.0.16 -Date: 25-MAR-2015 +Version: 0.0.17 +Date: 28-MAR-2015 Author: David Mathog, Biology Division, Caltech email: mathog@caltech.edu Copyright: 2014 David Mathog and California Institute of Technology (Caltech) @@ -696,7 +696,8 @@ int packed_DIB_safe( int usedbytes; if(!bitmapinfo_safe(record, blimit))return(0); // this DIB has issues with colors fitting into the record - uint32_t width, height, colortype, numCt, invert; // these values will be set in get_DIB_params + uint32_t numCt; // these values will be set in get_DIB_params + int32_t width, height, colortype, invert; // these values will be set in get_DIB_params // next call returns pointers and values, but allocates no memory dibparams = wget_DIB_params(record, &px, (const U_RGBQUAD **) &ct, &numCt, &width, &height, &colortype, &invert); // sanity checking @@ -1564,7 +1565,7 @@ int wmf_finish( #if U_BYTE_SWAP //This is a Big Endian machine, WMF data must be Little Endian - U_wmf_endian(wt->buf,wt->used,1); + U_wmf_endian(wt->buf,wt->used,1,0); // BE to LE, entire file #endif (void) U_wmr_properties(U_WMR_INVALID); /* force the release of the lookup table memory, returned value is irrelevant */ @@ -1610,7 +1611,7 @@ int wmf_readdata( else { #if U_BYTE_SWAP //This is a Big Endian machine, WMF data is Little Endian - U_wmf_endian(*contents,*length,0); // LE to BE + U_wmf_endian(*contents,*length,0,0); // LE to BE, entire file #endif } } @@ -4720,10 +4721,10 @@ int U_WMRCORE_PALETTE_get( */ void U_BITMAPCOREHEADER_get( const char *BmiCh, - int32_t *Size, - int32_t *Width, - int32_t *Height, - int32_t *BitCount + uint32_t *Size, + int32_t *Width, + int32_t *Height, + int32_t *BitCount ){ uint32_t utmp4; uint16_t utmp2; @@ -4800,14 +4801,14 @@ int wget_DIB_params( const char *dib, const char **px, const U_RGBQUAD **ct, - int32_t *numCt, - int32_t *width, - int32_t *height, - int32_t *colortype, - int32_t *invert + uint32_t *numCt, + int32_t *width, + int32_t *height, + int32_t *colortype, + int32_t *invert ){ uint32_t bic; - int32_t Size; + uint32_t Size; bic = U_BI_RGB; // this information is not in the coreheader; U_BITMAPCOREHEADER_get(dib, &Size, width, height, colortype); if(Size != 0xC ){ //BitmapCoreHeader @@ -4816,7 +4817,7 @@ int wget_DIB_params( */ uint32_t uig4; int32_t ig4; - U_BITMAPINFOHEADER_get(dib, &uig4, width, height,&uig4, (uint32_t *) colortype, &bic, &uig4, &ig4, &ig4,&uig4, &uig4); + U_BITMAPINFOHEADER_get(dib, &uig4, width, height,&uig4, (uint32_t *) colortype, &bic, &uig4, &ig4, &ig4, &uig4, &uig4); } if(*height < 0){ *height = -*height; @@ -5559,7 +5560,8 @@ int U_WMRPOLYGON_get( ){ int size = U_WMRCORE_2U16_N16_get(contents, (U_SIZE_WMRPOLYGON), NULL, Length, Data); if(size){ - if(IS_MEM_UNSAFE(*Data, (*Length)*sizeof(U_POINT16), contents+size))return(0); + int iLength = (*Length)*sizeof(U_POINT16); + if(IS_MEM_UNSAFE(*Data, iLength, contents+size))return(0); } return size; } @@ -5578,7 +5580,8 @@ int U_WMRPOLYLINE_get( ){ int size = U_WMRCORE_2U16_N16_get(contents, (U_SIZE_WMRPOLYGON), NULL, Length, Data); if(size){ - if(IS_MEM_UNSAFE(*Data, (*Length)*sizeof(U_POINT16), contents+size))return(0); + int iLength = (*Length)*sizeof(U_POINT16); + if(IS_MEM_UNSAFE(*Data, iLength, contents+size))return(0); } return size; } @@ -5605,7 +5608,8 @@ int U_WMRESCAPE_get( ){ int size = U_WMRCORE_2U16_N16_get(contents, (U_SIZE_WMRESCAPE), Escape, Length, Data); if(size){ - if(IS_MEM_UNSAFE(*Data, *Length, contents+size))return(0); + int iLength=*Length; + if(IS_MEM_UNSAFE(*Data, iLength, contents+size))return(0); } return size; } diff --git a/src/libuemf/uwmf.h b/src/libuemf/uwmf.h index 2237d2221..027de8e06 100644 --- a/src/libuemf/uwmf.h +++ b/src/libuemf/uwmf.h @@ -36,11 +36,11 @@ /* File: uwmf.h -Version: 0.0.11 -Date: 23-APR-2014 +Version: 0.0.12 +Date: 28-APR-2015 Author: David Mathog, Biology Division, Caltech email: mathog@caltech.edu -Copyright: 2014 David Mathog and California Institute of Technology (Caltech) +Copyright: 2015 David Mathog and California Institute of Technology (Caltech) */ #ifndef _UWMF_ @@ -2407,8 +2407,8 @@ int wmr_arc_points(U_RECT16 rclBox, U_POINT16 ArcStart, U_POINT16 ArcEn void U_BITMAPINFOHEADER_get(const char *Bmih, uint32_t *Size, int32_t *Width, int32_t *Height, uint32_t *Planes, uint32_t *BitCount, uint32_t *Compression, uint32_t *SizeImage, int32_t *XPelsPerMeter, int32_t *YPelsPerMeter, uint32_t *ClrUsed, uint32_t *ClrImportant); -void U_BITMAPCOREHEADER_get(const char *BmiCh, int32_t *Size, int32_t *Width, int32_t *Height, int32_t *BitCount); -int wget_DIB_params(const char *dib, const char **px, const U_RGBQUAD **ct, int32_t *numCt, +void U_BITMAPCOREHEADER_get(const char *BmiCh, uint32_t *Size, int32_t *Width, int32_t *Height, int32_t *BitCount); +int wget_DIB_params(const char *dib, const char **px, const U_RGBQUAD **ct, uint32_t *numCt, int32_t *width, int32_t *height, int32_t *colortype, int32_t *invert); int U_WMREOF_get(const char *contents); int U_WMRSETBKCOLOR_get(const char *contents, U_COLORREF *Color); diff --git a/src/libuemf/uwmf_endian.c b/src/libuemf/uwmf_endian.c index 38a321ad0..de0b3ef87 100644 --- a/src/libuemf/uwmf_endian.c +++ b/src/libuemf/uwmf_endian.c @@ -6,11 +6,11 @@ /* File: uwmf_endian.c -Version: 0.1.3 -Date: 27-MAR-2014 +Version: 0.1.4 +Date: 28-APR-2015 Author: David Mathog, Biology Division, Caltech email: mathog@caltech.edu -Copyright: 2014 David Mathog and California Institute of Technology (Caltech) +Copyright: 2015 David Mathog and California Institute of Technology (Caltech) */ #ifdef __cplusplus @@ -1470,21 +1470,24 @@ void U_WMRCREATEREGION_swap(char *record, int torev){ \param contents pointer to the buffer holding the entire EMF in memory \param length number of bytes in the buffer \param torev 1 for native to reversed, 0 for reversed to native + \param onerec 1 if this is operating on a single record instead of an entire file Normally this would be called immediately before writing the data to a file or immediately after reading the data from a file. */ -int U_wmf_endian(char *contents, size_t length, int torev){ - size_t off; +int U_wmf_endian(char *contents, size_t length, int torev, int onerec){ + size_t off=0; uint32_t OK, Size16; uint8_t iType; char *record; int recnum, offset; record = contents; - off = wmfheader_swap(record,torev); fflush(stdout); /* WMF header is not a normal record, handle it separately */ - record += off; - offset = off; + if(!onerec){ + off = wmfheader_swap(record,torev); fflush(stdout); /* WMF header is not a normal record, handle it separately */ + record += off; + offset = off; + } OK = 1; recnum = 1; /* used when debugging */ @@ -1759,6 +1762,7 @@ int U_wmf_endian(char *contents, size_t length, int torev){ record += 2*Size16; offset += 2*Size16; recnum++; + if(onerec)break; } //end of while return(1); } diff --git a/src/libuemf/uwmf_endian.h b/src/libuemf/uwmf_endian.h index 57fd4ae44..6ce7f1984 100644 --- a/src/libuemf/uwmf_endian.h +++ b/src/libuemf/uwmf_endian.h @@ -6,11 +6,11 @@ /* File: uwmf_endian.h -Version: 0.0.2 -Date: 26-NOV-2013 +Version: 0.0.3 +Date: 28-APR-2015 Author: David Mathog, Biology Division, Caltech email: mathog@caltech.edu -Copyright: 2013 David Mathog and California Institute of Technology (Caltech) +Copyright: 2015 David Mathog and California Institute of Technology (Caltech) */ #ifndef _UWMF_ENDIAN_ @@ -24,7 +24,7 @@ extern "C" { //! \cond // prototypes -int U_wmf_endian(char *contents, size_t length, int torev); +int U_wmf_endian(char *contents, size_t length, int torev, int onerec); //! \endcond #ifdef __cplusplus diff --git a/src/libuemf/uwmf_print.c b/src/libuemf/uwmf_print.c index dd460b2b0..d6d1b584e 100644 --- a/src/libuemf/uwmf_print.c +++ b/src/libuemf/uwmf_print.c @@ -6,11 +6,11 @@ /* File: uwmf_print.c -Version: 0.0.4 -Date: 05-FEB-2014 +Version: 0.0.6 +Date: 21-MAY-2015 Author: David Mathog, Biology Division, Caltech email: mathog@caltech.edu -Copyright: 2014 David Mathog and California Institute of Technology (Caltech) +Copyright: 2015 David Mathog and California Institute of Technology (Caltech) */ #ifdef __cplusplus @@ -1351,13 +1351,20 @@ int U_wmf_onerec_print(const char *contents, const char *blimit, int recnum, siz iType = *(uint8_t *)(contents + offsetof(U_METARECORD, iType ) ); -#if 1 - printf("%-30srecord:%5d type:%-4u offset:%8d rsize:%8u\n", - U_wmr_names(iType), recnum, iType, (int) off, (int) size); -#else /* show record checksums, this is NOT portable, result changes with endian type, useful for debugging */ - printf("%-30srecord:%5d type:%-4u offset:%8d size:%8u recchecksum:%u\n", - U_wmr_names(iType), recnum, iType, (int) off, (int) size, U_16_checksum((int16_t *)contents, size)); + uint32_t crc; +#if U_BYTE_SWAP + //This is a Big Endian machine, WMF crc values must be calculated on Little Endian form + char *swapbuf=malloc(size); + if(!swapbuf)return(-1); + memcpy(swapbuf,contents,size); + U_wmf_endian(swapbuf,size,1,1); // BE to LE + crc=lu_crc32(swapbuf,size); + free(swapbuf); +#else + crc=lu_crc32(contents,size); #endif + printf("%-30srecord:%5d type:%-4u offset:%8d rsize:%8u crc32:%8.8X\n", + U_wmr_names(iType), recnum, iType, (int) off, (int) size, crc); switch (iType) { -- cgit v1.2.3 From 25fa09178b7d0d0befa708e93ea5316ef381caa0 Mon Sep 17 00:00:00 2001 From: Krzysztof Kosi??ski Date: Fri, 22 May 2015 10:23:27 +0200 Subject: Update to 2Geom revision 2396 (bzr r14059.2.16) --- src/2geom/CMakeLists.txt | 12 +- src/2geom/Makefile_insert | 15 +- src/2geom/angle.h | 112 ++++-- src/2geom/bezier-curve.cpp | 36 +- src/2geom/bezier-curve.h | 14 +- src/2geom/bezier.cpp | 2 +- src/2geom/bezier.h | 6 +- src/2geom/cairo-path-sink.cpp | 4 +- src/2geom/circle-circle.cpp | 139 ------- src/2geom/circle.cpp | 246 ++++++++++-- src/2geom/circle.h | 72 +++- src/2geom/concepts.h | 10 + src/2geom/crossing.h | 2 +- src/2geom/curve.h | 11 +- src/2geom/curves.h | 1 - src/2geom/d2.h | 88 ++-- src/2geom/ellipse.cpp | 421 ++++++++++++++++--- src/2geom/ellipse.h | 118 +++++- src/2geom/elliptical-arc-from-sbasis.cpp | 345 ++++++++++++++++ src/2geom/elliptical-arc.cpp | 444 ++++++++++----------- src/2geom/elliptical-arc.h | 92 +++-- src/2geom/forward.h | 9 +- src/2geom/intersection-graph.cpp | 37 ++ src/2geom/intersection-graph.h | 5 + src/2geom/intersection.h | 20 +- src/2geom/interval.h | 17 +- src/2geom/line.cpp | 70 +++- src/2geom/line.h | 42 +- src/2geom/numeric/fitting-model.h | 2 +- src/2geom/path-intersection.h | 6 +- src/2geom/path-sink.cpp | 22 + src/2geom/path-sink.h | 9 +- src/2geom/path.cpp | 146 ++++++- src/2geom/path.h | 21 +- src/2geom/pathvector.cpp | 14 +- src/2geom/pathvector.h | 2 + src/2geom/point.cpp | 8 + src/2geom/point.h | 7 +- src/2geom/poly.cpp | 201 ---------- src/2geom/poly.h | 249 ------------ src/2geom/polynomial.cpp | 326 +++++++++++++++ src/2geom/polynomial.h | 262 ++++++++++++ src/2geom/quadtree.cpp | 286 ------------- src/2geom/quadtree.h | 105 ----- src/2geom/sbasis-curve.h | 1 + src/2geom/sbasis-poly.h | 2 +- src/2geom/sbasis-to-bezier.cpp | 14 +- src/2geom/svg-elliptical-arc.cpp | 275 ------------- src/2geom/svg-elliptical-arc.h | 280 ------------- src/2geom/svg-path-parser.cpp | 2 +- src/2geom/svg-path-parser.h | 1 + src/2geom/sweep-bounds.cpp | 157 ++++++++ src/2geom/sweep-bounds.h | 62 +++ src/2geom/sweep.cpp | 139 ------- src/2geom/sweep.h | 79 ---- src/2geom/sweeper.h | 220 ++++++++++ src/2geom/transforms.cpp | 26 +- src/2geom/transforms.h | 1 + src/extension/internal/wmf-print.cpp | 2 +- src/helper/geom-pathstroke.cpp | 130 ++---- src/livarot/PathCutting.cpp | 12 +- src/live_effects/lpe-circle_3pts.cpp | 3 +- src/live_effects/lpe-circle_with_radius.cpp | 10 +- src/live_effects/lpe-fillet-chamfer.cpp | 10 +- src/live_effects/lpe-jointype.cpp | 2 +- src/live_effects/lpe-offset.cpp | 4 +- src/live_effects/lpe-powerstroke.cpp | 94 +---- .../parameter/filletchamferpointarray.cpp | 1 - src/object-snapper.cpp | 6 +- src/sp-ellipse.cpp | 1 + src/svg/svg-path.cpp | 10 +- src/ui/tools/calligraphic-tool.cpp | 3 +- src/ui/tools/dropper-tool.cpp | 3 +- src/ui/tools/spray-tool.cpp | 3 +- src/ui/tools/tweak-tool.cpp | 3 +- 75 files changed, 3073 insertions(+), 2539 deletions(-) delete mode 100644 src/2geom/circle-circle.cpp create mode 100644 src/2geom/elliptical-arc-from-sbasis.cpp delete mode 100644 src/2geom/poly.cpp delete mode 100644 src/2geom/poly.h create mode 100644 src/2geom/polynomial.cpp create mode 100644 src/2geom/polynomial.h delete mode 100644 src/2geom/quadtree.cpp delete mode 100644 src/2geom/quadtree.h delete mode 100644 src/2geom/svg-elliptical-arc.cpp delete mode 100644 src/2geom/svg-elliptical-arc.h create mode 100644 src/2geom/sweep-bounds.cpp create mode 100644 src/2geom/sweep-bounds.h delete mode 100644 src/2geom/sweep.cpp delete mode 100644 src/2geom/sweep.h create mode 100644 src/2geom/sweeper.h (limited to 'src') diff --git a/src/2geom/CMakeLists.txt b/src/2geom/CMakeLists.txt index eb25074ef..d0c196f56 100644 --- a/src/2geom/CMakeLists.txt +++ b/src/2geom/CMakeLists.txt @@ -7,7 +7,6 @@ set(2geom_SRC bezier-curve.cpp bezier-utils.cpp cairo-path-sink.cpp - circle-circle.cpp circle.cpp # conic_section_clipper_impl.cpp # conicsec.cpp @@ -18,6 +17,7 @@ set(2geom_SRC d2-sbasis.cpp ellipse.cpp elliptical-arc.cpp + elliptical-arc-from-sbasis.cpp geom.cpp intersection-graph.cpp line.cpp @@ -29,8 +29,7 @@ set(2geom_SRC pathvector.cpp piecewise.cpp point.cpp - poly.cpp - quadtree.cpp + polynomial.cpp rect.cpp # recursive-bezier-intersection.cpp sbasis-2d.cpp @@ -43,8 +42,8 @@ set(2geom_SRC solve-bezier.cpp solve-bezier-one-d.cpp solve-bezier-parametric.cpp - svg-elliptical-arc.cpp svg-path-parser.cpp + svg-path-writer.cpp sweep.cpp toposweep.cpp transforms.cpp @@ -101,8 +100,7 @@ set(2geom_SRC piecewise.h point-ops.h point.h - poly.h - quadtree.h + polynomial.h ray.h rect.h region.h @@ -115,8 +113,8 @@ set(2geom_SRC sbasis.h shape.h solver.h - svg-elliptical-arc.h svg-path-parser.h + svg-path-writer.h sweep.h toposweep.h transforms.h diff --git a/src/2geom/Makefile_insert b/src/2geom/Makefile_insert index aeb0b20a1..01f48ab39 100644 --- a/src/2geom/Makefile_insert +++ b/src/2geom/Makefile_insert @@ -23,7 +23,6 @@ 2geom/cairo-path-sink.cpp \ 2geom/cairo-path-sink.h \ 2geom/choose.h \ - 2geom/circle-circle.cpp \ 2geom/circle.cpp \ 2geom/circle.h \ 2geom/circulator.h \ @@ -51,6 +50,7 @@ 2geom/ellipse.h \ 2geom/elliptical-arc.cpp \ 2geom/elliptical-arc.h \ + 2geom/elliptical-arc-from-sbasis.cpp \ 2geom/exception.h \ 2geom/forward.h \ 2geom/generic-interval.h \ @@ -84,10 +84,8 @@ 2geom/piecewise.h \ 2geom/point.cpp \ 2geom/point.h \ - 2geom/poly.cpp \ - 2geom/poly.h \ - 2geom/quadtree.cpp \ - 2geom/quadtree.h \ + 2geom/polynomial.cpp \ + 2geom/polynomial.h \ 2geom/ray.h \ 2geom/rect.cpp \ 2geom/rect.h \ @@ -110,14 +108,13 @@ 2geom/solve-bezier-one-d.cpp \ 2geom/solve-bezier-parametric.cpp \ 2geom/solver.h \ - 2geom/svg-elliptical-arc.cpp \ - 2geom/svg-elliptical-arc.h \ 2geom/svg-path-parser.cpp \ 2geom/svg-path-parser.h \ 2geom/svg-path-writer.cpp \ 2geom/svg-path-writer.h \ - 2geom/sweep.cpp \ - 2geom/sweep.h \ + 2geom/sweep-bounds.cpp \ + 2geom/sweep-bounds.h \ + 2geom/sweeper.h \ 2geom/toposweep.cpp \ 2geom/toposweep.h \ 2geom/transforms.cpp \ diff --git a/src/2geom/angle.h b/src/2geom/angle.h index 77ecd5eb4..9ece3b9fe 100644 --- a/src/2geom/angle.h +++ b/src/2geom/angle.h @@ -63,11 +63,13 @@ namespace Geom { */ class Angle : boost::additive< Angle + , boost::additive< Angle, Coord , boost::equality_comparable< Angle - > > + , boost::equality_comparable< Angle, Coord + > > > > { public: - Angle() : _angle(0) {} //added default constructor because of cython + Angle() : _angle(0) {} Angle(Coord v) : _angle(v) { _normalize(); } // this can be called implicitly explicit Angle(Point const &p) : _angle(atan2(p)) { _normalize(); } Angle(Point const &a, Point const &b) : _angle(angle_between(a, b)) { _normalize(); } @@ -82,9 +84,20 @@ public: _normalize(); return *this; } + Angle &operator+=(Coord a) { + *this += Angle(a); + return *this; + } + Angle &operator-=(Coord a) { + *this -= Angle(a); + return *this; + } bool operator==(Angle const &o) const { return _angle == o._angle; } + bool operator==(Coord c) const { + return _angle == Angle(c)._angle; + } /** @brief Get the angle as radians. * @return Number in range \f$[-\pi, \pi)\f$. */ @@ -136,12 +149,22 @@ public: private: void _normalize() { - _angle -= floor(_angle * (1.0/(2*M_PI))) * 2*M_PI; + _angle = std::fmod(_angle, 2*M_PI); + if (_angle < 0) _angle += 2*M_PI; + //_angle -= floor(_angle * (1.0/(2*M_PI))) * 2*M_PI; } Coord _angle; // this is always in [0, 2pi) friend class AngleInterval; }; +inline Angle distance(Angle const &a, Angle const &b) { + // the distance cannot be larger than M_PI. + Coord ac = a.radians0(); + Coord bc = b.radians0(); + Coord d = fabs(ac - bc); + return Angle(d > M_PI ? 2*M_PI - d : d); +} + /** @brief Directed angular interval. * * Wrapper for directed angles with defined start and end values. Useful e.g. for representing @@ -149,7 +172,11 @@ private: * in the interval (it is a closed interval). Angular intervals can also be interptered * as functions \f$f: [0, 1] \to [-\pi, \pi)\f$, which return the start angle for 0, * the end angle for 1, and interpolate linearly for other values. Note that such functions - * are not continuous if the interval contains the zero angle. + * are not continuous if the interval crosses the angle \f$\pi\f$. + * + * It is currently not possible to represent the full angle with this class. + * If you specify the same start and end angle, the interval will be treated as empty + * except for that value. * * This class is immutable - you cannot change the values of start and end angles * without creating a new instance of this class. @@ -158,39 +185,58 @@ private: */ class AngleInterval { public: + /** @brief Create an angular interval. + * @param s Starting angle + * @param e Ending angle + * @param cw Which direction the interval goes. True means that it goes + * in the direction of increasing angles, while false means in the direction + * of decreasing angles. */ AngleInterval(Angle const &s, Angle const &e, bool cw = false) : _start_angle(s), _end_angle(e), _sweep(cw) {} AngleInterval(double s, double e, bool cw = false) : _start_angle(s), _end_angle(e), _sweep(cw) {} - /** @brief Get the angular coordinate of the interval's initial point - * @return Angle in range \f$[0,2\pi)\f$ corresponding to the start of arc */ + + /// Get the start angle. Angle const &initialAngle() const { return _start_angle; } - /** @brief Get the angular coordinate of the interval's final point - * @return Angle in range \f$[0,2\pi)\f$ corresponding to the end of arc */ + /// Get the end angle. Angle const &finalAngle() const { return _end_angle; } + /// Check whether the interval contains only a single angle. bool isDegenerate() const { return initialAngle() == finalAngle(); } - /** @brief Get an angle corresponding to the specified time value. */ + + /// Get an angle corresponding to the specified time value. Angle angleAt(Coord t) const { Coord span = extent(); Angle ret = _start_angle.radians0() + span * (_sweep ? t : -t); return ret; } Angle operator()(Coord t) const { return angleAt(t); } -#if 0 - /** @brief Find an angle nearest to the specified time value. - * @param a Query angle - * @return If the interval contains the query angle, a number from the range [0, 1] - * such that a = angleAt(t); otherwise, 0 or 1, depending on which extreme - * angle is nearer. */ - Coord nearestAngle(Angle const &a) const { - Coord dist = distance(_start_angle, a, _sweep).radians0(); - Coord span = distance(_start_angle, _end_angle, _sweep).radians0(); - if (dist <= span) return dist / span; - else return distance_abs(_start_angle, a).radians0() > distance_abs(_end_angle, a).radians0() ? 1.0 : 0.0; + + /** @brief Compute a time value that would evaluate to the given angle. + * If the start and end angle are exactly the same, NaN will be returned. */ + Coord timeAtAngle(Angle const &a) const { + Coord ex = extent(); + Coord outex = 2*M_PI - ex; + if (_sweep) { + Angle midout = _start_angle - outex / 2; + Angle acmp = a - midout, scmp = _start_angle - midout; + if (acmp.radians0() >= scmp.radians0()) { + return (a - _start_angle).radians0() / ex; + } else { + return -(_start_angle - a).radians0() / ex; + } + } else { + Angle midout = _start_angle + outex / 2; + Angle acmp = a - midout, scmp = _start_angle - midout; + if (acmp.radians0() <= scmp.radians0()) { + return (_start_angle - a).radians0() / ex; + } else { + return -(a - _start_angle).radians0() / ex; + } + } } -#endif + /** @brief Check whether the interval includes the given angle. */ bool contains(Angle const &a) const { Coord s = _start_angle.radians0(); @@ -205,12 +251,22 @@ public: } } /** @brief Extent of the angle interval. - * @return Extent in range \f$[0, 2\pi)\f$ */ + * Equivalent to the absolute value of the sweep angle. + * @return Extent in range \f$[0, 2\pi)\f$. */ Coord extent() const { - Coord d = _end_angle - _start_angle; - if (!_sweep) d = -d; - if (d < 0) d += 2*M_PI; - return d; + return _sweep + ? (_end_angle - _start_angle).radians0() + : (_start_angle - _end_angle).radians0(); + } + /** @brief Get the sweep angle of the interval. + * This is the value you need to add to the initial angle to get the final angle. + * It is positive when sweep is true. Denoted as \f$\Delta\theta\f$ in the SVG + * elliptical arc implementation notes. */ + Coord sweepAngle() const { + Coord sa = _end_angle.radians0() - _start_angle.radians0(); + if (_sweep && sa < 0) sa += 2*M_PI; + if (!_sweep && sa > 0) sa -= 2*M_PI; + return sa; } protected: AngleInterval() {} @@ -308,6 +364,10 @@ bool arc_contains (double a, double sa, double ia, double ea) } // end namespace Geom +namespace std { +template <> class iterator_traits {}; +} + #endif // LIB2GEOM_SEEN_ANGLE_H /* diff --git a/src/2geom/bezier-curve.cpp b/src/2geom/bezier-curve.cpp index b81041f29..17221264b 100644 --- a/src/2geom/bezier-curve.cpp +++ b/src/2geom/bezier-curve.cpp @@ -143,9 +143,15 @@ BezierCurve::intersect(Curve const &other, Coord eps) const { std::vector result; - // optimization for the common case of no intersections - if (!boundsFast().intersects(other.boundsFast())) return result; + // in case we encounter an order-1 curve created from a vector + // or a degenerate elliptical arc + if (isLineSegment()) { + LineSegment ls(initialPoint(), finalPoint()); + result = ls.intersect(other); + return result; + } + // here we are sure that this curve is at least a quadratic Bezier BezierCurve const *bez = dynamic_cast(&other); if (bez) { std::vector > xs; @@ -154,10 +160,12 @@ BezierCurve::intersect(Curve const &other, Coord eps) const CurveIntersection x(*this, other, xs[i].first, xs[i].second); result.push_back(x); } - } else { - THROW_NOTIMPLEMENTED(); + return result; } + // pass other intersection types to the other curve + result = other.intersect(*this, eps); + transpose_in_place(result); return result; } @@ -252,6 +260,26 @@ Coord BezierCurveN<1>::nearestTime(Point const& p, Coord from, Coord to) const else return from + t*(to-from); } +template <> +std::vector BezierCurveN<1>::intersect(Curve const &other, Coord eps) const +{ + std::vector result; + + // only handle intersections with other LineSegments here + if (other.isLineSegment()) { + Line this_line(initialPoint(), finalPoint()); + Line other_line(other.initialPoint(), other.finalPoint()); + result = this_line.intersect(other_line); + filter_line_segment_intersections(result, true, true); + return result; + } + + // pass all other types to the other curve + result = other.intersect(*this, eps); + transpose_in_place(result); + return result; +} + template <> void BezierCurveN<1>::feed(PathSink &sink, bool moveto_initial) const { diff --git a/src/2geom/bezier-curve.h b/src/2geom/bezier-curve.h index 9b08466f8..636a263a7 100644 --- a/src/2geom/bezier-curve.h +++ b/src/2geom/bezier-curve.h @@ -69,6 +69,7 @@ public: /** @brief Get the control points. * @return Vector with order() + 1 control points. */ std::vector controlPoints() const { return bezier_points(inner); } + D2 const &fragment() const { return inner; } /** @brief Modify a control point. * @param ix The zero-based index of the point to modify. Note that the caller is responsible for checking that this value is <= order(). @@ -104,6 +105,7 @@ public: virtual Point initialPoint() const { return inner.at0(); } virtual Point finalPoint() const { return inner.at1(); } virtual bool isDegenerate() const { return inner.isConstant(0); } + virtual bool isLineSegment() const { return size() == 2; } virtual void setInitial(Point const &v) { setPoint(0, v); } virtual void setFinal(Point const &v) { setPoint(order(), v); } virtual Rect boundsFast() const { return *bounds_fast(inner); } @@ -145,7 +147,7 @@ public: virtual Coord nearestTime(Point const &p, Coord from = 0, Coord to = 1) const; virtual Coord length(Coord tolerance) const; virtual std::vector intersect(Curve const &other, Coord eps = EPSILON) const; - virtual Point pointAt(Coord t) const { return inner.valueAt(t); } + virtual Point pointAt(Coord t) const { return inner.pointAt(t); } virtual std::vector pointAndDerivatives(Coord t, unsigned n) const { return inner.valueAndDerivatives(t, n); } @@ -229,6 +231,10 @@ public: BezierCurveN(sx.second, sy.second)); } + virtual bool isLineSegment() const { + return size() == 2; + } + virtual Curve *duplicate() const { return new BezierCurveN(*this); } @@ -251,6 +257,10 @@ public: virtual Coord nearestTime(Point const &p, Coord from = 0, Coord to = 1) const { return BezierCurve::nearestTime(p, from, to); } + virtual std::vector intersect(Curve const &other, Coord eps = EPSILON) const { + // call super. this is implemented only to allow specializations + return BezierCurve::intersect(other, eps); + } virtual void feed(PathSink &sink, bool moveto_initial) const { // call super. this is implemented only to allow specializations BezierCurve::feed(sink, moveto_initial); @@ -281,8 +291,10 @@ Curve *BezierCurveN::derivative() const { } // optimized specializations +template <> inline bool BezierCurveN<1>::isLineSegment() const { return true; } template <> Curve *BezierCurveN<1>::derivative() const; template <> Coord BezierCurveN<1>::nearestTime(Point const &, Coord, Coord) const; +template <> std::vector BezierCurveN<1>::intersect(Curve const &, Coord) const; template <> void BezierCurveN<1>::feed(PathSink &sink, bool moveto_initial) const; template <> void BezierCurveN<2>::feed(PathSink &sink, bool moveto_initial) const; template <> void BezierCurveN<3>::feed(PathSink &sink, bool moveto_initial) const; diff --git a/src/2geom/bezier.cpp b/src/2geom/bezier.cpp index 45496b75c..0c9d12c3b 100644 --- a/src/2geom/bezier.cpp +++ b/src/2geom/bezier.cpp @@ -210,7 +210,7 @@ Bezier &Bezier::operator-=(Bezier const &other) -Bezier multiply(Bezier const &f, Bezier const &g) +Bezier operator*(Bezier const &f, Bezier const &g) { unsigned m = f.order(); unsigned n = g.order(); diff --git a/src/2geom/bezier.h b/src/2geom/bezier.h index be7df1a6b..c41c2b3a7 100644 --- a/src/2geom/bezier.h +++ b/src/2geom/bezier.h @@ -308,7 +308,11 @@ public: void bezier_to_sbasis (SBasis &sb, Bezier const &bz); -Bezier multiply(Bezier const &f, Bezier const &g); +Bezier operator*(Bezier const &f, Bezier const &g); +inline Bezier multiply(Bezier const &f, Bezier const &g) { + Bezier result = f * g; + return result; +} inline Bezier reverse(const Bezier & a) { Bezier result = Bezier(Bezier::Order(a)); diff --git a/src/2geom/cairo-path-sink.cpp b/src/2geom/cairo-path-sink.cpp index f327bf04d..244a08ba4 100644 --- a/src/2geom/cairo-path-sink.cpp +++ b/src/2geom/cairo-path-sink.cpp @@ -31,7 +31,7 @@ #include #include <2geom/cairo-path-sink.h> -#include <2geom/svg-elliptical-arc.h> +#include <2geom/elliptical-arc.h> namespace Geom { @@ -71,7 +71,7 @@ void CairoPathSink::quadTo(Point const &p1, Point const &p2) void CairoPathSink::arcTo(double rx, double ry, double angle, bool large_arc, bool sweep, Point const &p) { - SVGEllipticalArc arc(_current_point, rx, ry, angle, large_arc, sweep, p); + EllipticalArc arc(_current_point, rx, ry, angle, large_arc, sweep, p); // Cairo only does circular arcs. // To do elliptical arcs, we must use a temporary transform. Affine uct = arc.unitCircleTransform(); diff --git a/src/2geom/circle-circle.cpp b/src/2geom/circle-circle.cpp deleted file mode 100644 index 134fa33a2..000000000 --- a/src/2geom/circle-circle.cpp +++ /dev/null @@ -1,139 +0,0 @@ -/* circle_circle_intersection() * - * Determine the points where 2 circles in a common plane intersect. - * - * int circle_circle_intersection( - * // center and radius of 1st circle - * double x0, double y0, double r0, - * // center and radius of 2nd circle - * double x1, double y1, double r1, - * // 1st intersection point - * double *xi, double *yi, - * // 2nd intersection point - * double *xi_prime, double *yi_prime) - * - * This is a public domain work. 3/26/2005 Tim Voght - * Ported to lib2geom, 2006 Nathan Hurst - * - * Copyright 2006 Nathan Hurst - * - * This library is free software; you can redistribute it and/or - * modify it either under the terms of the GNU Lesser General Public - * License version 2.1 as published by the Free Software Foundation - * (the "LGPL") or, at your option, under the terms of the Mozilla - * Public License Version 1.1 (the "MPL"). If you do not alter this - * notice, a recipient may use your version of this file under either - * the MPL or the LGPL. - * - * You should have received a copy of the LGPL along with this library - * in the file COPYING-LGPL-2.1; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * You should have received a copy of the MPL along with this library - * in the file COPYING-MPL-1.1 - * - * The contents of this file are subject to the Mozilla Public License - * Version 1.1 (the "License"); you may not use this file except in - * compliance with the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY - * OF ANY KIND, either express or implied. See the LGPL or the MPL for - * the specific language governing rights and limitations. - * - */ -#include -#include -#include <2geom/point.h> - -namespace Geom{ - -int circle_circle_intersection(Point X0, double r0, - Point X1, double r1, - Point & p0, Point & p1) -{ - /* dx and dy are the vertical and horizontal distances between - * the circle centers. - */ - Point D = X1 - X0; - - /* Determine the straight-line distance between the centers. */ - double d = L2(D); - - /* Check for solvability. */ - if (d > (r0 + r1)) - { - /* no solution. circles do not intersect. */ - return 0; - } - if (d <= fabs(r0 - r1)) - { - /* no solution. one circle is contained in the other */ - return 1; - } - - /* 'point 2' is the point where the line through the circle - * intersection points crosses the line between the circle - * centers. - */ - - /* Determine the distance from point 0 to point 2. */ - double a = ((r0*r0) - (r1*r1) + (d*d)) / (2.0 * d) ; - - /* Determine the coordinates of point 2. */ - Point p2 = X0 + D * (a/d); - - /* Determine the distance from point 2 to either of the - * intersection points. - */ - double h = sqrt((r0*r0) - (a*a)); - - /* Now determine the offsets of the intersection points from - * point 2. - */ - Point r = (h/d)*rot90(D); - - /* Determine the absolute intersection points. */ - p0 = p2 + r; - p1 = p2 - r; - - return 2; -} - -}; - - -#ifdef TEST - -void run_test(double x0, double y0, double r0, - double x1, double y1, double r1) -{ - printf("x0=%F, y0=%F, r0=%F, x1=%F, y1=%F, r1=%F :\n", - x0, y0, r0, x1, y1, r1); - Geom::Point p0, p1; - Geom::circle_circle_intersection(Geom::Point(x0, y0), r0, - Geom::Point(x1, y1), r1, - p0, p1); - printf(" x3=%F, y3=%F, x3_prime=%F, y3_prime=%F\n", - p0[0], p0[1], p1[0], p1[1]); -} - -int main(void) -{ - /* Add more! */ - run_test(-1.0, -1.0, 1.5, 1.0, 1.0, 2.0); - run_test(1.0, -1.0, 1.5, -1.0, 1.0, 2.0); - run_test(-1.0, 1.0, 1.5, 1.0, -1.0, 2.0); - run_test(1.0, 1.0, 1.5, -1.0, -1.0, 2.0); - exit(0); -} -#endif - -/* - Local Variables: - mode:c++ - c-file-style:"stroustrup" - c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) - indent-tabs-mode:nil - fill-column:99 - End: -*/ -// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 : diff --git a/src/2geom/circle.cpp b/src/2geom/circle.cpp index 0b1dddc8e..ec59bbe4a 100644 --- a/src/2geom/circle.cpp +++ b/src/2geom/circle.cpp @@ -33,12 +33,19 @@ #include <2geom/circle.h> #include <2geom/ellipse.h> -#include <2geom/svg-elliptical-arc.h> +#include <2geom/elliptical-arc.h> #include <2geom/numeric/fitting-tool.h> #include <2geom/numeric/fitting-model.h> namespace Geom { +Rect Circle::boundsFast() const +{ + Point rr(_radius, _radius); + Rect bbox(_center - rr, _center + rr); + return bbox; +} + void Circle::setCoefficients(Coord A, Coord B, Coord C, Coord D) { if (A == 0) { @@ -62,44 +69,197 @@ void Circle::setCoefficients(Coord A, Coord B, Coord C, Coord D) _radius = std::sqrt(r2); } +void Circle::coefficients(Coord &A, Coord &B, Coord &C, Coord &D) const +{ + A = 1; + B = -2 * _center[X]; + C = -2 * _center[Y]; + D = _center[X] * _center[X] + _center[Y] * _center[Y] - _radius * _radius; +} -void Circle::fit(std::vector const& points) +std::vector Circle::coefficients() const { - size_t sz = points.size(); - if (sz < 2) { - THROW_RANGEERROR("fitting error: too few points passed"); + std::vector c(4); + coefficients(c[0], c[1], c[2], c[3]); + return c; +} + + +Zoom Circle::unitCircleTransform() const +{ + Zoom ret(_radius, _center / _radius); + return ret; +} + +Zoom Circle::inverseUnitCircleTransform() const +{ + if (_radius == 0) { + THROW_RANGEERROR("degenerate circle does not have an inverse unit circle transform"); } - if (sz == 2) { - _center = points[0] * 0.5 + points[1] * 0.5; - _radius = distance(points[0], points[1]) / 2; - return; + + Zoom ret(1/_radius, Translate(-_center)); + return ret; +} + + +Point Circle::pointAt(Coord t) const { + return _center + Point::polar(t) * _radius; +} + +Coord Circle::valueAt(Coord t, Dim2 d) const { + Coord delta = (d == X ? std::cos(t) : std::sin(t)); + return _center[d] + delta * _radius; +} + +Coord Circle::timeAt(Point const &p) const { + return atan2(p - _center); +} + +Coord Circle::nearestTime(Point const &p) const { + if (_center == p) return 0; + return timeAt(p); +} + +bool Circle::contains(Rect const &r) const +{ + for (unsigned i = 0; i < 4; ++i) { + if (!contains(r.corner(i))) return false; } + return true; +} - NL::LFMCircle model; - NL::least_squeares_fitter fitter(model, sz); +bool Circle::contains(Circle const &other) const +{ + Coord cdist = distance(_center, other._center); + Coord rdist = fabs(_radius - other._radius); + return cdist <= rdist; +} - for (size_t i = 0; i < sz; ++i) { - fitter.append(points[i]); +bool Circle::intersects(Line const &l) const +{ + // http://mathworld.wolfram.com/Circle-LineIntersection.html + Coord dr = l.versor().length(); + Coord r = _radius; + Coord D = cross(l.initialPoint(), l.finalPoint()); + Coord delta = r*r * dr*dr - D*D; + if (delta >= 0) return true; + return false; +} + +bool Circle::intersects(Circle const &other) const +{ + Coord cdist = distance(_center, other._center); + Coord rsum = _radius + other._radius; + return cdist <= rsum; +} + + +std::vector Circle::intersect(Line const &l) const +{ + // http://mathworld.wolfram.com/Circle-LineIntersection.html + Coord dr = l.versor().length(); + Coord dx = l.versor().x(); + Coord dy = l.versor().y(); + Coord D = cross(l.initialPoint() - _center, l.finalPoint() - _center); + Coord delta = _radius*_radius * dr*dr - D*D; + + std::vector result; + if (delta < 0) return result; + if (delta == 0) { + Coord ix = (D*dy) / (dr*dr); + Coord iy = (-D*dx) / (dr*dr); + Point ip(ix, iy); ip += _center; + result.push_back(ShapeIntersection(timeAt(ip), l.timeAt(ip), ip)); + return result; } - fitter.update(); - NL::Vector z(sz, 0.0); - model.instance(*this, fitter.result(z)); + Coord sqrt_delta = std::sqrt(delta); + Coord signmod = dy < 0 ? -1 : 1; + + Coord i1x = (D*dy + signmod * dx * sqrt_delta) / (dr*dr); + Coord i1y = (-D*dx + fabs(dy) * sqrt_delta) / (dr*dr); + Point i1p(i1x, i1y); i1p += _center; + + Coord i2x = (D*dy - signmod * dx * sqrt_delta) / (dr*dr); + Coord i2y = (-D*dx - fabs(dy) * sqrt_delta) / (dr*dr); + Point i2p(i2x, i2y); i2p += _center; + + result.push_back(ShapeIntersection(timeAt(i1p), l.timeAt(i1p), i1p)); + result.push_back(ShapeIntersection(timeAt(i2p), l.timeAt(i2p), i2p)); + return result; +} + +std::vector Circle::intersect(LineSegment const &l) const +{ + std::vector result = intersect(Line(l)); + filter_line_segment_intersections(result); + return result; +} + +std::vector Circle::intersect(Circle const &other) const +{ + std::vector result; + + if (*this == other) { + THROW_INFINITESOLUTIONS(); + } + if (contains(other)) return result; + if (!intersects(other)) return result; + + // See e.g. http://mathworld.wolfram.com/Circle-CircleIntersection.html + // Basically, we figure out where is the third point of a triangle + // with two points in the centers and with edge lengths equal to radii + Point cv = other._center - _center; + Coord d = cv.length(); + Coord R = radius(), r = other.radius(); + + if (d == R + r) { + Point px = lerp(R / d, _center, other._center); + Coord T = timeAt(px), t = other.timeAt(px); + result.push_back(ShapeIntersection(T, t, px)); + return result; + } + + // q is the distance along the line between centers to the perpendicular line + // that goes through both intersections. + Coord q = (d*d - r*r + R*R) / (2*d); + Point qp = lerp(q/d, _center, other._center); + + // The triangle given by the points: + // _center, qp, intersection + // is a right triangle. Determine the distance between qp and intersection + // using the Pythagorean theorem. + Coord h = std::sqrt(R*R - q*q); + Point qd = (h/d) * cv.cw(); + + // now compute the intersection points + Point x1 = qp + qd; + Point x2 = qp - qd; + + result.push_back(ShapeIntersection(timeAt(x1), other.timeAt(x1), x1)); + result.push_back(ShapeIntersection(timeAt(x2), other.timeAt(x2), x2)); + return result; } /** @param inner a point whose angle with the circle center is inside the angle that the arc spans */ EllipticalArc * -Circle::arc(Point const& initial, Point const& inner, Point const& final, - bool svg_compliant) +Circle::arc(Point const& initial, Point const& inner, Point const& final) const { // TODO native implementation! Ellipse e(_center[X], _center[Y], _radius, _radius, 0); - return e.arc(initial, inner, final, svg_compliant); + return e.arc(initial, inner, final); +} + +bool Circle::operator==(Circle const &other) const +{ + if (_center != other._center) return false; + if (_radius != other._radius) return false; + return true; } -D2 Circle::toSBasis() +D2 Circle::toSBasis() const { D2 B; Linear bo = Linear(0, 2 * M_PI); @@ -112,22 +272,52 @@ D2 Circle::toSBasis() return B; } -void -Circle::getPath(PathVector &path_out) { - Path pb; - D2 B = toSBasis(); +void Circle::fit(std::vector const& points) +{ + size_t sz = points.size(); + if (sz < 2) { + THROW_RANGEERROR("fitting error: too few points passed"); + } + if (sz == 2) { + _center = points[0] * 0.5 + points[1] * 0.5; + _radius = distance(points[0], points[1]) / 2; + return; + } + + NL::LFMCircle model; + NL::least_squeares_fitter fitter(model, sz); - pb.append(SBasisCurve(B)); + for (size_t i = 0; i < sz; ++i) { + fitter.append(points[i]); + } + fitter.update(); - path_out.push_back(pb); + NL::Vector z(sz, 0.0); + model.instance(*this, fitter.result(z)); } -} // end namespace Geom - +bool are_near(Circle const &a, Circle const &b, Coord eps) +{ + // to check whether no point on a is further than eps from b, + // we check two things: + // 1. if radii differ by more than eps, there is definitely a point that fails + // 2. if they differ by less, we check the centers. They have to be closer + // together if the radius differs, since the maximum distance will be + // equal to sum of radius difference and distance between centers. + if (!are_near(a.radius(), b.radius(), eps)) return false; + Coord adjusted_eps = eps - fabs(a.radius() - b.radius()); + return are_near(a.center(), b.center(), adjusted_eps); +} +std::ostream &operator<<(std::ostream &out, Circle const &c) +{ + out << "Circle(" << c.center() << ", " << format_coord_nice(c.radius()) << ")"; + return out; +} +} // end namespace Geom /* Local Variables: diff --git a/src/2geom/circle.h b/src/2geom/circle.h index 3c2115b12..c42cb7f80 100644 --- a/src/2geom/circle.h +++ b/src/2geom/circle.h @@ -34,8 +34,10 @@ #ifndef LIB2GEOM_SEEN_CIRCLE_H #define LIB2GEOM_SEEN_CIRCLE_H -#include <2geom/point.h> #include <2geom/forward.h> +#include <2geom/intersection.h> +#include <2geom/point.h> +#include <2geom/rect.h> #include <2geom/transforms.h> namespace Geom { @@ -45,10 +47,11 @@ class EllipticalArc; /** @brief Set of all points at a fixed distance from the center * @ingroup Shapes */ class Circle - : MultipliableNoncommutative< Circle, Translate + : boost::equality_comparable1< Circle + , MultipliableNoncommutative< Circle, Translate , MultipliableNoncommutative< Circle, Rotate , MultipliableNoncommutative< Circle, Zoom - > > > + > > > > { Point _center; Coord _radius; @@ -66,28 +69,51 @@ public: setCoefficients(A, B, C, D); } - // build a circle by its implicit equation: - // Ax^2 + Ay^2 + Bx + Cy + D = 0 - void setCoefficients(Coord A, Coord B, Coord C, Coord D); - - /** @brief Fit the circle to the passed points using the least squares method. - * @param points Samples at the perimeter of the circle */ - void fit(std::vector const &points); - - EllipticalArc * - arc(Point const& initial, Point const& inner, Point const& final, - bool svg_compliant = true); - - D2 toSBasis(); - void getPath(PathVector &path_out); + // Construct the unique circle passing through three points. + //Circle(Point const &a, Point const &b, Point const &c); Point center() const { return _center; } Coord center(Dim2 d) const { return _center[d]; } Coord radius() const { return _radius; } + Coord area() const { return M_PI * _radius * _radius; } void setCenter(Point const &p) { _center = p; } void setRadius(Coord c) { _radius = c; } + Rect boundsFast() const; + Rect boundsExact() const { return boundsFast(); } + + Point pointAt(Coord t) const; + Coord valueAt(Coord t, Dim2 d) const; + Coord timeAt(Point const &p) const; + Coord nearestTime(Point const &p) const; + + bool contains(Point const &p) const { return distance(p, _center) <= _radius; } + bool contains(Rect const &other) const; + bool contains(Circle const &other) const; + + bool intersects(Line const &l) const; + bool intersects(LineSegment const &l) const; + bool intersects(Circle const &other) const; + + std::vector intersect(Line const &other) const; + std::vector intersect(LineSegment const &other) const; + std::vector intersect(Circle const &other) const; + + // build a circle by its implicit equation: + // Ax^2 + Ay^2 + Bx + Cy + D = 0 + void setCoefficients(Coord A, Coord B, Coord C, Coord D); + void coefficients(Coord &A, Coord &B, Coord &C, Coord &D) const; + std::vector coefficients() const; + + Zoom unitCircleTransform() const; + Zoom inverseUnitCircleTransform() const; + + EllipticalArc * + arc(Point const& initial, Point const& inner, Point const& final) const; + + D2 toSBasis() const; + Circle &operator*=(Translate const &t) { _center *= t; return *this; @@ -100,8 +126,20 @@ public: _radius *= z.scale(); return *this; } + + bool operator==(Circle const &other) const; + + /** @brief Fit the circle to the passed points using the least squares method. + * @param points Samples at the perimeter of the circle */ + void fit(std::vector const &points); }; +bool are_near(Circle const &a, Circle const &b, Coord eps=EPSILON); + +std::ostream &operator<<(std::ostream &out, Circle const &c); + +//bool are_near(Circle const &a, Circle const &b, Coord eps = EPSILON); + } // end namespace Geom #endif // LIB2GEOM_SEEN_CIRCLE_H diff --git a/src/2geom/concepts.h b/src/2geom/concepts.h index f571ddc60..7bc1bc0fd 100644 --- a/src/2geom/concepts.h +++ b/src/2geom/concepts.h @@ -130,6 +130,16 @@ struct ShapeConcept { template inline T portion(const T& t, const Interval& i) { return portion(t, i.min(), i.max()); } +template +struct EqualityComparableConcept { + T a, b; + bool bool_; + void constaints() { + bool_ = (a == b); + bool_ = (a != b); + } +}; + template struct NearConcept { T a, b; diff --git a/src/2geom/crossing.h b/src/2geom/crossing.h index be41fe893..425fa58f5 100644 --- a/src/2geom/crossing.h +++ b/src/2geom/crossing.h @@ -38,7 +38,7 @@ #include #include <2geom/rect.h> -#include <2geom/sweep.h> +#include <2geom/sweep-bounds.h> #include #include <2geom/pathvector.h> diff --git a/src/2geom/curve.h b/src/2geom/curve.h index 893dc6bdb..7da0d17a0 100644 --- a/src/2geom/curve.h +++ b/src/2geom/curve.h @@ -94,6 +94,9 @@ public: * no other points (its value set contains only one element). */ virtual bool isDegenerate() const = 0; + /// Check whether the curve is a line segment. + virtual bool isLineSegment() const { return false; } + /** @brief Get the interval of allowed time values. * @return \f$[0, 1]\f$ */ virtual Interval timeRange() const { @@ -294,13 +297,7 @@ public: * derivative could be found. * @param t Time value * @param n The maximum order of derivative to consider - * @return Unit tangent vector \f$\mathbf{v}(t)\f$ - * @bug This method might currently break for the case of t being exactly 1. A workaround - * is to reverse the curve and use the negated unit tangent at 0 like this: - * @code - Curve *c_reverse = c.reverse(); - Point tangent = - c_reverse->unitTangentAt(0); - delete c_reverse; @endcode */ + * @return Unit tangent vector \f$\mathbf{v}(t)\f$ */ virtual Point unitTangentAt(Coord t, unsigned n = 3) const; /** @brief Convert the curve to a symmetric power basis polynomial. diff --git a/src/2geom/curves.h b/src/2geom/curves.h index 6022c71d8..46fb6d973 100644 --- a/src/2geom/curves.h +++ b/src/2geom/curves.h @@ -38,7 +38,6 @@ #include <2geom/sbasis-curve.h> #include <2geom/bezier-curve.h> #include <2geom/elliptical-arc.h> -#include <2geom/svg-elliptical-arc.h> #endif // LIB2GEOM_SEEN_CURVES_H diff --git a/src/2geom/d2.h b/src/2geom/d2.h index 714319f99..bf764539d 100644 --- a/src/2geom/d2.h +++ b/src/2geom/d2.h @@ -33,7 +33,7 @@ #define LIB2GEOM_SEEN_D2_H #include -#include +#include #include #include <2geom/point.h> #include <2geom/interval.h> @@ -107,30 +107,36 @@ class D2{ //IMPL: FragmentConcept typedef Point output_type; bool isZero(double eps=EPSILON) const { - boost::function_requires >(); + BOOST_CONCEPT_ASSERT((FragmentConcept)); return f[X].isZero(eps) && f[Y].isZero(eps); } bool isConstant(double eps=EPSILON) const { - boost::function_requires >(); + BOOST_CONCEPT_ASSERT((FragmentConcept)); return f[X].isConstant(eps) && f[Y].isConstant(eps); } bool isFinite() const { - boost::function_requires >(); + BOOST_CONCEPT_ASSERT((FragmentConcept)); return f[X].isFinite() && f[Y].isFinite(); } Point at0() const { - boost::function_requires >(); + BOOST_CONCEPT_ASSERT((FragmentConcept)); return Point(f[X].at0(), f[Y].at0()); } Point at1() const { - boost::function_requires >(); + BOOST_CONCEPT_ASSERT((FragmentConcept)); return Point(f[X].at1(), f[Y].at1()); } + Point pointAt(double t) const { + BOOST_CONCEPT_ASSERT((FragmentConcept)); + return (*this)(t); + } Point valueAt(double t) const { - boost::function_requires >(); + // TODO: remove this alias + BOOST_CONCEPT_ASSERT((FragmentConcept)); return (*this)(t); } std::vector valueAndDerivatives(double t, unsigned n) const { + BOOST_CONCEPT_ASSERT((FragmentConcept)); std::vector x = f[X].valueAndDerivatives(t, n), y = f[Y].valueAndDerivatives(t, n); // always returns a vector of size n+1 std::vector res(n+1); @@ -140,7 +146,7 @@ class D2{ return res; } D2 toSBasis() const { - boost::function_requires >(); + BOOST_CONCEPT_ASSERT((FragmentConcept)); return D2(f[X].toSBasis(), f[Y].toSBasis()); } @@ -149,33 +155,33 @@ class D2{ }; template inline D2 reverse(const D2 &a) { - boost::function_requires >(); + BOOST_CONCEPT_ASSERT((FragmentConcept)); return D2(reverse(a[X]), reverse(a[Y])); } template inline D2 portion(const D2 &a, Coord f, Coord t) { - boost::function_requires >(); + BOOST_CONCEPT_ASSERT((FragmentConcept)); return D2(portion(a[X], f, t), portion(a[Y], f, t)); } template inline D2 portion(const D2 &a, Interval i) { - boost::function_requires >(); + BOOST_CONCEPT_ASSERT((FragmentConcept)); return D2(portion(a[X], i), portion(a[Y], i)); } -//IMPL: boost::EqualityComparableConcept +//IMPL: EqualityComparableConcept template inline bool operator==(D2 const &a, D2 const &b) { - boost::function_requires >(); + BOOST_CONCEPT_ASSERT((EqualityComparableConcept)); return a[0]==b[0] && a[1]==b[1]; } template inline bool operator!=(D2 const &a, D2 const &b) { - boost::function_requires >(); + BOOST_CONCEPT_ASSERT((EqualityComparableConcept)); return a[0]!=b[0] || a[1]!=b[1]; } @@ -183,7 +189,7 @@ operator!=(D2 const &a, D2 const &b) { template inline bool are_near(D2 const &a, D2 const &b, double tol) { - boost::function_requires >(); + BOOST_CONCEPT_ASSERT((NearConcept)); return are_near(a[0], b[0], tol) && are_near(a[1], b[1], tol); } @@ -191,7 +197,7 @@ are_near(D2 const &a, D2 const &b, double tol) { template inline D2 operator+(D2 const &a, D2 const &b) { - boost::function_requires >(); + BOOST_CONCEPT_ASSERT((AddableConcept)); D2 r; for(unsigned i = 0; i < 2; i++) @@ -201,7 +207,7 @@ operator+(D2 const &a, D2 const &b) { template inline D2 operator-(D2 const &a, D2 const &b) { - boost::function_requires >(); + BOOST_CONCEPT_ASSERT((AddableConcept)); D2 r; for(unsigned i = 0; i < 2; i++) @@ -211,7 +217,7 @@ operator-(D2 const &a, D2 const &b) { template inline D2 operator+=(D2 &a, D2 const &b) { - boost::function_requires >(); + BOOST_CONCEPT_ASSERT((AddableConcept)); for(unsigned i = 0; i < 2; i++) a[i] += b[i]; @@ -220,7 +226,7 @@ operator+=(D2 &a, D2 const &b) { template inline D2 operator-=(D2 &a, D2 const & b) { - boost::function_requires >(); + BOOST_CONCEPT_ASSERT((AddableConcept)); for(unsigned i = 0; i < 2; i++) a[i] -= b[i]; @@ -231,7 +237,7 @@ operator-=(D2 &a, D2 const & b) { template inline D2 operator-(D2 const & a) { - boost::function_requires >(); + BOOST_CONCEPT_ASSERT((ScalableConcept)); D2 r; for(unsigned i = 0; i < 2; i++) r[i] = -a[i]; @@ -240,7 +246,7 @@ operator-(D2 const & a) { template inline D2 operator*(D2 const & a, Point const & b) { - boost::function_requires >(); + BOOST_CONCEPT_ASSERT((ScalableConcept)); D2 r; for(unsigned i = 0; i < 2; i++) @@ -250,7 +256,7 @@ operator*(D2 const & a, Point const & b) { template inline D2 operator/(D2 const & a, Point const & b) { - boost::function_requires >(); + BOOST_CONCEPT_ASSERT((ScalableConcept)); //TODO: b==0? D2 r; for(unsigned i = 0; i < 2; i++) @@ -260,7 +266,7 @@ operator/(D2 const & a, Point const & b) { template inline D2 operator*=(D2 &a, Point const & b) { - boost::function_requires >(); + BOOST_CONCEPT_ASSERT((ScalableConcept)); for(unsigned i = 0; i < 2; i++) a[i] *= b[i]; @@ -269,7 +275,7 @@ operator*=(D2 &a, Point const & b) { template inline D2 operator/=(D2 &a, Point const & b) { - boost::function_requires >(); + BOOST_CONCEPT_ASSERT((ScalableConcept)); //TODO: b==0? for(unsigned i = 0; i < 2; i++) a[i] /= b[i]; @@ -287,8 +293,8 @@ inline D2 operator/=(D2 & a, double b) { a[0] /= b; a[1] /= b; return a; } template D2 operator*(D2 const &v, Affine const &m) { - boost::function_requires >(); - boost::function_requires >(); + BOOST_CONCEPT_ASSERT((AddableConcept)); + BOOST_CONCEPT_ASSERT((ScalableConcept)); D2 ret; for(unsigned i = 0; i < 2; i++) ret[i] = v[X] * m[i] + v[Y] * m[i + 2] + m[i + 4]; @@ -299,7 +305,7 @@ D2 operator*(D2 const &v, Affine const &m) { template inline D2 operator*(D2 const & a, T const & b) { - boost::function_requires >(); + BOOST_CONCEPT_ASSERT((MultiplicableConcept)); D2 ret; for(unsigned i = 0; i < 2; i++) ret[i] = a[i] * b; @@ -312,7 +318,7 @@ operator*(D2 const & a, T const & b) { template inline D2 operator+(D2 const & a, Point b) { - boost::function_requires >(); + BOOST_CONCEPT_ASSERT((OffsetableConcept)); D2 r; for(unsigned i = 0; i < 2; i++) r[i] = a[i] + b[i]; @@ -321,7 +327,7 @@ operator+(D2 const & a, Point b) { template inline D2 operator-(D2 const & a, Point b) { - boost::function_requires >(); + BOOST_CONCEPT_ASSERT((OffsetableConcept)); D2 r; for(unsigned i = 0; i < 2; i++) r[i] = a[i] - b[i]; @@ -330,7 +336,7 @@ operator-(D2 const & a, Point b) { template inline D2 operator+=(D2 & a, Point b) { - boost::function_requires >(); + BOOST_CONCEPT_ASSERT((OffsetableConcept)); for(unsigned i = 0; i < 2; i++) a[i] += b[i]; return a; @@ -338,7 +344,7 @@ operator+=(D2 & a, Point b) { template inline D2 operator-=(D2 & a, Point b) { - boost::function_requires >(); + BOOST_CONCEPT_ASSERT((OffsetableConcept)); for(unsigned i = 0; i < 2; i++) a[i] -= b[i]; return a; @@ -347,8 +353,8 @@ operator-=(D2 & a, Point b) { template inline T dot(D2 const & a, D2 const & b) { - boost::function_requires >(); - boost::function_requires >(); + BOOST_CONCEPT_ASSERT((AddableConcept)); + BOOST_CONCEPT_ASSERT((MultiplicableConcept)); T r; for(unsigned i = 0; i < 2; i++) @@ -362,8 +368,8 @@ dot(D2 const & a, D2 const & b) { template inline T dot(D2 const & a, Point const & b) { - boost::function_requires >(); - boost::function_requires >(); + BOOST_CONCEPT_ASSERT((AddableConcept)); + BOOST_CONCEPT_ASSERT((ScalableConcept)); T r; for(unsigned i = 0; i < 2; i++) { @@ -378,8 +384,8 @@ dot(D2 const & a, Point const & b) { template inline T cross(D2 const & a, D2 const & b) { - boost::function_requires >(); - boost::function_requires >(); + BOOST_CONCEPT_ASSERT((ScalableConcept)); + BOOST_CONCEPT_ASSERT((MultiplicableConcept)); return a[1] * b[0] - a[0] * b[1]; } @@ -389,7 +395,7 @@ cross(D2 const & a, D2 const & b) { template inline D2 rot90(D2 const & a) { - boost::function_requires >(); + BOOST_CONCEPT_ASSERT((ScalableConcept)); return D2(-a[Y], a[X]); } @@ -468,17 +474,17 @@ namespace Geom { //Some D2 Fragment implementation which requires rect: template OptRect bounds_fast(const D2 &a) { - boost::function_requires >(); + BOOST_CONCEPT_ASSERT((FragmentConcept)); return OptRect(bounds_fast(a[X]), bounds_fast(a[Y])); } template OptRect bounds_exact(const D2 &a) { - boost::function_requires >(); + BOOST_CONCEPT_ASSERT((FragmentConcept)); return OptRect(bounds_exact(a[X]), bounds_exact(a[Y])); } template OptRect bounds_local(const D2 &a, const OptInterval &t) { - boost::function_requires >(); + BOOST_CONCEPT_ASSERT((FragmentConcept)); return OptRect(bounds_local(a[X], t), bounds_local(a[Y], t)); } diff --git a/src/2geom/ellipse.cpp b/src/2geom/ellipse.cpp index f23c9b24e..46c60d85d 100644 --- a/src/2geom/ellipse.cpp +++ b/src/2geom/ellipse.cpp @@ -32,12 +32,18 @@ */ #include <2geom/ellipse.h> -#include <2geom/svg-elliptical-arc.h> +#include <2geom/elliptical-arc.h> #include <2geom/numeric/fitting-tool.h> #include <2geom/numeric/fitting-model.h> namespace Geom { +Ellipse::Ellipse(Geom::Circle const &c) + : _center(c.center()) + , _rays(c.radius(), c.radius()) + , _angle(0) +{} + void Ellipse::setCoefficients(double A, double B, double C, double D, double E, double F) { double den = 4*A*C - B*B; @@ -57,17 +63,11 @@ void Ellipse::setCoefficients(double A, double B, double C, double D, double E, //evaluate ellipse rotation angle - double rot = std::atan2( -B, -(A - C) )/2; -// std::cerr << "rot = " << rot << std::endl; - bool swap_axes = false; - - if (rot >= M_PI/2 || rot < 0) { - swap_axes = true; - } + _angle = std::atan2( -B, -(A - C) )/2; // evaluate the length of the ellipse rays double sinrot, cosrot; - sincos(rot, sinrot, cosrot); + sincos(_angle, sinrot, cosrot); double cos2 = cosrot * cosrot; double sin2 = sinrot * sinrot; double cossin = cosrot * sinrot; @@ -80,7 +80,7 @@ void Ellipse::setCoefficients(double A, double B, double C, double D, double E, if (rx2 < 0) { THROW_RANGEERROR("rx2 < 0, while computing 'rx' coefficient"); } - double rx = std::sqrt(rx2); + _rays[X] = std::sqrt(rx2); den = C * cos2 - B * cossin + A * sin2; if (den == 0) { @@ -90,24 +90,11 @@ void Ellipse::setCoefficients(double A, double B, double C, double D, double E, if (ry2 < 0) { THROW_RANGEERROR("ry2 < 0, while computing 'rx' coefficient"); } - double ry = std::sqrt(ry2); + _rays[Y] = std::sqrt(ry2); // the solution is not unique so we choose always the ellipse // with a rotation angle between 0 and PI/2 - if (swap_axes) { - std::swap(rx, ry); - } - - if (rx == ry) { - rot = 0; - } - if (rot < 0) { - rot += M_PI/2; - } - - _rays[X] = rx; - _rays[Y] = ry; - _angle = rot; + makeCanonical(); } @@ -118,14 +105,49 @@ Affine Ellipse::unitCircleTransform() const return ret; } +Affine Ellipse::inverseUnitCircleTransform() const +{ + if (ray(X) == 0 || ray(Y) == 0) { + THROW_RANGEERROR("a degenerate ellipse doesn't have an inverse unit circle transform"); + } + Affine ret = Translate(-center()) * Rotate(-_angle) * Scale(1/ray(X), 1/ray(Y)); + return ret; +} + + +LineSegment Ellipse::axis(Dim2 d) const +{ + Point a(0, 0), b(0, 0); + a[d] = -1; + b[d] = 1; + LineSegment ls(a, b); + ls.transform(unitCircleTransform()); + return ls; +} + +LineSegment Ellipse::semiaxis(Dim2 d, int sign) const +{ + Point a(0, 0), b(0, 0); + b[d] = sgn(sign); + LineSegment ls(a, b); + ls.transform(unitCircleTransform()); + return ls; +} + std::vector Ellipse::coefficients() const +{ + std::vector c(6); + coefficients(c[0], c[1], c[2], c[3], c[4], c[5]); + return c; +} + +void Ellipse::coefficients(Coord &A, Coord &B, Coord &C, Coord &D, Coord &E, Coord &F) const { if (ray(X) == 0 || ray(Y) == 0) { THROW_RANGEERROR("a degenerate ellipse doesn't have an implicit form"); } - std::vector coeff(6); double cosrot, sinrot; sincos(_angle, sinrot, cosrot); double cos2 = cosrot * cosrot; @@ -134,16 +156,15 @@ std::vector Ellipse::coefficients() const double invrx2 = 1 / (ray(X) * ray(X)); double invry2 = 1 / (ray(Y) * ray(Y)); - coeff[0] = invrx2 * cos2 + invry2 * sin2; - coeff[1] = 2 * (invrx2 - invry2) * cossin; - coeff[2] = invrx2 * sin2 + invry2 * cos2; - coeff[3] = -(2 * coeff[0] * center(X) + coeff[1] * center(Y)); - coeff[4] = -(2 * coeff[2] * center(Y) + coeff[1] * center(X)); - coeff[5] = coeff[0] * center(X) * center(X) - + coeff[1] * center(X) * center(Y) - + coeff[2] * center(Y) * center(Y) - - 1; - return coeff; + A = invrx2 * cos2 + invry2 * sin2; + B = 2 * (invrx2 - invry2) * cossin; + C = invrx2 * sin2 + invry2 * cos2; + D = -2 * A * center(X) - B * center(Y); + E = -2 * C * center(Y) - B * center(X); + F = A * center(X) * center(X) + + B * center(X) * center(Y) + + C * center(Y) * center(Y) + - 1; } @@ -167,8 +188,7 @@ void Ellipse::fit(std::vector const &points) EllipticalArc * -Ellipse::arc(Point const &ip, Point const &inner, Point const &fp, - bool _svg_compliant) +Ellipse::arc(Point const &ip, Point const &inner, Point const &fp) { // This is resistant to degenerate ellipses: // both flags evaluate to false in that case. @@ -196,28 +216,14 @@ Ellipse::arc(Point const &ip, Point const &inner, Point const &fp, sweep_flag = true; } - EllipticalArc *ret_arc; - if (_svg_compliant) { - ret_arc = new SVGEllipticalArc(ip, ray(X), ray(Y), rotationAngle(), - large_arc_flag, sweep_flag, fp); - } else { - ret_arc = new EllipticalArc(ip, ray(X), ray(Y), rotationAngle(), - large_arc_flag, sweep_flag, fp); - } + EllipticalArc *ret_arc = new EllipticalArc(ip, ray(X), ray(Y), rotationAngle(), + large_arc_flag, sweep_flag, fp); return ret_arc; } Ellipse &Ellipse::operator*=(Rotate const &r) { _angle += r.angle(); - // keep the angle in the first quadrant - if (_angle < 0) { - _angle += M_PI; - } - if (_angle >= M_PI/2) { - std::swap(_rays[X], _rays[Y]); - _angle -= M_PI/2; - } _center *= r; return *this; } @@ -261,10 +267,311 @@ Ellipse &Ellipse::operator*=(Affine const& m) return *this; } -Ellipse::Ellipse(Geom::Circle const &c) +Ellipse Ellipse::canonicalForm() const +{ + Ellipse result(*this); + result.makeCanonical(); + return result; +} + +void Ellipse::makeCanonical() +{ + if (_rays[X] == _rays[Y]) { + _angle = 0; + return; + } + + if (_angle < 0) { + _angle += M_PI; + } + if (_angle >= M_PI/2) { + std::swap(_rays[X], _rays[Y]); + _angle -= M_PI/2; + } +} + +Point Ellipse::pointAt(Coord t) const +{ + Point p = Point::polar(t); + p *= unitCircleTransform(); + return p; +} + +Coord Ellipse::valueAt(Coord t, Dim2 d) const +{ + // TODO: more efficient version. + return pointAt(t)[d]; +} + +Coord Ellipse::timeAt(Point const &p) const +{ + // degenerate ellipse is basically a reparametrized line segment + if (ray(X) == 0 || ray(Y) == 0) { + if (ray(X) != 0) { + return asin(Line(axis(X)).timeAt(p)); + } else if (ray(Y) != 0) { + return acos(Line(axis(Y)).timeAt(p)); + } else { + return 0; + } + } + Affine iuct = inverseUnitCircleTransform(); + return Angle(atan2(p * iuct)).radians0(); // return a value in [0, 2pi) +} + +std::vector Ellipse::intersect(Line const &line) const +{ + + std::vector result; + + if (line.isDegenerate()) return result; + if (ray(X) == 0 || ray(Y) == 0) { + // TODO intersect with line segment. + return result; + } + + // Ax^2 + Bxy + Cy^2 + Dx + Ey + F + Coord A, B, C, D, E, F; + coefficients(A, B, C, D, E, F); + Affine iuct = inverseUnitCircleTransform(); + + if (line.isHorizontal()) { + // substitute y into the ellipse equation and solve + Coord y = line.initialPoint()[Y]; + std::vector xs = solve_quadratic(A, B*y + D, C*y*y + E*y + F); + for (unsigned i = 0; i < xs.size(); ++i) { + Point p(xs[i], y); + result.push_back(ShapeIntersection(atan2(p * iuct), line.timeAt(p), p)); + } + return result; + } + if (line.isVertical()) { + // substitute y into the ellipse equation and solve + Coord x = line.initialPoint()[X]; + std::vector ys = solve_quadratic(C, B*x + E, A*x*x + D*x + F); + for (unsigned i = 0; i < ys.size(); ++i) { + Point p(x, ys[i]); + result.push_back(ShapeIntersection(atan2(p * iuct), line.timeAt(p), p)); + } + return result; + } + + // generic case + Coord a, b, c; + line.coefficients(a, b, c); + + // y = -a/b x - C/B + // TODO: when is it better to substitute X? + Coord q = -a/b; + Coord r = -c/b; + + // substitute that into the ellipse equation, making it quadratic in x + Coord I = A + B*q + C*q*q; // x^2 terms + Coord J = B*r + C*2*q*r + D + E*q; // x^1 terms + Coord K = C*r*r + E*r + F; // x^0 terms + std::vector xs = solve_quadratic(I, J, K); + + for (unsigned i = 0; i < xs.size(); ++i) { + Point p(xs[i], q*xs[i] + r); + result.push_back(ShapeIntersection(atan2(p * iuct), line.timeAt(p), p)); + } + return result; +} + +std::vector Ellipse::intersect(LineSegment const &seg) const +{ + // we simply re-use the procedure for lines and filter out + // results where the line time value is outside of the unit interval. + std::vector result = intersect(Line(seg)); + filter_line_segment_intersections(result); + return result; +} + +std::vector Ellipse::intersect(Ellipse const &other) const +{ + // handle degenerate cases first + if (ray(X) == 0 || ray(Y) == 0) { + + } + // intersection of two ellipses can be solved analytically. + // http://maptools.home.comcast.net/~maptools/BivariateQuadratics.pdf + + Coord A, B, C, D, E, F; + Coord a, b, c, d, e, f; + + // NOTE: the order of coefficients is different to match the convention in the PDF above + // Ax^2 + Bx^2 + Cx + Dy + Exy + F + this->coefficients(A, E, B, C, D, F); + other.coefficients(a, e, b, c, d, f); + + // Assume that Q is the ellipse equation given by uppercase letters + // and R is the equation given by lowercase ones. An intersection exists when + // there is a coefficient mu such that + // mu Q + R = 0 + // + // This can be written in the following way: + // + // | ff cc/2 dd/2 | |1| + // mu Q + R = [1 x y] | cc/2 aa ee/2 | |x| = 0 + // | dd/2 ee/2 bb | |y| + // + // where aa = mu A + a and so on. The determinant can be explicitly written out, + // giving an equation which is cubic in mu and can be solved analytically. + + Coord I, J, K, L; + I = (-E*E*F + 4*A*B*F + C*D*E - A*D*D - B*C*C) / 4; + J = -((E*E - 4*A*B) * f + (2*E*F - C*D) * e + (2*A*D - C*E) * d + + (2*B*C - D*E) * c + (C*C - 4*A*F) * b + (D*D - 4*B*F) * a) / 4; + K = -((e*e - 4*a*b) * F + (2*e*f - c*d) * E + (2*a*d - c*e) * D + + (2*b*c - d*e) * C + (c*c - 4*a*f) * B + (d*d - 4*b*f) * A) / 4; + L = (-e*e*f + 4*a*b*f + c*d*e - a*d*d - b*c*c) / 4; + + std::vector mus = solve_cubic(I, J, K, L); + Coord mu = infinity(); + std::vector result; + + // Now that we have solved for mu, we need to check whether the conic + // determined by mu Q + R is reducible to a product of two lines. If it's not, + // it means that there are no intersections. If it is, the intersections of these + // lines with the original ellipses (if there are any) give the coordinates + // of intersections. + + // Prefer middle root if there are three. + // Out of three possible pairs of lines that go through four points of intersection + // of two ellipses, this corresponds to cross-lines. These intersect the ellipses + // at less shallow angles than the other two options. + if (mus.size() == 3) { + std::swap(mus[1], mus[0]); + } + for (unsigned i = 0; i < mus.size(); ++i) { + Coord aa = mus[i] * A + a; + Coord bb = mus[i] * B + b; + Coord ee = mus[i] * E + e; + Coord delta = ee*ee - 4*aa*bb; + if (delta < 0) continue; + mu = mus[i]; + break; + } + + // if no suitable mu was found, there are no intersections + if (mu == infinity()) return result; + + Coord aa = mu * A + a; + Coord bb = mu * B + b; + Coord cc = mu * C + c; + Coord dd = mu * D + d; + Coord ee = mu * E + e; + Coord ff = mu * F + f; + + Line lines[2]; + + if (aa != 0) { + bb /= aa; cc /= aa; dd /= aa; ee /= aa; ff /= aa; + Coord s = (ee + std::sqrt(ee*ee - 4*bb)) / 2; + Coord q = ee - s; + Coord alpha = (dd - cc*q) / (s - q); + Coord beta = cc - alpha; + + lines[0] = Line(1, q, alpha); + lines[1] = Line(1, s, beta); + } else if (bb != 0) { + cc /= bb; dd /= bb; ee /= bb; ff /= bb; + Coord s = ee; + Coord q = 0; + Coord alpha = cc / ee; + Coord beta = ff * ee / cc; + + lines[0] = Line(q, 1, alpha); + lines[1] = Line(s, 1, beta); + } else { + lines[0] = Line(ee, 0, dd); + lines[1] = Line(0, 1, cc/ee); + } + + // intersect with the obtained lines and report intersections + for (unsigned li = 0; li < 2; ++li) { + std::vector as = intersect(lines[li]); + std::vector bs = other.intersect(lines[li]); + + if (!as.empty() && as.size() == bs.size()) { + for (unsigned i = 0; i < as.size(); ++i) { + ShapeIntersection ix(as[i].first, bs[i].first, + middle_point(as[i].point(), bs[i].point())); + result.push_back(ix); + } + } + } + return result; +} + +std::vector Ellipse::intersect(D2 const &b) const +{ + Coord A, B, C, D, E, F; + coefficients(A, B, C, D, E, F); + + Bezier x = A*b[X]*b[X] + B*b[X]*b[Y] + C*b[Y]*b[Y] + D*b[X] + E*b[Y] + F; + std::vector r = x.roots(); + + std::vector result; + for (unsigned i = 0; i < r.size(); ++i) { + Point p = b.valueAt(r[i]); + result.push_back(ShapeIntersection(timeAt(p), r[i], p)); + } + return result; +} + +bool Ellipse::operator==(Ellipse const &other) const +{ + if (_center != other._center) return false; + + Ellipse a = this->canonicalForm(); + Ellipse b = other.canonicalForm(); + + if (a._rays != b._rays) return false; + if (a._angle != b._angle) return false; + + return true; +} + + +bool are_near(Ellipse const &a, Ellipse const &b, Coord precision) +{ + // We want to know whether no point on ellipse a is further than precision + // from the corresponding point on ellipse b. To check this, we compute + // the four extreme points at the end of each ray for each ellipse + // and check whether they are sufficiently close. + + // First, we need to correct the angles on the ellipses, so that they are + // no further than M_PI/4 apart. This can always be done by rotating + // and exchanging axes. + Ellipse ac = a, bc = b; + if (distance(ac.rotationAngle(), bc.rotationAngle()).radians0() >= M_PI/2) { + ac.setRotationAngle(ac.rotationAngle() + M_PI); + } + if (distance(ac.rotationAngle(), bc.rotationAngle()) >= M_PI/4) { + Angle d1 = distance(ac.rotationAngle() + M_PI/2, bc.rotationAngle()); + Angle d2 = distance(ac.rotationAngle() - M_PI/2, bc.rotationAngle()); + Coord adj = d1.radians0() < d2.radians0() ? M_PI/2 : -M_PI/2; + ac.setRotationAngle(ac.rotationAngle() + adj); + ac.setRays(ac.ray(Y), ac.ray(X)); + } + + // Do the actual comparison by computing four points on each ellipse. + Point tps[] = {Point(1,0), Point(0,1), Point(-1,0), Point(0,-1)}; + for (unsigned i = 0; i < 4; ++i) { + if (!are_near(tps[i] * ac.unitCircleTransform(), + tps[i] * bc.unitCircleTransform(), + precision)) + return false; + } + return true; +} + +std::ostream &operator<<(std::ostream &out, Ellipse const &e) { - _center = c.center(); - _rays[X] = _rays[Y] = c.radius(); + out << "Ellipse(" << e.center() << ", " << e.rays() + << ", " << format_coord_nice(e.rotationAngle()) << ")"; + return out; } } // end namespace Geom diff --git a/src/2geom/ellipse.h b/src/2geom/ellipse.h index a67969933..6fb5ed254 100644 --- a/src/2geom/ellipse.h +++ b/src/2geom/ellipse.h @@ -37,8 +37,10 @@ #include #include <2geom/angle.h> +#include <2geom/bezier-curve.h> #include <2geom/exception.h> -#include <2geom/point.h> +#include <2geom/forward.h> +#include <2geom/line.h> #include <2geom/transforms.h> namespace Geom { @@ -46,7 +48,14 @@ namespace Geom { class EllipticalArc; class Circle; -/** @brief Set of points with a constant sum of distances from two foci +/** @brief Set of points with a constant sum of distances from two foci. + * + * An ellipse can be specified in several ways. Internally, 2Geom uses + * the SVG style representation: center, rays and angle between the +X ray + * and the +X axis. Another popular way is to use an implicit equation, + * which is as follows: + * \f$Ax^2 + Bxy + Cy^2 + Dx + Ey + F = 0\f$ + * * @ingroup Shapes */ class Ellipse : boost::multipliable< Ellipse, Translate @@ -54,7 +63,8 @@ class Ellipse , boost::multipliable< Ellipse, Rotate , boost::multipliable< Ellipse, Zoom , boost::multipliable< Ellipse, Affine - > > > > > + , boost::equality_comparable< Ellipse + > > > > > > { Point _center; Point _rays; @@ -74,13 +84,16 @@ public: Ellipse(double A, double B, double C, double D, double E, double F) { setCoefficients(A, B, C, D, E, F); } + /// Construct ellipse from a circle. Ellipse(Geom::Circle const &c); + /// Set center, rays and angle. void set(Point const &c, Point const &r, Coord angle) { _center = c; _rays = r; _angle = angle; } + /// Set center, rays and angle as constituent values. void set(Coord cx, Coord cy, Coord rx, Coord ry, Coord a) { _center[X] = cx; _center[Y] = cy; @@ -88,31 +101,97 @@ public: _rays[Y] = ry; _angle = a; } - - // build an ellipse by its implicit equation: - // Ax^2 + Bxy + Cy^2 + Dx + Ey + F = 0 + /// Set an ellipse by solving its implicit equation. void setCoefficients(double A, double B, double C, double D, double E, double F); - - // biuld up the best fitting ellipse wrt the passed points - // prerequisite: at least 5 points must be passed - void fit(std::vector const& points); - - EllipticalArc *arc(Point const &ip, Point const &inner, Point const &fp, - bool svg_compliant = true); + /// Set the center. + void setCenter(Point const &p) { _center = p; } + /// Set the center by coordinates. + void setCenter(Coord cx, Coord cy) { _center[X] = cx; _center[Y] = cy; } + /// Set both rays of the ellipse. + void setRays(Point const &p) { _rays = p; } + /// Set both rays of the ellipse as coordinates. + void setRays(Coord x, Coord y) { _rays[X] = x; _rays[Y] = y; } + /// Set one of the rays of the ellipse. + void setRay(Coord r, Dim2 d) { _rays[d] = r; } + /// Set the angle the X ray makes with the +X axis. + void setRotationAngle(Angle a) { _angle = a; } Point center() const { return _center; } Coord center(Dim2 d) const { return _center[d]; } + /// Get both rays as a point. Point rays() const { return _rays; } + /// Get one ray of the ellipse. Coord ray(Dim2 d) const { return _rays[d]; } + /// Get the angle the X ray makes with the +X axis. Angle rotationAngle() const { return _angle; } + /** @brief Create an ellipse passing through the specified points + * At least five points have to be specified. */ + void fit(std::vector const& points); + + /** @brief Create an elliptical arc from a section of the ellipse. + * This is mainly useful to determine the flags of the new arc. + * The passed points should lie on the ellipse, otherwise the results + * will be undefined. + * @param ip Initial point of the arc + * @param inner Point in the middle of the arc, used to pick one of two possibilities + * @param fp Final point of the arc + * @return Newly allocated arc, delete when no longer used */ + EllipticalArc *arc(Point const &ip, Point const &inner, Point const &fp); + + /** @brief Return an ellipse with less degrees of freedom. + * The canonical form always has the angle less than \f$\frac{\pi}{2}\f$, + * and zero if the rays are equal (i.e. the ellipse is a circle). */ + Ellipse canonicalForm() const; + void makeCanonical(); + /** @brief Compute the transform that maps the unit circle to this ellipse. * Each ellipse can be interpreted as a translated, scaled and rotate unit circle. * This function returns the transform that maps the unit circle to this ellipse. * @return Transform from unit circle to the ellipse */ Affine unitCircleTransform() const; + /** @brief Compute the transform that maps this ellipse to the unit circle. + * This may be a little more precise and/or faster than simply using + * unitCircleTransform().inverse(). An exception will be thrown for + * degenerate ellipses. */ + Affine inverseUnitCircleTransform() const; + + LineSegment majorAxis() const { return ray(X) >= ray(Y) ? axis(X) : axis(Y); } + LineSegment minorAxis() const { return ray(X) < ray(Y) ? axis(X) : axis(Y); } + LineSegment semimajorAxis(int sign = 1) const { + return ray(X) >= ray(Y) ? semiaxis(X, sign) : semiaxis(Y, sign); + } + LineSegment semiminorAxis(int sign = 1) const { + return ray(X) < ray(Y) ? semiaxis(X, sign) : semiaxis(Y, sign); + } + LineSegment axis(Dim2 d) const; + LineSegment semiaxis(Dim2 d, int sign = 1) const; + /// Get the coefficients of the ellipse's implicit equation. std::vector coefficients() const; + void coefficients(Coord &A, Coord &B, Coord &C, Coord &D, Coord &E, Coord &F) const; + + /** @brief Evaluate a point on the ellipse. + * The parameter range is \f$[0, 2\pi)\f$; larger and smaller values + * wrap around. */ + Point pointAt(Coord t) const; + /// Evaluate a single coordinate of a point on the ellipse. + Coord valueAt(Coord t, Dim2 d) const; + + /** @brief Find the time value of a point on an ellipse. + * If the point is not on the ellipse, the returned time value will correspond + * to an intersection with a ray from the origin passing through the point + * with the ellipse. Note that this is NOT the nearest point on the ellipse. */ + Coord timeAt(Point const &p) const; + + /// Compute intersections with an infinite line. + std::vector intersect(Line const &line) const; + /// Compute intersections with a line segment. + std::vector intersect(LineSegment const &seg) const; + /// Compute intersections with another ellipse. + std::vector intersect(Ellipse const &other) const; + /// Compute intersections with a 2D Bezier polynomial. + std::vector intersect(D2 const &other) const; Ellipse &operator*=(Translate const &t) { _center *= t; @@ -130,8 +209,21 @@ public: } Ellipse &operator*=(Rotate const &r); Ellipse &operator*=(Affine const &m); + + /// Compare ellipses for exact equality. + bool operator==(Ellipse const &other) const; }; +/** @brief Test whether two ellipses are approximately the same. + * This will check whether no point on ellipse a is further away from + * the corresponding point on ellipse b than precision. + * @relates Ellipse */ +bool are_near(Ellipse const &a, Ellipse const &b, Coord precision = EPSILON); + +/** @brief Outputs ellipse data, useful for debugging. + * @relates Ellipse */ +std::ostream &operator<<(std::ostream &out, Ellipse const &e); + } // end namespace Geom #endif // LIB2GEOM_SEEN_ELLIPSE_H diff --git a/src/2geom/elliptical-arc-from-sbasis.cpp b/src/2geom/elliptical-arc-from-sbasis.cpp new file mode 100644 index 000000000..54f995fb6 --- /dev/null +++ b/src/2geom/elliptical-arc-from-sbasis.cpp @@ -0,0 +1,345 @@ +/** @file + * @brief Fitting elliptical arc to SBasis + * + * This file contains the implementation of the function arc_from_sbasis. + *//* + * Copyright 2008 Marco Cecchetti + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + */ + +#include <2geom/curve.h> +#include <2geom/angle.h> +#include <2geom/utils.h> +#include <2geom/bezier-curve.h> +#include <2geom/elliptical-arc.h> +#include <2geom/sbasis-curve.h> // for non-native methods +#include <2geom/numeric/vector.h> +#include <2geom/numeric/fitting-tool.h> +#include <2geom/numeric/fitting-model.h> +#include + +namespace Geom { + +// forward declation +namespace detail +{ + struct ellipse_equation; +} + +/* + * make_elliptical_arc + * + * convert a parametric polynomial curve given in symmetric power basis form + * into an EllipticalArc type; in order to be successfull the input curve + * has to look like an actual elliptical arc even if a certain tolerance + * is allowed through an ad-hoc parameter. + * The conversion is performed through an interpolation on a certain amount of + * sample points computed on the input curve; + * the interpolation computes the coefficients of the general implicit equation + * of an ellipse (A*X^2 + B*XY + C*Y^2 + D*X + E*Y + F = 0), then from the + * implicit equation we compute the parametric form. + * + */ +class make_elliptical_arc +{ + public: + typedef D2 curve_type; + + /* + * constructor + * + * it doesn't execute the conversion but set the input and output parameters + * + * _ea: the output EllipticalArc that will be generated; + * _curve: the input curve to be converted; + * _total_samples: the amount of sample points to be taken + * on the input curve for performing the conversion + * _tolerance: how much likelihood is required between the input curve + * and the generated elliptical arc; the smaller it is the + * the tolerance the higher it is the likelihood. + */ + make_elliptical_arc( EllipticalArc& _ea, + curve_type const& _curve, + unsigned int _total_samples, + double _tolerance ); + + private: + bool bound_exceeded( unsigned int k, detail::ellipse_equation const & ee, + double e1x, double e1y, double e2 ); + + bool check_bound(double A, double B, double C, double D, double E, double F); + + void fit(); + + bool make_elliptiarc(); + + void print_bound_error(unsigned int k) + { + std::cerr + << "tolerance error" << std::endl + << "at point: " << k << std::endl + << "error value: "<< dist_err << std::endl + << "bound: " << dist_bound << std::endl + << "angle error: " << angle_err + << " (" << angle_tol << ")" << std::endl; + } + + public: + /* + * perform the actual conversion + * return true if the conversion is successfull, false on the contrary + */ + bool operator()() + { + // initialize the reference + const NL::Vector & coeff = fitter.result(); + fit(); + if ( !check_bound(1, coeff[0], coeff[1], coeff[2], coeff[3], coeff[4]) ) + return false; + if ( !(make_elliptiarc()) ) return false; + return true; + } + + private: + EllipticalArc& ea; // output elliptical arc + const curve_type & curve; // input curve + Piecewise > dcurve; // derivative of the input curve + NL::LFMEllipse model; // model used for fitting + // perform the actual fitting task + NL::least_squeares_fitter fitter; + // tolerance: the user-defined tolerance parameter; + // tol_at_extr: the tolerance at end-points automatically computed + // on the value of "tolerance", and usually more strict; + // tol_at_center: tolerance at the center of the ellipse + // angle_tol: tolerance for the angle btw the input curve tangent + // versor and the ellipse normal versor at the sample points + double tolerance, tol_at_extr, tol_at_center, angle_tol; + Point initial_point, final_point; // initial and final end-points + unsigned int N; // total samples + unsigned int last; // N-1 + double partitions; // N-1 + std::vector p; // sample points + double dist_err, dist_bound, angle_err; +}; + +namespace detail +{ +/* + * ellipse_equation + * + * this is an helper struct, it provides two routines: + * the first one evaluates the implicit form of an ellipse on a given point + * the second one computes the normal versor at a given point of an ellipse + * in implicit form + */ +struct ellipse_equation +{ + ellipse_equation(double a, double b, double c, double d, double e, double f) + : A(a), B(b), C(c), D(d), E(e), F(f) + { + } + + double operator()(double x, double y) const + { + // A * x * x + B * x * y + C * y * y + D * x + E * y + F; + return (A * x + B * y + D) * x + (C * y + E) * y + F; + } + + double operator()(Point const& p) const + { + return (*this)(p[X], p[Y]); + } + + Point normal(double x, double y) const + { + Point n( 2 * A * x + B * y + D, 2 * C * y + B * x + E ); + return unit_vector(n); + } + + Point normal(Point const& p) const + { + return normal(p[X], p[Y]); + } + + double A, B, C, D, E, F; +}; + +} // end namespace detail + +make_elliptical_arc:: +make_elliptical_arc( EllipticalArc& _ea, + curve_type const& _curve, + unsigned int _total_samples, + double _tolerance ) + : ea(_ea), curve(_curve), + dcurve( unitVector(derivative(curve)) ), + model(), fitter(model, _total_samples), + tolerance(_tolerance), tol_at_extr(tolerance/2), + tol_at_center(0.1), angle_tol(0.1), + initial_point(curve.at0()), final_point(curve.at1()), + N(_total_samples), last(N-1), partitions(N-1), p(N) +{ +} + +/* + * check that the coefficients computed by the fit method satisfy + * the tolerance parameters at the k-th sample point + */ +bool +make_elliptical_arc:: +bound_exceeded( unsigned int k, detail::ellipse_equation const & ee, + double e1x, double e1y, double e2 ) +{ + dist_err = std::fabs( ee(p[k]) ); + dist_bound = std::fabs( e1x * p[k][X] + e1y * p[k][Y] + e2 ); + // check that the angle btw the tangent versor to the input curve + // and the normal versor of the elliptical arc, both evaluate + // at the k-th sample point, are really othogonal + angle_err = std::fabs( dot( dcurve(k/partitions), ee.normal(p[k]) ) ); + //angle_err *= angle_err; + return ( dist_err > dist_bound || angle_err > angle_tol ); +} + +/* + * check that the coefficients computed by the fit method satisfy + * the tolerance parameters at each sample point + */ +bool +make_elliptical_arc:: +check_bound(double A, double B, double C, double D, double E, double F) +{ + detail::ellipse_equation ee(A, B, C, D, E, F); + + // check error magnitude at the end-points + double e1x = (2*A + B) * tol_at_extr; + double e1y = (B + 2*C) * tol_at_extr; + double e2 = ((D + E) + (A + B + C) * tol_at_extr) * tol_at_extr; + if (bound_exceeded(0, ee, e1x, e1y, e2)) + { + print_bound_error(0); + return false; + } + if (bound_exceeded(0, ee, e1x, e1y, e2)) + { + print_bound_error(last); + return false; + } + + // e1x = derivative((ee(x,y), x) | x->tolerance, y->tolerance + e1x = (2*A + B) * tolerance; + // e1y = derivative((ee(x,y), y) | x->tolerance, y->tolerance + e1y = (B + 2*C) * tolerance; + // e2 = ee(tolerance, tolerance) - F; + e2 = ((D + E) + (A + B + C) * tolerance) * tolerance; +// std::cerr << "e1x = " << e1x << std::endl; +// std::cerr << "e1y = " << e1y << std::endl; +// std::cerr << "e2 = " << e2 << std::endl; + + // check error magnitude at sample points + for ( unsigned int k = 1; k < last; ++k ) + { + if ( bound_exceeded(k, ee, e1x, e1y, e2) ) + { + print_bound_error(k); + return false; + } + } + + return true; +} + +/* + * fit + * + * supply the samples to the fitter and compute + * the ellipse implicit equation coefficients + */ +void make_elliptical_arc::fit() +{ + for (unsigned int k = 0; k < N; ++k) + { + p[k] = curve( k / partitions ); + fitter.append(p[k]); + } + fitter.update(); + + NL::Vector z(N, 0.0); + fitter.result(z); +} + +bool make_elliptical_arc::make_elliptiarc() +{ + const NL::Vector & coeff = fitter.result(); + Ellipse e; + try + { + e.setCoefficients(1, coeff[0], coeff[1], coeff[2], coeff[3], coeff[4]); + } + catch(LogicalError const &exc) + { + return false; + } + + Point inner_point = curve(0.5); + +#ifdef CPP11 + std::unique_ptr arc( e.arc(initial_point, inner_point, final_point) ); +#else + std::auto_ptr arc( e.arc(initial_point, inner_point, final_point) ); +#endif + ea = *arc; + + if ( !are_near( e.center(), + ea.center(), + tol_at_center * std::min(e.ray(X),e.ray(Y)) + ) + ) + { + return false; + } + return true; +} + + + +bool arc_from_sbasis(EllipticalArc &ea, D2 const &in, + double tolerance, unsigned num_samples) +{ + make_elliptical_arc convert(ea, in, num_samples, tolerance); + return convert(); +} + +} // end namespace Geom + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 : diff --git a/src/2geom/elliptical-arc.cpp b/src/2geom/elliptical-arc.cpp index 601f0c8c8..a04b730b3 100644 --- a/src/2geom/elliptical-arc.cpp +++ b/src/2geom/elliptical-arc.cpp @@ -38,7 +38,6 @@ #include <2geom/ellipse.h> #include <2geom/elliptical-arc.h> #include <2geom/path-sink.h> -#include <2geom/poly.h> #include <2geom/sbasis-geometric.h> #include <2geom/transforms.h> #include <2geom/utils.h> @@ -93,11 +92,16 @@ namespace Geom Rect EllipticalArc::boundsExact() const { + if (isChord()) { + return chord().boundsExact(); + } + using std::swap; + // TODO: simplify / document what is going on here. double extremes[4]; double sinrot, cosrot; - sincos(_rot_angle, sinrot, cosrot); + sincos(rotationAngle(), sinrot, cosrot); extremes[0] = std::atan2( -ray(Y) * sinrot, ray(X) * cosrot ); extremes[1] = extremes[0] + M_PI; @@ -132,14 +136,14 @@ Rect EllipticalArc::boundsExact() const Point EllipticalArc::pointAtAngle(Coord t) const { - Point ret = Point::polar(t) * unitCircleTransform(); + Point ret = _ellipse.pointAt(t); return ret; } Coord EllipticalArc::valueAtAngle(Coord t, Dim2 d) const { Coord sinrot, cosrot, cost, sint; - sincos(_rot_angle, sinrot, cosrot); + sincos(rotationAngle(), sinrot, cosrot); sincos(t, sint, cost); if ( d == X ) { @@ -155,13 +159,22 @@ Coord EllipticalArc::valueAtAngle(Coord t, Dim2 d) const Affine EllipticalArc::unitCircleTransform() const { - Affine ret = Scale(ray(X), ray(Y)) * Rotate(_rot_angle); - ret.setTranslation(center()); + Affine ret = _ellipse.unitCircleTransform(); + return ret; +} + +Affine EllipticalArc::inverseUnitCircleTransform() const +{ + Affine ret = _ellipse.inverseUnitCircleTransform(); return ret; } std::vector EllipticalArc::roots(Coord v, Dim2 d) const { + if (isChord()) { + return chord().roots(v, d); + } + std::vector sol; if ( are_near(ray(X), 0) && are_near(ray(Y), 0) ) { @@ -190,7 +203,7 @@ std::vector EllipticalArc::roots(Coord v, Dim2 d) const for ( unsigned int dim = 0; dim < 2; ++dim ) { - if ( are_near(ray((Dim2) dim), 0) ) + if (ray((Dim2) dim) == 0) { if ( initialPoint()[d] == v && finalPoint()[d] == v ) { @@ -212,18 +225,18 @@ std::vector EllipticalArc::roots(Coord v, Dim2 d) const case X: switch(dim) { - case X: ray_prj = -ray(Y) * std::sin(_rot_angle); + case X: ray_prj = -ray(Y) * std::sin(rotationAngle()); break; - case Y: ray_prj = ray(X) * std::cos(_rot_angle); + case Y: ray_prj = ray(X) * std::cos(rotationAngle()); break; } break; case Y: switch(dim) { - case X: ray_prj = ray(Y) * std::cos(_rot_angle); + case X: ray_prj = ray(Y) * std::cos(rotationAngle()); break; - case Y: ray_prj = ray(X) * std::sin(_rot_angle); + case Y: ray_prj = ray(X) * std::sin(rotationAngle()); break; } break; @@ -269,10 +282,10 @@ std::vector EllipticalArc::roots(Coord v, Dim2 d) const double rotx, roty; if (d == X) { - sincos(_rot_angle, roty, rotx); + sincos(rotationAngle(), roty, rotx); roty = -roty; } else { - sincos(_rot_angle, rotx, roty); + sincos(rotationAngle(), rotx, roty); } double rxrotx = ray(X) * rotx; @@ -336,8 +349,12 @@ std::vector EllipticalArc::roots(Coord v, Dim2 d) const // of such an angle in the cw direction Curve *EllipticalArc::derivative() const { + if (isChord()) { + return chord().derivative(); + } + EllipticalArc *result = static_cast(duplicate()); - result->_center[X] = result->_center[Y] = 0; + result->_ellipse.setCenter(0, 0); result->_start_angle += M_PI/2; if( !( result->_start_angle < 2*M_PI ) ) { @@ -357,13 +374,17 @@ Curve *EllipticalArc::derivative() const std::vector EllipticalArc::pointAndDerivatives(Coord t, unsigned int n) const { + if (isChord()) { + return chord().pointAndDerivatives(t, n); + } + unsigned int nn = n+1; // nn represents the size of the result vector. std::vector result; result.reserve(nn); double angle = map_unit_interval_on_circular_arc(t, initialAngle(), finalAngle(), _sweep); std::auto_ptr ea( static_cast(duplicate()) ); - ea->_center = Point(0,0); + ea->_ellipse.setCenter(0, 0); unsigned int m = std::min(nn, 4u); for ( unsigned int i = 0; i < m; ++i ) { @@ -392,6 +413,12 @@ bool EllipticalArc::containsAngle(Coord angle) const return AngleInterval::contains(angle); } +Point EllipticalArc::pointAt(Coord t) const +{ + if (isChord()) return chord().pointAt(t); + return _ellipse.pointAt(angleAt(t)); +} + Curve* EllipticalArc::portion(double f, double t) const { // fix input arguments @@ -400,14 +427,14 @@ Curve* EllipticalArc::portion(double f, double t) const if (t < 0) t = 0; if (t > 1) t = 1; - if ( are_near(f, t) ) + if (f == t) { EllipticalArc *arc = static_cast(duplicate()); - arc->_center = arc->_initial_point = arc->_final_point = pointAt(f); - arc->_start_angle = arc->_end_angle = _start_angle; - arc->_rot_angle = _rot_angle; - arc->_sweep = _sweep; - arc->_large_arc = _large_arc; + arc->_initial_point = arc->_final_point = pointAt(f); + arc->_start_angle = arc->_end_angle = 0; + arc->_ellipse = Ellipse(); + arc->_sweep = false; + arc->_large_arc = false; return arc; } @@ -415,21 +442,24 @@ Curve* EllipticalArc::portion(double f, double t) const arc->_initial_point = pointAt(f); arc->_final_point = pointAt(t); if ( f > t ) arc->_sweep = !_sweep; - if ( _large_arc && fabs(sweepAngle() * (t-f)) < M_PI) + if ( _large_arc && fabs(sweepAngle() * (t-f)) < M_PI) { arc->_large_arc = false; - arc->_updateCenterAndAngles(arc->isSVGCompliant()); //TODO: be more clever + } + //arc->_start_angle = angleAt(f); + //arc->_end_angle = angleAt(t); + arc->_updateCenterAndAngles(); //TODO: be more clever return arc; } // the arc is the same but traversed in the opposite direction -Curve *EllipticalArc::reverse() const { +Curve *EllipticalArc::reverse() const +{ EllipticalArc *rarc = static_cast(duplicate()); rarc->_sweep = !_sweep; rarc->_initial_point = _final_point; rarc->_final_point = _initial_point; rarc->_start_angle = _end_angle; rarc->_end_angle = _start_angle; - rarc->_updateCenterAndAngles(rarc->isSVGCompliant()); return rarc; } @@ -455,8 +485,8 @@ std::vector EllipticalArc::allNearestTimes( Point const& p, double from, Point np = seg.pointAt( seg.nearestTime(p) ); if ( are_near(ray(Y), 0) ) { - if ( are_near(_rot_angle, M_PI/2) - || are_near(_rot_angle, 3*M_PI/2) ) + if ( are_near(rotationAngle(), M_PI/2) + || are_near(rotationAngle(), 3*M_PI/2) ) { result = roots(np[Y], Y); } @@ -467,8 +497,8 @@ std::vector EllipticalArc::allNearestTimes( Point const& p, double from, } else { - if ( are_near(_rot_angle, M_PI/2) - || are_near(_rot_angle, 3*M_PI/2) ) + if ( are_near(rotationAngle(), M_PI/2) + || are_near(rotationAngle(), 3*M_PI/2) ) { result = roots(np[X], X); } @@ -527,7 +557,7 @@ std::vector EllipticalArc::allNearestTimes( Point const& p, double from, Point p_c = p - center(); double rx2_ry2 = (ray(X) - ray(Y)) * (ray(X) + ray(Y)); double sinrot, cosrot; - sincos(_rot_angle, sinrot, cosrot); + sincos(rotationAngle(), sinrot, cosrot); double expr1 = ray(X) * (p_c[X] * cosrot + p_c[Y] * sinrot); Poly coeff; coeff.resize(5); @@ -662,227 +692,156 @@ std::vector EllipticalArc::allNearestTimes( Point const& p, double from, } #endif -/* - * NOTE: this implementation follows Standard SVG 1.1 implementation guidelines - * for elliptical arc curves. See Appendix F.6. - */ -void EllipticalArc::_updateCenterAndAngles(bool svg) -{ - Point d = initialPoint() - finalPoint(); - // TODO move this to SVGElipticalArc? - if (svg) - { - if ( initialPoint() == finalPoint() ) - { - _rot_angle = _start_angle = _end_angle = 0; - _center = initialPoint(); - _rays = Geom::Point(0,0); - _large_arc = _sweep = false; - return; +void EllipticalArc::_filterIntersections(std::vector &xs, bool is_first) const +{ + Interval unit(0, 1); + std::vector::reverse_iterator i = xs.rbegin(), last = xs.rend(); + while (i != last) { + Coord &t = is_first ? i->first : i->second; + assert(are_near(_ellipse.pointAt(t), i->point(), 1e-6)); + t = timeAtAngle(t); + if (!unit.contains(t)) { + xs.erase((++i).base()); + continue; + } else { + assert(are_near(pointAt(t), i->point(), 1e-6)); + ++i; } + } +} - _rays[X] = std::fabs(_rays[X]); - _rays[Y] = std::fabs(_rays[Y]); - - if ( are_near(ray(X), 0) || are_near(ray(Y), 0) ) - { - _rays[X] = L2(d) / 2; - _rays[Y] = 0; - _rot_angle = std::atan2(d[Y], d[X]); - _start_angle = 0; - _end_angle = M_PI; - _center = middle_point(initialPoint(), finalPoint()); - _large_arc = false; - _sweep = false; - return; - } +std::vector EllipticalArc::intersect(Curve const &other, Coord eps) const +{ + if (isLineSegment()) { + LineSegment ls(_initial_point, _final_point); + return ls.intersect(other, eps); } - else - { - if ( are_near(initialPoint(), finalPoint()) ) - { - if ( are_near(ray(X), 0) && are_near(ray(Y), 0) ) - { - _start_angle = _end_angle = 0; - _center = initialPoint(); - return; - } - else - { - THROW_RANGEERROR("initial and final point are the same"); - } - } - if ( are_near(ray(X), 0) && are_near(ray(Y), 0) ) - { // but initialPoint != finalPoint - THROW_RANGEERROR( - "there is no ellipse that satisfies the given constraints: " - "ray(X) == 0 && ray(Y) == 0 but initialPoint != finalPoint" - ); - } - if ( are_near(ray(Y), 0) ) - { - Point v = initialPoint() - finalPoint(); - if ( are_near(L2sq(v), 4*ray(X)*ray(X)) ) - { - Angle angle(v); - if ( are_near( angle, _rot_angle ) ) - { - _start_angle = 0; - _end_angle = M_PI; - _center = v/2 + finalPoint(); - return; - } - angle -= M_PI; - if ( are_near( angle, _rot_angle ) ) - { - _start_angle = M_PI; - _end_angle = 0; - _center = v/2 + finalPoint(); - return; - } - THROW_RANGEERROR( - "there is no ellipse that satisfies the given constraints: " - "ray(Y) == 0 " - "and slope(initialPoint - finalPoint) != rotation_angle " - "and != rotation_angle + PI" - ); - } - if ( L2sq(v) > 4*ray(X)*ray(X) ) - { - THROW_RANGEERROR( - "there is no ellipse that satisfies the given constraints: " - "ray(Y) == 0 and distance(initialPoint, finalPoint) > 2*ray(X)" - ); - } - else - { - THROW_RANGEERROR( - "there is infinite ellipses that satisfy the given constraints: " - "ray(Y) == 0 and distance(initialPoint, finalPoint) < 2*ray(X)" - ); - } - } + std::vector result; - if ( are_near(ray(X), 0) ) - { - Point v = initialPoint() - finalPoint(); - if ( are_near(L2sq(v), 4*ray(Y)*ray(Y)) ) - { - double angle = std::atan2(v[Y], v[X]); - if (angle < 0) angle += 2*M_PI; - double rot_angle = _rot_angle.radians() + M_PI/2; - if ( !(rot_angle < 2*M_PI) ) rot_angle -= 2*M_PI; - if ( are_near( angle, rot_angle ) ) - { - _start_angle = M_PI/2; - _end_angle = 3*M_PI/2; - _center = v/2 + finalPoint(); - return; - } - angle -= M_PI; - if ( angle < 0 ) angle += 2*M_PI; - if ( are_near( angle, rot_angle ) ) - { - _start_angle = 3*M_PI/2; - _end_angle = M_PI/2; - _center = v/2 + finalPoint(); - return; - } - THROW_RANGEERROR( - "there is no ellipse that satisfies the given constraints: " - "ray(X) == 0 " - "and slope(initialPoint - finalPoint) != rotation_angle + PI/2 " - "and != rotation_angle + (3/2)*PI" - ); - } - if ( L2sq(v) > 4*ray(Y)*ray(Y) ) - { - THROW_RANGEERROR( - "there is no ellipse that satisfies the given constraints: " - "ray(X) == 0 and distance(initialPoint, finalPoint) > 2*ray(Y)" - ); - } - else - { - THROW_RANGEERROR( - "there is infinite ellipses that satisfy the given constraints: " - "ray(X) == 0 and distance(initialPoint, finalPoint) < 2*ray(Y)" - ); - } + if (other.isLineSegment()) { + LineSegment ls(other.initialPoint(), other.finalPoint()); + result = _ellipse.intersect(ls); + _filterIntersections(result, true); + return result; + } - } + BezierCurve const *bez = dynamic_cast(&other); + if (bez) { + result = _ellipse.intersect(bez->fragment()); + _filterIntersections(result, true); + return result; + } + EllipticalArc const *arc = dynamic_cast(&other); + if (arc) { + result = _ellipse.intersect(arc->_ellipse); + _filterIntersections(result, true); + arc->_filterIntersections(result, false); + return result; } - Rotate rm(_rot_angle); - Affine m(rm); - m[1] = -m[1]; - m[2] = -m[2]; - - Point p = (d / 2) * m; - double rx2 = _rays[X] * _rays[X]; - double ry2 = _rays[Y] * _rays[Y]; - double rxpy = _rays[X] * p[Y]; - double rypx = _rays[Y] * p[X]; - double rx2py2 = rxpy * rxpy; - double ry2px2 = rypx * rypx; - double num = rx2 * ry2; - double den = rx2py2 + ry2px2; - assert(den != 0); - double rad = num / den; - Point c(0,0); - if (rad > 1) - { - rad -= 1; - rad = std::sqrt(rad); + // in case someone wants to make a custom curve type + result = other.intersect(*this, eps); + transpose_in_place(result); + return result; +} - if (_large_arc == _sweep) rad = -rad; - c = rad * Point(rxpy / ray(Y), -rypx / ray(X)); - _center = c * rm + middle_point(initialPoint(), finalPoint()); +void EllipticalArc::_updateCenterAndAngles() +{ + // See: http://www.w3.org/TR/SVG/implnote.html#ArcImplementationNotes + Point d = initialPoint() - finalPoint(); + Point mid = middle_point(initialPoint(), finalPoint()); + + // if ip = sp, the arc contains no other points + if (initialPoint() == finalPoint()) { + _start_angle = _end_angle = 0; + _ellipse.setRotationAngle(0); + _ellipse.setCenter(initialPoint()); + _ellipse.setRays(0, 0); + _large_arc = _sweep = false; + return; } - else if (rad == 1 || svg) - { - double lamda = std::sqrt(1 / rad); - _rays[X] *= lamda; - _rays[Y] *= lamda; - _center = middle_point(initialPoint(), finalPoint()); + + // rays should be positive + _ellipse.setRays(std::fabs(ray(X)), std::fabs(ray(Y))); + + if (ray(X) == 0 || ray(Y) == 0) { + _start_angle = 0; + _end_angle = M_PI; + _ellipse.setRays(L2(d) / 2, 0); + _ellipse.setRotationAngle(atan2(d)); + _ellipse.setCenter(mid); + _large_arc = false; + _sweep = false; + return; } - else - { - THROW_RANGEERROR( - "there is no ellipse that satisfies the given constraints" - ); + + Rotate rot(rotationAngle()); // the matrix in F.6.5.3 + Rotate invrot = rot.inverse(); // the matrix in F.6.5.1 + + Point r = rays(); + Point p = (initialPoint() - mid) * invrot; // x', y' in F.6.5.1 + Point c(0,0); // cx', cy' in F.6.5.2 + + // Correct out-of-range radii + Coord lambda = hypot(p[X]/r[X], p[Y]/r[Y]); + if (lambda > 1) { + r *= lambda; + _ellipse.setRays(r); + _ellipse.setCenter(mid); + } else { + // evaluate F.6.5.2 + Coord rxry = r[X]*r[X] * r[Y]*r[Y]; + Coord pxry = p[X]*p[X] * r[Y]*r[Y]; + Coord rxpy = r[X]*r[X] * p[Y]*p[Y]; + Coord rad = (rxry - pxry - rxpy)/(rxpy + pxry); + // normally rad should never be negative, but numerical inaccuracy may cause this + if (rad > 0) { + rad = std::sqrt(rad); + if (_sweep == _large_arc) { + rad = -rad; + } + c = rad * Point(r[X]*p[Y]/r[Y], -r[Y]*p[X]/r[X]); + _ellipse.setCenter(c * rot + mid); + } else { + _ellipse.setCenter(mid); + } } - Point sp((p[X] - c[X]) / ray(X), (p[Y] - c[Y]) / ray(Y)); - Point ep((-p[X] - c[X]) / ray(X), (-p[Y] - c[Y]) / ray(Y)); + // Compute start and end angles. + // If the ellipse was enlarged, c will be zero - this is correct. + Point sp((p[X] - c[X]) / r[X], (p[Y] - c[Y]) / r[Y]); + Point ep((-p[X] - c[X]) / r[X], (-p[Y] - c[Y]) / r[Y]); Point v(1, 0); _start_angle = angle_between(v, sp); double sweep_angle = angle_between(sp, ep); if (!_sweep && sweep_angle > 0) sweep_angle -= 2*M_PI; if (_sweep && sweep_angle < 0) sweep_angle += 2*M_PI; - _end_angle = _start_angle; - _end_angle += sweep_angle; + _end_angle = _start_angle + sweep_angle; } D2 EllipticalArc::toSBasis() const { + if (isChord()) { + return chord().toSBasis(); + } + D2 arc; // the interval of parametrization has to be [0,1] - Coord et = initialAngle().radians() + ( _sweep ? sweepAngle() : -sweepAngle() ); - Linear param(initialAngle(), et); - Coord cos_rot_angle, sin_rot_angle; - sincos(_rot_angle, sin_rot_angle, cos_rot_angle); + Coord et = initialAngle().radians() + sweepAngle(); + Linear param(initialAngle().radians(), et); + Coord cosrot, sinrot; + sincos(rotationAngle(), sinrot, cosrot); // order = 4 seems to be enough to get a perfect looking elliptical arc SBasis arc_x = ray(X) * cos(param,4); SBasis arc_y = ray(Y) * sin(param,4); - arc[0] = arc_x * cos_rot_angle - arc_y * sin_rot_angle + Linear(center(X),center(X)); - arc[1] = arc_x * sin_rot_angle + arc_y * cos_rot_angle + Linear(center(Y),center(Y)); + arc[0] = arc_x * cosrot - arc_y * sinrot + Linear(center(X), center(X)); + arc[1] = arc_x * sinrot + arc_y * cosrot + Linear(center(Y), center(Y)); // ensure that endpoints remain exact for ( int d = 0 ; d < 2 ; d++ ) { @@ -898,22 +857,24 @@ void EllipticalArc::transform(Affine const& m) if (isChord()) { _initial_point *= m; _final_point *= m; - _center = middle_point(_initial_point, _final_point); - _rays = Point(0,0); - _rot_angle = 0; + _ellipse.setCenter(middle_point(_initial_point, _final_point)); + _ellipse.setRays(0, 0); + _ellipse.setRotationAngle(0); return; } - // TODO avoid allocating a new arc here - Ellipse e(center(X), center(Y), ray(X), ray(Y), _rot_angle); - e *= m; - Point inner_point = pointAt(0.5); - EllipticalArc *arc = e.arc(initialPoint() * m, - inner_point * m, - finalPoint() * m, - isSVGCompliant()); - *this = *arc; - delete arc; + _initial_point *= m; + _final_point *= m; + _ellipse *= m; + if (m.det() < 0) { + _sweep = !_sweep; + } + + // ellipse transformation does not preserve its functional form, + // i.e. e.pointAt(0.5)*m and (e*m).pointAt(0.5) can be different. + // We need to recompute start / end angles. + _start_angle = _ellipse.timeAt(_initial_point); + _end_angle = _ellipse.timeAt(_final_point); } bool EllipticalArc::operator==(Curve const &c) const @@ -924,8 +885,8 @@ bool EllipticalArc::operator==(Curve const &c) const if (_final_point != other->_final_point) return false; // TODO: all arcs with ellipse rays which are too small // and fall back to a line should probably be equal - if (_rays != other->_rays) return false; - if (_rot_angle != other->_rot_angle) return false; + if (rays() != other->rays()) return false; + if (rotationAngle() != other->rotationAngle()) return false; if (_large_arc != other->_large_arc) return false; if (_sweep != other->_sweep) return false; return true; @@ -936,7 +897,7 @@ void EllipticalArc::feed(PathSink &sink, bool moveto_initial) const if (moveto_initial) { sink.moveTo(_initial_point); } - sink.arcTo(_rays[X], _rays[Y], _rot_angle, _large_arc, _sweep, _final_point); + sink.arcTo(ray(X), ray(Y), rotationAngle(), _large_arc, _sweep, _final_point); } Coord EllipticalArc::map_to_01(Coord angle) const @@ -945,6 +906,19 @@ Coord EllipticalArc::map_to_01(Coord angle) const finalAngle(), _sweep); } + +std::ostream &operator<<(std::ostream &out, EllipticalArc const &ea) +{ + out << "EllipticalArc(" + << ea.initialPoint() << ", " + << format_coord_nice(ea.ray(X)) << ", " << format_coord_nice(ea.ray(Y)) << ", " + << format_coord_nice(ea.rotationAngle()) << ", " + << "large_arc=" << (ea.largeArc() ? "true" : "false") << ", " + << "sweep=" << (ea.sweep() ? "true" : "false") << ", " + << ea.finalPoint() << ")"; + return out; +} + } // end namespace Geom /* diff --git a/src/2geom/elliptical-arc.h b/src/2geom/elliptical-arc.h index 342b8c8c9..83909370e 100644 --- a/src/2geom/elliptical-arc.h +++ b/src/2geom/elliptical-arc.h @@ -38,10 +38,11 @@ #define LIB2GEOM_SEEN_ELLIPTICAL_ARC_H #include +#include <2geom/affine.h> #include <2geom/angle.h> #include <2geom/bezier-curve.h> #include <2geom/curve.h> -#include <2geom/affine.h> +#include <2geom/ellipse.h> #include <2geom/sbasis-curve.h> // for non-native methods #include <2geom/utils.h> @@ -56,21 +57,30 @@ public: : AngleInterval(0, 0, true) , _initial_point(0,0) , _final_point(0,0) - , _rays(0,0) - , _center(0,0) - , _rot_angle(0) , _large_arc(true) {} /** @brief Create a new elliptical arc. * @param ip Initial point of the arc - * @param rx First ray of the ellipse - * @param ry Second ray of the ellipse + * @param r Rays of the ellipse as a point * @param rot Angle of rotation of the X axis of the ellipse in radians * @param large If true, the large arc is chosen (always >= 180 degrees), otherwise * the smaller arc is chosen * @param sweep If true, the clockwise arc is chosen, otherwise the counter-clockwise * arc is chosen * @param fp Final point of the arc */ + EllipticalArc( Point const &ip, Point const &r, + Coord rot_angle, bool large_arc, bool sweep, + Point const &fp + ) + : AngleInterval(0,0,sweep) + , _initial_point(ip) + , _final_point(fp) + , _ellipse(0, 0, r[X], r[Y], rot_angle) + , _large_arc(large_arc) + { + _updateCenterAndAngles(); + } + EllipticalArc( Point const &ip, Coord rx, Coord ry, Coord rot_angle, bool large_arc, bool sweep, Point const &fp @@ -78,11 +88,10 @@ public: : AngleInterval(0,0,sweep) , _initial_point(ip) , _final_point(fp) - , _rays(rx, ry) - , _rot_angle(rot_angle) + , _ellipse(0, 0, rx, ry, rot_angle) , _large_arc(large_arc) { - _updateCenterAndAngles(false); + _updateCenterAndAngles(); } // methods new to EllipticalArc go here @@ -98,15 +107,15 @@ public: /** @brief Get the defining ellipse's rotation * @return Angle between the +X ray of the ellipse and the +X axis */ Angle rotationAngle() const { - return _rot_angle; + return _ellipse.rotationAngle(); } /** @brief Get one of the ellipse's rays * @param d Dimension to retrieve * @return The selected ray of the ellipse */ - Coord ray(Dim2 d) const { return _rays[d]; } + Coord ray(Dim2 d) const { return _ellipse.ray(d); } /** @brief Get both rays as a point * @return Point with X equal to the X ray and Y to Y ray */ - Point rays() const { return _rays; } + Point rays() const { return _ellipse.rays(); } /** @brief Whether the arc is larger than half an ellipse. * @return True if the arc is larger than \f$\pi\f$, false otherwise */ bool largeArc() const { return _large_arc; } @@ -125,12 +134,11 @@ public: { _initial_point = ip; _final_point = fp; - _rays[X] = rx; - _rays[Y] = ry; - _rot_angle = Angle(rot_angle); + _ellipse.setRays(rx, ry); + _ellipse.setRotationAngle(rot_angle); _large_arc = large_arc; _sweep = sweep; - _updateCenterAndAngles(isSVGCompliant()); + _updateCenterAndAngles(); } /** @brief Change the initial and final point in one operation. * This method exists because modifying any of the endpoints causes rather costly @@ -140,21 +148,16 @@ public: void setEndpoints(Point const &ip, Point const &fp) { _initial_point = ip; _final_point = fp; - _updateCenterAndAngles(isSVGCompliant()); + _updateCenterAndAngles(); } /// @} /// @name Access computed parameters of the arc /// @{ - Coord center(Dim2 d) const { return _center[d]; } + Coord center(Dim2 d) const { return _ellipse.center(d); } /** @brief Get the arc's center * @return The arc's center, situated on the intersection of the ellipse's rays */ - Point center() const { return _center; } - /** @brief Get the extent of the arc - * @return The angle between the initial and final point, in arc's angular coordinates */ - Coord sweepAngle() const { - return extent(); - } + Point center() const { return _ellipse.center(); } /// @} /// @name Angular evaluation @@ -177,14 +180,13 @@ public: * This function returns the transform that maps the unit circle to the arc's ellipse. * @return Transform from unit circle to the arc's ellipse */ Affine unitCircleTransform() const; + Affine inverseUnitCircleTransform() const; /// @} - /** @brief Check whether the arc adheres to SVG 1.1 implementation guidelines */ - virtual bool isSVGCompliant() const { return false; } - - /// Check whether both rays are nonzero + /** @brief Check whether both rays are nonzero. + * If they are not, the arc is represented as a line segment instead. */ bool isChord() const { - return _rays[0] == 0 || _rays[Y] == 0; + return ray(X) == 0 || ray(Y) == 0; } std::pair subdivide(Coord t) const { @@ -203,15 +205,16 @@ public: virtual Curve* duplicate() const { return new EllipticalArc(*this); } virtual void setInitial(Point const &p) { _initial_point = p; - _updateCenterAndAngles(isSVGCompliant()); + _updateCenterAndAngles(); } virtual void setFinal(Point const &p) { _final_point = p; - _updateCenterAndAngles(isSVGCompliant()); + _updateCenterAndAngles(); } virtual bool isDegenerate() const { return _initial_point == _final_point; } + virtual bool isLineSegment() const { return isChord(); } virtual Rect boundsFast() const { return boundsExact(); } @@ -230,13 +233,14 @@ public: } return allNearestTimes(p, from, to).front(); } + virtual std::vector intersect(Curve const &other, Coord eps=EPSILON) const; virtual int degreesOfFreedom() const { return 7; } virtual Curve *derivative() const; virtual void transform(Affine const &m); virtual Curve &operator*=(Translate const &m) { - _initial_point += m.vector(); - _final_point += m.vector(); - _center += m.vector(); + _initial_point *= m; + _final_point *= m; + _ellipse *= m; return *this; } @@ -248,28 +252,34 @@ public: virtual D2 toSBasis() const; virtual double valueAt(Coord t, Dim2 d) const { - return valueAtAngle(angleAt(t), d); - } - virtual Point pointAt(Coord t) const { - return pointAtAngle(angleAt(t)); + if (isChord()) return chord().valueAt(t, d); + return valueAtAngle(angleAt(t), d); } + virtual Point pointAt(Coord t) const; virtual Curve* portion(double f, double t) const; virtual Curve* reverse() const; virtual bool operator==(Curve const &c) const; virtual void feed(PathSink &sink, bool moveto_initial) const; protected: - void _updateCenterAndAngles(bool svg); + void _updateCenterAndAngles(); + void _filterIntersections(std::vector &xs, bool is_first) const; Point _initial_point, _final_point; - Point _rays, _center; - Angle _rot_angle; + Ellipse _ellipse; bool _large_arc; private: Coord map_to_01(Coord angle) const; }; // end class EllipticalArc + +// implemented in elliptical-arc-from-sbasis.cpp +bool arc_from_sbasis(EllipticalArc &ea, D2 const &in, + double tolerance = EPSILON, unsigned num_samples = 20); + +std::ostream &operator<<(std::ostream &out, EllipticalArc const &ea); + } // end namespace Geom #endif // LIB2GEOM_SEEN_ELLIPTICAL_ARC_H diff --git a/src/2geom/forward.h b/src/2geom/forward.h index a6e420122..cf9c75988 100644 --- a/src/2geom/forward.h +++ b/src/2geom/forward.h @@ -37,7 +37,7 @@ namespace Geom { -// basic types +// primitives typedef double Coord; typedef int IntCoord; class Point; @@ -61,6 +61,12 @@ typedef GenericOptRect OptIntRect; class Linear; class Bezier; class SBasis; +class Poly; + +// shapes +class Circle; +class Ellipse; +class ConvexHull; // curves class Curve; @@ -73,7 +79,6 @@ typedef BezierCurveN<1> LineSegment; typedef BezierCurveN<2> QuadraticBezier; typedef BezierCurveN<3> CubicBezier; class EllipticalArc; -class SVGEllipticalArc; // paths and path sequences class Path; diff --git a/src/2geom/intersection-graph.cpp b/src/2geom/intersection-graph.cpp index b9e2feeed..ff96c28a8 100644 --- a/src/2geom/intersection-graph.cpp +++ b/src/2geom/intersection-graph.cpp @@ -35,6 +35,7 @@ #include <2geom/path.h> #include <2geom/pathvector.h> #include +#include namespace Geom { @@ -157,6 +158,41 @@ PathVector PathIntersectionGraph::getIntersection() return result; } +PathVector PathIntersectionGraph::getAminusB() +{ + PathVector result = _getResult(false, true); + _handleNonintersectingPaths(result, 0, false); + return result; +} + +PathVector PathIntersectionGraph::getBminusA() +{ + PathVector result = _getResult(true, false); + _handleNonintersectingPaths(result, 1, false); + return result; +} + +PathVector PathIntersectionGraph::getXOR() +{ + PathVector r1 = getAminusB(); + PathVector r2 = getBminusA(); + std::copy(r2.begin(), r2.end(), std::back_inserter(r1)); + return r1; +} + +std::vector PathIntersectionGraph::intersectionPoints() const +{ + std::vector result; + + typedef IntersectionList::const_iterator Iter; + for (std::size_t i = 0; i < _xalists.size(); ++i) { + for (Iter j = _xalists[i].begin(); j != _xalists[i].end(); ++j) { + result.push_back(j->p); + } + } + return result; +} + PathVector PathIntersectionGraph::_getResult(bool enter_a, bool enter_b) { typedef IntersectionList::iterator Iter; @@ -231,6 +267,7 @@ PathVector PathIntersectionGraph::_getResult(bool enter_a, bool enter_b) std::swap(lscur, lsother); std::swap(cur, other); } + result.back().close(true); assert(!result.back().empty()); } diff --git a/src/2geom/intersection-graph.h b/src/2geom/intersection-graph.h index dd70d3d5b..44beaf46b 100644 --- a/src/2geom/intersection-graph.h +++ b/src/2geom/intersection-graph.h @@ -79,6 +79,11 @@ public: PathVector getUnion(); PathVector getIntersection(); + PathVector getAminusB(); + PathVector getBminusA(); + PathVector getXOR(); + + std::vector intersectionPoints() const; private: PathVector _getResult(bool enter_a, bool enter_b); diff --git a/src/2geom/intersection.h b/src/2geom/intersection.h index 848797682..ae4b50dd1 100644 --- a/src/2geom/intersection.h +++ b/src/2geom/intersection.h @@ -92,7 +92,7 @@ private: }; -// TODO: move into new header +// TODO: move into new header? template struct ShapeTraits { typedef Coord TimeType; @@ -101,6 +101,24 @@ struct ShapeTraits { typedef Intersection<> IntersectionType; }; +template inline +std::vector< Intersection > transpose(std::vector< Intersection > const &in) { + std::vector< Intersection > result; + for (std::size_t i = 0; i < in.size(); ++i) { + result.push_back(Intersection(in[i].second, in[i].first, in[i].point())); + } + return result; +} + +template inline +void transpose_in_place(std::vector< Intersection > &xs) { + for (std::size_t i = 0; i < xs.size(); ++i) { + std::swap(xs[i].first, xs[i].second); + } +} + +typedef Intersection<> ShapeIntersection; + } // namespace Geom diff --git a/src/2geom/interval.h b/src/2geom/interval.h index 09ea46923..fd446a1c6 100644 --- a/src/2geom/interval.h +++ b/src/2geom/interval.h @@ -93,7 +93,7 @@ public: /// @name Inspect contained values. /// @{ - /** @brief Check whether both endpoints are finite. */ + /// Check whether both endpoints are finite. bool isFinite() const { return IS_FINITE(min()) && IS_FINITE(max()); } @@ -102,11 +102,16 @@ public: Coord valueAt(Coord t) { return lerp(t, min(), max()); } - /** @brief Find closest time in [0,1] that maps to the given value. */ - Coord nearestTime(Coord t) { - if (t < min()) return 0; - if (t > max()) return 1; - return (t - min()) / extent(); + /** @brief Compute a time value that maps to the given value. + * The supplied value does not need to be in the interval for this method to work. */ + Coord timeAt(Coord v) { + return (v - min()) / extent(); + } + /// Find closest time in [0,1] that maps to the given value. */ + Coord nearestTime(Coord v) { + if (v <= min()) return 0; + if (v >= max()) return 1; + return timeAt(v); } /// @} diff --git a/src/2geom/line.cpp b/src/2geom/line.cpp index 35cf2d379..8bea33638 100644 --- a/src/2geom/line.cpp +++ b/src/2geom/line.cpp @@ -62,7 +62,7 @@ void Line::setCoefficients (Coord a, Coord b, Coord c) { if (a == 0 && b == 0) { if (c != 0) { - THROW_LOGICALERROR("the passed coefficients gives the empty set"); + THROW_LOGICALERROR("the passed coefficients give the empty set"); } _initial = Point(0,0); _final = Point(0,0); @@ -70,20 +70,20 @@ void Line::setCoefficients (Coord a, Coord b, Coord c) } if (a == 0) { // b must be nonzero - _initial = Point(0, c / b); + _initial = Point(0, -c / b); _final = _initial; _final[X] = 1; return; } if (b == 0) { - _initial = Point(c / a, 0); + _initial = Point(-c / a, 0); _final = _initial; _final[Y] = 1; return; } - _initial = Point(c / a, 0); - _final = Point(0, c / b); + _initial = Point(-c / a, 0); + _final = Point(0, -c / b); } void Line::coefficients(Coord &a, Coord &b, Coord &c) const @@ -217,6 +217,66 @@ Coord Line::timeAt(Point const &p) const } } +std::vector Line::intersect(Line const &other) const +{ + std::vector result; + + Point v1 = versor(); + Point v2 = other.versor(); + Coord cp = cross(v1, v2); + if (cp == 0) return result; + + Point odiff = other.initialPoint() - initialPoint(); + Coord t1 = cross(odiff, v2) / cp; + Coord t2 = cross(odiff, v1) / cp; + result.push_back(ShapeIntersection(*this, other, t1, t2)); + return result; +} + +std::vector Line::intersect(Ray const &r) const +{ + Line other(r); + std::vector result = intersect(other); + filter_ray_intersections(result, false, true); + return result; +} + +std::vector Line::intersect(LineSegment const &ls) const +{ + Line other(ls); + std::vector result = intersect(other); + filter_line_segment_intersections(result, false, true); + return result; +} + + + +void filter_line_segment_intersections(std::vector &xs, bool a, bool b) +{ + Interval unit(0, 1); + std::vector::reverse_iterator i = xs.rbegin(), last = xs.rend(); + while (i != last) { + if ((a && !unit.contains(i->first)) || (b && !unit.contains(i->second))) { + xs.erase((++i).base()); + } else { + ++i; + } + } +} + +void filter_ray_intersections(std::vector &xs, bool a, bool b) +{ + Interval unit(0, 1); + std::vector::reverse_iterator i = xs.rbegin(), last = xs.rend(); + while (i != last) { + if ((a && i->first < 0) || (b && i->second < 0)) { + xs.erase((++i).base()); + } else { + ++i; + } + } +} + namespace detail { diff --git a/src/2geom/line.h b/src/2geom/line.h index 2c47b4486..5d92c436d 100644 --- a/src/2geom/line.h +++ b/src/2geom/line.h @@ -49,9 +49,15 @@ namespace Geom // class docs in cpp file class Line - : boost::equality_comparable1 > + : boost::equality_comparable1< Line + , MultipliableNoncommutative< Line, Translate + , MultipliableNoncommutative< Line, Scale + , MultipliableNoncommutative< Line, Rotate + , MultipliableNoncommutative< Line, HShear + , MultipliableNoncommutative< Line, VShear + , MultipliableNoncommutative< Line, Zoom + , MultipliableNoncommutative< Line, Affine + > > > > > > > > { private: Point _initial; @@ -188,6 +194,14 @@ public: bool isDegenerate() const { return _initial == _final; } + /// Check if the line is horizontal (y is constant). + bool isHorizontal() const { + return _initial[Y] == _final[Y]; + } + /// Check if the line is vertical (x is constant). + bool isVertical() const { + return _initial[X] == _final[X]; + } /** @brief Reparametrize the line so that it has unit speed. */ void normalize() { @@ -349,13 +363,18 @@ public: } /// @} - //std::vector intersect(Line const &other, Coord precision = EPSILON) const; + std::vector intersect(Line const &other) const; + std::vector intersect(Ray const &r) const; + std::vector intersect(LineSegment const &ls) const; - Line &operator*=(Affine const &m) { - _initial *= m; - _final *= m; + template + Line &operator*=(T const &tr) { + BOOST_CONCEPT_ASSERT((TransformConcept)); + _initial *= tr; + _final *= tr; return *this; } + bool operator==(Line const &other) const { if (distance(pointAt(nearestTime(other._initial)), other._initial) != 0) return false; if (distance(pointAt(nearestTime(other._final)), other._final) != 0) return false; @@ -363,6 +382,15 @@ public: } }; // end class Line +/** @brief Removes intersections outside of the unit interval. + * A helper used to implement line segment intersections. + * @param xs Line intersections + * @param a Whether the first time value has to be in the unit interval + * @param b Whether the second time value has to be in the unit interval + * @return Appropriately filtered intersections */ +void filter_line_segment_intersections(std::vector &xs, bool a=false, bool b=true); +void filter_ray_intersections(std::vector &xs, bool a=false, bool b=true); + /// @brief Compute distance from point to line. /// @relates Line inline diff --git a/src/2geom/numeric/fitting-model.h b/src/2geom/numeric/fitting-model.h index 5cc6dde7a..fb96d1d2a 100644 --- a/src/2geom/numeric/fitting-model.h +++ b/src/2geom/numeric/fitting-model.h @@ -39,7 +39,7 @@ #include <2geom/sbasis.h> #include <2geom/bezier.h> #include <2geom/bezier-curve.h> -#include <2geom/poly.h> +#include <2geom/polynomial.h> #include <2geom/ellipse.h> #include <2geom/circle.h> #include <2geom/utils.h> diff --git a/src/2geom/path-intersection.h b/src/2geom/path-intersection.h index e3a8d1de3..f06eeaf94 100644 --- a/src/2geom/path-intersection.h +++ b/src/2geom/path-intersection.h @@ -35,11 +35,9 @@ #ifndef LIB2GEOM_SEEN_PATH_INTERSECTION_H #define LIB2GEOM_SEEN_PATH_INTERSECTION_H -#include <2geom/path.h> - #include <2geom/crossing.h> - -#include <2geom/sweep.h> +#include <2geom/path.h> +#include <2geom/sweep-bounds.h> namespace Geom { diff --git a/src/2geom/path-sink.cpp b/src/2geom/path-sink.cpp index 6ccc21e7b..3b8d407f8 100644 --- a/src/2geom/path-sink.cpp +++ b/src/2geom/path-sink.cpp @@ -31,6 +31,8 @@ #include <2geom/sbasis-to-bezier.h> #include <2geom/path-sink.h> #include <2geom/exception.h> +#include <2geom/circle.h> +#include <2geom/ellipse.h> namespace Geom { @@ -68,6 +70,26 @@ void PathSink::feed(Rect const &r) { closePath(); } +void PathSink::feed(Circle const &e) { + Coord r = e.radius(); + Point c = e.center(); + Point a = c + Point(0, c[Y] + r); + Point b = c + Point(0, c[Y] - r); + + moveTo(a); + arcTo(r, r, 0, false, false, b); + arcTo(r, r, 0, false, false, a); + closePath(); +} + +void PathSink::feed(Ellipse const &e) { + Point s = e.pointAt(0); + moveTo(s); + arcTo(e.ray(X), e.ray(Y), e.rotationAngle(), false, false, e.pointAt(M_PI)); + arcTo(e.ray(X), e.ray(Y), e.rotationAngle(), false, false, s); + closePath(); +} + } /* diff --git a/src/2geom/path-sink.h b/src/2geom/path-sink.h index d6806031d..17ede18a4 100644 --- a/src/2geom/path-sink.h +++ b/src/2geom/path-sink.h @@ -32,6 +32,7 @@ #ifndef LIB2GEOM_SEEN_PATH_SINK_H #define LIB2GEOM_SEEN_PATH_SINK_H +#include <2geom/forward.h> #include <2geom/pathvector.h> #include <2geom/curves.h> #include @@ -101,6 +102,10 @@ public: virtual void feed(PathVector const &v); /// Output an axis-aligned rectangle, using moveTo, lineTo and closePath. virtual void feed(Rect const &); + /// Output a circle as two elliptical arcs. + virtual void feed(Circle const &e); + /// Output an ellipse as two elliptical arcs. + virtual void feed(Ellipse const &e); virtual ~PathSink() {} }; @@ -152,8 +157,8 @@ public: if (!_in_path) { moveTo(_start_p); } - _path.template appendNew(rx, ry, angle, - large_arc, sweep, p); + _path.template appendNew(rx, ry, angle, + large_arc, sweep, p); } bool backspace() diff --git a/src/2geom/path.cpp b/src/2geom/path.cpp index 8cba316f5..5fbc65b3e 100644 --- a/src/2geom/path.cpp +++ b/src/2geom/path.cpp @@ -35,8 +35,11 @@ #include <2geom/path.h> #include <2geom/pathvector.h> #include <2geom/transforms.h> +#include <2geom/circle.h> +#include <2geom/ellipse.h> #include <2geom/convex-hull.h> #include <2geom/svg-path-writer.h> +#include <2geom/sweeper.h> #include #include @@ -231,7 +234,7 @@ Path::Path(Rect const &r) Path::Path(ConvexHull const &ch) : _curves(new Sequence()) , _closing_seg(new ClosingSegment(Point(), Point())) - , _closed(false) + , _closed(true) , _exception_on_stitch(true) { if (ch.empty()) { @@ -253,6 +256,49 @@ Path::Path(ConvexHull const &ch) _closed = true; } +Path::Path(Circle const &c) + : _curves(new Sequence()) + , _closing_seg(NULL) + , _closed(true) + , _exception_on_stitch(true) +{ + Point p1 = c.pointAt(0); + Point p2 = c.pointAt(M_PI); + _curves->push_back(new EllipticalArc(p1, c.radius(), c.radius(), 0, false, true, p2)); + _curves->push_back(new EllipticalArc(p2, c.radius(), c.radius(), 0, false, true, p1)); + _closing_seg = new ClosingSegment(p1, p1); + _curves->push_back(_closing_seg); +} + +Path::Path(Ellipse const &e) + : _curves(new Sequence()) + , _closing_seg(NULL) + , _closed(true) + , _exception_on_stitch(true) +{ + Point p1 = e.pointAt(0); + Point p2 = e.pointAt(M_PI); + _curves->push_back(new EllipticalArc(p1, e.rays(), e.rotationAngle(), false, true, p2)); + _curves->push_back(new EllipticalArc(p2, e.rays(), e.rotationAngle(), false, true, p1)); + _closing_seg = new ClosingSegment(p1, p1); + _curves->push_back(_closing_seg); +} + +void Path::close(bool c) +{ + if (c == _closed) return; + if (c && _curves->size() >= 2) { + // when closing, if last segment is linear and ends at initial point, + // replace it with the closing segment + Sequence::iterator last = _curves->end() - 2; + if (last->isLineSegment() && last->finalPoint() == initialPoint()) { + _closing_seg->setInitial(last->initialPoint()); + _curves->erase(last); + } + } + _closed = c; +} + void Path::clear() { _unshare(); @@ -405,23 +451,91 @@ std::vector Path::roots(Coord v, Dim2 d) const return res; } -std::vector Path::intersect(Path const &other, Coord precision) const + +// The class below implements sweepline optimization for curve intersection in paths. +// Instead of O(N^2), this takes O(N + X), where X is the number of overlaps +// between the bounding boxes of curves. +namespace { + +struct CurveSweepTraits { + struct Bound { + Rect r; + std::size_t index; + int which; + }; + typedef std::less Compare; + inline static Coord entry_value(Bound const &b) { return b.r[X].min(); } + inline static Coord exit_value(Bound const &b) { return b.r[X].max(); } +}; + +class CurveSweeper + : public Sweeper { - std::vector result; +public: + CurveSweeper(Path const &a, Path const &b, std::vector &result, Coord prec) + : _result(result) + , _precision(prec) + { + for (std::size_t i = 0; i < a.size(); ++i) { + Bound bound; + bound.r = a[i].boundsFast(); + bound.index = i; + bound.which = 0; + insert(bound, &a[i]); + } + for (std::size_t i = 0; i < b.size(); ++i) { + Bound bound; + bound.r = b[i].boundsFast(); + bound.index = i; + bound.which = 1; + insert(bound, &b[i]); + } + } + +protected: + void _enter(Record const &record) { + int which = record.bound.which; + + for (RecordList::iterator i = _active_items.begin(); i != _active_items.end(); ++i) { + // do not intersect in the same path + if (i->bound.which == which) continue; + // do not intersect if boxes do not overlap in Y + if (!record.bound.r[Y].intersects(i->bound.r[Y])) continue; + + std::vector cx; + int ia = record.bound.index; + int ib = i->bound.index; + + if (which == 0) { + cx = record.item->intersect(*i->item); + } else { + cx = i->item->intersect(*record.item, _precision); + std::swap(ia, ib); + } - // TODO: sweepline optimization - // TODO: remove multiple intersections within precision of each other? - for (size_type i = 0; i < size(); ++i) { - for (size_type j = 0; j < other.size(); ++j) { - std::vector cx = (*this)[i].intersect(other[j], precision); for (std::size_t ci = 0; ci < cx.size(); ++ci) { - PathTime a(i, cx[ci].first), b(j, cx[ci].second); + PathTime a(ia, cx[ci].first), b(ib, cx[ci].second); PathIntersection px(a, b, cx[ci].point()); - result.push_back(px); + _result.push_back(px); } } } +private: + std::vector &_result; + Coord _precision; +}; + +} // end anonymous namespace + +std::vector Path::intersect(Path const &other, Coord precision) const +{ + std::vector result; + + CurveSweeper sweeper(*this, other, result, precision); + sweeper.process(); + + // TODO: remove multiple intersections within precision of each other? return result; } @@ -700,11 +814,10 @@ Path Path::reversed() const if (_closed) { // when the path is closed, there are two cases: - BezierCurve const *iseg = dynamic_cast(&front()); - if (iseg && iseg->size() == 2) { + if (front().isLineSegment()) { // 1. initial segment is linear: it becomes the new closing segment. rend = RIter(_curves->begin() + 1); - ret._closing_seg = new ClosingSegment(iseg->finalPoint(), iseg->initialPoint()); + ret._closing_seg = new ClosingSegment(front().finalPoint(), front().initialPoint()); } else { // 2. initial segment is not linear: the closing segment becomes degenerate. // However, skip it if it's already degenerate. @@ -883,6 +996,13 @@ void Path::do_append(Curve *c) if (c->initialPoint() != _closing_seg->initialPoint()) { THROW_CONTINUITYERROR(); } + if (_closed && c->isLineSegment() && + c->finalPoint() == _closing_seg->finalPoint()) + { + // appending a curve that matches the closing segment has no effect + delete c; + return; + } } _curves->insert(_curves->end() - 1, c); _closing_seg->setInitial(c->finalPoint()); diff --git a/src/2geom/path.h b/src/2geom/path.h index 5340df0c5..a6473e0d2 100644 --- a/src/2geom/path.h +++ b/src/2geom/path.h @@ -371,11 +371,14 @@ public: _curves->push_back(_closing_seg); } - /// Construct a path from a rectangle. - Path(Rect const &r); - - /// Construct a path from a convex hull. - Path(ConvexHull const &); + /// Create a path from a rectangle. + explicit Path(Rect const &r); + /// Create a path from a convex hull. + explicit Path(ConvexHull const &); + /// Create a path from a circle, using two elliptical arcs. + explicit Path(Circle const &c); + /// Create a path from an ellipse, using two elliptical arcs. + explicit Path(Ellipse const &e); virtual ~Path() {} @@ -463,8 +466,12 @@ public: /// Check whether the path is closed. bool closed() const { return _closed; } - /// Set whether the path is closed. - void close(bool closed = true) { _closed = closed; } + /** @brief Set whether the path is closed. + * When closing a path where the last segment can be represented as a closing + * segment, the last segment will be removed. When opening a path, the closing + * segment will be erased. This means that closing and then opening a path + * will not always give back the original path. */ + void close(bool closed = true); /** @brief Remove all curves from the path. * The initial and final points of the closing segment are set to (0,0). diff --git a/src/2geom/pathvector.cpp b/src/2geom/pathvector.cpp index 720428e97..bff201c71 100644 --- a/src/2geom/pathvector.cpp +++ b/src/2geom/pathvector.cpp @@ -31,10 +31,10 @@ * the specific language governing rights and limitations. */ -#include <2geom/pathvector.h> - -#include <2geom/path.h> #include <2geom/affine.h> +#include <2geom/path.h> +#include <2geom/pathvector.h> +#include <2geom/svg-path-writer.h> namespace Geom { @@ -221,6 +221,14 @@ PathVectorTime PathVector::_factorTime(Coord t) const return ret; } +std::ostream &operator<<(std::ostream &out, PathVector const &pv) +{ + SVGPathWriter wr; + wr.feed(pv); + out << wr.str(); + return out; +} + } // namespace Geom /* diff --git a/src/2geom/pathvector.h b/src/2geom/pathvector.h index 955cd1d37..6636cbf2e 100644 --- a/src/2geom/pathvector.h +++ b/src/2geom/pathvector.h @@ -276,6 +276,8 @@ private: inline OptRect bounds_fast(PathVector const &pv) { return pv.boundsFast(); } inline OptRect bounds_exact(PathVector const &pv) { return pv.boundsExact(); } +std::ostream &operator<<(std::ostream &out, PathVector const &pv); + } // end namespace Geom #endif // LIB2GEOM_SEEN_PATHVECTOR_H diff --git a/src/2geom/point.cpp b/src/2geom/point.cpp index e2662becd..bcdbab429 100644 --- a/src/2geom/point.cpp +++ b/src/2geom/point.cpp @@ -35,6 +35,7 @@ #include #include +#include <2geom/coord.h> #include <2geom/point.h> #include <2geom/transforms.h> @@ -230,6 +231,13 @@ Point constrain_angle(Point const &A, Point const &B, unsigned int n, Point cons return A + dir * Rotate(k * 2.0 * M_PI / (double)n) * L2(diff); } +std::ostream &operator<<(std::ostream &out, const Geom::Point &p) +{ + out << "(" << format_coord_nice(p[X]) << ", " + << format_coord_nice(p[Y]) << ")"; + return out; +} + } // end namespace Geom /* diff --git a/src/2geom/point.h b/src/2geom/point.h index 3e56ae358..f2659d351 100644 --- a/src/2geom/point.h +++ b/src/2geom/point.h @@ -250,17 +250,12 @@ public: Dim2 dim; }; //template , typename Second = std::less > LexOrder - - friend inline std::ostream &operator<< (std::ostream &out_file, const Geom::Point &in_pnt); }; /** @brief Output operator for points. * Prints out the coordinates. * @relates Point */ -inline std::ostream &operator<< (std::ostream &out_file, const Geom::Point &in_pnt) { - out_file << "X: " << in_pnt[X] << " Y: " << in_pnt[Y]; - return out_file; -} +std::ostream &operator<<(std::ostream &out, const Geom::Point &p); template<> struct Point::LexLess { typedef std::less Primary; diff --git a/src/2geom/poly.cpp b/src/2geom/poly.cpp deleted file mode 100644 index de0229172..000000000 --- a/src/2geom/poly.cpp +++ /dev/null @@ -1,201 +0,0 @@ -#include <2geom/poly.h> - -#ifdef HAVE_GSL -#include -#endif - -namespace Geom { - -Poly Poly::operator*(const Poly& p) const { - Poly result; - result.resize(degree() + p.degree()+1); - - for(unsigned i = 0; i < size(); i++) { - for(unsigned j = 0; j < p.size(); j++) { - result[i+j] += (*this)[i] * p[j]; - } - } - return result; -} - -/*double Poly::eval(double x) const { - return gsl_poly_eval(&coeff[0], size(), x); - }*/ - -void Poly::normalize() { - while(back() == 0) - pop_back(); -} - -void Poly::monicify() { - normalize(); - - double scale = 1./back(); // unitize - - for(unsigned i = 0; i < size(); i++) { - (*this)[i] *= scale; - } -} - - -#ifdef HAVE_GSL -std::vector > solve(Poly const & pp) { - Poly p(pp); - p.normalize(); - gsl_poly_complex_workspace * w - = gsl_poly_complex_workspace_alloc (p.size()); - - gsl_complex_packed_ptr z = new double[p.degree()*2]; - double* a = new double[p.size()]; - for(unsigned int i = 0; i < p.size(); i++) - a[i] = p[i]; - std::vector > roots; - //roots.resize(p.degree()); - - gsl_poly_complex_solve (a, p.size(), w, z); - delete[]a; - - gsl_poly_complex_workspace_free (w); - - for (unsigned int i = 0; i < p.degree(); i++) { - roots.push_back(std::complex (z[2*i] ,z[2*i+1])); - //printf ("z%d = %+.18f %+.18f\n", i, z[2*i], z[2*i+1]); - } - delete[] z; - return roots; -} - -std::vector solve_reals(Poly const & p) { - std::vector > roots = solve(p); - std::vector real_roots; - - for(unsigned int i = 0; i < roots.size(); i++) { - if(roots[i].imag() == 0) // should be more lenient perhaps - real_roots.push_back(roots[i].real()); - } - return real_roots; -} -#endif - -double polish_root(Poly const & p, double guess, double tol) { - Poly dp = derivative(p); - - double fn = p(guess); - while(fabs(fn) > tol) { - guess -= fn/dp(guess); - fn = p(guess); - } - return guess; -} - -Poly integral(Poly const & p) { - Poly result; - - result.reserve(p.size()+1); - result.push_back(0); // arbitrary const - for(unsigned i = 0; i < p.size(); i++) { - result.push_back(p[i]/(i+1)); - } - return result; - -} - -Poly derivative(Poly const & p) { - Poly result; - - if(p.size() <= 1) - return Poly(0); - result.reserve(p.size()-1); - for(unsigned i = 1; i < p.size(); i++) { - result.push_back(i*p[i]); - } - return result; -} - -Poly compose(Poly const & a, Poly const & b) { - Poly result; - - for(unsigned i = a.size(); i > 0; i--) { - result = Poly(a[i-1]) + result * b; - } - return result; - -} - -/* This version is backwards - dividing taylor terms -Poly divide(Poly const &a, Poly const &b, Poly &r) { - Poly c; - r = a; // remainder - - const unsigned k = a.size(); - r.resize(k, 0); - c.resize(k, 0); - - for(unsigned i = 0; i < k; i++) { - double ci = r[i]/b[0]; - c[i] += ci; - Poly bb = ci*b; - std::cout << ci <<"*" << b << ", r= " << r << std::endl; - r -= bb.shifted(i); - } - - return c; -} -*/ - -Poly divide(Poly const &a, Poly const &b, Poly &r) { - Poly c; - r = a; // remainder - assert(b.size() > 0); - - const unsigned k = a.degree(); - const unsigned l = b.degree(); - c.resize(k, 0.); - - for(unsigned i = k; i >= l; i--) { - //assert(i >= 0); - double ci = r.back()/b.back(); - c[i-l] += ci; - Poly bb = ci*b; - //std::cout << ci <<"*(" << b.shifted(i-l) << ") = " - // << bb.shifted(i-l) << " r= " << r << std::endl; - r -= bb.shifted(i-l); - r.pop_back(); - } - //std::cout << "r= " << r << std::endl; - r.normalize(); - c.normalize(); - - return c; -} - -Poly gcd(Poly const &a, Poly const &b, const double /*tol*/) { - if(a.size() < b.size()) - return gcd(b, a); - if(b.size() <= 0) - return a; - if(b.size() == 1) - return a; - Poly r; - divide(a, b, r); - return gcd(b, r); -} - - - -/*Poly divide_out_root(Poly const & p, double x) { - assert(1); - }*/ - -} //namespace Geom - -/* - Local Variables: - mode:c++ - c-file-style:"stroustrup" - c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) - indent-tabs-mode:nil - fill-column:99 - End: -*/ -// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 : diff --git a/src/2geom/poly.h b/src/2geom/poly.h deleted file mode 100644 index 7d93d0a85..000000000 --- a/src/2geom/poly.h +++ /dev/null @@ -1,249 +0,0 @@ -/** - * \file - * \brief Polynomial in canonical (monomial) basis - *//* - * Authors: - * ? - * - * Copyright ?-? authors - * - * This library is free software; you can redistribute it and/or - * modify it either under the terms of the GNU Lesser General Public - * License version 2.1 as published by the Free Software Foundation - * (the "LGPL") or, at your option, under the terms of the Mozilla - * Public License Version 1.1 (the "MPL"). If you do not alter this - * notice, a recipient may use your version of this file under either - * the MPL or the LGPL. - * - * You should have received a copy of the LGPL along with this library - * in the file COPYING-LGPL-2.1; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * You should have received a copy of the MPL along with this library - * in the file COPYING-MPL-1.1 - * - * The contents of this file are subject to the Mozilla Public License - * Version 1.1 (the "License"); you may not use this file except in - * compliance with the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY - * OF ANY KIND, either express or implied. See the LGPL or the MPL for - * the specific language governing rights and limitations. - * - */ - -#ifndef LIB2GEOM_SEEN_POLY_H -#define LIB2GEOM_SEEN_POLY_H -#include -#include -#include -#include -#include -#include <2geom/utils.h> - -namespace Geom { - -class Poly : public std::vector{ -public: - // coeff; // sum x^i*coeff[i] - - //unsigned size() const { return coeff.size();} - unsigned degree() const { return size()-1;} - - //double operator[](const int i) const { return (*this)[i];} - //double& operator[](const int i) { return (*this)[i];} - - Poly operator+(const Poly& p) const { - Poly result; - const unsigned out_size = std::max(size(), p.size()); - const unsigned min_size = std::min(size(), p.size()); - //result.reserve(out_size); - - for(unsigned i = 0; i < min_size; i++) { - result.push_back((*this)[i] + p[i]); - } - for(unsigned i = min_size; i < size(); i++) - result.push_back((*this)[i]); - for(unsigned i = min_size; i < p.size(); i++) - result.push_back(p[i]); - assert(result.size() == out_size); - return result; - } - Poly operator-(const Poly& p) const { - Poly result; - const unsigned out_size = std::max(size(), p.size()); - const unsigned min_size = std::min(size(), p.size()); - result.reserve(out_size); - - for(unsigned i = 0; i < min_size; i++) { - result.push_back((*this)[i] - p[i]); - } - for(unsigned i = min_size; i < size(); i++) - result.push_back((*this)[i]); - for(unsigned i = min_size; i < p.size(); i++) - result.push_back(-p[i]); - assert(result.size() == out_size); - return result; - } - Poly operator-=(const Poly& p) { - const unsigned out_size = std::max(size(), p.size()); - const unsigned min_size = std::min(size(), p.size()); - resize(out_size); - - for(unsigned i = 0; i < min_size; i++) { - (*this)[i] -= p[i]; - } - for(unsigned i = min_size; i < out_size; i++) - (*this)[i] = -p[i]; - return *this; - } - Poly operator-(const double k) const { - Poly result; - const unsigned out_size = size(); - result.reserve(out_size); - - for(unsigned i = 0; i < out_size; i++) { - result.push_back((*this)[i]); - } - result[0] -= k; - return result; - } - Poly operator-() const { - Poly result; - result.resize(size()); - - for(unsigned i = 0; i < size(); i++) { - result[i] = -(*this)[i]; - } - return result; - } - Poly operator*(const double p) const { - Poly result; - const unsigned out_size = size(); - result.reserve(out_size); - - for(unsigned i = 0; i < out_size; i++) { - result.push_back((*this)[i]*p); - } - assert(result.size() == out_size); - return result; - } - // equivalent to multiply by x^terms, negative terms are disallowed - Poly shifted(unsigned const terms) const { - Poly result; - size_type const out_size = size() + terms; - result.reserve(out_size); - - result.resize(terms, 0.0); - result.insert(result.end(), this->begin(), this->end()); - - assert(result.size() == out_size); - return result; - } - Poly operator*(const Poly& p) const; - - template - T eval(T x) const { - T r = 0; - for(int k = size()-1; k >= 0; k--) { - r = r*x + T((*this)[k]); - } - return r; - } - - template - T operator()(T t) const { return (T)eval(t);} - - void normalize(); - - void monicify(); - Poly() {} - Poly(const Poly& p) : std::vector(p) {} - Poly(const double a) {push_back(a);} - -public: - template - void val_and_deriv(T x, U &pd) const { - pd[0] = back(); - int nc = size() - 1; - int nd = pd.size() - 1; - for(unsigned j = 1; j < pd.size(); j++) - pd[j] = 0.0; - for(int i = nc -1; i >= 0; i--) { - int nnd = std::min(nd, nc-i); - for(int j = nnd; j >= 1; j--) - pd[j] = pd[j]*x + operator[](i); - pd[0] = pd[0]*x + operator[](i); - } - double cnst = 1; - for(int i = 2; i <= nd; i++) { - cnst *= i; - pd[i] *= cnst; - } - } - - static Poly linear(double ax, double b) { - Poly p; - p.push_back(b); - p.push_back(ax); - return p; - } -}; - -inline Poly operator*(double a, Poly const & b) { return b * a;} - -Poly integral(Poly const & p); -Poly derivative(Poly const & p); -Poly divide_out_root(Poly const & p, double x); -Poly compose(Poly const & a, Poly const & b); -Poly divide(Poly const &a, Poly const &b, Poly &r); -Poly gcd(Poly const &a, Poly const &b, const double tol=1e-10); - -/*** solve(Poly p) - * find all p.degree() roots of p. - * This function can take a long time with suitably crafted polynomials, but in practice it should be fast. Should we provide special forms for degree() <= 4? - */ -std::vector > solve(const Poly & p); - -#ifdef HAVE_GSL -/*** solve_reals(Poly p) - * find all real solutions to Poly p. - * currently we just use solve and pick out the suitably real looking values, there may be a better algorithm. - */ -std::vector solve_reals(const Poly & p); -#endif -double polish_root(Poly const & p, double guess, double tol); - -inline std::ostream &operator<< (std::ostream &out_file, const Poly &in_poly) { - if(in_poly.size() == 0) - out_file << "0"; - else { - for(int i = (int)in_poly.size()-1; i >= 0; --i) { - if(i == 1) { - out_file << "" << in_poly[i] << "*x"; - out_file << " + "; - } else if(i) { - out_file << "" << in_poly[i] << "*x^" << i; - out_file << " + "; - } else - out_file << in_poly[i]; - - } - } - return out_file; -} - -} // namespace Geom - -#endif //LIB2GEOM_SEEN_POLY_H - -/* - Local Variables: - mode:c++ - c-file-style:"stroustrup" - c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) - indent-tabs-mode:nil - fill-column:99 - End: -*/ -// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 : diff --git a/src/2geom/polynomial.cpp b/src/2geom/polynomial.cpp new file mode 100644 index 000000000..a0689f0c5 --- /dev/null +++ b/src/2geom/polynomial.cpp @@ -0,0 +1,326 @@ +/** + * \file + * \brief Polynomial in canonical (monomial) basis + *//* + * Authors: + * MenTaLguY + * Krzysztof Kosiński + * + * Copyright 2007-2015 Authors + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + */ + +#include +#include <2geom/polynomial.h> +#include + +#ifdef HAVE_GSL +#include +#endif + +namespace Geom { + +Poly Poly::operator*(const Poly& p) const { + Poly result; + result.resize(degree() + p.degree()+1); + + for(unsigned i = 0; i < size(); i++) { + for(unsigned j = 0; j < p.size(); j++) { + result[i+j] += (*this)[i] * p[j]; + } + } + return result; +} + +/*double Poly::eval(double x) const { + return gsl_poly_eval(&coeff[0], size(), x); + }*/ + +void Poly::normalize() { + while(back() == 0) + pop_back(); +} + +void Poly::monicify() { + normalize(); + + double scale = 1./back(); // unitize + + for(unsigned i = 0; i < size(); i++) { + (*this)[i] *= scale; + } +} + + +#ifdef HAVE_GSL +std::vector > solve(Poly const & pp) { + Poly p(pp); + p.normalize(); + gsl_poly_complex_workspace * w + = gsl_poly_complex_workspace_alloc (p.size()); + + gsl_complex_packed_ptr z = new double[p.degree()*2]; + double* a = new double[p.size()]; + for(unsigned int i = 0; i < p.size(); i++) + a[i] = p[i]; + std::vector > roots; + //roots.resize(p.degree()); + + gsl_poly_complex_solve (a, p.size(), w, z); + delete[]a; + + gsl_poly_complex_workspace_free (w); + + for (unsigned int i = 0; i < p.degree(); i++) { + roots.push_back(std::complex (z[2*i] ,z[2*i+1])); + //printf ("z%d = %+.18f %+.18f\n", i, z[2*i], z[2*i+1]); + } + delete[] z; + return roots; +} + +std::vector solve_reals(Poly const & p) { + std::vector > roots = solve(p); + std::vector real_roots; + + for(unsigned int i = 0; i < roots.size(); i++) { + if(roots[i].imag() == 0) // should be more lenient perhaps + real_roots.push_back(roots[i].real()); + } + return real_roots; +} +#endif + +double polish_root(Poly const & p, double guess, double tol) { + Poly dp = derivative(p); + + double fn = p(guess); + while(fabs(fn) > tol) { + guess -= fn/dp(guess); + fn = p(guess); + } + return guess; +} + +Poly integral(Poly const & p) { + Poly result; + + result.reserve(p.size()+1); + result.push_back(0); // arbitrary const + for(unsigned i = 0; i < p.size(); i++) { + result.push_back(p[i]/(i+1)); + } + return result; + +} + +Poly derivative(Poly const & p) { + Poly result; + + if(p.size() <= 1) + return Poly(0); + result.reserve(p.size()-1); + for(unsigned i = 1; i < p.size(); i++) { + result.push_back(i*p[i]); + } + return result; +} + +Poly compose(Poly const & a, Poly const & b) { + Poly result; + + for(unsigned i = a.size(); i > 0; i--) { + result = Poly(a[i-1]) + result * b; + } + return result; + +} + +/* This version is backwards - dividing taylor terms +Poly divide(Poly const &a, Poly const &b, Poly &r) { + Poly c; + r = a; // remainder + + const unsigned k = a.size(); + r.resize(k, 0); + c.resize(k, 0); + + for(unsigned i = 0; i < k; i++) { + double ci = r[i]/b[0]; + c[i] += ci; + Poly bb = ci*b; + std::cout << ci <<"*" << b << ", r= " << r << std::endl; + r -= bb.shifted(i); + } + + return c; +} +*/ + +Poly divide(Poly const &a, Poly const &b, Poly &r) { + Poly c; + r = a; // remainder + assert(b.size() > 0); + + const unsigned k = a.degree(); + const unsigned l = b.degree(); + c.resize(k, 0.); + + for(unsigned i = k; i >= l; i--) { + //assert(i >= 0); + double ci = r.back()/b.back(); + c[i-l] += ci; + Poly bb = ci*b; + //std::cout << ci <<"*(" << b.shifted(i-l) << ") = " + // << bb.shifted(i-l) << " r= " << r << std::endl; + r -= bb.shifted(i-l); + r.pop_back(); + } + //std::cout << "r= " << r << std::endl; + r.normalize(); + c.normalize(); + + return c; +} + +Poly gcd(Poly const &a, Poly const &b, const double /*tol*/) { + if(a.size() < b.size()) + return gcd(b, a); + if(b.size() <= 0) + return a; + if(b.size() == 1) + return a; + Poly r; + divide(a, b, r); + return gcd(b, r); +} + + + + +std::vector solve_quadratic(Coord a, Coord b, Coord c) +{ + std::vector result; + + if (a == 0) { + // linear equation + if (b == 0) return result; + result.push_back(-c/b); + return result; + } + + Coord delta = b*b - 4*a*c; + + if (delta == 0) { + // one root + result.push_back(-0.5 * b / a); + } else if (delta > 0) { + // two roots + Coord delta_sqrt = sqrt(delta); + result.push_back((-b + delta_sqrt)/(2*a)); + result.push_back((-b - delta_sqrt)/(2*a)); + } + // no roots otherwise + + std::sort(result.begin(), result.end()); + return result; +} + + +std::vector solve_cubic(Coord a, Coord b, Coord c, Coord d) +{ + // based on: + // http://mathworld.wolfram.com/CubicFormula.html + + if (a == 0) { + return solve_quadratic(b, c, d); + } + if (d == 0) { + // divide by x + std::vector result = solve_quadratic(a, b, c); + result.push_back(0); + std::sort(result.begin(), result.end()); + return result; + } + + std::vector result; + + // 1. divide everything by a to bring to canonical form + b /= a; + c /= a; + d /= a; + + // 2. eliminate x^2 term: x^3 + 3Qx - 2R = 0 + Coord Q = (3*c - b*b) / 9; + Coord R = (-27 * d + b * (9*c - 2*b*b)) / 54; + + // 3. compute polynomial discriminant + Coord D = Q*Q*Q + R*R; + Coord term1 = b/3; + + if (D > 0) { + // only one real root + Coord S = cbrt(R + sqrt(D)); + Coord T = cbrt(R - sqrt(D)); + result.push_back(-b/3 + S + T); + } else if (D == 0) { + // 3 real roots, 2 of which are equal + Coord rroot = cbrt(R); + result.reserve(3); + result.push_back(-term1 + 2*rroot); + result.push_back(-term1 - rroot); + result.push_back(-term1 - rroot); + } else { + // 3 distinct real roots + assert(Q < 0); + Coord theta = acos(R / sqrt(-Q*Q*Q)); + Coord rroot = 2 * sqrt(-Q); + result.reserve(3); + result.push_back(-term1 + rroot * cos(theta / 3)); + result.push_back(-term1 + rroot * cos((theta + 2*M_PI) / 3)); + result.push_back(-term1 + rroot * cos((theta + 4*M_PI) / 3)); + } + + std::sort(result.begin(), result.end()); + return result; +} + + +/*Poly divide_out_root(Poly const & p, double x) { + assert(1); + }*/ + +} //namespace Geom + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 : diff --git a/src/2geom/polynomial.h b/src/2geom/polynomial.h new file mode 100644 index 000000000..aeac2f3fa --- /dev/null +++ b/src/2geom/polynomial.h @@ -0,0 +1,262 @@ +/** + * \file + * \brief Polynomial in canonical (monomial) basis + *//* + * Authors: + * MenTaLguY + * Krzysztof Kosiński + * + * Copyright 2007-2015 Authors + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + */ + +#ifndef LIB2GEOM_SEEN_POLY_H +#define LIB2GEOM_SEEN_POLY_H +#include +#include +#include +#include +#include +#include <2geom/coord.h> +#include <2geom/utils.h> + +namespace Geom { + +class Poly : public std::vector{ +public: + // coeff; // sum x^i*coeff[i] + + //unsigned size() const { return coeff.size();} + unsigned degree() const { return size()-1;} + + //double operator[](const int i) const { return (*this)[i];} + //double& operator[](const int i) { return (*this)[i];} + + Poly operator+(const Poly& p) const { + Poly result; + const unsigned out_size = std::max(size(), p.size()); + const unsigned min_size = std::min(size(), p.size()); + //result.reserve(out_size); + + for(unsigned i = 0; i < min_size; i++) { + result.push_back((*this)[i] + p[i]); + } + for(unsigned i = min_size; i < size(); i++) + result.push_back((*this)[i]); + for(unsigned i = min_size; i < p.size(); i++) + result.push_back(p[i]); + assert(result.size() == out_size); + return result; + } + Poly operator-(const Poly& p) const { + Poly result; + const unsigned out_size = std::max(size(), p.size()); + const unsigned min_size = std::min(size(), p.size()); + result.reserve(out_size); + + for(unsigned i = 0; i < min_size; i++) { + result.push_back((*this)[i] - p[i]); + } + for(unsigned i = min_size; i < size(); i++) + result.push_back((*this)[i]); + for(unsigned i = min_size; i < p.size(); i++) + result.push_back(-p[i]); + assert(result.size() == out_size); + return result; + } + Poly operator-=(const Poly& p) { + const unsigned out_size = std::max(size(), p.size()); + const unsigned min_size = std::min(size(), p.size()); + resize(out_size); + + for(unsigned i = 0; i < min_size; i++) { + (*this)[i] -= p[i]; + } + for(unsigned i = min_size; i < out_size; i++) + (*this)[i] = -p[i]; + return *this; + } + Poly operator-(const double k) const { + Poly result; + const unsigned out_size = size(); + result.reserve(out_size); + + for(unsigned i = 0; i < out_size; i++) { + result.push_back((*this)[i]); + } + result[0] -= k; + return result; + } + Poly operator-() const { + Poly result; + result.resize(size()); + + for(unsigned i = 0; i < size(); i++) { + result[i] = -(*this)[i]; + } + return result; + } + Poly operator*(const double p) const { + Poly result; + const unsigned out_size = size(); + result.reserve(out_size); + + for(unsigned i = 0; i < out_size; i++) { + result.push_back((*this)[i]*p); + } + assert(result.size() == out_size); + return result; + } + // equivalent to multiply by x^terms, negative terms are disallowed + Poly shifted(unsigned const terms) const { + Poly result; + size_type const out_size = size() + terms; + result.reserve(out_size); + + result.resize(terms, 0.0); + result.insert(result.end(), this->begin(), this->end()); + + assert(result.size() == out_size); + return result; + } + Poly operator*(const Poly& p) const; + + template + T eval(T x) const { + T r = 0; + for(int k = size()-1; k >= 0; k--) { + r = r*x + T((*this)[k]); + } + return r; + } + + template + T operator()(T t) const { return (T)eval(t);} + + void normalize(); + + void monicify(); + Poly() {} + Poly(const Poly& p) : std::vector(p) {} + Poly(const double a) {push_back(a);} + +public: + template + void val_and_deriv(T x, U &pd) const { + pd[0] = back(); + int nc = size() - 1; + int nd = pd.size() - 1; + for(unsigned j = 1; j < pd.size(); j++) + pd[j] = 0.0; + for(int i = nc -1; i >= 0; i--) { + int nnd = std::min(nd, nc-i); + for(int j = nnd; j >= 1; j--) + pd[j] = pd[j]*x + operator[](i); + pd[0] = pd[0]*x + operator[](i); + } + double cnst = 1; + for(int i = 2; i <= nd; i++) { + cnst *= i; + pd[i] *= cnst; + } + } + + static Poly linear(double ax, double b) { + Poly p; + p.push_back(b); + p.push_back(ax); + return p; + } +}; + +inline Poly operator*(double a, Poly const & b) { return b * a;} + +Poly integral(Poly const & p); +Poly derivative(Poly const & p); +Poly divide_out_root(Poly const & p, double x); +Poly compose(Poly const & a, Poly const & b); +Poly divide(Poly const &a, Poly const &b, Poly &r); +Poly gcd(Poly const &a, Poly const &b, const double tol=1e-10); + +/*** solve(Poly p) + * find all p.degree() roots of p. + * This function can take a long time with suitably crafted polynomials, but in practice it should be fast. Should we provide special forms for degree() <= 4? + */ +std::vector > solve(const Poly & p); + +#ifdef HAVE_GSL +/*** solve_reals(Poly p) + * find all real solutions to Poly p. + * currently we just use solve and pick out the suitably real looking values, there may be a better algorithm. + */ +std::vector solve_reals(const Poly & p); +#endif +double polish_root(Poly const & p, double guess, double tol); + + +/** @brief Analytically solve quadratic equation. + * The equation is given in the standard form: ax^2 + bx + c = 0. + * Only real roots are returned. */ +std::vector solve_quadratic(Coord a, Coord b, Coord c); + +/** @brief Analytically solve cubic equation. + * The equation is given in the standard form: ax^3 + bx^2 + cx + d = 0. + * Only real roots are returned. */ +std::vector solve_cubic(Coord a, Coord b, Coord c, Coord d); + + +inline std::ostream &operator<< (std::ostream &out_file, const Poly &in_poly) { + if(in_poly.size() == 0) + out_file << "0"; + else { + for(int i = (int)in_poly.size()-1; i >= 0; --i) { + if(i == 1) { + out_file << "" << in_poly[i] << "*x"; + out_file << " + "; + } else if(i) { + out_file << "" << in_poly[i] << "*x^" << i; + out_file << " + "; + } else + out_file << in_poly[i]; + + } + } + return out_file; +} + +} // namespace Geom + +#endif //LIB2GEOM_SEEN_POLY_H + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 : diff --git a/src/2geom/quadtree.cpp b/src/2geom/quadtree.cpp deleted file mode 100644 index 76dc68774..000000000 --- a/src/2geom/quadtree.cpp +++ /dev/null @@ -1,286 +0,0 @@ -#include <2geom/quadtree.h> - -namespace Geom{ -Quad* QuadTree::search(Rect const &r) { - return search(r[0].min(), r[1].min(), - r[0].max(), r[1].max()); -} - -void QuadTree::insert(Rect const &r, int shape) { - insert(r[0].min(), r[1].min(), - r[0].max(), r[1].max(), shape); -} - - -Quad* QuadTree::search(double x0, double y0, double x1, double y1) { - Quad *q = root; - - double bxx0 = bx1, bxx1 = bx1; - double byy0 = by1, byy1 = by1; - while(q) { - double cx = (bxx0 + bxx1)/2; - double cy = (byy0 + byy1)/2; - unsigned i = 0; - if(x0 >= cx) { - i += 1; - bxx0 = cx; // zoom in a quad - } else if(x1 <= cx) { - bxx1 = cx; - } else - break; - if(y0 >= cy) { - i += 2; - byy0 = cy; - } else if(y1 <= cy) { - byy1 = cy; - } else - break; - - assert(i < 4); - Quad *qq = q->children[i]; - if(qq == 0) break; // last non-null - q = qq; - } - return q; -} - - -/* -Comments by Vangelis (use with caution :P ) - -Insert Rect (x0, y0), (x1, y1) in the QuadTree Q. - -=================================================================================== -* QuadTree Q has: Quadtree's Quad root R, QuadTree's bounding box B. - -* Each Quad has a Quad::data where we store the id of the Rect that belong to -this Quad. (In reality we'll store a pointer to the shape). - -* Each Quad has 4 Quad children: 0, 1, 2, 3. Each child Quad represents one of the following quarters -of the bounding box B: - -+---------------------+ -| | | -| NW=0 | NE=1 | -| | | -| | | -+---------------------+ -| | | -| SW=2 | SE=3 | -| | | -| | | -+---------------------+ - -Each Quad can further be divided in 4 Quads as above and so on. Below there is an example - - Root - / || \ - / / \ \ - 0 1 2 3 - /\ - / | | \ - 0 1 2 3 - -+---------------------+ -| | 1-0 | 1-1| -| 0 | | | -| |-----|----| -| | 1-2 | 1-3| -| | | | -+---------------------+ -| | | -| | | -| 2 | 3 | -| | | -+---------------------+ - - - -=================================================================================== -Insert Rect (x0, y0), (x1, y1) in the QuadTree Q. Algorithm: -1) check if Rect is bigger than QuadTree's bounding box -2) find in which Quad we should add the Rect: - - - ------------------------------------------------------------------------------------ -How we find in which Quad we should add the Rect R: - -Q = Quadtree's Quad root -B = QuadTree's bounding box B -WHILE (Q) { - IF ( Rect cannot fit in one unique quarter of B ){ - Q = current Quad ; - BREAK; - } - IF ( Rect can fit in the quarter I ) { - IF (Q.children[I] doesn't exist) { - create the Quad Q.children[I]; - } - B = bounding box of the Quad Q.children[I] ; - Q = Q.children[I] ; - CHECK(R, B) ; - } -} -add Rect R to Q ; - - -*/ - -void QuadTree::insert(double x0, double y0, double x1, double y1, int shape) { - // loop until a quad would break the box. - - // empty root => empty QuadTree. Create initial bounding box (0,0), (1,1) - if(root == NULL) { - root = new Quad; - - bx0 = 0; - bx1 = 1; - by0 = 0; - by1 = 1; - } - Quad *q = root; - - //A temp bounding box. Same as root's bounting box (ie of the whole QuadTree) - double bxx0 = bx0, bxx1 = bx1; - double byy0 = by0, byy1 = by1; - - while((bxx0 > x0) || - (bxx1 < x1) || - (byy0 > y0) || - (byy1 < y1)) { - // QuadTree has small size, can't accomodate new rect. Double the size: - unsigned i = 0; - - if(bxx0 > x0) { - bxx0 = 2*bxx0 - bxx1; - i += 1; - } else { - bxx1 = 2*bxx1 - bxx0; - } - if(byy0 > y0) { - byy0 = 2*byy0 - byy1; - i += 2; - } else { - byy1 = 2*byy1 - byy0; - } - q = new Quad; - //check if root is empty (no rects, no quad children) - if( clean_root() ){ - root = q; - } - else{ - q->children[i] = root; - root = q; - } - bx0 = bxx0; - bx1 = bxx1; - by0 = byy0; - by1 = byy1; - } - - while(true) { - // Find the center of the temp bounding box - double cx = (bxx0 + bxx1)/2; - double cy = (byy0 + byy1)/2; - unsigned i = 0; - assert(x0 >= bxx0); - assert(x1 <= bxx1); - assert(y0 >= byy0); - assert(y1 <= byy1); - - if(x0 >= cx) { - i += 1; - bxx0 = cx; // zoom in a quad - } else if(x1 <= cx) { - bxx1 = cx; - } else{ - // rect does not fit in one unique quarter (in X axis) of the temp bounding box - break; - } - if(y0 >= cy) { - i += 2; - byy0 = cy; - } else if(y1 <= cy) { - byy1 = cy; - } else{ - // rect does not fit in one unique quarter (in Y axis) of the temp bounding box - break; - } - - // check if rect's bounding box has size 1x1. This means that rect is defined by 2 points - // that are in the same place. - if( ( fabs(bxx0 - bxx1) < 1.0 ) && ( fabs(byy0 - byy1) < 1.0 )){ - break; - } - - /* - 1 rect does fit in one unique quarter of the temp bounding box. And we have found which. - 2 temp bounding box = bounding box of this quarter. - 3 "Go in" this quarter (create if doesn't exist) - */ - assert(i < 4); - Quad *qq = q->children[i]; - if(qq == NULL) { - qq = new Quad; - q->children[i] = qq; - } - q = qq; - } - q->data.push_back(shape); -} - - -void QuadTree::erase(Quad *q, int shape) { - for(Quad::iterator i = q->data.begin(); i != q->data.end(); ++i) { - if(*i == shape) { - q->data.erase(i); - if(q->data.empty()) { - - } - } - } - return; -} - -/* -Returns: -false: if root isn't empty -true: if root is empty it cleans root -*/ -bool QuadTree::clean_root() { - assert(root); - - // false if root *has* rects assigned to it. - bool all_clean = root->data.empty(); - - // if root has children we get false - for(unsigned i = 0; i < 4; i++) - { - if(root->children[i]) - { - all_clean = false; - } - } - - if(all_clean) - { - delete root; - root=0; - return true; - } - return false; -} - -}; - -/* - Local Variables: - mode:c++ - c-file-style:"stroustrup" - c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) - indent-tabs-mode:nil - fill-column:99 - End: -*/ -// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 : diff --git a/src/2geom/quadtree.h b/src/2geom/quadtree.h deleted file mode 100644 index 62f2b8321..000000000 --- a/src/2geom/quadtree.h +++ /dev/null @@ -1,105 +0,0 @@ -/** - * \file - * \brief Quad tree data structure - *//* - * Authors: - * ? - * - * Copyright ?-? authors - * - * This library is free software; you can redistribute it and/or - * modify it either under the terms of the GNU Lesser General Public - * License version 2.1 as published by the Free Software Foundation - * (the "LGPL") or, at your option, under the terms of the Mozilla - * Public License Version 1.1 (the "MPL"). If you do not alter this - * notice, a recipient may use your version of this file under either - * the MPL or the LGPL. - * - * You should have received a copy of the LGPL along with this library - * in the file COPYING-LGPL-2.1; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * You should have received a copy of the MPL along with this library - * in the file COPYING-MPL-1.1 - * - * The contents of this file are subject to the Mozilla Public License - * Version 1.1 (the "License"); you may not use this file except in - * compliance with the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY - * OF ANY KIND, either express or implied. See the LGPL or the MPL for - * the specific language governing rights and limitations. - * - */ - -#ifndef LIB2GEOM_SEEN_QUADTREE_H -#define LIB2GEOM_SEEN_QUADTREE_H - -#include -#include - -#include <2geom/d2.h> - -namespace Geom{ - -class Quad{ -public: - Quad* children[4]; - std::vector data; - Quad() { - for(int i = 0; i < 4; i++) - children[i] = 0; - } - typedef std::vector::iterator iterator; - Rect bounds(unsigned i, double x, double y, double d) { - double dd = d/2; - switch(i % 4) { - case 0: - return Rect(Interval(x, x+dd), Interval(y, y+dd)); - case 1: - return Rect(Interval(x+dd, x+d), Interval(y, y+dd)); - case 2: - return Rect(Interval(x, x+dd), Interval(y+dd, y+d)); - case 3: - return Rect(Interval(x+dd, x+d), Interval(y+dd, y+d)); - default: - /* just to suppress warning message - * this case should be never reached */ - assert(false); - } - assert(false); - return Rect(); - } -}; - -class QuadTree{ -public: - Quad* root; - double scale; - double bx0, bx1; - double by0, by1; - - QuadTree() : root(0), scale(1) {} - - Quad* search(double x0, double y0, double x1, double y1); - void insert(double x0, double y0, double x1, double y1, int shape); - Quad* search(Geom::Rect const &r); - void insert(Geom::Rect const &r, int shape); - void erase(Quad *q, int shape); -private: - bool clean_root(); -}; - -}; - -#endif -/* - Local Variables: - mode:c++ - c-file-style:"stroustrup" - c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) - indent-tabs-mode:nil - fill-column:99 - End: -*/ -// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 : diff --git a/src/2geom/sbasis-curve.h b/src/2geom/sbasis-curve.h index a7b74dcee..17ee8f4c9 100644 --- a/src/2geom/sbasis-curve.h +++ b/src/2geom/sbasis-curve.h @@ -88,6 +88,7 @@ public: virtual Point initialPoint() const { return inner.at0(); } virtual Point finalPoint() const { return inner.at1(); } virtual bool isDegenerate() const { return inner.isConstant(0); } + virtual bool isLineSegment() const { return inner[X].size() == 1; } virtual Point pointAt(Coord t) const { return inner.valueAt(t); } virtual std::vector pointAndDerivatives(Coord t, unsigned n) const { return inner.valueAndDerivatives(t, n); diff --git a/src/2geom/sbasis-poly.h b/src/2geom/sbasis-poly.h index 81eeca72c..d18bc369e 100644 --- a/src/2geom/sbasis-poly.h +++ b/src/2geom/sbasis-poly.h @@ -33,7 +33,7 @@ #ifndef LIB2GEOM_SEEN_SBASIS_POLY_H #define LIB2GEOM_SEEN_SBASIS_POLY_H -#include <2geom/poly.h> +#include <2geom/polynomial.h> #include <2geom/sbasis.h> namespace Geom{ diff --git a/src/2geom/sbasis-to-bezier.cpp b/src/2geom/sbasis-to-bezier.cpp index dfd07d84c..09fbb03ef 100644 --- a/src/2geom/sbasis-to-bezier.cpp +++ b/src/2geom/sbasis-to-bezier.cpp @@ -239,8 +239,6 @@ void sbasis_to_cubic_bezier (std::vector & bz, D2 const& sb) midx = 8*midx - 4*bz[0][X] - 4*bz[3][X]; // re-define relative to center midy = 8*midy - 4*bz[0][Y] - 4*bz[3][Y]; - if ((std::abs(midx) < EPSILON) && (std::abs(midy) < EPSILON)) - return; if ((std::abs(xprime[0]) < EPSILON) && (std::abs(yprime[0]) < EPSILON) && ((std::abs(xprime[1]) > EPSILON) || (std::abs(yprime[1]) > EPSILON))) { // degenerate handle at 0 : use distance of closest approach @@ -264,11 +262,11 @@ void sbasis_to_cubic_bezier (std::vector & bz, D2 const& sb) double test2 = (bz[2][Y] - bz[0][Y])*(bz[3][X] - bz[0][X]) - (bz[2][X] - bz[0][X])*(bz[3][Y] - bz[0][Y]); if (test1*test2 < 0) // reject anti-symmetric case, LP Bug 1428267 & Bug 1428683 return; - denom = xprime[1]*yprime[0] - yprime[1]*xprime[0]; + denom = 3.0*(xprime[1]*yprime[0] - yprime[1]*xprime[0]); for (int i = 0; i < 2; ++i) { numer = xprime[1 - i]*midy - yprime[1 - i]*midx; - delx[i] = xprime[i]*numer/denom/3; - dely[i] = yprime[i]*numer/denom/3; + delx[i] = xprime[i]*numer/denom; + dely[i] = yprime[i]*numer/denom; } } else if ((xprime[0]*xprime[1] < 0) || (yprime[0]*yprime[1] < 0)) { // symmetric case : use distance of closest approach numer = midx*xprime[0] + midy*yprime[0]; @@ -515,10 +513,10 @@ path_from_sbasis(D2 const &B, double tol, bool only_cubicbeziers) { TODO: some of this logic should be lifted into svg-path */ PathVector -path_from_piecewise(Piecewise > const &B, double tol, bool only_cubicbeziers) { - PathBuilder pb; +path_from_piecewise(Geom::Piecewise > const &B, double tol, bool only_cubicbeziers) { + Geom::PathBuilder pb; if(B.size() == 0) return pb.peek(); - Point start = B[0].at0(); + Geom::Point start = B[0].at0(); pb.moveTo(start); for(unsigned i = 0; ; i++) { if ( (i+1 == B.size()) diff --git a/src/2geom/svg-elliptical-arc.cpp b/src/2geom/svg-elliptical-arc.cpp deleted file mode 100644 index 3a5154d08..000000000 --- a/src/2geom/svg-elliptical-arc.cpp +++ /dev/null @@ -1,275 +0,0 @@ -/* - * SVG Elliptical Arc Class - * - * Copyright 2008 Marco Cecchetti - * - * This library is free software; you can redistribute it and/or - * modify it either under the terms of the GNU Lesser General Public - * License version 2.1 as published by the Free Software Foundation - * (the "LGPL") or, at your option, under the terms of the Mozilla - * Public License Version 1.1 (the "MPL"). If you do not alter this - * notice, a recipient may use your version of this file under either - * the MPL or the LGPL. - * - * You should have received a copy of the LGPL along with this library - * in the file COPYING-LGPL-2.1; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * You should have received a copy of the MPL along with this library - * in the file COPYING-MPL-1.1 - * - * The contents of this file are subject to the Mozilla Public License - * Version 1.1 (the "License"); you may not use this file except in - * compliance with the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY - * OF ANY KIND, either express or implied. See the LGPL or the MPL for - * the specific language governing rights and limitations. - */ - - -#include <2geom/bezier-curve.h> -#include <2geom/ellipse.h> -#include <2geom/numeric/fitting-model.h> -#include <2geom/numeric/fitting-tool.h> -#include <2geom/numeric/vector.h> -#include <2geom/poly.h> -#include <2geom/sbasis-geometric.h> -#include <2geom/svg-elliptical-arc.h> - -#include -#include -#include - - -namespace Geom -{ - -/** - * @class SVGEllipticalArc - * @brief SVG 1.1-compliant elliptical arc. - * - * This class is almost identical to the normal elliptical arc, but it differs slightly - * in the handling of degenerate arcs to be compliant with SVG 1.1 implementation guidelines. - * - * @ingroup Curves - */ - -namespace detail -{ -/* - * ellipse_equation - * - * this is an helper struct, it provides two routines: - * the first one evaluates the implicit form of an ellipse on a given point - * the second one computes the normal versor at a given point of an ellipse - * in implicit form - */ -struct ellipse_equation -{ - ellipse_equation(double a, double b, double c, double d, double e, double f) - : A(a), B(b), C(c), D(d), E(e), F(f) - { - } - - double operator()(double x, double y) const - { - // A * x * x + B * x * y + C * y * y + D * x + E * y + F; - return (A * x + B * y + D) * x + (C * y + E) * y + F; - } - - double operator()(Point const& p) const - { - return (*this)(p[X], p[Y]); - } - - Point normal(double x, double y) const - { - Point n( 2 * A * x + B * y + D, 2 * C * y + B * x + E ); - return unit_vector(n); - } - - Point normal(Point const& p) const - { - return normal(p[X], p[Y]); - } - - double A, B, C, D, E, F; -}; - -} - -make_elliptical_arc:: -make_elliptical_arc( EllipticalArc& _ea, - curve_type const& _curve, - unsigned int _total_samples, - double _tolerance ) - : ea(_ea), curve(_curve), - dcurve( unitVector(derivative(curve)) ), - model(), fitter(model, _total_samples), - tolerance(_tolerance), tol_at_extr(tolerance/2), - tol_at_center(0.1), angle_tol(0.1), - initial_point(curve.at0()), final_point(curve.at1()), - N(_total_samples), last(N-1), partitions(N-1), p(N), - svg_compliant(true) -{ -} - -/* - * check that the coefficients computed by the fit method satisfy - * the tolerance parameters at the k-th sample point - */ -bool -make_elliptical_arc:: -bound_exceeded( unsigned int k, detail::ellipse_equation const & ee, - double e1x, double e1y, double e2 ) -{ - dist_err = std::fabs( ee(p[k]) ); - dist_bound = std::fabs( e1x * p[k][X] + e1y * p[k][Y] + e2 ); - // check that the angle btw the tangent versor to the input curve - // and the normal versor of the elliptical arc, both evaluate - // at the k-th sample point, are really othogonal - angle_err = std::fabs( dot( dcurve(k/partitions), ee.normal(p[k]) ) ); - //angle_err *= angle_err; - return ( dist_err > dist_bound || angle_err > angle_tol ); -} - -/* - * check that the coefficients computed by the fit method satisfy - * the tolerance parameters at each sample point - */ -bool -make_elliptical_arc:: -check_bound(double A, double B, double C, double D, double E, double F) -{ - detail::ellipse_equation ee(A, B, C, D, E, F); - - // check error magnitude at the end-points - double e1x = (2*A + B) * tol_at_extr; - double e1y = (B + 2*C) * tol_at_extr; - double e2 = ((D + E) + (A + B + C) * tol_at_extr) * tol_at_extr; - if (bound_exceeded(0, ee, e1x, e1y, e2)) - { - print_bound_error(0); - return false; - } - if (bound_exceeded(0, ee, e1x, e1y, e2)) - { - print_bound_error(last); - return false; - } - - // e1x = derivative((ee(x,y), x) | x->tolerance, y->tolerance - e1x = (2*A + B) * tolerance; - // e1y = derivative((ee(x,y), y) | x->tolerance, y->tolerance - e1y = (B + 2*C) * tolerance; - // e2 = ee(tolerance, tolerance) - F; - e2 = ((D + E) + (A + B + C) * tolerance) * tolerance; -// std::cerr << "e1x = " << e1x << std::endl; -// std::cerr << "e1y = " << e1y << std::endl; -// std::cerr << "e2 = " << e2 << std::endl; - - // check error magnitude at sample points - for ( unsigned int k = 1; k < last; ++k ) - { - if ( bound_exceeded(k, ee, e1x, e1y, e2) ) - { - print_bound_error(k); - return false; - } - } - - return true; -} - -/* - * fit - * - * supply the samples to the fitter and compute - * the ellipse implicit equation coefficients - */ -void make_elliptical_arc::fit() -{ - for (unsigned int k = 0; k < N; ++k) - { - p[k] = curve( k / partitions ); - fitter.append(p[k]); - } - fitter.update(); - - NL::Vector z(N, 0.0); - fitter.result(z); -} - -bool make_elliptical_arc::make_elliptiarc() -{ - const NL::Vector & coeff = fitter.result(); - Ellipse e; - try - { - e.setCoefficients(1, coeff[0], coeff[1], coeff[2], coeff[3], coeff[4]); - } - catch(LogicalError const &exc) - { - return false; - } - - Point inner_point = curve(0.5); - - if (svg_compliant_flag()) - { -#ifdef CPP11 - std::unique_ptr arc( e.arc(initial_point, inner_point, final_point, true) ); -#else - std::auto_ptr arc( e.arc(initial_point, inner_point, final_point, true) ); -#endif - ea = *arc; - } - else - { - try - { -#ifdef CPP11 - std::unique_ptr -#else - std::auto_ptr -#endif - eap( e.arc(initial_point, inner_point, final_point, false) ); - ea = *eap; - } - catch(RangeError const &exc) - { - return false; - } - } - - - if ( !are_near( e.center(), - ea.center(), - tol_at_center * std::min(e.ray(X),e.ray(Y)) - ) - ) - { - return false; - } - return true; -} - - - -} // end namespace Geom - - - - -/* - Local Variables: - mode:c++ - c-file-style:"stroustrup" - c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) - indent-tabs-mode:nil - fill-column:99 - End: -*/ -// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 : - diff --git a/src/2geom/svg-elliptical-arc.h b/src/2geom/svg-elliptical-arc.h deleted file mode 100644 index 90e16a999..000000000 --- a/src/2geom/svg-elliptical-arc.h +++ /dev/null @@ -1,280 +0,0 @@ -/** - * \file - * \brief SVG 1.1-compliant elliptical arc curve - *//* - * Authors: - * MenTaLguY - * Marco Cecchetti - * Krzysztof Kosiński - * - * Copyright 2007-2009 Authors - * - * This library is free software; you can redistribute it and/or - * modify it either under the terms of the GNU Lesser General Public - * License version 2.1 as published by the Free Software Foundation - * (the "LGPL") or, at your option, under the terms of the Mozilla - * Public License Version 1.1 (the "MPL"). If you do not alter this - * notice, a recipient may use your version of this file under either - * the MPL or the LGPL. - * - * You should have received a copy of the LGPL along with this library - * in the file COPYING-LGPL-2.1; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * You should have received a copy of the MPL along with this library - * in the file COPYING-MPL-1.1 - * - * The contents of this file are subject to the Mozilla Public License - * Version 1.1 (the "License"); you may not use this file except in - * compliance with the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY - * OF ANY KIND, either express or implied. See the LGPL or the MPL for - * the specific language governing rights and limitations. - */ - - -#ifndef LIB2GEOM_SEEN_SVG_ELLIPTICAL_ARC_H -#define LIB2GEOM_SEEN_SVG_ELLIPTICAL_ARC_H - -#include <2geom/curve.h> -#include <2geom/angle.h> -#include <2geom/utils.h> -#include <2geom/bezier-curve.h> -#include <2geom/elliptical-arc.h> -#include <2geom/sbasis-curve.h> // for non-native methods -#include <2geom/numeric/vector.h> -#include <2geom/numeric/fitting-tool.h> -#include <2geom/numeric/fitting-model.h> -#include - -namespace Geom { - -class SVGEllipticalArc : public EllipticalArc { -public: - SVGEllipticalArc() - : EllipticalArc() - {} - SVGEllipticalArc( Point ip, double rx, double ry, - double rot_angle, bool large_arc, bool sweep, - Point fp - ) - : EllipticalArc() - { - _initial_point = ip; - _final_point = fp; - _rays[X] = rx; _rays[Y] = ry; - _rot_angle = rot_angle; - _large_arc = large_arc; - _sweep = sweep; - _updateCenterAndAngles(true); - } - - virtual Curve *duplicate() const { - return new SVGEllipticalArc(*this); - } - virtual Coord valueAt(Coord t, Dim2 d) const { - if (isChord()) return chord().valueAt(t, d); - return EllipticalArc::valueAt(t, d); - } - virtual Point pointAt(Coord t) const { - if (isChord()) return chord().pointAt(t); - return EllipticalArc::pointAt(t); - } - virtual std::vector pointAndDerivatives(Coord t, unsigned int n) const { - if (isChord()) return chord().pointAndDerivatives(t, n); - return EllipticalArc::pointAndDerivatives(t, n); - } - virtual Rect boundsExact() const { - if (isChord()) return chord().boundsExact(); - return EllipticalArc::boundsExact(); - } - virtual OptRect boundsLocal(OptInterval const &i, unsigned int deg) const { - if (isChord()) return chord().boundsLocal(i, deg); - return EllipticalArc::boundsLocal(i, deg); - } - - virtual Curve *derivative() const { - if (isChord()) return chord().derivative(); - return EllipticalArc::derivative(); - } - - virtual std::vector roots(Coord v, Dim2 d) const { - if (isChord()) return chord().roots(v, d); - return EllipticalArc::roots(v, d); - } -#ifdef HAVE_GSL - virtual std::vector allNearestTimes( Point const& p, double from = 0, double to = 1 ) const { - if (isChord()) { - std::vector result; - result.push_back(chord().nearestTime(p, from, to)); - return result; - } - return EllipticalArc::allNearestTimes(p, from, to); - } -#endif - virtual D2 toSBasis() const { - if (isChord()) return chord().toSBasis(); - return EllipticalArc::toSBasis(); - } - virtual bool isSVGCompliant() const { return true; } - // TODO move SVG-specific behavior here. -//protected: - //virtual void _updateCenterAndAngles(); -}; // end class SVGEllipticalArc - -/* - * useful for testing and debugging - */ -template< class charT > -inline -std::basic_ostream & -operator<< (std::basic_ostream & os, const SVGEllipticalArc & ea) -{ - os << "{ cx: " << ea.center(X) << ", cy: " << ea.center(Y) - << ", rx: " << ea.ray(X) << ", ry: " << ea.ray(Y) - << ", rot angle: " << decimal_round(rad_to_deg(ea.rotationAngle()),2) - << ", start angle: " << decimal_round(rad_to_deg(ea.initialAngle()),2) - << ", end angle: " << decimal_round(rad_to_deg(ea.finalAngle()),2) - << " }"; - - return os; -} - - - - -// forward declation -namespace detail -{ - struct ellipse_equation; -} - -// TODO this needs to be rewritten and moved to EllipticalArc header -/* - * make_elliptical_arc - * - * convert a parametric polynomial curve given in symmetric power basis form - * into an SVGEllipticalArc type; in order to be successfull the input curve - * has to look like an actual elliptical arc even if a certain tolerance - * is allowed through an ad-hoc parameter. - * The conversion is performed through an interpolation on a certain amount of - * sample points computed on the input curve; - * the interpolation computes the coefficients of the general implicit equation - * of an ellipse (A*X^2 + B*XY + C*Y^2 + D*X + E*Y + F = 0), then from the - * implicit equation we compute the parametric form. - * - */ -class make_elliptical_arc -{ - public: - typedef D2 curve_type; - - /* - * constructor - * - * it doesn't execute the conversion but set the input and output parameters - * - * _ea: the output SVGEllipticalArc that will be generated; - * _curve: the input curve to be converted; - * _total_samples: the amount of sample points to be taken - * on the input curve for performing the conversion - * _tolerance: how much likelihood is required between the input curve - * and the generated elliptical arc; the smaller it is the - * the tolerance the higher it is the likelihood. - */ - make_elliptical_arc( EllipticalArc& _ea, - curve_type const& _curve, - unsigned int _total_samples, - double _tolerance ); - - private: - bool bound_exceeded( unsigned int k, detail::ellipse_equation const & ee, - double e1x, double e1y, double e2 ); - - bool check_bound(double A, double B, double C, double D, double E, double F); - - void fit(); - - bool make_elliptiarc(); - - void print_bound_error(unsigned int k) - { - std::cerr - << "tolerance error" << std::endl - << "at point: " << k << std::endl - << "error value: "<< dist_err << std::endl - << "bound: " << dist_bound << std::endl - << "angle error: " << angle_err - << " (" << angle_tol << ")" << std::endl; - } - - public: - /* - * perform the actual conversion - * return true if the conversion is successfull, false on the contrary - */ - bool operator()() - { - // initialize the reference - const NL::Vector & coeff = fitter.result(); - fit(); - if ( !check_bound(1, coeff[0], coeff[1], coeff[2], coeff[3], coeff[4]) ) - return false; - if ( !(make_elliptiarc()) ) return false; - return true; - } - - /* - * you can set a boolean parameter to tell the conversion routine - * if the output elliptical arc has to be svg compliant or not; - * the default value is true - */ - bool svg_compliant_flag() const - { - return svg_compliant; - } - - void svg_compliant_flag(bool _svg_compliant) - { - svg_compliant = _svg_compliant; - } - - private: - EllipticalArc& ea; // output elliptical arc - const curve_type & curve; // input curve - Piecewise > dcurve; // derivative of the input curve - NL::LFMEllipse model; // model used for fitting - // perform the actual fitting task - NL::least_squeares_fitter fitter; - // tolerance: the user-defined tolerance parameter; - // tol_at_extr: the tolerance at end-points automatically computed - // on the value of "tolerance", and usually more strict; - // tol_at_center: tolerance at the center of the ellipse - // angle_tol: tolerance for the angle btw the input curve tangent - // versor and the ellipse normal versor at the sample points - double tolerance, tol_at_extr, tol_at_center, angle_tol; - Point initial_point, final_point; // initial and final end-points - unsigned int N; // total samples - unsigned int last; // N-1 - double partitions; // N-1 - std::vector p; // sample points - double dist_err, dist_bound, angle_err; - bool svg_compliant; -}; - -} // end namespace Geom - -#endif // LIB2GEOM_SEEN_SVG_ELLIPTICAL_ARC_H - -/* - Local Variables: - mode:c++ - c-file-style:"stroustrup" - c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) - indent-tabs-mode:nil - fill-column:99 - End: -*/ -// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 : - diff --git a/src/2geom/svg-path-parser.cpp b/src/2geom/svg-path-parser.cpp index 6ee55171e..b6e6da869 100644 --- a/src/2geom/svg-path-parser.cpp +++ b/src/2geom/svg-path-parser.cpp @@ -1209,7 +1209,7 @@ void SVGPathParser::_arcTo(Coord rx, Coord ry, Coord angle, return; // ignore invalid (ambiguous) arc segments where start and end point are the same (per SVG spec) } - _pushCurve(new SVGEllipticalArc(_current, rx, ry, angle, large_arc, sweep, p)); + _pushCurve(new EllipticalArc(_current, rx, ry, angle, large_arc, sweep, p)); _quad_tangent = _cubic_tangent = _current = p; } diff --git a/src/2geom/svg-path-parser.h b/src/2geom/svg-path-parser.h index 9f304b9ed..e25316cf8 100644 --- a/src/2geom/svg-path-parser.h +++ b/src/2geom/svg-path-parser.h @@ -37,6 +37,7 @@ #include #include #include +#include #include <2geom/exception.h> #include <2geom/point.h> #include <2geom/path-sink.h> diff --git a/src/2geom/sweep-bounds.cpp b/src/2geom/sweep-bounds.cpp new file mode 100644 index 000000000..48f168b97 --- /dev/null +++ b/src/2geom/sweep-bounds.cpp @@ -0,0 +1,157 @@ +#include <2geom/sweep-bounds.h> + +#include + +namespace Geom { + +struct Event { + double x; + unsigned ix; + bool closing; + Event(double pos, unsigned i, bool c) : x(pos), ix(i), closing(c) {} +// Lexicographic ordering by x then closing + bool operator<(Event const &other) const { + if(x < other.x) return true; + if(x > other.x) return false; + return closing < other.closing; + } + bool operator==(Event const &other) const { + return other.x == x && other.ix == ix && other.closing == closing; + } +}; + +std::vector > fake_cull(unsigned a, unsigned b); + +/** + * \brief Make a list of pairs of self intersections in a list of Rects. + * + * \param rs: vector of Rect. + * \param d: dimension to sweep along + * + * [(A = rs[i], B = rs[j]) for i,J in enumerate(pairs) for j in J] + * then A.left <= B.left + */ + +std::vector > sweep_bounds(std::vector rs, Dim2 d) { + std::vector events; events.reserve(rs.size()*2); + std::vector > pairs(rs.size()); + + for(unsigned i = 0; i < rs.size(); i++) { + events.push_back(Event(rs[i][d].min(), i, false)); + events.push_back(Event(rs[i][d].max(), i, true)); + } + std::sort(events.begin(), events.end()); + + std::vector open; + for(unsigned i = 0; i < events.size(); i++) { + unsigned ix = events[i].ix; + if(events[i].closing) { + std::vector::iterator iter = std::find(open.begin(), open.end(), ix); + //if(iter != open.end()) + open.erase(iter); + } else { + for(unsigned j = 0; j < open.size(); j++) { + unsigned jx = open[j]; + if(rs[jx][1-d].intersects(rs[ix][1-d])) { + pairs[jx].push_back(ix); + } + } + open.push_back(ix); + } + } + return pairs; +} + +/** + * \brief Make a list of pairs of red-blue intersections between two lists of Rects. + * + * \param a: vector of Rect. + * \param b: vector of Rect. + * \param d: dimension to scan along + * + * [(A = rs[i], B = rs[j]) for i,J in enumerate(pairs) for j in J] + * then A.left <= B.left, A in a, B in b + */ +std::vector > sweep_bounds(std::vector a, std::vector b, Dim2 d) { + std::vector > pairs(a.size()); + if(a.empty() || b.empty()) return pairs; + std::vector events[2]; + events[0].reserve(a.size()*2); + events[1].reserve(b.size()*2); + + for(unsigned n = 0; n < 2; n++) { + unsigned sz = n ? b.size() : a.size(); + events[n].reserve(sz*2); + for(unsigned i = 0; i < sz; i++) { + Rect r = n ? b[i] : a[i]; + events[n].push_back(Event(r[d].min(), i, false)); + events[n].push_back(Event(r[d].max(), i, true)); + } + std::sort(events[n].begin(), events[n].end()); + } + + std::vector open[2]; + bool n = events[1].front() < events[0].front(); + {// As elegant as putting the initialiser in the for was, it upsets some legacy compilers (MS VS C++) + unsigned i[] = {0,0}; + for(; i[n] < events[n].size();) { + unsigned ix = events[n][i[n]].ix; + bool closing = events[n][i[n]].closing; + //std::cout << n << "[" << ix << "] - " << (closing ? "closer" : "opener") << "\n"; + if(closing) { + open[n].erase(std::find(open[n].begin(), open[n].end(), ix)); + } else { + if(n) { + //n = 1 + //opening a B, add to all open a + for(unsigned j = 0; j < open[0].size(); j++) { + unsigned jx = open[0][j]; + if(a[jx][1-d].intersects(b[ix][1-d])) { + pairs[jx].push_back(ix); + } + } + } else { + //n = 0 + //opening an A, add all open b + for(unsigned j = 0; j < open[1].size(); j++) { + unsigned jx = open[1][j]; + if(b[jx][1-d].intersects(a[ix][1-d])) { + pairs[ix].push_back(jx); + } + } + } + open[n].push_back(ix); + } + i[n]++; + if(i[n]>=events[n].size()) {break;} + n = (events[!n][i[!n]] < events[n][i[n]]) ? !n : n; + }} + return pairs; +} + +//Fake cull, until the switch to the real sweep is made. +std::vector > fake_cull(unsigned a, unsigned b) { + std::vector > ret; + + std::vector all; + for(unsigned j = 0; j < b; j++) + all.push_back(j); + + for(unsigned i = 0; i < a; i++) + ret.push_back(all); + + return ret; +} + +} + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 : diff --git a/src/2geom/sweep-bounds.h b/src/2geom/sweep-bounds.h new file mode 100644 index 000000000..e0ebf2975 --- /dev/null +++ b/src/2geom/sweep-bounds.h @@ -0,0 +1,62 @@ +/** + * \file + * \brief Sweepline intersection of groups of rectangles + *//* + * Authors: + * ? + * + * Copyright ?-? authors + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + */ + +#ifndef LIB2GEOM_SEEN_SWEEP_H +#define LIB2GEOM_SEEN_SWEEP_H + +#include +#include <2geom/d2.h> + +namespace Geom { + +std::vector > +sweep_bounds(std::vector, Dim2 dim = X); + +std::vector > +sweep_bounds(std::vector, std::vector, Dim2 dim = X); + +} + +#endif + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 : diff --git a/src/2geom/sweep.cpp b/src/2geom/sweep.cpp deleted file mode 100644 index 6910d5d02..000000000 --- a/src/2geom/sweep.cpp +++ /dev/null @@ -1,139 +0,0 @@ -#include <2geom/sweep.h> - -#include - -namespace Geom { - -/** - * \brief Make a list of pairs of self intersections in a list of Rects. - * - * \param rs: vector of Rect. - * \param d: dimension to sweep along - * - * [(A = rs[i], B = rs[j]) for i,J in enumerate(pairs) for j in J] - * then A.left <= B.left - */ - -std::vector > sweep_bounds(std::vector rs, Dim2 d) { - std::vector events; events.reserve(rs.size()*2); - std::vector > pairs(rs.size()); - - for(unsigned i = 0; i < rs.size(); i++) { - events.push_back(Event(rs[i][d].min(), i, false)); - events.push_back(Event(rs[i][d].max(), i, true)); - } - std::sort(events.begin(), events.end()); - - std::vector open; - for(unsigned i = 0; i < events.size(); i++) { - unsigned ix = events[i].ix; - if(events[i].closing) { - std::vector::iterator iter = std::find(open.begin(), open.end(), ix); - //if(iter != open.end()) - open.erase(iter); - } else { - for(unsigned j = 0; j < open.size(); j++) { - unsigned jx = open[j]; - if(rs[jx][1-d].intersects(rs[ix][1-d])) { - pairs[jx].push_back(ix); - } - } - open.push_back(ix); - } - } - return pairs; -} - -/** - * \brief Make a list of pairs of red-blue intersections between two lists of Rects. - * - * \param a: vector of Rect. - * \param b: vector of Rect. - * \param d: dimension to scan along - * - * [(A = rs[i], B = rs[j]) for i,J in enumerate(pairs) for j in J] - * then A.left <= B.left, A in a, B in b - */ -std::vector > sweep_bounds(std::vector a, std::vector b, Dim2 d) { - std::vector > pairs(a.size()); - if(a.empty() || b.empty()) return pairs; - std::vector events[2]; - events[0].reserve(a.size()*2); - events[1].reserve(b.size()*2); - - for(unsigned n = 0; n < 2; n++) { - unsigned sz = n ? b.size() : a.size(); - events[n].reserve(sz*2); - for(unsigned i = 0; i < sz; i++) { - Rect r = n ? b[i] : a[i]; - events[n].push_back(Event(r[d].min(), i, false)); - events[n].push_back(Event(r[d].max(), i, true)); - } - std::sort(events[n].begin(), events[n].end()); - } - - std::vector open[2]; - bool n = events[1].front() < events[0].front(); - {// As elegant as putting the initialiser in the for was, it upsets some legacy compilers (MS VS C++) - unsigned i[] = {0,0}; - for(; i[n] < events[n].size();) { - unsigned ix = events[n][i[n]].ix; - bool closing = events[n][i[n]].closing; - //std::cout << n << "[" << ix << "] - " << (closing ? "closer" : "opener") << "\n"; - if(closing) { - open[n].erase(std::find(open[n].begin(), open[n].end(), ix)); - } else { - if(n) { - //n = 1 - //opening a B, add to all open a - for(unsigned j = 0; j < open[0].size(); j++) { - unsigned jx = open[0][j]; - if(a[jx][1-d].intersects(b[ix][1-d])) { - pairs[jx].push_back(ix); - } - } - } else { - //n = 0 - //opening an A, add all open b - for(unsigned j = 0; j < open[1].size(); j++) { - unsigned jx = open[1][j]; - if(b[jx][1-d].intersects(a[ix][1-d])) { - pairs[ix].push_back(jx); - } - } - } - open[n].push_back(ix); - } - i[n]++; - if(i[n]>=events[n].size()) {break;} - n = (events[!n][i[!n]] < events[n][i[n]]) ? !n : n; - }} - return pairs; -} - -//Fake cull, until the switch to the real sweep is made. -std::vector > fake_cull(unsigned a, unsigned b) { - std::vector > ret; - - std::vector all; - for(unsigned j = 0; j < b; j++) - all.push_back(j); - - for(unsigned i = 0; i < a; i++) - ret.push_back(all); - - return ret; -} - -} - -/* - Local Variables: - mode:c++ - c-file-style:"stroustrup" - c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) - indent-tabs-mode:nil - fill-column:99 - End: -*/ -// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 : diff --git a/src/2geom/sweep.h b/src/2geom/sweep.h deleted file mode 100644 index 9c012958b..000000000 --- a/src/2geom/sweep.h +++ /dev/null @@ -1,79 +0,0 @@ -/** - * \file - * \brief Sweepline intersection of groups of rectangles - *//* - * Authors: - * ? - * - * Copyright ?-? authors - * - * This library is free software; you can redistribute it and/or - * modify it either under the terms of the GNU Lesser General Public - * License version 2.1 as published by the Free Software Foundation - * (the "LGPL") or, at your option, under the terms of the Mozilla - * Public License Version 1.1 (the "MPL"). If you do not alter this - * notice, a recipient may use your version of this file under either - * the MPL or the LGPL. - * - * You should have received a copy of the LGPL along with this library - * in the file COPYING-LGPL-2.1; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * You should have received a copy of the MPL along with this library - * in the file COPYING-MPL-1.1 - * - * The contents of this file are subject to the Mozilla Public License - * Version 1.1 (the "License"); you may not use this file except in - * compliance with the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY - * OF ANY KIND, either express or implied. See the LGPL or the MPL for - * the specific language governing rights and limitations. - * - */ - -#ifndef LIB2GEOM_SEEN_SWEEP_H -#define LIB2GEOM_SEEN_SWEEP_H - -#include -#include <2geom/d2.h> - -namespace Geom { - -struct Event { - double x; - unsigned ix; - bool closing; - Event(double pos, unsigned i, bool c) : x(pos), ix(i), closing(c) {} -// Lexicographic ordering by x then closing - bool operator<(Event const &other) const { - if(x < other.x) return true; - if(x > other.x) return false; - return closing < other.closing; - } - bool operator==(Event const &other) const { - return other.x == x && other.ix == ix && other.closing == closing; - } -}; -std::vector > -sweep_bounds(std::vector, Dim2 dim = X); - -std::vector > -sweep_bounds(std::vector, std::vector, Dim2 dim = X); - -std::vector > fake_cull(unsigned a, unsigned b); - -} - -#endif - -/* - Local Variables: - mode:c++ - c-file-style:"stroustrup" - c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) - indent-tabs-mode:nil - fill-column:99 - End: -*/ -// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 : diff --git a/src/2geom/sweeper.h b/src/2geom/sweeper.h new file mode 100644 index 000000000..1cbce52b0 --- /dev/null +++ b/src/2geom/sweeper.h @@ -0,0 +1,220 @@ +/** @file + * @brief Class for implementing sweepline algorithms + *//* + * Authors: + * Krzysztof Kosiński + * + * Copyright 2015 Authors + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + */ + +#ifndef LIB2GEOM_SEEN_SWEEPER_H +#define LIB2GEOM_SEEN_SWEEPER_H + +#include <2geom/coord.h> +#include +#include +#include +#include + +namespace Geom { + +struct IntervalSweepTraits { + typedef Interval Bound; + typedef std::less Compare; + inline static Coord entry_value(Bound const &b) { return b.min(); } + inline static Coord exit_value(Bound const &b) { return b.max(); } +}; + +template +struct RectSweepTraits { + typedef Rect Bound; + typedef std::less Compare; + inline static Coord entry_value(Bound const &b) { return b[d].min(); } + inline static Coord exit_value(Bound const &b) { return b[d].max(); } +}; + +/** @brief Generic sweepline algorithm. + * + * This class encapsulates an algorithm that sorts the objects according + * to their bounds, then moves an imaginary line (sweepline) over those + * bounds from left to right. Objects are added to the active list when + * the line starts intersecting their bounds, and removed when it completely + * passes over them. + * + * To use this, create a derived class and reimplement the _enter() + * and/or _leave() virtual functions, insert all the objects, + * and finally call process(). You can specify the bound type + * and how it should be accessed by defining a custom SweepTraits class. + * + * Look in path.cpp for example usage. + */ +template +class Sweeper { +public: + typedef typename SweepTraits::Bound Bound; + + Sweeper() {} + + void insert(Bound const &bound, Item const &item) { + assert(!(typename SweepTraits::Compare()( + SweepTraits::exit_value(bound), + SweepTraits::entry_value(bound)))); + _items.push_back(Record(bound, item)); + } + + template + void insert(Iter first, Iter last, BoundFunc f = BoundFunc()) { + for (; first != last; ++first) { + Bound b = f(*first); + assert(!(typename SweepTraits::Compare()( + SweepTraits::exit_value(b), + SweepTraits::entry_value(b)))); + _items.push_back(Record(b, *first)); + } + } + + /** @brief Process entry and exit events. + * This will iterate over all inserted items, calling the virtual protected + * functions _enter() and _leave() according to the order of the boundaries + * of each item. */ + void process() { + if (_items.empty()) return; + + typename SweepTraits::Compare cmp; + + for (RecordIter i = _items.begin(); i != _items.end(); ++i) { + _entry_events.push_back(i); + _exit_events.push_back(i); + } + boost::make_heap(_entry_events, _entry_heap_compare); + boost::make_heap(_exit_events, _exit_heap_compare); + boost::pop_heap(_entry_events, _entry_heap_compare); + boost::pop_heap(_exit_events, _exit_heap_compare); + + RecordIter next_entry = _entry_events.back(); + RecordIter next_exit = _exit_events.back(); + _entry_events.pop_back(); + _exit_events.pop_back(); + + while (next_entry != _items.end() || next_exit != _items.end()) { + assert(next_exit != _items.end()); + + if (next_entry == _items.end() || + cmp(SweepTraits::exit_value(next_exit->bound), + SweepTraits::entry_value(next_entry->bound))) + { + // exit event - remove record from active list + _leave(*next_exit); + _active_items.erase(_active_items.iterator_to(*next_exit)); + if (!_exit_events.empty()) { + boost::pop_heap(_exit_events, _exit_heap_compare); + next_exit = _exit_events.back(); + _exit_events.pop_back(); + } else { + next_exit = _items.end(); + // we should end the loop after this happens + } + } else { + // entry event - add record to active list + _enter(*next_entry); + _active_items.push_back(*next_entry); + if (!_entry_events.empty()) { + boost::pop_heap(_entry_events, _entry_heap_compare); + next_entry = _entry_events.back(); + _entry_events.pop_back(); + } else { + next_entry = _items.end(); + } + } + } + + assert(_active_items.empty()); + } + +protected: + /// The item and its sweepline boundary. + struct Record { + boost::intrusive::list_member_hook<> _hook; + Bound bound; + Item item; + + Record(Bound const &b, Item const &i) + : bound(b), item(i) + {} + }; + typedef typename std::vector::iterator RecordIter; + + typedef boost::intrusive::list + < Record + , boost::intrusive::member_hook + < Record + , boost::intrusive::list_member_hook<> + , &Record::_hook + > + > RecordList; + + /** @brief Enter an item record. + * Override this to process an item as it is about to enter the active list. + * When called, the passed record will not be part of the active list. */ + virtual void _enter(Record const &) {} + /** @brief Leave an item record. + * Override this to process an item as it is about to leave the active list. + * When called, the passed record will be part of the active list. */ + virtual void _leave(Record const &) {} + + /// The list of all item records undergoing sweeping. + std::vector _items; + /// The list of active item records. + RecordList _active_items; + +private: + inline static bool _entry_heap_compare(RecordIter a, RecordIter b) { + typename SweepTraits::Compare cmp; + return cmp(SweepTraits::entry_value(b->bound), SweepTraits::entry_value(a->bound)); + } + inline static bool _exit_heap_compare(RecordIter a, RecordIter b) { + typename SweepTraits::Compare cmp; + return cmp(SweepTraits::exit_value(b->bound), SweepTraits::exit_value(a->bound)); + } + + std::vector _entry_events; + std::vector _exit_events; +}; + +} // namespace Geom + +#endif // !LIB2GEOM_SEEN_SWEEPER_H + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 : diff --git a/src/2geom/transforms.cpp b/src/2geom/transforms.cpp index 091079d5a..41d395297 100644 --- a/src/2geom/transforms.cpp +++ b/src/2geom/transforms.cpp @@ -139,6 +139,24 @@ Affine &Affine::operator*=(Zoom const &z) { return *this; } +Affine Rotate::around(Point const &p, Coord angle) +{ + Affine result = Translate(-p) * Rotate(angle) * Translate(p); + return result; +} + +Affine reflection(Point const & vector, Point const & origin) +{ + Geom::Point vn = unit_vector(vector); + Coord cx2 = vn[X] * vn[X]; + Coord cy2 = vn[Y] * vn[Y]; + Coord c2xy = 2 * vn[X] * vn[Y]; + Affine mirror ( cx2 - cy2, c2xy, + c2xy, cy2 - cx2, + 0, 0 ); + return Translate(-origin) * mirror * Translate(origin); +} + // this checks whether the requirements of TransformConcept are satisfied for all transforms. // if you add a new transform type, include it here! void check_transforms() @@ -173,14 +191,6 @@ void check_transforms() m = z * t; m = z * s; m = z * r; m = z * h; m = z * v; m = z * z; } -Affine reflection(Point const & vector, Point const & origin) { - Geom::Point vec_norm = unit_vector(vector); - Affine mirror ( vec_norm[X]*vec_norm[X] - vec_norm[Y]*vec_norm[Y], 2 * vec_norm[X] * vec_norm[Y] , - 2 * vec_norm[X] * vec_norm[Y], vec_norm[Y]*vec_norm[Y] - vec_norm[X]*vec_norm[X] , - 0 ,0 ); - return Translate(-origin) * mirror * Translate(origin); -} - } // namespace Geom /* diff --git a/src/2geom/transforms.h b/src/2geom/transforms.h index 2e805786d..7c03c5226 100644 --- a/src/2geom/transforms.h +++ b/src/2geom/transforms.h @@ -217,6 +217,7 @@ public: Coord rad = (deg / 180.0) * M_PI; return Rotate(rad); } + static Affine around(Point const &p, Coord angle); friend class Point; }; diff --git a/src/extension/internal/wmf-print.cpp b/src/extension/internal/wmf-print.cpp index 271dec702..431053085 100644 --- a/src/extension/internal/wmf-print.cpp +++ b/src/extension/internal/wmf-print.cpp @@ -30,7 +30,7 @@ #include <2geom/sbasis-to-bezier.h> -#include <2geom/svg-elliptical-arc.h> +#include <2geom/elliptical-arc.h> #include <2geom/path.h> #include <2geom/pathvector.h> diff --git a/src/helper/geom-pathstroke.cpp b/src/helper/geom-pathstroke.cpp index a152af62c..888e55180 100644 --- a/src/helper/geom-pathstroke.cpp +++ b/src/helper/geom-pathstroke.cpp @@ -10,83 +10,14 @@ #include <2geom/path-sink.h> #include <2geom/point.h> #include <2geom/bezier-curve.h> -#include <2geom/svg-elliptical-arc.h> +#include <2geom/elliptical-arc.h> #include <2geom/sbasis-to-bezier.h> // cubicbezierpath_from_sbasis #include <2geom/path-intersection.h> +#include <2geom/circle.h> #include "helper/geom-pathstroke.h" namespace Geom { -// 2geom/circle-circle.cpp, no header -int circle_circle_intersection(Point X0, double r0, Point X1, double r1, Point &p0, Point &p1); - -/** - * Determine the intersection points between a circle C0 and a line defined - * by two points, X0 and X1. - * - * Which intersection point is assigned to p0 or p1 is unspecified, and callers - * should not depend on any particular intersection always being assigned to p0. - * - * Returns: - * If the line and circle do not cross, 0 is returned. - * If solution(s) exist, 2 is returned, and the results are written to p0 and p1. - */ -static int circle_line_intersection(Circle C0, Point X0, Point X1, Point &p0, Point &p1) -{ - /* equation of a circle: (x - h)^2 + (y - k)^2 = r^2 */ - Coord r = C0.radius(); - Coord h = C0.center()[X]; - Coord k = C0.center()[Y]; - - Coord x0, y0; - Coord x1, y1; - - if (are_near(X1[X], X0[X])) { - /* slope is undefined (vertical line) */ - Coord c = X0[X]; - Coord det = r*r - (c-h)*(c-h); - - /* no intersection */ - if (det < 0) - return 0; - - /* solve for y */ - y0 = k + std::sqrt(det); - y1 = k - std::sqrt(det); - - // x == c (always) - x0 = c; - x1 = c; - } else { - /* equation of a line: y = mx + b */ - Coord m = (X1[Y] - X0[Y]) / (X1[X] - X0[X]); - Coord b = X0[Y] - m*X0[X]; - - /* obtain quadratic for x: */ - Coord A = m*m + 1; - Coord B = 2*h - 2*b*m + 2*k*m; - Coord C = b*b + h*h + k*k - r*r - 2*b*k; - - Coord det = B*B - 4*A*C; - - /* no intersection, circle and line do not cross */ - if (det < 0) - return 0; - - /* solve quadratic */ - x0 = (B + std::sqrt(det)) / (2*A); - x1 = (B - std::sqrt(det)) / (2*A); - - /* substitute the calculated x times to determine the y values */ - y0 = m*x0 + b; - y1 = m*x1 + b; - } - - p0 = Point(x0, y0); - p1 = Point(x1, y1); - - return 2; -} static Point intersection_point(Point origin_a, Point vector_a, Point origin_b, Point vector_b) { @@ -160,7 +91,7 @@ void bevel_join(join_data jd) void round_join(join_data jd) { - jd.res.appendNew(jd.width, jd.width, 0, false, jd.width <= 0, jd.outgoing.initialPoint()); + jd.res.appendNew(jd.width, jd.width, 0, false, jd.width <= 0, jd.outgoing.initialPoint()); jd.res.append(jd.outgoing); } @@ -226,18 +157,20 @@ void miter_join_internal(join_data jd, bool clip) void miter_join(join_data jd) { miter_join_internal(jd, false); } void miter_clip_join(join_data jd) { miter_join_internal(jd, true); } -Geom::Point pick_solution(Geom::Point points[2], Geom::Point tang2, Geom::Point endPt) +Geom::Point pick_solution(std::vector points, Geom::Point tang2, Geom::Point endPt) { + assert(points.size() == 2); Geom::Point sol; - if ( dot(tang2,points[0]-endPt) > 0 ) { + if ( dot(tang2, points[0].point() - endPt) > 0 ) { // points[0] is bad, choose points[1] sol = points[1]; - } else if ( dot(tang2,points[1]-endPt) > 0 ) { // points[0] could be good, now check points[1] + } else if ( dot(tang2, points[1].point() - endPt) > 0 ) { // points[0] could be good, now check points[1] // points[1] is bad, choose points[0] sol = points[0]; } else { // both points are good, choose nearest - sol = ( distanceSq(endPt, points[0]) < distanceSq(endPt, points[1]) ) ? points[0] : points[1]; + sol = ( distanceSq(endPt, points[0].point()) < distanceSq(endPt, points[1].point()) ) + ? points[0].point() : points[1].point(); } return sol; } @@ -261,9 +194,8 @@ void extrapolate_join(join_data jd) bool inc_ls = !circle1.center().isFinite(); bool out_ls = !circle2.center().isFinite(); - Geom::Point points[2]; + std::vector points; - int solutions = 0; Geom::EllipticalArc *arc1 = NULL; Geom::EllipticalArc *arc2 = NULL; Geom::Point sol; @@ -272,33 +204,29 @@ void extrapolate_join(join_data jd) if (!inc_ls && !out_ls) { // Two circles - solutions = Geom::circle_circle_intersection(circle1.center(), circle1.radius(), - circle2.center(), circle2.radius(), - points[0], points[1]); - if (solutions == 2) { + points = circle1.intersect(circle2); + if (points.size() == 2) { sol = pick_solution(points, tang2, endPt); - arc1 = circle1.arc(startPt, 0.5*(startPt+sol), sol, true); - arc2 = circle2.arc(sol, 0.5*(sol+endPt), endPt, true); + arc1 = circle1.arc(startPt, 0.5*(startPt+sol), sol); + arc2 = circle2.arc(sol, 0.5*(sol+endPt), endPt); } } else if (inc_ls && !out_ls) { // Line and circle - solutions = Geom::circle_line_intersection(circle2, incoming.initialPoint(), incoming.finalPoint(), points[0], points[1]); - - if (solutions == 2) { + points = circle2.intersect(Line(incoming.initialPoint(), incoming.finalPoint())); + if (points.size() == 2) { sol = pick_solution(points, tang2, endPt); - arc2 = circle2.arc(sol, 0.5*(sol+endPt), endPt, true); + arc2 = circle2.arc(sol, 0.5*(sol+endPt), endPt); } } else if (!inc_ls && out_ls) { // Circle and line - solutions = Geom::circle_line_intersection(circle1, outgoing.initialPoint(), outgoing.finalPoint(), points[0], points[1]); - - if (solutions == 2) { + points = circle1.intersect(Line(outgoing.initialPoint(), outgoing.finalPoint())); + if (points.size() == 2) { sol = pick_solution(points, tang2, endPt); - arc1 = circle1.arc(startPt, 0.5*(sol+startPt), sol, true); + arc1 = circle1.arc(startPt, 0.5*(sol+startPt), sol); } } - if (solutions != 2) + if (points.size() != 2) // no solutions available, fall back to miter return miter_clip_join(jd); @@ -348,19 +276,18 @@ void extrapolate_join(join_data jd) limit_line.setAngle(start_ray.angle() + limit_angle); } - Geom::EllipticalArc *arc_center = circle_center.arc(point_on_path, 0.5*(point_on_path + sol), sol, true); + Geom::EllipticalArc *arc_center = circle_center.arc(point_on_path, 0.5*(point_on_path + sol), sol); if (arc_center && arc_center->sweepAngle() > limit_angle) { // We need to clip clipped = true; if (!inc_ls) { // Incoming circular - solutions = Geom::circle_line_intersection(circle1, limit_line.pointAt(0), limit_line.pointAt(1), points[0], points[1]); - - if (solutions == 2) { + points = circle1.intersect(limit_line); + if (points.size() == 2) { p1 = pick_solution(points, tang2, endPt); delete arc1; - arc1 = circle1.arc(startPt, 0.5*(p1+startPt), p1, true); + arc1 = circle1.arc(startPt, 0.5*(p1+startPt), p1); } } else { p1 = Geom::intersection_point(startPt, tang1, limit_line.pointAt(0), limit_line.versor()); @@ -368,12 +295,11 @@ void extrapolate_join(join_data jd) if (!out_ls) { // Outgoing circular - solutions = Geom::circle_line_intersection(circle2, limit_line.pointAt(0), limit_line.pointAt(1), points[0], points[1]); - - if (solutions == 2) { + points = circle2.intersect(limit_line); + if (points.size() == 2) { p2 = pick_solution(points, tang1, endPt); delete arc2; - arc2 = circle2.arc(p2, 0.5*(p2+endPt), endPt, true); + arc2 = circle2.arc(p2, 0.5*(p2+endPt), endPt); } } else { p2 = Geom::intersection_point(endPt, tang2, limit_line.pointAt(0), limit_line.versor()); diff --git a/src/livarot/PathCutting.cpp b/src/livarot/PathCutting.cpp index d6ad6c94a..086b30557 100644 --- a/src/livarot/PathCutting.cpp +++ b/src/livarot/PathCutting.cpp @@ -308,7 +308,7 @@ Path::MakePathVector() { /* TODO: add testcase for this descr_arcto case */ PathDescrArcTo *nData = dynamic_cast(descr_cmd[i]); - currentpath->appendNew( nData->rx, nData->ry, nData->angle*M_PI/180.0, nData->large, !nData->clockwise, nData->p ); + currentpath->appendNew( nData->rx, nData->ry, nData->angle*M_PI/180.0, nData->large, !nData->clockwise, nData->p ); lastP = nData->p; } break; @@ -400,11 +400,11 @@ void Path::AddCurve(Geom::Curve const &c) Geom::Point tme = 3 * ((*cubic_bezier)[3] - (*cubic_bezier)[2]); CubicTo (tmp, tms, tme); } - else if(Geom::SVGEllipticalArc const *svg_elliptical_arc = dynamic_cast(&c)) { - ArcTo( svg_elliptical_arc->finalPoint(), - svg_elliptical_arc->ray(Geom::X), svg_elliptical_arc->ray(Geom::Y), - svg_elliptical_arc->rotationAngle()*180.0/M_PI, // convert from radians to degrees - svg_elliptical_arc->largeArc(), !svg_elliptical_arc->sweep() ); + else if(Geom::EllipticalArc const *elliptical_arc = dynamic_cast(&c)) { + ArcTo( elliptical_arc->finalPoint(), + elliptical_arc->ray(Geom::X), elliptical_arc->ray(Geom::Y), + elliptical_arc->rotationAngle()*180.0/M_PI, // convert from radians to degrees + elliptical_arc->largeArc(), !elliptical_arc->sweep() ); } else { //this case handles sbasis as well as all other curve types Geom::Path sbasis_path = Geom::cubicbezierpath_from_sbasis(c.toSBasis(), 0.1); diff --git a/src/live_effects/lpe-circle_3pts.cpp b/src/live_effects/lpe-circle_3pts.cpp index cbabb5a6c..dbb1f4b6b 100644 --- a/src/live_effects/lpe-circle_3pts.cpp +++ b/src/live_effects/lpe-circle_3pts.cpp @@ -17,6 +17,7 @@ // You might need to include other 2geom files. You can add them here: #include <2geom/path.h> #include <2geom/circle.h> +#include <2geom/path-sink.h> namespace Inkscape { namespace LivePathEffect { @@ -47,7 +48,7 @@ static void _circle3(Geom::Point const &A, Geom::Point const &B, Geom::Point con double radius = L2(M - A); Geom::Circle c(M, radius); - c.getPath(path_out); + path_out = Geom::Path(c); } Geom::PathVector diff --git a/src/live_effects/lpe-circle_with_radius.cpp b/src/live_effects/lpe-circle_with_radius.cpp index 32d0c0bf5..8f2156044 100644 --- a/src/live_effects/lpe-circle_with_radius.cpp +++ b/src/live_effects/lpe-circle_with_radius.cpp @@ -15,11 +15,9 @@ #include "display/curve.h" // You might need to include other 2geom files. You can add them here: -#include <2geom/path.h> -#include <2geom/sbasis.h> -#include <2geom/bezier-to-sbasis.h> -#include <2geom/d2.h> +#include <2geom/pathvector.h> #include <2geom/circle.h> +#include <2geom/path-sink.h> using namespace Geom; @@ -51,9 +49,7 @@ LPECircleWithRadius::doEffect_path (Geom::PathVector const & path_in) double radius = Geom::L2(pt - center); Geom::Circle c(center, radius); - c.getPath(path_out); - - return path_out; + return Geom::Path(c); } /* diff --git a/src/live_effects/lpe-fillet-chamfer.cpp b/src/live_effects/lpe-fillet-chamfer.cpp index 992c45a43..a9a96864a 100644 --- a/src/live_effects/lpe-fillet-chamfer.cpp +++ b/src/live_effects/lpe-fillet-chamfer.cpp @@ -16,7 +16,7 @@ #include "live_effects/lpe-fillet-chamfer.h" #include <2geom/sbasis-to-bezier.h> -#include <2geom/svg-elliptical-arc.h> +#include <2geom/elliptical-arc.h> #include <2geom/line.h> #include "desktop.h" @@ -582,7 +582,7 @@ LPEFilletChamfer::doEffect_path(Geom::PathVector const &path_in) Geom::Path path_chamfer; path_chamfer.start(path_out.finalPoint()); if((is_straight_curve(*curve_it1) && is_straight_curve(*curve_it2Fixed) && method != FM_BEZIER )|| method == FM_ARC){ - path_chamfer.appendNew(rx, ry, angleArc, 0, ccwToggle, endArcPoint); + path_chamfer.appendNew(rx, ry, angleArc, 0, ccwToggle, endArcPoint); } else { path_chamfer.appendNew(handle1, handle2, endArcPoint); } @@ -598,7 +598,7 @@ LPEFilletChamfer::doEffect_path(Geom::PathVector const &path_in) path_chamfer.start(path_out.finalPoint()); if((is_straight_curve(*curve_it1) && is_straight_curve(*curve_it2Fixed) && method != FM_BEZIER )|| method == FM_ARC){ ccwToggle = ccwToggle?0:1; - path_chamfer.appendNew(rx, ry, angleArc, 0, ccwToggle, endArcPoint); + path_chamfer.appendNew(rx, ry, angleArc, 0, ccwToggle, endArcPoint); }else{ path_chamfer.appendNew(inverseHandle1, inverseHandle2, endArcPoint); } @@ -611,13 +611,13 @@ LPEFilletChamfer::doEffect_path(Geom::PathVector const &path_in) } else if (type == 2) { if((is_straight_curve(*curve_it1) && is_straight_curve(*curve_it2Fixed) && method != FM_BEZIER )|| method == FM_ARC){ ccwToggle = ccwToggle?0:1; - path_out.appendNew(rx, ry, angleArc, 0, ccwToggle, endArcPoint); + path_out.appendNew(rx, ry, angleArc, 0, ccwToggle, endArcPoint); }else{ path_out.appendNew(inverseHandle1, inverseHandle2, endArcPoint); } } else if (type == 1){ if((is_straight_curve(*curve_it1) && is_straight_curve(*curve_it2Fixed) && method != FM_BEZIER )|| method == FM_ARC){ - path_out.appendNew(rx, ry, angleArc, 0, ccwToggle, endArcPoint); + path_out.appendNew(rx, ry, angleArc, 0, ccwToggle, endArcPoint); } else { path_out.appendNew(handle1, handle2, endArcPoint); } diff --git a/src/live_effects/lpe-jointype.cpp b/src/live_effects/lpe-jointype.cpp index 893f3ab4e..cc5587194 100644 --- a/src/live_effects/lpe-jointype.cpp +++ b/src/live_effects/lpe-jointype.cpp @@ -20,7 +20,7 @@ #include "display/curve.h" #include <2geom/path.h> -#include <2geom/svg-elliptical-arc.h> +#include <2geom/elliptical-arc.h> #include "lpe-jointype.h" diff --git a/src/live_effects/lpe-offset.cpp b/src/live_effects/lpe-offset.cpp index c841a5442..dd7af92a2 100644 --- a/src/live_effects/lpe-offset.cpp +++ b/src/live_effects/lpe-offset.cpp @@ -20,7 +20,7 @@ #include <2geom/path.h> #include <2geom/piecewise.h> #include <2geom/sbasis-geometric.h> -#include <2geom/svg-elliptical-arc.h> +#include <2geom/elliptical-arc.h> #include <2geom/transforms.h> namespace Inkscape { @@ -52,7 +52,7 @@ static void append_half_circle(Geom::Piecewise > &pwd2, using namespace Geom; double r = L2(dir); - SVGEllipticalArc cap(center + dir, r, r, angle_between(Point(1,0), dir), false, false, center - dir); + EllipticalArc cap(center + dir, r, r, angle_between(Point(1,0), dir), false, false, center - dir); Piecewise > cap_pwd2(cap.toSBasis()); pwd2.continuousConcat(cap_pwd2); } diff --git a/src/live_effects/lpe-powerstroke.cpp b/src/live_effects/lpe-powerstroke.cpp index 6a823e943..6ce912bcb 100644 --- a/src/live_effects/lpe-powerstroke.cpp +++ b/src/live_effects/lpe-powerstroke.cpp @@ -27,12 +27,13 @@ #include <2geom/sbasis-geometric.h> #include <2geom/transforms.h> #include <2geom/bezier-utils.h> -#include <2geom/svg-elliptical-arc.h> +#include <2geom/elliptical-arc.h> #include <2geom/sbasis-to-bezier.h> #include <2geom/path-sink.h> #include <2geom/path-intersection.h> #include <2geom/crossing.h> #include <2geom/ellipse.h> +#include <2geom/circle.h> #include <2geom/math-utils.h> #include @@ -93,71 +94,6 @@ static Ellipse find_ellipse(Point P, Point Q, Point O) return Ellipse(A, B, C, D, E, F); } -/** - * Refer to: Weisstein, Eric W. "Circle-Circle Intersection." - From MathWorld--A Wolfram Web Resource. - http://mathworld.wolfram.com/Circle-CircleIntersection.html - * - * @return 0 if no intersection - * @return 1 if one circle is contained in the other - * @return 2 if intersections are found (they are written to p0 and p1) - */ -static int circle_circle_intersection(Circle const &circle0, Circle const &circle1, - Point & p0, Point & p1) -{ - Point X0 = circle0.center(); - double r0 = circle0.radius(); - Point X1 = circle1.center(); - double r1 = circle1.radius(); - - /* dx and dy are the vertical and horizontal distances between - * the circle centers. - */ - Point D = X1 - X0; - - /* Determine the straight-line distance between the centers. */ - double d = L2(D); - - /* Check for solvability. */ - if (d > (r0 + r1)) - { - /* no solution. circles do not intersect. */ - return 0; - } - if (d <= fabs(r0 - r1)) - { - /* no solution. one circle is contained in the other */ - return 1; - } - - /* 'point 2' is the point where the line through the circle - * intersection points crosses the line between the circle - * centers. - */ - - /* Determine the distance from point 0 to point 2. */ - double a = ((r0*r0) - (r1*r1) + (d*d)) / (2.0 * d) ; - - /* Determine the coordinates of point 2. */ - Point p2 = X0 + D * (a/d); - - /* Determine the distance from point 2 to either of the - * intersection points. - */ - double h = std::sqrt((r0*r0) - (a*a)); - - /* Now determine the offsets of the intersection points from - * point 2. - */ - Point r = (h/d)*rot90(D); - - /* Determine the absolute intersection points. */ - p0 = p2 + r; - p1 = p2 - r; - - return 2; -} - /** * Find circle that touches inside of the curve, with radius matching the curvature, at time value \c t. * Because this method internally uses unitTangentAt, t should be smaller than 1.0 (see unitTangentAt). @@ -484,24 +420,24 @@ static Geom::Path path_from_piecewise_fix_cusps( Geom::Piecewise solutions; + solutions = circle1.intersect(circle2); + if (solutions.size() == 2) { Geom::Point sol(0.,0.); - if ( dot(tang2,points[0]-B[i].at0()) > 0 ) { + if ( dot(tang2, solutions[0].point() - B[i].at0()) > 0 ) { // points[0] is bad, choose points[1] - sol = points[1]; - } else if ( dot(tang2,points[1]-B[i].at0()) > 0 ) { // points[0] could be good, now check points[1] + sol = solutions[1].point(); + } else if ( dot(tang2, solutions[1].point() - B[i].at0()) > 0 ) { // points[0] could be good, now check points[1] // points[1] is bad, choose points[0] - sol = points[0]; + sol = solutions[0].point(); } else { // both points are good, choose nearest - sol = ( distanceSq(B[i].at0(), points[0]) < distanceSq(B[i].at0(), points[1]) ) ? - points[0] : points[1]; + sol = ( distanceSq(B[i].at0(), solutions[0].point()) < distanceSq(B[i].at0(), solutions[1].point()) ) ? + solutions[0].point() : solutions[1].point(); } - Geom::EllipticalArc *arc0 = circle1.arc(B[prev_i].at1(), 0.5*(B[prev_i].at1()+sol), sol, true); - Geom::EllipticalArc *arc1 = circle2.arc(sol, 0.5*(sol+B[i].at0()), B[i].at0(), true); + Geom::EllipticalArc *arc0 = circle1.arc(B[prev_i].at1(), 0.5*(B[prev_i].at1()+sol), sol); + Geom::EllipticalArc *arc1 = circle2.arc(sol, 0.5*(sol+B[i].at0()), B[i].at0()); if (arc0) { build_from_sbasis(pb,arc0->toSBasis(), tol, false); @@ -739,7 +675,7 @@ LPEPowerStroke::doEffect_path (Geom::PathVector const & path_in) default: { double radius1 = 0.5 * distance(pwd2_out.lastValue(), mirrorpath.firstValue()); - fixed_path.appendNew( radius1, radius1, M_PI/2., false, y.lastValue() < 0, mirrorpath.firstValue() ); + fixed_path.appendNew( radius1, radius1, M_PI/2., false, y.lastValue() < 0, mirrorpath.firstValue() ); break; } } @@ -777,7 +713,7 @@ LPEPowerStroke::doEffect_path (Geom::PathVector const & path_in) default: { double radius2 = 0.5 * distance(pwd2_out.firstValue(), mirrorpath.lastValue()); - fixed_path.appendNew( radius2, radius2, M_PI/2., false, y.firstValue() < 0, pwd2_out.firstValue() ); + fixed_path.appendNew( radius2, radius2, M_PI/2., false, y.firstValue() < 0, pwd2_out.firstValue() ); break; } } diff --git a/src/live_effects/parameter/filletchamferpointarray.cpp b/src/live_effects/parameter/filletchamferpointarray.cpp index a3ff4c96f..955fcd621 100644 --- a/src/live_effects/parameter/filletchamferpointarray.cpp +++ b/src/live_effects/parameter/filletchamferpointarray.cpp @@ -11,7 +11,6 @@ #include <2geom/piecewise.h> #include <2geom/sbasis-to-bezier.h> #include <2geom/sbasis-geometric.h> -#include <2geom/svg-elliptical-arc.h> #include <2geom/line.h> #include <2geom/path-intersection.h> diff --git a/src/object-snapper.cpp b/src/object-snapper.cpp index 1293d19aa..634d56aa6 100644 --- a/src/object-snapper.cpp +++ b/src/object-snapper.cpp @@ -19,6 +19,7 @@ #include <2geom/rect.h> #include <2geom/line.h> #include <2geom/circle.h> +#include <2geom/path-sink.h> #include "document.h" #include "sp-namedview.h" #include "sp-image.h" @@ -626,7 +627,10 @@ void Inkscape::ObjectSnapper::_snapPathsConstrained(IntermSnapResults &isr, Geom::PathVector constraint_path; if (c.isCircular()) { Geom::Circle constraint_circle(dt->dt2doc(c.getPoint()), c.getRadius()); - constraint_circle.getPath(constraint_path); + Geom::PathBuilder pb; + pb.feed(constraint_circle); + pb.flush(); + constraint_path = pb.peek(); } else { Geom::Path constraint_line; constraint_line.start(p_min_on_cl); diff --git a/src/sp-ellipse.cpp b/src/sp-ellipse.cpp index 932a3a1b7..0675b7781 100644 --- a/src/sp-ellipse.cpp +++ b/src/sp-ellipse.cpp @@ -18,6 +18,7 @@ #include #include <2geom/angle.h> +#include <2geom/circle.h> #include <2geom/ellipse.h> #include <2geom/path-sink.h> #include <2geom/pathvector.h> diff --git a/src/svg/svg-path.cpp b/src/svg/svg-path.cpp index ab51a5537..ba9e11452 100644 --- a/src/svg/svg-path.cpp +++ b/src/svg/svg-path.cpp @@ -82,11 +82,11 @@ static void sp_svg_write_curve(Inkscape::SVG::PathString & str, Geom::Curve cons (*cubic_bezier)[2][0], (*cubic_bezier)[2][1], (*cubic_bezier)[3][0], (*cubic_bezier)[3][1] ); } - else if(Geom::SVGEllipticalArc const *svg_elliptical_arc = dynamic_cast(c)) { - str.arcTo( svg_elliptical_arc->ray(Geom::X), svg_elliptical_arc->ray(Geom::Y), - Geom::rad_to_deg(svg_elliptical_arc->rotationAngle()), - svg_elliptical_arc->largeArc(), svg_elliptical_arc->sweep(), - svg_elliptical_arc->finalPoint() ); + else if(Geom::EllipticalArc const *elliptical_arc = dynamic_cast(c)) { + str.arcTo( elliptical_arc->ray(Geom::X), elliptical_arc->ray(Geom::Y), + Geom::rad_to_deg(elliptical_arc->rotationAngle()), + elliptical_arc->largeArc(), elliptical_arc->sweep(), + elliptical_arc->finalPoint() ); } else { //this case handles sbasis as well as all other curve types Geom::Path sbasis_path = Geom::cubicbezierpath_from_sbasis(c->toSBasis(), 0.1); diff --git a/src/ui/tools/calligraphic-tool.cpp b/src/ui/tools/calligraphic-tool.cpp index 15e6527a3..28195eb75 100644 --- a/src/ui/tools/calligraphic-tool.cpp +++ b/src/ui/tools/calligraphic-tool.cpp @@ -140,8 +140,7 @@ void CalligraphicTool::setup() { { /* TODO: have a look at DropperTool::setup where the same is done.. generalize? */ - Geom::PathVector path; - Geom::Circle(0, 0, 1).getPath(path); + Geom::PathVector path = Geom::Path(Geom::Circle(0,0,1)); SPCurve *c = new SPCurve(path); diff --git a/src/ui/tools/dropper-tool.cpp b/src/ui/tools/dropper-tool.cpp index bda9d8e8a..c838c27d5 100644 --- a/src/ui/tools/dropper-tool.cpp +++ b/src/ui/tools/dropper-tool.cpp @@ -84,8 +84,7 @@ void DropperTool::setup() { ToolBase::setup(); /* TODO: have a look at CalligraphicTool::setup where the same is done.. generalize? */ - Geom::PathVector path; - Geom::Circle(0, 0, 1).getPath(path); + Geom::PathVector path = Geom::Path(Geom::Circle(0,0,1)); SPCurve *c = new SPCurve(path); diff --git a/src/ui/tools/spray-tool.cpp b/src/ui/tools/spray-tool.cpp index 26d74733a..6e3a06345 100644 --- a/src/ui/tools/spray-tool.cpp +++ b/src/ui/tools/spray-tool.cpp @@ -207,8 +207,7 @@ void SprayTool::setup() { { /* TODO: have a look at sp_dyna_draw_context_setup where the same is done.. generalize? at least make it an arcto! */ - Geom::PathVector path; - Geom::Circle(0, 0, 1).getPath(path); + Geom::PathVector path = Geom::Path(Geom::Circle(0,0,1)); SPCurve *c = new SPCurve(path); diff --git a/src/ui/tools/tweak-tool.cpp b/src/ui/tools/tweak-tool.cpp index 76b52f9be..94f7aa135 100644 --- a/src/ui/tools/tweak-tool.cpp +++ b/src/ui/tools/tweak-tool.cpp @@ -259,8 +259,7 @@ void TweakTool::setup() { { /* TODO: have a look at sp_dyna_draw_context_setup where the same is done.. generalize? at least make it an arcto! */ - Geom::PathVector path; - Geom::Circle(0, 0, 1).getPath(path); + Geom::PathVector path = Geom::Path(Geom::Circle(0,0,1)); SPCurve *c = new SPCurve(path); -- cgit v1.2.3 From 72b5c71727e8837c5994966a0dfcbe7937f928dd Mon Sep 17 00:00:00 2001 From: Krzysztof Kosi??ski Date: Fri, 22 May 2015 11:39:48 +0200 Subject: 2Geom CMake adjustment (bzr r14059.2.17) --- src/2geom/CMakeLists.txt | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/2geom/CMakeLists.txt b/src/2geom/CMakeLists.txt index d0c196f56..8a2884a2a 100644 --- a/src/2geom/CMakeLists.txt +++ b/src/2geom/CMakeLists.txt @@ -44,7 +44,7 @@ set(2geom_SRC solve-bezier-parametric.cpp svg-path-parser.cpp svg-path-writer.cpp - sweep.cpp + sweep-bounds.cpp toposweep.cpp transforms.cpp utils.cpp @@ -115,7 +115,8 @@ set(2geom_SRC solver.h svg-path-parser.h svg-path-writer.h - sweep.h + sweeper.h + sweep-bounds.h toposweep.h transforms.h utils.h -- cgit v1.2.3 From 2f2b64bd4a267775e948957c8c815d8efb644c93 Mon Sep 17 00:00:00 2001 From: Tavmjong Bah Date: Sun, 24 May 2015 11:51:12 +0200 Subject: Reorganized PDF import dialog, disabling unused options as appropriate. (bzr r14170) --- src/extension/internal/pdfinput/pdf-input.cpp | 144 ++++++++++++++------------ src/extension/internal/pdfinput/pdf-input.h | 13 ++- 2 files changed, 90 insertions(+), 67 deletions(-) (limited to 'src') diff --git a/src/extension/internal/pdfinput/pdf-input.cpp b/src/extension/internal/pdfinput/pdf-input.cpp index 148d2dcba..0fa5dc3df 100644 --- a/src/extension/internal/pdfinput/pdf-input.cpp +++ b/src/extension/internal/pdfinput/pdf-input.cpp @@ -125,8 +125,13 @@ PdfImportDialog::PdfImportDialog(PDFDoc *doc, const gchar */*uri*/) _labelPrecisionWarning = Gtk::manage(new class Gtk::Label(_("Note: setting the precision too high may result in a large SVG file and slow performance."))); #ifdef HAVE_POPPLER_CAIRO - _importviaPopplerCheck = Gtk::manage(new class Gtk::CheckButton(_("import via Poppler"))); + Gtk::RadioButton::Group group; + _importViaPoppler = Gtk::manage(new class Gtk::RadioButton(group,_("Poppler/Cairo import"))); + _labelViaPoppler = Gtk::manage(new class Gtk::Label(_("Import via external library. Text consists of groups containing cloned glyphs where each glyph is a path. Images are stored internally. Meshes cause entire document to be rendered as a raster image."))); + _importViaInternal = Gtk::manage(new class Gtk::RadioButton(group,_("Internal import"))); + _labelViaInternal = Gtk::manage(new class Gtk::Label(_("Import via internal (Poppler derived) library. Text is stored as text but white space is missing. Meshes are converted to tiles, the number depends on the precision set below."))); #endif + #if WITH_GTKMM_3_0 _fallbackPrecisionSlider_adj = Gtk::Adjustment::create(2, 1, 256, 1, 10, 10); _fallbackPrecisionSlider = Gtk::manage(new class Gtk::Scale(_fallbackPrecisionSlider_adj)); @@ -139,13 +144,15 @@ PdfImportDialog::PdfImportDialog(PDFDoc *doc, const gchar */*uri*/) hbox6 = Gtk::manage(new class Gtk::HBox(false, 4)); // Text options - _labelText = Gtk::manage(new class Gtk::Label(_("Text handling:"))); - _textHandlingCombo = Gtk::manage(new class Gtk::ComboBoxText()); - _textHandlingCombo->append(_("Import text as text")); - _textHandlingCombo->set_active_text(_("Import text as text")); + // _labelText = Gtk::manage(new class Gtk::Label(_("Text handling:"))); + // _textHandlingCombo = Gtk::manage(new class Gtk::ComboBoxText()); + // _textHandlingCombo->append(_("Import text as text")); + // _textHandlingCombo->set_active_text(_("Import text as text")); + // hbox5 = Gtk::manage(new class Gtk::HBox(false, 4)); + + // Font option _localFontsCheck = Gtk::manage(new class Gtk::CheckButton(_("Replace PDF fonts by closest-named installed fonts"))); - hbox5 = Gtk::manage(new class Gtk::HBox(false, 4)); _embedImagesCheck = Gtk::manage(new class Gtk::CheckButton(_("Embed images"))); vbox3 = Gtk::manage(new class Gtk::VBox(false, 4)); _importSettingsFrame = Gtk::manage(new class Inkscape::UI::Widget::Frame(_("Import settings"))); @@ -202,12 +209,19 @@ PdfImportDialog::PdfImportDialog(PDFDoc *doc, const gchar */*uri*/) _labelPrecisionWarning->set_line_wrap(true); _labelPrecisionWarning->set_use_markup(true); _labelPrecisionWarning->set_selectable(false); + #ifdef HAVE_POPPLER_CAIRO - _importviaPopplerCheck->set_can_focus(); - _importviaPopplerCheck->set_relief(Gtk::RELIEF_NORMAL); - _importviaPopplerCheck->set_mode(true); - _importviaPopplerCheck->set_active(false); + _importViaPoppler->set_can_focus(); + _importViaPoppler->set_relief(Gtk::RELIEF_NORMAL); + _importViaPoppler->set_mode(true); + _importViaPoppler->set_active(false); + _importViaInternal->set_can_focus(); + _importViaInternal->set_relief(Gtk::RELIEF_NORMAL); + _importViaInternal->set_mode(true); + _labelViaPoppler->set_line_wrap(true); + _labelViaInternal->set_line_wrap(true); #endif + _fallbackPrecisionSlider->set_size_request(180,-1); _fallbackPrecisionSlider->set_can_focus(); _fallbackPrecisionSlider->set_inverted(false); @@ -223,14 +237,14 @@ PdfImportDialog::PdfImportDialog(PDFDoc *doc, const gchar */*uri*/) _labelPrecisionComment->set_selectable(false); hbox6->pack_start(*_fallbackPrecisionSlider, Gtk::PACK_SHRINK, 4); hbox6->pack_start(*_labelPrecisionComment, Gtk::PACK_SHRINK, 0); - _labelText->set_alignment(0.5,0.5); - _labelText->set_padding(4,0); - _labelText->set_justify(Gtk::JUSTIFY_LEFT); - _labelText->set_line_wrap(false); - _labelText->set_use_markup(false); - _labelText->set_selectable(false); - hbox5->pack_start(*_labelText, Gtk::PACK_SHRINK, 0); - hbox5->pack_start(*_textHandlingCombo, Gtk::PACK_SHRINK, 0); + // _labelText->set_alignment(0.5,0.5); + // _labelText->set_padding(4,0); + // _labelText->set_justify(Gtk::JUSTIFY_LEFT); + // _labelText->set_line_wrap(false); + // _labelText->set_use_markup(false); + // _labelText->set_selectable(false); + // hbox5->pack_start(*_labelText, Gtk::PACK_SHRINK, 0); + // hbox5->pack_start(*_textHandlingCombo, Gtk::PACK_SHRINK, 0); _localFontsCheck->set_can_focus(); _localFontsCheck->set_relief(Gtk::RELIEF_NORMAL); _localFontsCheck->set_mode(true); @@ -240,14 +254,17 @@ PdfImportDialog::PdfImportDialog(PDFDoc *doc, const gchar */*uri*/) _embedImagesCheck->set_mode(true); _embedImagesCheck->set_active(true); #ifdef HAVE_POPPLER_CAIRO - vbox3->pack_start(*_importviaPopplerCheck, Gtk::PACK_SHRINK, 0); + vbox3->pack_start(*_importViaPoppler, Gtk::PACK_SHRINK, 0); + vbox3->pack_start(*_labelViaPoppler, Gtk::PACK_SHRINK, 0); + vbox3->pack_start(*_importViaInternal, Gtk::PACK_SHRINK, 0); + vbox3->pack_start(*_labelViaInternal, Gtk::PACK_SHRINK, 0); #endif + vbox3->pack_start(*_localFontsCheck, Gtk::PACK_SHRINK, 0); + vbox3->pack_start(*_embedImagesCheck, Gtk::PACK_SHRINK, 0); vbox3->pack_start(*_labelPrecision, Gtk::PACK_SHRINK, 0); vbox3->pack_start(*hbox6, Gtk::PACK_SHRINK, 0); vbox3->pack_start(*_labelPrecisionWarning, Gtk::PACK_SHRINK, 0); - vbox3->pack_start(*hbox5, Gtk::PACK_SHRINK, 4); - vbox3->pack_start(*_localFontsCheck, Gtk::PACK_SHRINK, 0); - vbox3->pack_start(*_embedImagesCheck, Gtk::PACK_SHRINK, 0); + // vbox3->pack_start(*hbox5, Gtk::PACK_SHRINK, 4); _importSettingsFrame->add(*vbox3); _importSettingsFrame->set_border_width(4); vbox1->pack_start(*_pageSettingsFrame, Gtk::PACK_EXPAND_PADDING, 0); @@ -273,36 +290,9 @@ PdfImportDialog::PdfImportDialog(PDFDoc *doc, const gchar */*uri*/) this->property_destroy_with_parent().set_value(false); this->add_action_widget(*cancelbutton, -6); this->add_action_widget(*okbutton, -5); - cancelbutton->show(); - okbutton->show(); - _labelSelect->show(); - _pageNumberSpin->show(); - _labelTotalPages->show(); - hbox2->show(); - _cropCheck->show(); - _cropTypeCombo->show(); - hbox3->show(); - vbox2->show(); - _pageSettingsFrame->show(); - _labelPrecision->show(); - _labelPrecisionWarning->show(); -#ifdef HAVE_POPPLER_CAIRO - _importviaPopplerCheck->show(); -#endif - _fallbackPrecisionSlider->show(); - _labelPrecisionComment->show(); - hbox6->show(); - _labelText->show(); - _textHandlingCombo->show(); - hbox5->show(); - _localFontsCheck->show(); - _embedImagesCheck->show(); - vbox3->show(); - _importSettingsFrame->show(); - vbox1->show(); - _previewArea->show(); - hbox1->show(); + this->show_all(); + // Connect signals #if WITH_GTKMM_3_0 _previewArea->signal_draw().connect(sigc::mem_fun(*this, &PdfImportDialog::_onDraw)); @@ -313,6 +303,9 @@ PdfImportDialog::PdfImportDialog(PDFDoc *doc, const gchar */*uri*/) _pageNumberSpin_adj->signal_value_changed().connect(sigc::mem_fun(*this, &PdfImportDialog::_onPageNumberChanged)); _cropCheck->signal_toggled().connect(sigc::mem_fun(*this, &PdfImportDialog::_onToggleCropping)); _fallbackPrecisionSlider_adj->signal_value_changed().connect(sigc::mem_fun(*this, &PdfImportDialog::_onPrecisionChanged)); +#ifdef HAVE_POPPLER_CAIRO + _importViaPoppler->signal_toggled().connect(sigc::mem_fun(*this, &PdfImportDialog::_onToggleImport)); +#endif _render_thumb = false; #ifdef HAVE_POPPLER_CAIRO @@ -324,6 +317,9 @@ PdfImportDialog::PdfImportDialog(PDFDoc *doc, const gchar */*uri*/) _poppler_doc = poppler_document_new_from_file(doc_uri, NULL, NULL); g_free(doc_uri); } + + // Set sensitivity of some widgets based on selected import type. + _onToggleImport(); #endif // Set default preview size @@ -373,11 +369,11 @@ int PdfImportDialog::getSelectedPage() { return _current_page; } -int PdfImportDialog::getImportMethod() { +bool PdfImportDialog::getImportMethod() { #ifdef HAVE_POPPLER_CAIRO - return (_importviaPopplerCheck->get_active()) ? 1 : 0; + return _importViaPoppler->get_active(); #else - return 0; + return false; #endif } @@ -413,7 +409,7 @@ void PdfImportDialog::getImportSettings(Inkscape::XML::Node *prefs) { prefs->setAttribute("embedImages", "0"); } #ifdef HAVE_POPPLER_CAIRO - if (_importviaPopplerCheck->get_active()) { + if (_importViaPoppler->get_active()) { prefs->setAttribute("importviapoppler", "1"); } else { prefs->setAttribute("importviapoppler", "0"); @@ -453,6 +449,23 @@ void PdfImportDialog::_onPageNumberChanged() { _setPreviewPage(_current_page); } +#ifdef HAVE_POPPLER_CAIRO +void PdfImportDialog::_onToggleImport() { + if( _importViaPoppler->get_active() ) { + hbox3->set_sensitive(false); + _localFontsCheck->set_sensitive(false); + _embedImagesCheck->set_sensitive(false); + hbox6->set_sensitive(false); + } else { + hbox3->set_sensitive(); + _localFontsCheck->set_sensitive(); + _embedImagesCheck->set_sensitive(); + hbox6->set_sensitive(); + } +} +#endif + + #ifdef HAVE_POPPLER_CAIRO /** * \brief Copies image data from a Cairo surface to a pixbuf @@ -673,8 +686,12 @@ PdfInput::open(::Inkscape::Extension::Input * /*mod*/, const gchar * uri) { globalParams = new GlobalParams(); #endif // ENABLE_OSX_APP_LOCATIONS } - // poppler does not use glib g_open. So on win32 we must use unicode call. code was copied from glib gstdio.c + + + // PDFDoc is from poppler. #ifndef WIN32 + // poppler does not use glib g_open. So on win32 we must use unicode call. code was copied from + // glib gstdio.c GooString *filename_goo = new GooString(uri); PDFDoc *pdf_doc = new PDFDoc(filename_goo, NULL, NULL, NULL); // TODO: Could ask for password //delete filename_goo; @@ -739,17 +756,18 @@ PdfInput::open(::Inkscape::Extension::Input * /*mod*/, const gchar * uri) { Catalog *catalog = pdf_doc->getCatalog(); Page *page = catalog->getPage(page_num); - int is_importvia_poppler = 0; + bool is_importvia_poppler = false; if(dlg) { #ifdef HAVE_POPPLER_CAIRO is_importvia_poppler = dlg->getImportMethod(); + // printf("PDF import via %s.\n", is_importvia_poppler ? "poppler" : "native"); #endif } SPDocument *doc = NULL; bool saved = false; - if(is_importvia_poppler == 0) + if(!is_importvia_poppler) { // native importer doc = SPDocument::createNewDoc(NULL, TRUE, TRUE); @@ -769,8 +787,6 @@ PdfInput::open(::Inkscape::Extension::Input * /*mod*/, const gchar * uri) { if (dlg) dlg->getImportSettings(prefs); - printf("pdf import via %s.", (is_importvia_poppler != 0) ? "poppler" : "native"); - // Apply crop settings PDFRectangle *clipToBox = NULL; double crop_setting; @@ -798,11 +814,11 @@ PdfInput::open(::Inkscape::Extension::Input * /*mod*/, const gchar * uri) { } } - // Create parser + // Create parser (extension/internal/pdfinput/pdf-parser.h) PdfParser *pdf_parser = new PdfParser(pdf_doc->getXRef(), builder, page_num-1, page->getRotate(), page->getResourceDict(), page->getCropBox(), clipToBox); - // Set up approximation precision for parser + // Set up approximation precision for parser. Used for convering Mesh Gradients into tiles. double color_delta; sp_repr_get_double(prefs, "approximationPrecision", &color_delta); if ( color_delta <= 0.0 ) { @@ -833,7 +849,7 @@ PdfInput::open(::Inkscape::Extension::Input * /*mod*/, const gchar * uri) { // the poppler import gchar* filename_uri = g_filename_to_uri(uri, NULL, NULL); GError *error = NULL; - /// @todo handle passwort + /// @todo handle password /// @todo check if win32 unicode needs special attention PopplerDocument* document = poppler_document_new_from_file(filename_uri, NULL, &error); @@ -867,7 +883,7 @@ PdfInput::open(::Inkscape::Extension::Input * /*mod*/, const gchar * uri) { } else { - doc = SPDocument::createNewDoc(NULL, TRUE, TRUE); // fallback create empthy document + doc = SPDocument::createNewDoc(NULL, TRUE, TRUE); // fallback create empty document } saved = DocumentUndo::getUndoSensitive(doc); DocumentUndo::setUndoSensitive(doc, false); // No need to undo in this temporary document diff --git a/src/extension/internal/pdfinput/pdf-input.h b/src/extension/internal/pdfinput/pdf-input.h index 866db5d82..6e36603c3 100644 --- a/src/extension/internal/pdfinput/pdf-input.h +++ b/src/extension/internal/pdfinput/pdf-input.h @@ -44,6 +44,7 @@ namespace Gtk { #else class HScale; #endif + class RadioButton; class VBox; class Label; } @@ -71,7 +72,7 @@ public: bool showDialog(); int getSelectedPage(); - int getImportMethod(); + bool getImportMethod(); void getImportSettings(Inkscape::XML::Node *prefs); private: @@ -86,7 +87,10 @@ private: void _onPageNumberChanged(); void _onToggleCropping(); void _onPrecisionChanged(); - +#ifdef HAVE_POPPLER_CAIRO + void _onToggleImport(); +#endif + class Gtk::Button * cancelbutton; class Gtk::Button * okbutton; class Gtk::Label * _labelSelect; @@ -101,7 +105,10 @@ private: class Gtk::Label * _labelPrecision; class Gtk::Label * _labelPrecisionWarning; #ifdef HAVE_POPPLER_CAIRO - class Gtk::CheckButton * _importviaPopplerCheck; // using poppler_cairo for importing + class Gtk::RadioButton * _importViaPoppler; // Use poppler_cairo importing + class Gtk::Label * _labelViaPoppler; + class Gtk::RadioButton * _importViaInternal; // Use native (poppler based) importing + class Gtk::Label * _labelViaInternal; #endif #if WITH_GTKMM_3_0 class Gtk::Scale * _fallbackPrecisionSlider; -- cgit v1.2.3 From e362cec58fb273941e3aea562ba042e2e9b95c98 Mon Sep 17 00:00:00 2001 From: Tavmjong Bah Date: Sun, 24 May 2015 13:11:43 +0200 Subject: Respect PDF image 'interpolate' value on import. (bzr r14171) --- src/extension/internal/pdfinput/pdf-parser.cpp | 47 +++++++++++++++++++++---- src/extension/internal/pdfinput/svg-builder.cpp | 36 ++++++++++++------- src/extension/internal/pdfinput/svg-builder.h | 17 ++++----- 3 files changed, 73 insertions(+), 27 deletions(-) (limited to 'src') diff --git a/src/extension/internal/pdfinput/pdf-parser.cpp b/src/extension/internal/pdfinput/pdf-parser.cpp index cc0b38515..836c34c32 100644 --- a/src/extension/internal/pdfinput/pdf-parser.cpp +++ b/src/extension/internal/pdfinput/pdf-parser.cpp @@ -2780,12 +2780,14 @@ void PdfParser::doImage(Object * /*ref*/, Stream *str, GBool inlineImg) Dict *dict; int width, height; int bits; + GBool interpolate; StreamColorSpaceMode csMode; GBool mask; GBool invert; Object maskObj, smaskObj; GBool haveColorKeyMask, haveExplicitMask, haveSoftMask; GBool maskInvert; + GBool maskInterpolate; Object obj1, obj2; // get info from the stream @@ -2828,6 +2830,19 @@ void PdfParser::doImage(Object * /*ref*/, Stream *str, GBool inlineImg) } obj1.free(); + // image interpolation + dict->lookup("Interpolate", &obj1); + if (obj1.isNull()) { + obj1.free(); + dict->lookup("I", &obj1); + } + if (obj1.isBool()) + interpolate = obj1.getBool(); + else + interpolate = gFalse; + obj1.free(); + maskInterpolate = gFalse; + // image or mask? dict->lookup(const_cast("ImageMask"), &obj1); if (obj1.isNull()) { @@ -2884,7 +2899,7 @@ void PdfParser::doImage(Object * /*ref*/, Stream *str, GBool inlineImg) obj1.free(); // draw it - builder->addImageMask(state, str, width, height, invert); + builder->addImageMask(state, str, width, height, invert, interpolate); } else { // get color space and color map @@ -2986,6 +3001,16 @@ void PdfParser::doImage(Object * /*ref*/, Stream *str, GBool inlineImg) } int maskBits = obj1.getInt(); obj1.free(); + maskDict->lookup("Interpolate", &obj1); + if (obj1.isNull()) { + obj1.free(); + maskDict->lookup("I", &obj1); + } + if (obj1.isBool()) + maskInterpolate = obj1.getBool(); + else + maskInterpolate = gFalse; + obj1.free(); maskDict->lookup(const_cast("ColorSpace"), &obj1); if (obj1.isNull()) { obj1.free(); @@ -3071,6 +3096,16 @@ void PdfParser::doImage(Object * /*ref*/, Stream *str, GBool inlineImg) goto err2; } obj1.free(); + maskDict->lookup("Interpolate", &obj1); + if (obj1.isNull()) { + obj1.free(); + maskDict->lookup("I", &obj1); + } + if (obj1.isBool()) + maskInterpolate = obj1.getBool(); + else + maskInterpolate = gFalse; + obj1.free(); maskInvert = gFalse; maskDict->lookup(const_cast("Decode"), &obj1); if (obj1.isNull()) { @@ -3092,14 +3127,14 @@ void PdfParser::doImage(Object * /*ref*/, Stream *str, GBool inlineImg) // draw it if (haveSoftMask) { - builder->addSoftMaskedImage(state, str, width, height, colorMap, - maskStr, maskWidth, maskHeight, maskColorMap); + builder->addSoftMaskedImage(state, str, width, height, colorMap, interpolate, + maskStr, maskWidth, maskHeight, maskColorMap, maskInterpolate); delete maskColorMap; } else if (haveExplicitMask) { - builder->addMaskedImage(state, str, width, height, colorMap, - maskStr, maskWidth, maskHeight, maskInvert); + builder->addMaskedImage(state, str, width, height, colorMap, interpolate, + maskStr, maskWidth, maskHeight, maskInvert, maskInterpolate); } else { - builder->addImage(state, str, width, height, colorMap, + builder->addImage(state, str, width, height, colorMap, interpolate, haveColorKeyMask ? maskColors : static_cast(NULL)); } delete colorMap; diff --git a/src/extension/internal/pdfinput/svg-builder.cpp b/src/extension/internal/pdfinput/svg-builder.cpp index a3abb4045..58e2030d9 100644 --- a/src/extension/internal/pdfinput/svg-builder.cpp +++ b/src/extension/internal/pdfinput/svg-builder.cpp @@ -1485,7 +1485,9 @@ void png_flush_base64stream(png_structp png_ptr) * */ Inkscape::XML::Node *SvgBuilder::_createImage(Stream *str, int width, int height, - GfxImageColorMap *color_map, int *mask_colors, bool alpha_only, bool invert_alpha) { + GfxImageColorMap *color_map, bool interpolate, + int *mask_colors, bool alpha_only, + bool invert_alpha) { // Create PNG write struct png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); @@ -1655,6 +1657,13 @@ Inkscape::XML::Node *SvgBuilder::_createImage(Stream *str, int width, int height Inkscape::XML::Node *image_node = _xml_doc->createElement("svg:image"); sp_repr_set_svg_double(image_node, "width", 1); sp_repr_set_svg_double(image_node, "height", 1); + if( !interpolate ) { + SPCSSAttr *css = sp_repr_css_attr_new(); + // This should be changed after CSS4 Images widely supported. + sp_repr_css_set_property(css, "image-rendering", "optimizeSpeed"); + sp_repr_css_change(image_node, css, "style"); + sp_repr_css_attr_unref(css); + } // PS/PDF images are placed via a transformation matrix, no preserveAspectRatio used image_node->setAttribute("preserveAspectRatio", "none"); @@ -1715,9 +1724,9 @@ Inkscape::XML::Node *SvgBuilder::_createMask(double width, double height) { } void SvgBuilder::addImage(GfxState * /*state*/, Stream *str, int width, int height, - GfxImageColorMap *color_map, int *mask_colors) { + GfxImageColorMap *color_map, bool interpolate, int *mask_colors) { - Inkscape::XML::Node *image_node = _createImage(str, width, height, color_map, mask_colors); + Inkscape::XML::Node *image_node = _createImage(str, width, height, color_map, interpolate, mask_colors); if (image_node) { _container->appendChild(image_node); Inkscape::GC::release(image_node); @@ -1725,7 +1734,7 @@ void SvgBuilder::addImage(GfxState * /*state*/, Stream *str, int width, int heig } void SvgBuilder::addImageMask(GfxState *state, Stream *str, int width, int height, - bool invert) { + bool invert, bool interpolate) { // Create a rectangle Inkscape::XML::Node *rect = _xml_doc->createElement("svg:rect"); @@ -1742,7 +1751,8 @@ void SvgBuilder::addImageMask(GfxState *state, Stream *str, int width, int heigh // Scaling 1x1 surfaces might not work so skip setting a mask with this size if ( width > 1 || height > 1 ) { - Inkscape::XML::Node *mask_image_node = _createImage(str, width, height, NULL, NULL, true, invert); + Inkscape::XML::Node *mask_image_node = + _createImage(str, width, height, NULL, interpolate, NULL, true, invert); if (mask_image_node) { // Create the mask Inkscape::XML::Node *mask_node = _createMask(1.0, 1.0); @@ -1762,13 +1772,13 @@ void SvgBuilder::addImageMask(GfxState *state, Stream *str, int width, int heigh } void SvgBuilder::addMaskedImage(GfxState * /*state*/, Stream *str, int width, int height, - GfxImageColorMap *color_map, + GfxImageColorMap *color_map, bool interpolate, Stream *mask_str, int mask_width, int mask_height, - bool invert_mask) { + bool invert_mask, bool mask_interpolate) { Inkscape::XML::Node *mask_image_node = _createImage(mask_str, mask_width, mask_height, - NULL, NULL, true, invert_mask); - Inkscape::XML::Node *image_node = _createImage(str, width, height, color_map, NULL); + NULL, mask_interpolate, NULL, true, invert_mask); + Inkscape::XML::Node *image_node = _createImage(str, width, height, color_map, interpolate, NULL); if ( mask_image_node && image_node ) { // Create mask for the image Inkscape::XML::Node *mask_node = _createMask(1.0, 1.0); @@ -1795,13 +1805,13 @@ void SvgBuilder::addMaskedImage(GfxState * /*state*/, Stream *str, int width, in } void SvgBuilder::addSoftMaskedImage(GfxState * /*state*/, Stream *str, int width, int height, - GfxImageColorMap *color_map, + GfxImageColorMap *color_map, bool interpolate, Stream *mask_str, int mask_width, int mask_height, - GfxImageColorMap *mask_color_map) { + GfxImageColorMap *mask_color_map, bool mask_interpolate) { Inkscape::XML::Node *mask_image_node = _createImage(mask_str, mask_width, mask_height, - mask_color_map, NULL, true); - Inkscape::XML::Node *image_node = _createImage(str, width, height, color_map, NULL); + mask_color_map, mask_interpolate, NULL, true); + Inkscape::XML::Node *image_node = _createImage(str, width, height, color_map, interpolate, NULL); if ( mask_image_node && image_node ) { // Create mask for the image Inkscape::XML::Node *mask_node = _createMask(1.0, 1.0); diff --git a/src/extension/internal/pdfinput/svg-builder.h b/src/extension/internal/pdfinput/svg-builder.h index f1ce02cf0..ad15c9c06 100644 --- a/src/extension/internal/pdfinput/svg-builder.h +++ b/src/extension/internal/pdfinput/svg-builder.h @@ -112,17 +112,17 @@ public: // Image handling void addImage(GfxState *state, Stream *str, int width, int height, - GfxImageColorMap *color_map, int *mask_colors); + GfxImageColorMap *color_map, bool interpolate, int *mask_colors); void addImageMask(GfxState *state, Stream *str, int width, int height, - bool invert); + bool invert, bool interpolate); void addMaskedImage(GfxState *state, Stream *str, int width, int height, - GfxImageColorMap *color_map, + GfxImageColorMap *color_map, bool interpolate, Stream *mask_str, int mask_width, int mask_height, - bool invert_mask); + bool invert_mask, bool mask_interpolate); void addSoftMaskedImage(GfxState *state, Stream *str, int width, int height, - GfxImageColorMap *color_map, + GfxImageColorMap *color_map, bool interpolate, Stream *mask_str, int mask_width, int mask_height, - GfxImageColorMap *mask_color_map); + GfxImageColorMap *mask_color_map, bool mask_interpolate); // Transparency group and soft mask handling void pushTransparencyGroup(GfxState *state, double *bbox, @@ -180,8 +180,9 @@ private: bool is_stroke=false); // Image/mask creation Inkscape::XML::Node *_createImage(Stream *str, int width, int height, - GfxImageColorMap *color_map, int *mask_colors, - bool alpha_only=false, bool invert_alpha=false); + GfxImageColorMap *color_map, bool interpolate, + int *mask_colors, bool alpha_only=false, + bool invert_alpha=false); Inkscape::XML::Node *_createMask(double width, double height); // Style setting SPCSSAttr *_setStyle(GfxState *state, bool fill, bool stroke, bool even_odd=false); -- cgit v1.2.3 From ad6dce6b6ccf624a4cf31c8439d26180d9da8d80 Mon Sep 17 00:00:00 2001 From: Tavmjong Bah Date: Sun, 24 May 2015 22:51:57 +0200 Subject: Fix crash in import of PDF via Poppler/Cairo with relative path. Fixed bugs: - https://launchpad.net/bugs/1351246 (bzr r14172) --- src/extension/internal/pdfinput/pdf-input.cpp | 50 +++++++++++++++------------ 1 file changed, 28 insertions(+), 22 deletions(-) (limited to 'src') diff --git a/src/extension/internal/pdfinput/pdf-input.cpp b/src/extension/internal/pdfinput/pdf-input.cpp index 0fa5dc3df..2d0873233 100644 --- a/src/extension/internal/pdfinput/pdf-input.cpp +++ b/src/extension/internal/pdfinput/pdf-input.cpp @@ -81,7 +81,6 @@ PdfImportDialog::PdfImportDialog(PDFDoc *doc, const gchar */*uri*/) _poppler_doc = NULL; #endif // HAVE_POPPLER_CAIRO _pdf_doc = doc; - cancelbutton = Gtk::manage(new class Gtk::Button(Gtk::StockID("gtk-cancel"))); okbutton = Gtk::manage(new class Gtk::Button(Gtk::StockID("gtk-ok"))); _labelSelect = Gtk::manage(new class Gtk::Label(_("Select page:"))); @@ -311,11 +310,16 @@ PdfImportDialog::PdfImportDialog(PDFDoc *doc, const gchar */*uri*/) #ifdef HAVE_POPPLER_CAIRO _cairo_surface = NULL; _render_thumb = true; + // Create PopplerDocument - gchar *doc_uri = g_filename_to_uri(_pdf_doc->getFileName()->getCString(),NULL,NULL); - if (doc_uri) { - _poppler_doc = poppler_document_new_from_file(doc_uri, NULL, NULL); - g_free(doc_uri); + Glib::ustring filename = _pdf_doc->getFileName()->getCString(); + if (!Glib::path_is_absolute(filename)) { + filename = Glib::build_filename(Glib::get_current_dir(),filename); + } + Glib::ustring full_uri = Glib::filename_to_uri(filename); + + if (!full_uri.empty()) { + _poppler_doc = poppler_document_new_from_file(full_uri.c_str(), NULL, NULL); } // Set sensitivity of some widgets based on selected import type. @@ -688,7 +692,8 @@ PdfInput::open(::Inkscape::Extension::Input * /*mod*/, const gchar * uri) { } - // PDFDoc is from poppler. + // PDFDoc is from poppler. PDFDoc is used for preview and for native import. + #ifndef WIN32 // poppler does not use glib g_open. So on win32 we must use unicode call. code was copied from // glib gstdio.c @@ -747,18 +752,11 @@ PdfInput::open(::Inkscape::Extension::Input * /*mod*/, const gchar * uri) { } } - // Get needed page - int page_num; - if (dlg) - page_num = dlg->getSelectedPage(); - else - page_num = 1; - Catalog *catalog = pdf_doc->getCatalog(); - Page *page = catalog->getPage(page_num); - + // Get options + int page_num = 1; bool is_importvia_poppler = false; - if(dlg) - { + if (dlg) { + page_num = dlg->getSelectedPage(); #ifdef HAVE_POPPLER_CAIRO is_importvia_poppler = dlg->getImportMethod(); // printf("PDF import via %s.\n", is_importvia_poppler ? "poppler" : "native"); @@ -791,6 +789,10 @@ PdfInput::open(::Inkscape::Extension::Input * /*mod*/, const gchar * uri) { PDFRectangle *clipToBox = NULL; double crop_setting; sp_repr_get_double(prefs, "cropTo", &crop_setting); + + Catalog *catalog = pdf_doc->getCatalog(); + Page *page = catalog->getPage(page_num); + if ( crop_setting >= 0.0 ) { // Do page clipping int crop_choice = (int)crop_setting; switch (crop_choice) { @@ -847,13 +849,20 @@ PdfInput::open(::Inkscape::Extension::Input * /*mod*/, const gchar * uri) { { #ifdef HAVE_POPPLER_CAIRO // the poppler import - gchar* filename_uri = g_filename_to_uri(uri, NULL, NULL); + + Glib::ustring full_path = uri; + if (!Glib::path_is_absolute(uri)) { + full_path = Glib::build_filename(Glib::get_current_dir(),uri); + } + Glib::ustring full_uri = Glib::filename_to_uri(full_path); + GError *error = NULL; /// @todo handle password /// @todo check if win32 unicode needs special attention - PopplerDocument* document = poppler_document_new_from_file(filename_uri, NULL, &error); + PopplerDocument* document = poppler_document_new_from_file(full_uri.c_str(), NULL, &error); if(error != NULL) { + std::cerr << "PDFInput::open: error opening document: " << full_uri << std::endl; g_error_free (error); } @@ -887,9 +896,6 @@ PdfInput::open(::Inkscape::Extension::Input * /*mod*/, const gchar * uri) { } saved = DocumentUndo::getUndoSensitive(doc); DocumentUndo::setUndoSensitive(doc, false); // No need to undo in this temporary document - - // Cleanup - g_free(filename_uri); #endif } -- cgit v1.2.3 From 8d4ad16f759312fc28024de1df745888999392a5 Mon Sep 17 00:00:00 2001 From: Ben Scholzen 'DASPRiD Date: Mon, 25 May 2015 16:41:32 +0200 Subject: Fix taper stroke path generation (bzr r14172.1.1) --- src/live_effects/lpe-taperstroke.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/live_effects/lpe-taperstroke.cpp b/src/live_effects/lpe-taperstroke.cpp index 451810d04..1f2c3c79e 100644 --- a/src/live_effects/lpe-taperstroke.cpp +++ b/src/live_effects/lpe-taperstroke.cpp @@ -275,7 +275,7 @@ Geom::PathVector LPETaperStroke::doEffect_path(Geom::PathVector const& path_in) pat_str << "M 1,0 C " << 1 - (double)smoothing << ",0 0,0.5 0,0.5 0,0.5 " << 1 - (double)smoothing << ",1 1,1"; pat_vec = sp_svg_read_pathv(pat_str.str().c_str()); - pwd2.concat(stretch_along(pathv_out[0].toPwSb(), pat_vec[0], -fabs(line_width))); + pwd2.concat(stretch_along(pathv_out[0].toPwSb(), pat_vec[0], fabs(line_width))); throwaway_path = Geom::path_from_piecewise(pwd2, LPE_CONVERSION_TOLERANCE)[0]; real_path.append(throwaway_path); @@ -304,7 +304,7 @@ Geom::PathVector LPETaperStroke::doEffect_path(Geom::PathVector const& path_in) pat_vec = sp_svg_read_pathv(pat_str_1.str().c_str()); pwd2 = Piecewise >(); - pwd2.concat(stretch_along(pathv_out[2].toPwSb(), pat_vec[0], -fabs(line_width))); + pwd2.concat(stretch_along(pathv_out[2].toPwSb(), pat_vec[0], fabs(line_width))); throwaway_path = Geom::path_from_piecewise(pwd2, LPE_CONVERSION_TOLERANCE)[0]; if (!Geom::are_near(real_path.finalPoint(), throwaway_path.initialPoint()) && real_path.size() >= 1) { -- cgit v1.2.3 From 688ccdb666afbbe379a4b67c5765f557e019bdbc Mon Sep 17 00:00:00 2001 From: "Liam P. White" Date: Mon, 25 May 2015 21:18:34 -0400 Subject: never let me try this again (bzr r14176) --- src/helper/geom-pathstroke.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/helper/geom-pathstroke.cpp b/src/helper/geom-pathstroke.cpp index 1df17acf5..930737572 100644 --- a/src/helper/geom-pathstroke.cpp +++ b/src/helper/geom-pathstroke.cpp @@ -420,7 +420,7 @@ void join_inside(join_data jd) else if (cross.size() > 1) { // I am not sure how well this will work -- we pick the join node closest // to the cross point of the paths - Geom::Point original = res.finalPoint()+Geom::rot90(jd.in_tang)*jd.width; + /*Geom::Point original = res.finalPoint()+Geom::rot90(jd.in_tang)*jd.width; Geom::Coord trial = Geom::L2(res.pointAt(cross[0].ta)-original); solution = 0; for (size_t i = 1; i < cross.size(); ++i) { @@ -431,7 +431,7 @@ void join_inside(join_data jd) solution = i; //printf("Found improved solution: %f\n", trial); } - } + }*/ } if (solution != -1) { -- cgit v1.2.3 From 871e15cd5f6972b71649a9acec4bfa6ace63b3f6 Mon Sep 17 00:00:00 2001 From: Tavmjong Bah Date: Tue, 26 May 2015 11:04:59 +0200 Subject: Fix Gtk3 build. (bzr r14177) --- src/extension/internal/pdfinput/pdf-input.cpp | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'src') diff --git a/src/extension/internal/pdfinput/pdf-input.cpp b/src/extension/internal/pdfinput/pdf-input.cpp index 2d0873233..1cd409a0a 100644 --- a/src/extension/internal/pdfinput/pdf-input.cpp +++ b/src/extension/internal/pdfinput/pdf-input.cpp @@ -36,8 +36,14 @@ #include #include #include +#include #include +#if WITH_GTKMM_3_0 +#include +#include +#endif + #include "extension/system.h" #include "extension/input.h" #include "svg-builder.h" -- cgit v1.2.3 From 57a2eea2de55a3849f8d78d107c25ace75fe63f9 Mon Sep 17 00:00:00 2001 From: Marc Jeanmougin Date: Tue, 26 May 2015 22:27:00 +0200 Subject: Fix duplicate order (bzr r14178) --- src/selection-chemistry.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/selection-chemistry.cpp b/src/selection-chemistry.cpp index 16585413e..3999156db 100644 --- a/src/selection-chemistry.cpp +++ b/src/selection-chemistry.cpp @@ -475,7 +475,7 @@ void sp_selection_duplicate(SPDesktop *desktop, bool suppressDone, bool duplicat bool relink_clones = prefs->getBool("/options/relinkclonesonduplicate/value"); const bool fork_livepatheffects = prefs->getBool("/options/forklpeonduplicate/value", true); - for(std::vector::const_reverse_iterator i=reprs.rbegin();i!=reprs.rend();i++){ + for(std::vector::const_iterator i=reprs.begin();i!=reprs.end();i++){ Inkscape::XML::Node *old_repr = *i; Inkscape::XML::Node *parent = old_repr->parent(); Inkscape::XML::Node *copy = old_repr->duplicate(xml_doc); @@ -2577,7 +2577,7 @@ void sp_selection_clone(SPDesktop *desktop) std::vector newsel; - for(std::vector::const_reverse_iterator i=reprs.rbegin();i!=reprs.rend();i++){ + for(std::vector::const_iterator i=reprs.begin();i!=reprs.end();i++){ Inkscape::XML::Node *sel_repr = *i; Inkscape::XML::Node *parent = sel_repr->parent(); -- cgit v1.2.3 From dd0a71ebdfaea505a14acedcc81f7386666be8fe Mon Sep 17 00:00:00 2001 From: Ben Scholzen 'DASPRiD Date: Wed, 27 May 2015 21:42:16 +0200 Subject: Write line_width back to SVG after initially setting it on jointype and taperstroke LPE (bzr r14178.1.1) --- src/live_effects/lpe-jointype.cpp | 1 + src/live_effects/lpe-taperstroke.cpp | 1 + 2 files changed, 2 insertions(+) (limited to 'src') diff --git a/src/live_effects/lpe-jointype.cpp b/src/live_effects/lpe-jointype.cpp index 0111a0f99..c6a08d336 100644 --- a/src/live_effects/lpe-jointype.cpp +++ b/src/live_effects/lpe-jointype.cpp @@ -110,6 +110,7 @@ void LPEJoinType::doOnApply(SPLPEItem const* lpeitem) sp_repr_css_attr_unref (css); line_width.param_set_value(width); + line_width.write_to_SVG(); } } diff --git a/src/live_effects/lpe-taperstroke.cpp b/src/live_effects/lpe-taperstroke.cpp index 1f2c3c79e..5765febbd 100644 --- a/src/live_effects/lpe-taperstroke.cpp +++ b/src/live_effects/lpe-taperstroke.cpp @@ -126,6 +126,7 @@ void LPETaperStroke::doOnApply(SPLPEItem const* lpeitem) sp_repr_css_attr_unref (css); line_width.param_set_value(width); + line_width.write_to_SVG(); } else { printf("WARNING: It only makes sense to apply Taper stroke to paths (not groups).\n"); } -- cgit v1.2.3 From ebcbea982c7b7dce6a5d3641e3a5d3a556b4d69f Mon Sep 17 00:00:00 2001 From: Tavmjong Bah Date: Wed, 27 May 2015 22:02:55 +0200 Subject: Add 'font-variant-xxx' to properties that should not be set on non-text elements. (bzr r14179) --- src/extension/internal/pdfinput/pdf-parser.cpp | 35 +++++++ src/extension/internal/pdfinput/svg-builder.cpp | 132 ++++++++++++++++++++++-- src/style.cpp | 8 ++ 3 files changed, 167 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/src/extension/internal/pdfinput/pdf-parser.cpp b/src/extension/internal/pdfinput/pdf-parser.cpp index 836c34c32..a70b42d41 100644 --- a/src/extension/internal/pdfinput/pdf-parser.cpp +++ b/src/extension/internal/pdfinput/pdf-parser.cpp @@ -409,6 +409,7 @@ PdfParser::~PdfParser() { } } +// Equivalent to Gfx::display() void PdfParser::parse(Object *obj, GBool topLevel) { Object obj2; @@ -1578,11 +1579,13 @@ void PdfParser::opCloseStroke(Object * /*args[]*/, int /*numArgs*/) { void PdfParser::opFill(Object /*args*/[], int /*numArgs*/) { + std::cout << "PdfParser::opFill" << std::endl; if (!state->isCurPt()) { //error(getPos(), const_cast("No path in fill")); return; } if (state->isPath()) { + std::cout << " isPath" << std::endl; if (state->getFillColorSpace()->getMode() == csPattern && !builder->isPatternTypeSupported(state->getFillPattern())) { doPatternFillFallback(gFalse); @@ -1595,6 +1598,7 @@ void PdfParser::opFill(Object /*args*/[], int /*numArgs*/) void PdfParser::opEOFill(Object /*args*/[], int /*numArgs*/) { + std::cout << "PdfParser::opEOFill" << std::endl; if (!state->isCurPt()) { //error(getPos(), const_cast("No path in eofill")); return; @@ -1663,6 +1667,7 @@ void PdfParser::opCloseEOFillStroke(Object /*args*/[], int /*numArgs*/) } void PdfParser::doFillAndStroke(GBool eoFill) { + std::cout << "PdfParser::doFillandStroke()" << std::endl; GBool fillOk = gTrue, strokeOk = gTrue; if (state->getFillColorSpace()->getMode() == csPattern && !builder->isPatternTypeSupported(state->getFillPattern())) { @@ -1673,14 +1678,17 @@ void PdfParser::doFillAndStroke(GBool eoFill) { strokeOk = gFalse; } if (fillOk && strokeOk) { + std::cout << " ... fillOk and StrokeOk" << std::endl; builder->addPath(state, true, true, eoFill); } else { + std::cout << " ... fillOk or StrokeOk not OK" << std::endl; doPatternFillFallback(eoFill); doPatternStrokeFallback(); } } void PdfParser::doPatternFillFallback(GBool eoFill) { + std::cout << "PdfParser::doPatternFillFallback: " << eoFill << std::endl; GfxPattern *pattern; if (!(pattern = state->getFillPattern())) { @@ -1704,6 +1712,7 @@ void PdfParser::doPatternFillFallback(GBool eoFill) { } void PdfParser::doPatternStrokeFallback() { + std::cout << "PdfParser::doPatternStrokeFallback" << std::endl; GfxPattern *pattern; if (!(pattern = state->getStrokePattern())) { @@ -1737,6 +1746,8 @@ void PdfParser::doShadingPatternFillFallback(GfxShadingPattern *sPat, shading = sPat->getShading(); + std::cout << "PdfParser::doShadingPatternFillFallback: " << shading->getType() << std::endl; + // save current graphics state savedPath = state->getPath()->copy(); saveState(); @@ -1823,6 +1834,12 @@ void PdfParser::doShadingPatternFillFallback(GfxShadingPattern *sPat, break; case 6: case 7: + std::cout << " Type 6/7: calling doPatchMeshShFill()" + << " Clip path? " << (clipHistory->getClipPath()?"true":"false") << std::endl; + if (clipHistory->getClipPath()) { + builder->addShadedFill(shading, NULL, clipHistory->getClipPath(), + clipHistory->getClipType() == clipEO ? true : false); + } doPatchMeshShFill(static_cast(shading)); break; } @@ -1856,6 +1873,7 @@ void PdfParser::opShFill(Object args[], int /*numArgs*/) return; } #endif + std::cout << "PdfParser::opShFill: type: " << shading->getType() << std::endl; // save current graphics state if (shading->getType() != 2 && shading->getType() != 3) { @@ -1943,6 +1961,12 @@ void PdfParser::opShFill(Object args[], int /*numArgs*/) break; case 6: case 7: + std::cout << " Type 6/7: calling doPatchMeshShFill()" + << " Clip path? " << (clipHistory->getClipPath()?"true":"false") << std::endl; + if (clipHistory->getClipPath()) { + builder->addShadedFill(shading, matrix, clipHistory->getClipPath(), + clipHistory->getClipType() == clipEO ? true : false); + } doPatchMeshShFill(static_cast(shading)); break; } @@ -2141,6 +2165,10 @@ void PdfParser::gouraudFillTriangle(double x0, double y0, GfxColor *color0, void PdfParser::doPatchMeshShFill(GfxPatchMeshShading *shading) { int start, i; + // if( true ) { + // builder->patchMeshShadedFill( state, shading ); + // } + std::cout << "PdfParser::doPatchMeshShFill: Number of patches: " << shading->getNPatches() << std::endl; if (shading->getNPatches() > 128) { start = 3; } else if (shading->getNPatches() > 64) { @@ -2690,6 +2718,7 @@ void PdfParser::doShowText(GooString *s) { state->textTransformDelta(0, state->getRise(), &riseX, &riseY); p = s->getCString(); len = s->getLength(); + // std::cout << "PDFParser::doShowText: p: " << (p?p:"null") << " " << len << std::endl; while (len > 0) { n = font->getNextChar(p, len, &code, &u, &uLen, /* TODO: This looks like a memory leak for u. */ @@ -2713,6 +2742,12 @@ void PdfParser::doShowText(GooString *s) { originX *= state->getFontSize(); originY *= state->getFontSize(); state->textTransformDelta(originX, originY, &tOriginX, &tOriginY); + // std::cout << " dx: " << dx << " dy: " << dy + // << " originX: " << originX << " originY: " << originY + // << " tOriginX: " << tOriginX << " tOriginY: " << tOriginY + // << " riseX: " << riseX << " riseY: " << riseY + // << " curX: " << state->getCurX() + riseX + // << " curY: " << state->getCurY() + riseY << std::endl; builder->addChar(state, state->getCurX() + riseX, state->getCurY() + riseY, dx, dy, tOriginX, tOriginY, code, n, u, uLen); state->shift(tdx, tdy); diff --git a/src/extension/internal/pdfinput/svg-builder.cpp b/src/extension/internal/pdfinput/svg-builder.cpp index 58e2030d9..f104316a7 100644 --- a/src/extension/internal/pdfinput/svg-builder.cpp +++ b/src/extension/internal/pdfinput/svg-builder.cpp @@ -461,9 +461,17 @@ void SvgBuilder::addPath(GfxState *state, bool fill, bool stroke, bool even_odd) void SvgBuilder::addShadedFill(GfxShading *shading, double *matrix, GfxPath *path, bool even_odd) { + std::cout << "SvgBuilder::addShadedFill: " << shading->getType() << std::endl; Inkscape::XML::Node *path_node = _xml_doc->createElement("svg:path"); gchar *pathtext = svgInterpretPath(path); path_node->setAttribute("d", pathtext); + if ( shading->getType() == 6 || shading->getType() == 7) { + path_node->setAttribute("id", "MyMesh"); + std::cout << " pathtext: " << (pathtext?pathtext:"null") << std::endl; + std::cout << " " << path_node->name() << std::endl; + //g_free(pathtext); + //return; + } g_free(pathtext); // Set style @@ -601,7 +609,9 @@ bool SvgBuilder::isPatternTypeSupported(GfxPattern *pattern) { GfxShading *shading = (static_cast(pattern))->getShading(); int shadingType = shading->getType(); if ( shadingType == 2 || // axial shading - shadingType == 3 ) { // radial shading + shadingType == 3 || // radial shading + shadingType == 6 || // Coons patch + shadingType == 7) { // Tensor patch return true; } return false; @@ -782,6 +792,110 @@ gchar *SvgBuilder::_createGradient(GfxShading *shading, double *matrix, bool for extend1 = radial_shading->getExtend1(); num_funcs = radial_shading->getNFuncs(); func = radial_shading->getFunc(0); + } else if (shading->getType() == 6 || shading->getType() == 7) { // Mesh shading + GfxPatchMeshShading *mesh_shading = static_cast(shading); + std::cout << "SVGBuilder::_createGradient: Number of patches: " + << mesh_shading->getNPatches() << std::endl; + for( unsigned i=0; i < mesh_shading->getNPatches(); ++i ) { + GfxPatch *patch = mesh_shading->getPatch(i); + + std::cout << " Patch: " << i << " " + << "(" << patch->x[0][0] << "," << patch->y[0][0] << ") " + << "(" << patch->x[3][0] << "," << patch->y[3][0] << ") " + << "(" << patch->x[3][3] << "," << patch->y[3][3] << ") " + << "(" << patch->x[0][3] << "," << patch->y[0][3] << ") " + << std::endl; + if (i > 0 ) continue; // We can't handle multiple meshes + std::cout << " Creating mesh" << std::endl; + // Mesh + gradient = _xml_doc->createElement("svg:mesh"); + sp_repr_set_svg_double(gradient, "x", patch->x[0][0]); + sp_repr_set_svg_double(gradient, "y", patch->y[0][0]); + + std::cout << " Creating mesh row" << std::endl; + // Mesh Row + Inkscape::XML::Node *meshrow = _xml_doc->createElement("svg:meshrow"); + + std::cout << " Creating mesh patch" << std::endl; + // Mesh Patch + Inkscape::XML::Node *meshpatch = _xml_doc->createElement("svg:meshpatch"); + + std::cout << " Creating stops" << std::endl; + // Mesh Stops + Inkscape::XML::Node *stop0 = _xml_doc->createElement("svg:stop"); + Inkscape::XML::Node *stop1 = _xml_doc->createElement("svg:stop"); + Inkscape::XML::Node *stop2 = _xml_doc->createElement("svg:stop"); + Inkscape::XML::Node *stop3 = _xml_doc->createElement("svg:stop"); + Inkscape::SVG::PathString pathString0; + Inkscape::SVG::PathString pathString1; + Inkscape::SVG::PathString pathString2; + Inkscape::SVG::PathString pathString3; + pathString0.curveTo(patch->x[1][0]-patch->x[0][0], patch->y[1][0]-patch->y[0][0], + patch->x[2][0]-patch->x[0][0], patch->y[2][0]-patch->y[0][0], + patch->x[3][0]-patch->x[0][0], patch->y[3][0]-patch->y[0][0]); + pathString1.curveTo(patch->x[3][1]-patch->x[3][0], patch->y[3][1]-patch->y[3][0], + patch->x[3][2]-patch->x[3][0], patch->y[3][2]-patch->y[3][0], + patch->x[3][3]-patch->x[3][0], patch->y[3][3]-patch->y[3][0]); + pathString2.curveTo(patch->x[2][3]-patch->x[3][3], patch->y[2][3]-patch->y[3][3], + patch->x[1][3]-patch->x[3][3], patch->y[1][3]-patch->y[3][3], + patch->x[0][3]-patch->x[3][3], patch->y[0][3]-patch->y[3][3]); + pathString3.curveTo(patch->x[0][2]-patch->x[0][3], patch->y[0][2]-patch->y[0][3], + patch->x[0][1]-patch->x[0][3], patch->y[0][1]-patch->y[0][3], + patch->x[0][0]-patch->x[0][3], patch->y[0][0]-patch->y[0][3]); + std::cout << " path0: " << pathString0.c_str() << std::endl; + std::cout << " path1: " << pathString1.c_str() << std::endl; + std::cout << " path2: " << pathString2.c_str() << std::endl; + std::cout << " path3: " << pathString3.c_str() << std::endl; + stop0->setAttribute("path", pathString0.c_str()); + stop1->setAttribute("path", pathString1.c_str()); + stop2->setAttribute("path", pathString2.c_str()); + stop3->setAttribute("path", pathString3.c_str()); + SPCSSAttr *css0 = sp_repr_css_attr_new(); + SPCSSAttr *css1 = sp_repr_css_attr_new(); + SPCSSAttr *css2 = sp_repr_css_attr_new(); + SPCSSAttr *css3 = sp_repr_css_attr_new(); + // See comment in GfxState.h if there is more than one patch. + //gchar *color_text0 = svgConvertGfxRGB(patch->color[0][0]); + //gchar *color_text1 = svgConvertGfxRGB(patch->color[1][0]); + //gchar *color_text2 = svgConvertGfxRGB(patch->color[1][1]); + //gchar *color_text3 = svgConvertGfxRGB(patch->color[0][1]); + //sp_repr_css_set_property(css0, "stop-color", color_text0); + //sp_repr_css_set_property(css1, "stop-color", color_text1); + //sp_repr_css_set_property(css2, "stop-color", color_text2); + //sp_repr_css_set_property(css3, "stop-color", color_text3); + sp_repr_css_set_property(css0, "stop-color", "#ff0000"); + sp_repr_css_set_property(css1, "stop-color", "#0000ff"); + sp_repr_css_set_property(css2, "stop-color", "#00ff00"); + sp_repr_css_set_property(css3, "stop-color", "#ff00ff"); + sp_repr_css_set_property(css0, "stop-opacity", "1"); + sp_repr_css_set_property(css1, "stop-opacity", "1"); + sp_repr_css_set_property(css2, "stop-opacity", "1"); + sp_repr_css_set_property(css3, "stop-opacity", "1"); + sp_repr_css_change(stop0, css0, "style"); + sp_repr_css_change(stop1, css1, "style"); + sp_repr_css_change(stop2, css2, "style"); + sp_repr_css_change(stop3, css3, "style"); + sp_repr_css_attr_unref(css0); + sp_repr_css_attr_unref(css1); + sp_repr_css_attr_unref(css2); + sp_repr_css_attr_unref(css3); + + // Put them into document. + meshpatch->appendChild(stop0); + meshpatch->appendChild(stop1); + meshpatch->appendChild(stop2); + meshpatch->appendChild(stop3); + meshrow->appendChild(meshpatch); + gradient->appendChild(meshrow); + + Inkscape::GC::release(meshpatch); + Inkscape::GC::release(meshrow); + Inkscape::GC::release(stop0); + Inkscape::GC::release(stop1); + Inkscape::GC::release(stop2); + Inkscape::GC::release(stop3); + std::cout << " exit" << std::endl; + } } else { // Unsupported shading type return NULL; } @@ -799,20 +913,21 @@ gchar *SvgBuilder::_createGradient(GfxShading *shading, double *matrix, bool for g_free(transform_text); } - if ( extend0 && extend1 ) { - gradient->setAttribute("spreadMethod", "pad"); - } + // if ( extend0 && extend1 ) { + // gradient->setAttribute("spreadMethod", "pad"); + // } - if ( num_funcs > 1 || !_addGradientStops(gradient, shading, func) ) { - Inkscape::GC::release(gradient); - return NULL; - } + // if ( num_funcs > 1 || !_addGradientStops(gradient, shading, func) ) { + // Inkscape::GC::release(gradient); + // return NULL; + // } Inkscape::XML::Node *defs = _doc->getDefs()->getRepr(); defs->appendChild(gradient); gchar *id = g_strdup(gradient->attribute("id")); Inkscape::GC::release(gradient); + std::cout << " Exit: " << id << std::endl; return id; } @@ -1414,6 +1529,7 @@ void SvgBuilder::addChar(GfxState *state, double x, double y, } gchar *tmp = g_utf16_to_utf8(uu, uLen, NULL, NULL, NULL); + // std::cout << "tmp: " << (tmp?tmp:"null") << std::endl; if ( tmp && *tmp ) { new_glyph.code = tmp; } else { diff --git a/src/style.cpp b/src/style.cpp index b218f4e4d..1668646b6 100644 --- a/src/style.cpp +++ b/src/style.cpp @@ -1711,6 +1711,14 @@ sp_css_attr_unset_text(SPCSSAttr *css) sp_repr_css_set_property(css, "text-decoration-color", NULL); sp_repr_css_set_property(css, "text-decoration-style", NULL); + sp_repr_css_set_property(css, "font-variant-ligatures", NULL); + sp_repr_css_set_property(css, "font-variant-position", NULL); + sp_repr_css_set_property(css, "font-variant-caps", NULL); + sp_repr_css_set_property(css, "font-variant-numeric", NULL); + sp_repr_css_set_property(css, "font-variant-alternates", NULL); + sp_repr_css_set_property(css, "font-variant-east-asian", NULL); + sp_repr_css_set_property(css, "font-feature-settings", NULL); + return css; } -- cgit v1.2.3 From 158e9e378bd4875a27b57883d3f75415fb119e01 Mon Sep 17 00:00:00 2001 From: Tavmjong Bah Date: Wed, 27 May 2015 22:31:43 +0200 Subject: Revert unintended changes. (bzr r14181) --- src/extension/internal/pdfinput/pdf-parser.cpp | 35 ------- src/extension/internal/pdfinput/svg-builder.cpp | 132 ++---------------------- 2 files changed, 8 insertions(+), 159 deletions(-) (limited to 'src') diff --git a/src/extension/internal/pdfinput/pdf-parser.cpp b/src/extension/internal/pdfinput/pdf-parser.cpp index a70b42d41..836c34c32 100644 --- a/src/extension/internal/pdfinput/pdf-parser.cpp +++ b/src/extension/internal/pdfinput/pdf-parser.cpp @@ -409,7 +409,6 @@ PdfParser::~PdfParser() { } } -// Equivalent to Gfx::display() void PdfParser::parse(Object *obj, GBool topLevel) { Object obj2; @@ -1579,13 +1578,11 @@ void PdfParser::opCloseStroke(Object * /*args[]*/, int /*numArgs*/) { void PdfParser::opFill(Object /*args*/[], int /*numArgs*/) { - std::cout << "PdfParser::opFill" << std::endl; if (!state->isCurPt()) { //error(getPos(), const_cast("No path in fill")); return; } if (state->isPath()) { - std::cout << " isPath" << std::endl; if (state->getFillColorSpace()->getMode() == csPattern && !builder->isPatternTypeSupported(state->getFillPattern())) { doPatternFillFallback(gFalse); @@ -1598,7 +1595,6 @@ void PdfParser::opFill(Object /*args*/[], int /*numArgs*/) void PdfParser::opEOFill(Object /*args*/[], int /*numArgs*/) { - std::cout << "PdfParser::opEOFill" << std::endl; if (!state->isCurPt()) { //error(getPos(), const_cast("No path in eofill")); return; @@ -1667,7 +1663,6 @@ void PdfParser::opCloseEOFillStroke(Object /*args*/[], int /*numArgs*/) } void PdfParser::doFillAndStroke(GBool eoFill) { - std::cout << "PdfParser::doFillandStroke()" << std::endl; GBool fillOk = gTrue, strokeOk = gTrue; if (state->getFillColorSpace()->getMode() == csPattern && !builder->isPatternTypeSupported(state->getFillPattern())) { @@ -1678,17 +1673,14 @@ void PdfParser::doFillAndStroke(GBool eoFill) { strokeOk = gFalse; } if (fillOk && strokeOk) { - std::cout << " ... fillOk and StrokeOk" << std::endl; builder->addPath(state, true, true, eoFill); } else { - std::cout << " ... fillOk or StrokeOk not OK" << std::endl; doPatternFillFallback(eoFill); doPatternStrokeFallback(); } } void PdfParser::doPatternFillFallback(GBool eoFill) { - std::cout << "PdfParser::doPatternFillFallback: " << eoFill << std::endl; GfxPattern *pattern; if (!(pattern = state->getFillPattern())) { @@ -1712,7 +1704,6 @@ void PdfParser::doPatternFillFallback(GBool eoFill) { } void PdfParser::doPatternStrokeFallback() { - std::cout << "PdfParser::doPatternStrokeFallback" << std::endl; GfxPattern *pattern; if (!(pattern = state->getStrokePattern())) { @@ -1746,8 +1737,6 @@ void PdfParser::doShadingPatternFillFallback(GfxShadingPattern *sPat, shading = sPat->getShading(); - std::cout << "PdfParser::doShadingPatternFillFallback: " << shading->getType() << std::endl; - // save current graphics state savedPath = state->getPath()->copy(); saveState(); @@ -1834,12 +1823,6 @@ void PdfParser::doShadingPatternFillFallback(GfxShadingPattern *sPat, break; case 6: case 7: - std::cout << " Type 6/7: calling doPatchMeshShFill()" - << " Clip path? " << (clipHistory->getClipPath()?"true":"false") << std::endl; - if (clipHistory->getClipPath()) { - builder->addShadedFill(shading, NULL, clipHistory->getClipPath(), - clipHistory->getClipType() == clipEO ? true : false); - } doPatchMeshShFill(static_cast(shading)); break; } @@ -1873,7 +1856,6 @@ void PdfParser::opShFill(Object args[], int /*numArgs*/) return; } #endif - std::cout << "PdfParser::opShFill: type: " << shading->getType() << std::endl; // save current graphics state if (shading->getType() != 2 && shading->getType() != 3) { @@ -1961,12 +1943,6 @@ void PdfParser::opShFill(Object args[], int /*numArgs*/) break; case 6: case 7: - std::cout << " Type 6/7: calling doPatchMeshShFill()" - << " Clip path? " << (clipHistory->getClipPath()?"true":"false") << std::endl; - if (clipHistory->getClipPath()) { - builder->addShadedFill(shading, matrix, clipHistory->getClipPath(), - clipHistory->getClipType() == clipEO ? true : false); - } doPatchMeshShFill(static_cast(shading)); break; } @@ -2165,10 +2141,6 @@ void PdfParser::gouraudFillTriangle(double x0, double y0, GfxColor *color0, void PdfParser::doPatchMeshShFill(GfxPatchMeshShading *shading) { int start, i; - // if( true ) { - // builder->patchMeshShadedFill( state, shading ); - // } - std::cout << "PdfParser::doPatchMeshShFill: Number of patches: " << shading->getNPatches() << std::endl; if (shading->getNPatches() > 128) { start = 3; } else if (shading->getNPatches() > 64) { @@ -2718,7 +2690,6 @@ void PdfParser::doShowText(GooString *s) { state->textTransformDelta(0, state->getRise(), &riseX, &riseY); p = s->getCString(); len = s->getLength(); - // std::cout << "PDFParser::doShowText: p: " << (p?p:"null") << " " << len << std::endl; while (len > 0) { n = font->getNextChar(p, len, &code, &u, &uLen, /* TODO: This looks like a memory leak for u. */ @@ -2742,12 +2713,6 @@ void PdfParser::doShowText(GooString *s) { originX *= state->getFontSize(); originY *= state->getFontSize(); state->textTransformDelta(originX, originY, &tOriginX, &tOriginY); - // std::cout << " dx: " << dx << " dy: " << dy - // << " originX: " << originX << " originY: " << originY - // << " tOriginX: " << tOriginX << " tOriginY: " << tOriginY - // << " riseX: " << riseX << " riseY: " << riseY - // << " curX: " << state->getCurX() + riseX - // << " curY: " << state->getCurY() + riseY << std::endl; builder->addChar(state, state->getCurX() + riseX, state->getCurY() + riseY, dx, dy, tOriginX, tOriginY, code, n, u, uLen); state->shift(tdx, tdy); diff --git a/src/extension/internal/pdfinput/svg-builder.cpp b/src/extension/internal/pdfinput/svg-builder.cpp index f104316a7..58e2030d9 100644 --- a/src/extension/internal/pdfinput/svg-builder.cpp +++ b/src/extension/internal/pdfinput/svg-builder.cpp @@ -461,17 +461,9 @@ void SvgBuilder::addPath(GfxState *state, bool fill, bool stroke, bool even_odd) void SvgBuilder::addShadedFill(GfxShading *shading, double *matrix, GfxPath *path, bool even_odd) { - std::cout << "SvgBuilder::addShadedFill: " << shading->getType() << std::endl; Inkscape::XML::Node *path_node = _xml_doc->createElement("svg:path"); gchar *pathtext = svgInterpretPath(path); path_node->setAttribute("d", pathtext); - if ( shading->getType() == 6 || shading->getType() == 7) { - path_node->setAttribute("id", "MyMesh"); - std::cout << " pathtext: " << (pathtext?pathtext:"null") << std::endl; - std::cout << " " << path_node->name() << std::endl; - //g_free(pathtext); - //return; - } g_free(pathtext); // Set style @@ -609,9 +601,7 @@ bool SvgBuilder::isPatternTypeSupported(GfxPattern *pattern) { GfxShading *shading = (static_cast(pattern))->getShading(); int shadingType = shading->getType(); if ( shadingType == 2 || // axial shading - shadingType == 3 || // radial shading - shadingType == 6 || // Coons patch - shadingType == 7) { // Tensor patch + shadingType == 3 ) { // radial shading return true; } return false; @@ -792,110 +782,6 @@ gchar *SvgBuilder::_createGradient(GfxShading *shading, double *matrix, bool for extend1 = radial_shading->getExtend1(); num_funcs = radial_shading->getNFuncs(); func = radial_shading->getFunc(0); - } else if (shading->getType() == 6 || shading->getType() == 7) { // Mesh shading - GfxPatchMeshShading *mesh_shading = static_cast(shading); - std::cout << "SVGBuilder::_createGradient: Number of patches: " - << mesh_shading->getNPatches() << std::endl; - for( unsigned i=0; i < mesh_shading->getNPatches(); ++i ) { - GfxPatch *patch = mesh_shading->getPatch(i); - - std::cout << " Patch: " << i << " " - << "(" << patch->x[0][0] << "," << patch->y[0][0] << ") " - << "(" << patch->x[3][0] << "," << patch->y[3][0] << ") " - << "(" << patch->x[3][3] << "," << patch->y[3][3] << ") " - << "(" << patch->x[0][3] << "," << patch->y[0][3] << ") " - << std::endl; - if (i > 0 ) continue; // We can't handle multiple meshes - std::cout << " Creating mesh" << std::endl; - // Mesh - gradient = _xml_doc->createElement("svg:mesh"); - sp_repr_set_svg_double(gradient, "x", patch->x[0][0]); - sp_repr_set_svg_double(gradient, "y", patch->y[0][0]); - - std::cout << " Creating mesh row" << std::endl; - // Mesh Row - Inkscape::XML::Node *meshrow = _xml_doc->createElement("svg:meshrow"); - - std::cout << " Creating mesh patch" << std::endl; - // Mesh Patch - Inkscape::XML::Node *meshpatch = _xml_doc->createElement("svg:meshpatch"); - - std::cout << " Creating stops" << std::endl; - // Mesh Stops - Inkscape::XML::Node *stop0 = _xml_doc->createElement("svg:stop"); - Inkscape::XML::Node *stop1 = _xml_doc->createElement("svg:stop"); - Inkscape::XML::Node *stop2 = _xml_doc->createElement("svg:stop"); - Inkscape::XML::Node *stop3 = _xml_doc->createElement("svg:stop"); - Inkscape::SVG::PathString pathString0; - Inkscape::SVG::PathString pathString1; - Inkscape::SVG::PathString pathString2; - Inkscape::SVG::PathString pathString3; - pathString0.curveTo(patch->x[1][0]-patch->x[0][0], patch->y[1][0]-patch->y[0][0], - patch->x[2][0]-patch->x[0][0], patch->y[2][0]-patch->y[0][0], - patch->x[3][0]-patch->x[0][0], patch->y[3][0]-patch->y[0][0]); - pathString1.curveTo(patch->x[3][1]-patch->x[3][0], patch->y[3][1]-patch->y[3][0], - patch->x[3][2]-patch->x[3][0], patch->y[3][2]-patch->y[3][0], - patch->x[3][3]-patch->x[3][0], patch->y[3][3]-patch->y[3][0]); - pathString2.curveTo(patch->x[2][3]-patch->x[3][3], patch->y[2][3]-patch->y[3][3], - patch->x[1][3]-patch->x[3][3], patch->y[1][3]-patch->y[3][3], - patch->x[0][3]-patch->x[3][3], patch->y[0][3]-patch->y[3][3]); - pathString3.curveTo(patch->x[0][2]-patch->x[0][3], patch->y[0][2]-patch->y[0][3], - patch->x[0][1]-patch->x[0][3], patch->y[0][1]-patch->y[0][3], - patch->x[0][0]-patch->x[0][3], patch->y[0][0]-patch->y[0][3]); - std::cout << " path0: " << pathString0.c_str() << std::endl; - std::cout << " path1: " << pathString1.c_str() << std::endl; - std::cout << " path2: " << pathString2.c_str() << std::endl; - std::cout << " path3: " << pathString3.c_str() << std::endl; - stop0->setAttribute("path", pathString0.c_str()); - stop1->setAttribute("path", pathString1.c_str()); - stop2->setAttribute("path", pathString2.c_str()); - stop3->setAttribute("path", pathString3.c_str()); - SPCSSAttr *css0 = sp_repr_css_attr_new(); - SPCSSAttr *css1 = sp_repr_css_attr_new(); - SPCSSAttr *css2 = sp_repr_css_attr_new(); - SPCSSAttr *css3 = sp_repr_css_attr_new(); - // See comment in GfxState.h if there is more than one patch. - //gchar *color_text0 = svgConvertGfxRGB(patch->color[0][0]); - //gchar *color_text1 = svgConvertGfxRGB(patch->color[1][0]); - //gchar *color_text2 = svgConvertGfxRGB(patch->color[1][1]); - //gchar *color_text3 = svgConvertGfxRGB(patch->color[0][1]); - //sp_repr_css_set_property(css0, "stop-color", color_text0); - //sp_repr_css_set_property(css1, "stop-color", color_text1); - //sp_repr_css_set_property(css2, "stop-color", color_text2); - //sp_repr_css_set_property(css3, "stop-color", color_text3); - sp_repr_css_set_property(css0, "stop-color", "#ff0000"); - sp_repr_css_set_property(css1, "stop-color", "#0000ff"); - sp_repr_css_set_property(css2, "stop-color", "#00ff00"); - sp_repr_css_set_property(css3, "stop-color", "#ff00ff"); - sp_repr_css_set_property(css0, "stop-opacity", "1"); - sp_repr_css_set_property(css1, "stop-opacity", "1"); - sp_repr_css_set_property(css2, "stop-opacity", "1"); - sp_repr_css_set_property(css3, "stop-opacity", "1"); - sp_repr_css_change(stop0, css0, "style"); - sp_repr_css_change(stop1, css1, "style"); - sp_repr_css_change(stop2, css2, "style"); - sp_repr_css_change(stop3, css3, "style"); - sp_repr_css_attr_unref(css0); - sp_repr_css_attr_unref(css1); - sp_repr_css_attr_unref(css2); - sp_repr_css_attr_unref(css3); - - // Put them into document. - meshpatch->appendChild(stop0); - meshpatch->appendChild(stop1); - meshpatch->appendChild(stop2); - meshpatch->appendChild(stop3); - meshrow->appendChild(meshpatch); - gradient->appendChild(meshrow); - - Inkscape::GC::release(meshpatch); - Inkscape::GC::release(meshrow); - Inkscape::GC::release(stop0); - Inkscape::GC::release(stop1); - Inkscape::GC::release(stop2); - Inkscape::GC::release(stop3); - std::cout << " exit" << std::endl; - } } else { // Unsupported shading type return NULL; } @@ -913,21 +799,20 @@ gchar *SvgBuilder::_createGradient(GfxShading *shading, double *matrix, bool for g_free(transform_text); } - // if ( extend0 && extend1 ) { - // gradient->setAttribute("spreadMethod", "pad"); - // } + if ( extend0 && extend1 ) { + gradient->setAttribute("spreadMethod", "pad"); + } - // if ( num_funcs > 1 || !_addGradientStops(gradient, shading, func) ) { - // Inkscape::GC::release(gradient); - // return NULL; - // } + if ( num_funcs > 1 || !_addGradientStops(gradient, shading, func) ) { + Inkscape::GC::release(gradient); + return NULL; + } Inkscape::XML::Node *defs = _doc->getDefs()->getRepr(); defs->appendChild(gradient); gchar *id = g_strdup(gradient->attribute("id")); Inkscape::GC::release(gradient); - std::cout << " Exit: " << id << std::endl; return id; } @@ -1529,7 +1414,6 @@ void SvgBuilder::addChar(GfxState *state, double x, double y, } gchar *tmp = g_utf16_to_utf8(uu, uLen, NULL, NULL, NULL); - // std::cout << "tmp: " << (tmp?tmp:"null") << std::endl; if ( tmp && *tmp ) { new_glyph.code = tmp; } else { -- cgit v1.2.3 From 7743322d3c57f1d9c46b2705e5d68fc958d631f8 Mon Sep 17 00:00:00 2001 From: mathog <> Date: Thu, 28 May 2015 13:42:38 -0700 Subject: clean up a couple of clang warnings (bzr r14183) --- src/libuemf/upmf.c | 6 +++--- src/libuemf/uwmf_endian.c | 9 +++++---- 2 files changed, 8 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/libuemf/upmf.c b/src/libuemf/upmf.c index 2ba818fa4..fe929e443 100644 --- a/src/libuemf/upmf.c +++ b/src/libuemf/upmf.c @@ -21,8 +21,8 @@ /* File: upmf.c -Version: 0.0.10 -Date: 27-APR-2015 +Version: 0.0.11 +Date: 28-MAY-2015 Author: David Mathog, Biology Division, Caltech email: mathog@caltech.edu Copyright: 2015 David Mathog and California Institute of Technology (Caltech) @@ -3077,7 +3077,7 @@ U_PSEUDO_OBJ *U_PMF_POINTR_set(uint32_t Elements, const U_PMF_POINTF *Coords){ poi = U_PMF_4NUM_set(Elements); po = U_PO_append(po, poi->Data, poi->Used); U_PO_free(&poi); - if(po)goto end; + if(!po)goto end; for(Xf = Yf = 0.0 ;Elements; Elements--, Coords++){ Xf = U_ROUND(Coords->X) - Xf; diff --git a/src/libuemf/uwmf_endian.c b/src/libuemf/uwmf_endian.c index de0b3ef87..7a047c2a5 100644 --- a/src/libuemf/uwmf_endian.c +++ b/src/libuemf/uwmf_endian.c @@ -6,8 +6,8 @@ /* File: uwmf_endian.c -Version: 0.1.4 -Date: 28-APR-2015 +Version: 0.1.5 +Date: 28-MAY-2015 Author: David Mathog, Biology Division, Caltech email: mathog@caltech.edu Copyright: 2015 David Mathog and California Institute of Technology (Caltech) @@ -1480,7 +1480,8 @@ int U_wmf_endian(char *contents, size_t length, int torev, int onerec){ uint32_t OK, Size16; uint8_t iType; char *record; - int recnum, offset; + int recnum; + int offset=0; record = contents; if(!onerec){ @@ -1759,10 +1760,10 @@ int U_wmf_endian(char *contents, size_t length, int torev, int onerec){ case U_WMR_CREATEREGION: U_WMRCREATEREGION_swap(record, torev); break; default: U_WMRNOTIMPLEMENTED_swap(record, torev); break; } //end of switch + if(onerec)break; record += 2*Size16; offset += 2*Size16; recnum++; - if(onerec)break; } //end of while return(1); } -- cgit v1.2.3 From 74b8a70899955af0a132a1eb38bbe16b40110c73 Mon Sep 17 00:00:00 2001 From: Tavmjong Bah Date: Fri, 29 May 2015 13:15:32 +0200 Subject: Use more fine-grain fallbacks for Poppler/Cairo PDF imports. (bzr r14184) --- src/extension/internal/pdfinput/pdf-input.cpp | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'src') diff --git a/src/extension/internal/pdfinput/pdf-input.cpp b/src/extension/internal/pdfinput/pdf-input.cpp index 1cd409a0a..363061734 100644 --- a/src/extension/internal/pdfinput/pdf-input.cpp +++ b/src/extension/internal/pdfinput/pdf-input.cpp @@ -881,6 +881,13 @@ PdfInput::open(::Inkscape::Extension::Input * /*mod*/, const gchar * uri) { Glib::ustring output; cairo_surface_t* surface = cairo_svg_surface_create_for_stream(Inkscape::Extension::Internal::_write_ustring_cb, &output, width, height); + + // This magical function results in more fine-grain fallbacks. In particular, a mesh + // gradient won't necessarily result in the whole PDF being rasterized. Of course, SVG + // 1.2 never made it as a standard, but hey, we'll take what we can get. This trick was + // found by examining the 'pdftocairo' code. + cairo_svg_surface_restrict_to_version( surface, CAIRO_SVG_VERSION_1_2 ); + cairo_t* cr = cairo_create(surface); poppler_page_render_for_printing(page, cr); -- cgit v1.2.3 From ea3737623c19fa92b97ec6c3e228ea0f8db7a03b Mon Sep 17 00:00:00 2001 From: Ben Scholzen 'DASPRiD Date: Fri, 29 May 2015 19:21:52 +0200 Subject: Import all defs from clipboard or imported files Fixed bugs: - https://launchpad.net/bugs/1460057 (bzr r14185) --- src/document.cpp | 9 ++++++++- src/document.h | 1 + src/xml/repr-util.cpp | 28 ++++++++++++++++++++++++++++ src/xml/repr.h | 5 +++++ 4 files changed, 42 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/document.cpp b/src/document.cpp index 741e7c812..ebf5d312f 100644 --- a/src/document.cpp +++ b/src/document.cpp @@ -1634,11 +1634,18 @@ void SPDocument::setModifiedSinceSave(bool modified) { void SPDocument::importDefs(SPDocument *source) { Inkscape::XML::Node *root = source->getReprRoot(); - Inkscape::XML::Node *defs = sp_repr_lookup_name(root, "svg:defs", 1); Inkscape::XML::Node *target_defs = this->getDefs()->getRepr(); + std::vector defsNodes = sp_repr_lookup_name_many(root, "svg:defs"); prevent_id_clashes(source, this); + for (std::vector::iterator defs = defsNodes.begin(); defs != defsNodes.end(); ++defs) { + importDefsNode(source, const_cast(*defs), target_defs); + } +} + +void SPDocument::importDefsNode(SPDocument *source, Inkscape::XML::Node *defs, Inkscape::XML::Node *target_defs) +{ int stagger=0; /* Note, "clipboard" throughout the comments means "the document that is either the clipboard diff --git a/src/document.h b/src/document.h index 16b9bb28d..dd1e295a2 100644 --- a/src/document.h +++ b/src/document.h @@ -275,6 +275,7 @@ public: private: void do_change_uri(char const *const filename, bool const rebase); void setupViewport(SPItemCtx *ctx); + void importDefsNode(SPDocument *source, Inkscape::XML::Node *defs, Inkscape::XML::Node *target_defs); }; /* diff --git a/src/xml/repr-util.cpp b/src/xml/repr-util.cpp index 4cbe930a1..f7a437163 100644 --- a/src/xml/repr-util.cpp +++ b/src/xml/repr-util.cpp @@ -371,6 +371,34 @@ Inkscape::XML::Node *sp_repr_lookup_name( Inkscape::XML::Node *repr, gchar const return const_cast(found); } +std::vector sp_repr_lookup_name_many( Inkscape::XML::Node const *repr, gchar const *name, gint maxdepth ) +{ + std::vector nodes; + std::vector found; + g_return_val_if_fail(repr != NULL, nodes); + g_return_val_if_fail(name != NULL, nodes); + + GQuark const quark = g_quark_from_string(name); + + if ( (GQuark)repr->code() == quark ) { + nodes.push_back(repr); + } + + if ( maxdepth != 0 ) { + // maxdepth == -1 means unlimited + if ( maxdepth == -1 ) { + maxdepth = 0; + } + + for (Inkscape::XML::Node const *child = repr->firstChild() ; child; child = child->next() ) { + found = sp_repr_lookup_name_many( child, name, maxdepth - 1); + nodes.insert(nodes.end(), found.begin(), found.end()); + } + } + + return nodes; +} + /** * Determine if the node is a 'title', 'desc' or 'metadata' element. */ diff --git a/src/xml/repr.h b/src/xml/repr.h index 17763195a..e84b89813 100644 --- a/src/xml/repr.h +++ b/src/xml/repr.h @@ -14,6 +14,7 @@ #ifndef SEEN_SP_REPR_H #define SEEN_SP_REPR_H +#include #include #include "xml/node.h" @@ -144,6 +145,10 @@ Inkscape::XML::Node *sp_repr_lookup_name(Inkscape::XML::Node *repr, Inkscape::XML::Node const *sp_repr_lookup_name(Inkscape::XML::Node const *repr, char const *name, int maxdepth = -1); + +std::vector sp_repr_lookup_name_many(Inkscape::XML::Node const *repr, + char const *name, + int maxdepth = -1); Inkscape::XML::Node *sp_repr_lookup_child(Inkscape::XML::Node *repr, char const *key, -- cgit v1.2.3 From 40093a750e66acc37ade5dad2a6fca96ae3ebb37 Mon Sep 17 00:00:00 2001 From: Jabier Arraiza Cenoz Date: Fri, 29 May 2015 20:44:00 +0200 Subject: Alex Valavanis fix for a compiling bug (bzr r14186) --- src/display/sp-canvas.h | 1 + 1 file changed, 1 insertion(+) (limited to 'src') diff --git a/src/display/sp-canvas.h b/src/display/sp-canvas.h index 48c3de2fc..65b06ade8 100644 --- a/src/display/sp-canvas.h +++ b/src/display/sp-canvas.h @@ -23,6 +23,7 @@ #endif #include +#include #include #include <2geom/affine.h> #include <2geom/rect.h> -- cgit v1.2.3 From f01a7689716bf654bf10638e6e141597c88db8cf Mon Sep 17 00:00:00 2001 From: Jabier Arraiza Cenoz Date: Fri, 29 May 2015 21:37:41 +0200 Subject: Fix a bug in BSpline whith pencil mode and handles tolerance (bzr r14187) --- src/ui/tools/pencil-tool.cpp | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/ui/tools/pencil-tool.cpp b/src/ui/tools/pencil-tool.cpp index ba103fa8e..16c26546f 100644 --- a/src/ui/tools/pencil-tool.cpp +++ b/src/ui/tools/pencil-tool.cpp @@ -53,6 +53,7 @@ static Geom::Point pencil_drag_origin_w(0, 0); static bool pencil_within_tolerance = false; static bool in_svg_plane(Geom::Point const &p) { return Geom::LInfty(p) < 1e18; } +const double HANDLE_CUBIC_GAP = 0.01; const std::string& PencilTool::getPrefsPath() { return PencilTool::prefsPath; @@ -660,10 +661,10 @@ void PencilTool::_interpolate() { for (int c = 0; c < n_segs; c++) { // if we are in BSpline we modify the trace to create adhoc nodes if(mode == 2){ - Geom::Point point_at1 = b[4*c+0] + (1./3)*(b[4*c+3] - b[4*c+0]); - point_at1 = Geom::Point(point_at1[X] + 0.0001,point_at1[Y] + 0.0001); - Geom::Point point_at2 = b[4*c+3] + (1./3)*(b[4*c+0] - b[4*c+3]); - point_at2 = Geom::Point(point_at2[X] + 0.0001,point_at2[Y] + 0.0001); + Geom::Point point_at1 = b[4 * c + 0] + (1./3) * (b[4 * c + 3] - b[4 * c + 0]); + point_at1 = Geom::Point(point_at1[X] + HANDLE_CUBIC_GAP, point_at1[Y] + HANDLE_CUBIC_GAP); + Geom::Point point_at2 = b[4 * c + 3] + (1./3) * (b[4 * c + 0] - b[4 * c + 3]); + point_at2 = Geom::Point(point_at2[X] + HANDLE_CUBIC_GAP, point_at2[Y] + HANDLE_CUBIC_GAP); this->green_curve->curveto(point_at1,point_at2,b[4*c+3]); }else{ this->green_curve->curveto(b[4 * c + 1], b[4 * c + 2], b[4 * c + 3]); @@ -808,9 +809,9 @@ void PencilTool::_fitAndSplit() { guint mode = prefs->getInt("/tools/freehand/pencil/freehand-mode", 0); if(mode == 2){ Geom::Point point_at1 = b[0] + (1./3)*(b[3] - b[0]); - point_at1 = Geom::Point(point_at1[X] + 0.0001,point_at1[Y] + 0.0001); + point_at1 = Geom::Point(point_at1[X] + HANDLE_CUBIC_GAP, point_at1[Y] + HANDLE_CUBIC_GAP); Geom::Point point_at2 = b[3] + (1./3)*(b[0] - b[3]); - point_at2 = Geom::Point(point_at2[X] + 0.0001,point_at2[Y] + 0.0001); + point_at2 = Geom::Point(point_at2[X] + HANDLE_CUBIC_GAP, point_at2[Y] + HANDLE_CUBIC_GAP); this->red_curve->curveto(point_at1,point_at2,b[3]); }else{ this->red_curve->curveto(b[1], b[2], b[3]); -- cgit v1.2.3 From c4c42ebb66d55ca883ed93b2a72d26cd8a759a6d Mon Sep 17 00:00:00 2001 From: Diederik van Lierop Date: Sat, 30 May 2015 20:27:42 +0200 Subject: Snapping in node tool now also works when: - when double clicking to insert a node on a path - when dragging a part of the path to deform it Fixed bugs: - https://launchpad.net/bugs/1448859 (bzr r14189) --- src/snap-enums.h | 2 +- src/snap.cpp | 36 +++++++++-- src/snap.h | 11 +++- src/ui/tool/control-point.cpp | 15 +++-- src/ui/tool/control-point.h | 6 +- src/ui/tool/curve-drag-point.cpp | 20 ++++--- src/ui/tool/curve-drag-point.h | 6 +- src/ui/tool/multi-path-manipulator.cpp | 8 +++ src/ui/tool/multi-path-manipulator.h | 1 + src/ui/tool/path-manipulator.cpp | 36 +++++++++-- src/ui/tool/path-manipulator.h | 6 +- src/ui/tool/selector.cpp | 4 ++ src/ui/tool/selector.h | 1 + src/ui/tools/node-tool.cpp | 106 ++++++++++++++++++++++++--------- src/ui/tools/node-tool.h | 3 + 15 files changed, 204 insertions(+), 57 deletions(-) (limited to 'src') diff --git a/src/snap-enums.h b/src/snap-enums.h index c6ca97402..ab82aaf37 100644 --- a/src/snap-enums.h +++ b/src/snap-enums.h @@ -66,7 +66,7 @@ enum SnapTargetType { SNAPTARGET_NODE_SMOOTH, SNAPTARGET_NODE_CUSP, SNAPTARGET_LINE_MIDPOINT, - SNAPTARGET_PATH, + SNAPTARGET_PATH, // If path targets are added here, then also add them to the list in findBestSnap() SNAPTARGET_PATH_PERPENDICULAR, SNAPTARGET_PATH_TANGENTIAL, SNAPTARGET_PATH_INTERSECTION, diff --git a/src/snap.cpp b/src/snap.cpp index 30441ca0b..5a308777c 100644 --- a/src/snap.cpp +++ b/src/snap.cpp @@ -121,7 +121,8 @@ void SnapManager::freeSnapReturnByRef(Geom::Point &p, } Inkscape::SnappedPoint SnapManager::freeSnap(Inkscape::SnapCandidatePoint const &p, - Geom::OptRect const &bbox_to_snap) const + Geom::OptRect const &bbox_to_snap, + bool to_paths_only) const { if (!someSnapperMightSnap()) { return Inkscape::SnappedPoint(p, Inkscape::SNAPTARGET_UNDEFINED, Geom::infinity(), 0, false, false, false); @@ -134,16 +135,16 @@ Inkscape::SnappedPoint SnapManager::freeSnap(Inkscape::SnapCandidatePoint const (*i)->freeSnap(isr, p, bbox_to_snap, &_items_to_ignore, _unselected_nodes); } - return findBestSnap(p, isr, false); + return findBestSnap(p, isr, false, false, to_paths_only); } -void SnapManager::preSnap(Inkscape::SnapCandidatePoint const &p) +void SnapManager::preSnap(Inkscape::SnapCandidatePoint const &p, bool to_paths_only) { // setup() must have been called before calling this method! if (_snapindicator) { _snapindicator = false; // prevent other methods from drawing a snap indicator; we want to control this here - Inkscape::SnappedPoint s = freeSnap(p); + Inkscape::SnappedPoint s = freeSnap(p, Geom::OptRect(), to_paths_only); g_assert(_desktop != NULL); if (s.getSnapped()) { _desktop->snapindicator->set_new_snaptarget(s, true); @@ -855,7 +856,8 @@ Inkscape::SnappedPoint SnapManager::constrainedSnapRotate(std::vector::iterator i = sp_list.begin(); + + while (i != sp_list.end()) { + Inkscape::SnapTargetType t = (*i).getTarget(); + if (t == Inkscape::SNAPTARGET_LINE_MIDPOINT || + t == Inkscape::SNAPTARGET_PATH || + t == Inkscape::SNAPTARGET_PATH_PERPENDICULAR || + t == Inkscape::SNAPTARGET_PATH_TANGENTIAL || + t == Inkscape::SNAPTARGET_PATH_INTERSECTION || + t == Inkscape::SNAPTARGET_PATH_GUIDE_INTERSECTION || + t == Inkscape::SNAPTARGET_PATH_CLIP || + t == Inkscape::SNAPTARGET_PATH_MASK || + t == Inkscape::SNAPTARGET_ELLIPSE_QUADRANT_POINT) { + ++i; + } else { + i = sp_list.erase(i); + } + } + } + // now let's see which snapped point gets a thumbs up Inkscape::SnappedPoint bestSnappedPoint(p.getPoint()); // std::cout << "Finding the best snap..." << std::endl; diff --git a/src/snap.h b/src/snap.h index 49bdbfa7c..944c49b3e 100644 --- a/src/snap.h +++ b/src/snap.h @@ -192,12 +192,15 @@ public: * * @param p Source point to be snapped. * @param bbox_to_snap Bounding box hulling the set of points, all from the same selection and having the same transformation. + * @param to_path_only Only snap to points on a path, such as path intersections with itself or with grids/guides. This is used for + * example when adding nodes to a path. We will not snap for example to grid intersections * @return An instance of the SnappedPoint class, which holds data on the snap source, snap target, and various metrics. */ Inkscape::SnappedPoint freeSnap(Inkscape::SnapCandidatePoint const &p, - Geom::OptRect const &bbox_to_snap = Geom::OptRect() ) const; + Geom::OptRect const &bbox_to_snap = Geom::OptRect(), + bool to_path_only = false) const; - void preSnap(Inkscape::SnapCandidatePoint const &p); + void preSnap(Inkscape::SnapCandidatePoint const &p, bool to_path_only = false); /** * Snap to the closest multiple of a grid pitch. @@ -473,9 +476,11 @@ public: * @param isr A structure holding all snap targets that have been found so far. * @param constrained True if the snap is constrained, e.g. for stretching or for purely horizontal translation. * @param allowOffScreen If true, then snapping to points which are off the screen is allowed (needed for example when pasting to the grid). + * @param to_path_only Only snap to points on a path, such as path intersections with itself or with grids/guides. This is used for + * example when adding nodes to a path. We will not snap for example to grid intersections * @return An instance of the SnappedPoint class, which holds data on the snap source, snap target, and various metrics. */ - Inkscape::SnappedPoint findBestSnap(Inkscape::SnapCandidatePoint const &p, IntermSnapResults const &isr, bool constrained, bool allowOffScreen = false) const; + Inkscape::SnappedPoint findBestSnap(Inkscape::SnapCandidatePoint const &p, IntermSnapResults const &isr, bool constrained, bool allowOffScreen = false, bool to_paths_only = false) const; /** * Mark the location of the snap source (not the snap target!) on the canvas by drawing a symbol. diff --git a/src/ui/tool/control-point.cpp b/src/ui/tool/control-point.cpp index bcf5c9fce..636595016 100644 --- a/src/ui/tool/control-point.cpp +++ b/src/ui/tool/control-point.cpp @@ -71,7 +71,8 @@ ControlPoint::ControlPoint(SPDesktop *d, Geom::Point const &initial_pos, SPAncho _cset(cset), _state(STATE_NORMAL), _position(initial_pos), - _lurking(false) + _lurking(false), + _double_clicked(false) { _canvas_item = sp_canvas_item_new( group ? group : _desktop->getControls(), SP_TYPE_CTRL, @@ -80,6 +81,7 @@ ControlPoint::ControlPoint(SPDesktop *d, Geom::Point const &initial_pos, SPAncho "filled", TRUE, "fill_color", _cset.normal.fill, "stroked", TRUE, "stroke_color", _cset.normal.stroke, "mode", SP_CTRL_MODE_XOR, NULL); + _commonInit(); } @@ -91,7 +93,8 @@ ControlPoint::ControlPoint(SPDesktop *d, Geom::Point const &initial_pos, SPAncho _cset(cset), _state(STATE_NORMAL), _position(initial_pos), - _lurking(false) + _lurking(false), + _double_clicked(false) { _canvas_item = ControlManager::getManager().createControl(group ? group : _desktop->getControls(), type); g_object_set(_canvas_item, @@ -245,7 +248,8 @@ bool ControlPoint::_eventHandler(Inkscape::UI::Tools::ToolBase *event_context, G static Geom::Point pointer_offset; // number of last doubleclicked button static unsigned next_release_doubleclick = 0; - + _double_clicked = false; + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); int drag_tolerance = prefs->getIntLimited("/options/dragtolerance/value", 0, 0, 100); GdkEventMotion em; @@ -278,6 +282,7 @@ bool ControlPoint::_eventHandler(Inkscape::UI::Tools::ToolBase *event_context, G Ca = _desktop->canvas; em = event->motion; combine_motion_events(Ca, em, 0); + if (_event_grab && ! event_context->space_panning) { _desktop->snapindicator->remove_snaptarget(); bool transferred = false; @@ -298,6 +303,7 @@ bool ControlPoint::_eventHandler(Inkscape::UI::Tools::ToolBase *event_context, G _drag_initiated = true; } } + if (!transferred) { // dragging in progress Geom::Point new_pos = _desktop->w2d(event_point(event->motion)) + pointer_offset; @@ -305,7 +311,7 @@ bool ControlPoint::_eventHandler(Inkscape::UI::Tools::ToolBase *event_context, G dragged(new_pos, &em); move(new_pos); _updateDragTip(&em); // update dragging tip after moving to new position - + _desktop->scroll_to_point(new_pos); _desktop->set_coordinate_status(_position); sp_event_context_snap_delay_handler(event_context, NULL, @@ -342,6 +348,7 @@ bool ControlPoint::_eventHandler(Inkscape::UI::Tools::ToolBase *event_context, G } else { // it is the end of a click if (next_release_doubleclick) { + _double_clicked = true; return doubleclicked(&event->button); } else { return clicked(&event->button); diff --git a/src/ui/tool/control-point.h b/src/ui/tool/control-point.h index b3ed9545e..4a01b9f21 100644 --- a/src/ui/tool/control-point.h +++ b/src/ui/tool/control-point.h @@ -193,6 +193,8 @@ public: virtual bool _eventHandler(Inkscape::UI::Tools::ToolBase *event_context, GdkEvent *event); SPDesktop *const _desktop; ///< The desktop this control point resides on. + bool doubleClicked() {return _double_clicked;} + protected: struct ColorEntry { @@ -361,6 +363,8 @@ protected: /** Events which should be captured when a handle is being dragged. */ static int const _grab_event_mask; + static bool _drag_initiated; + private: ControlPoint(ControlPoint const &other); @@ -397,7 +401,7 @@ private: static bool _event_grab; - static bool _drag_initiated; + bool _double_clicked; }; diff --git a/src/ui/tool/curve-drag-point.cpp b/src/ui/tool/curve-drag-point.cpp index 23640456e..d1756fa2c 100644 --- a/src/ui/tool/curve-drag-point.cpp +++ b/src/ui/tool/curve-drag-point.cpp @@ -15,6 +15,8 @@ #include "ui/tool/multi-path-manipulator.h" #include "ui/tool/path-manipulator.h" #include "ui/tool/node.h" +#include "sp-namedview.h" +#include "snap.h" namespace Inkscape { namespace UI { @@ -77,6 +79,16 @@ void CurveDragPoint::dragged(Geom::Point &new_pos, GdkEventMotion *event) return; } + if (_drag_initiated && !(event->state & GDK_SHIFT_MASK)) { + SnapManager &m = _desktop->namedview->snap_manager; + SPItem *path = static_cast(_pm._path); + m.setup(_desktop, true, path); // We will not try to snap to "path" itself + Inkscape::SnapCandidatePoint scp(new_pos, Inkscape::SNAPSOURCE_OTHER_HANDLE); + Inkscape::SnappedPoint sp = m.freeSnap(scp, Geom::OptRect(), false); + new_pos = sp.getPoint(); + m.unSetup(); + } + // Magic Bezier Drag Equations follow! // "weight" describes how the influence of the drag should be distributed // among the handles; 0 = front handle only, 1 = back handle only. @@ -166,14 +178,8 @@ void CurveDragPoint::_insertNode(bool take_selection) // Otherwise clicks on the new node would only work after the user moves the mouse a bit. // PathManipulator will restore visibility when necessary. setVisible(false); - NodeList::iterator inserted = _pm.subdivideSegment(first, _t); - if (take_selection) { - _pm._selection.clear(); - } - _pm._selection.insert(inserted.ptr()); - _pm.update(true); - _pm._commit(_("Add node")); + _pm.insertNode(first, _t, take_selection); } Glib::ustring CurveDragPoint::_getTip(unsigned state) const diff --git a/src/ui/tool/curve-drag-point.h b/src/ui/tool/curve-drag-point.h index ea83978e0..c1d40575f 100644 --- a/src/ui/tool/curve-drag-point.h +++ b/src/ui/tool/curve-drag-point.h @@ -34,7 +34,9 @@ public: CurveDragPoint(PathManipulator &pm); void setSize(double sz) { _setSize(sz); } void setTimeValue(double t) { _t = t; } + double getTimeValue() { return _t; } void setIterator(NodeList::iterator i) { first = i; } + NodeList::iterator getIterator() { return first; } virtual bool _eventHandler(Inkscape::UI::Tools::ToolBase *event_context, GdkEvent *event); protected: @@ -47,9 +49,6 @@ protected: virtual bool doubleclicked(GdkEventButton *); private: - - void _insertNode(bool take_selection); - double _t; PathManipulator &_pm; NodeList::iterator first; @@ -57,6 +56,7 @@ private: static bool _drags_stroke; static bool _segment_was_degenerate; static Geom::Point _stroke_drag_origin; + void _insertNode(bool take_selection); }; } // namespace UI diff --git a/src/ui/tool/multi-path-manipulator.cpp b/src/ui/tool/multi-path-manipulator.cpp index f53cef5f4..46c6246a1 100644 --- a/src/ui/tool/multi-path-manipulator.cpp +++ b/src/ui/tool/multi-path-manipulator.cpp @@ -339,6 +339,14 @@ void MultiPathManipulator::insertNodesAtExtrema(ExtremumType extremum) _done(_("Add extremum nodes")); } +void MultiPathManipulator::insertNode(Geom::Point pt) +{ + // When double clicking to insert nodes, we might not have a selection of nodes (and we don't need one) + // so don't check for "_selection.empty()" here, contrary to the other methods above and below this one + invokeForAll(&PathManipulator::insertNode, pt); + _done(_("Add nodes")); +} + void MultiPathManipulator::duplicateNodes() { if (_selection.empty()) return; diff --git a/src/ui/tool/multi-path-manipulator.h b/src/ui/tool/multi-path-manipulator.h index 1bbcdd7ec..c908cede2 100644 --- a/src/ui/tool/multi-path-manipulator.h +++ b/src/ui/tool/multi-path-manipulator.h @@ -53,6 +53,7 @@ public: void insertNodesAtExtrema(ExtremumType extremum); void insertNodes(); + void insertNode(Geom::Point pt); void alertLPE(); void duplicateNodes(); void joinNodes(); diff --git a/src/ui/tool/path-manipulator.cpp b/src/ui/tool/path-manipulator.cpp index 6b0c95f68..a772c07c2 100644 --- a/src/ui/tool/path-manipulator.cpp +++ b/src/ui/tool/path-manipulator.cpp @@ -174,7 +174,8 @@ bool PathManipulator::event(Inkscape::UI::Tools::ToolBase * /*event_context*/, G case GDK_MOTION_NOTIFY: _updateDragPoint(event_point(event->motion)); break; - default: break; + default: + break; } return false; } @@ -275,6 +276,27 @@ void PathManipulator::insertNodes() } } +void PathManipulator::insertNode(Geom::Point pt) +{ + Geom::Coord dist = _updateDragPoint(pt); + if (dist < 1e-5) { // 1e-6 is too small, as observed occasionally when inserting a node at a snapped intersection of paths + insertNode(_dragpoint->getIterator(), _dragpoint->getTimeValue(), true); + } +} + +void PathManipulator::insertNode(NodeList::iterator first, double t, bool take_selection) +{ + NodeList::iterator inserted = subdivideSegment(first, t); + if (take_selection) { + _selection.clear(); + } + _selection.insert(inserted.ptr()); + + update(true); + _commit(_("Add node")); +} + + static void add_or_replace_if_extremum(std::vector< std::pair > &vec, double & extrvalue, double testvalue, NodeList::iterator const& node, double t) @@ -1643,13 +1665,15 @@ void PathManipulator::_commit(Glib::ustring const &annotation, gchar const *key) /** Update the position of the curve drag point such that it is over the nearest * point of the path. */ -void PathManipulator::_updateDragPoint(Geom::Point const &evp) +Geom::Coord PathManipulator::_updateDragPoint(Geom::Point const &evp) { + Geom::Coord dist = 1e23; + Geom::Affine to_desktop = _edit_transform * _i2d_transform; Geom::PathVector pv = _spcurve->get_pathvector(); boost::optional pvp = Geom::nearestPoint(pv, _desktop->w2d(evp) * to_desktop.inverse()); - if (!pvp) return; + if (!pvp) return dist; Geom::Point nearest_point = _desktop->d2w(pv.at(pvp->path_nr).pointAt(pvp->t) * to_desktop); double fracpart; @@ -1657,10 +1681,12 @@ void PathManipulator::_updateDragPoint(Geom::Point const &evp) for (unsigned i = 0; i < pvp->path_nr; ++i, ++spi) {} NodeList::iterator first = (*spi)->before(pvp->t, &fracpart); + dist = Geom::distance(evp, nearest_point); + double stroke_tolerance = _getStrokeTolerance(); if (first && first.next() && fracpart != 0.0 && - Geom::distance(evp, nearest_point) < stroke_tolerance) + dist < stroke_tolerance) { _dragpoint->setVisible(true); _dragpoint->setPosition(_desktop->w2d(nearest_point)); @@ -1670,6 +1696,8 @@ void PathManipulator::_updateDragPoint(Geom::Point const &evp) } else { _dragpoint->setVisible(false); } + + return dist; } /// This is called on zoom change to update the direction arrows diff --git a/src/ui/tool/path-manipulator.h b/src/ui/tool/path-manipulator.h index 2219af849..4c6f74ba4 100644 --- a/src/ui/tool/path-manipulator.h +++ b/src/ui/tool/path-manipulator.h @@ -70,6 +70,8 @@ public: void insertNodeAtExtremum(ExtremumType extremum); void insertNodes(); + void insertNode(Geom::Point); + void insertNode(NodeList::iterator first, double t, bool take_selection); void duplicateNodes(); void weldNodes(NodeList::iterator preserve_pos = NodeList::iterator()); void weldSegments(); @@ -133,7 +135,7 @@ private: void _removeNodesFromSelection(); void _commit(Glib::ustring const &annotation); void _commit(Glib::ustring const &annotation, gchar const *key); - void _updateDragPoint(Geom::Point const &); + Geom::Coord _updateDragPoint(Geom::Point const &); void _updateOutlineOnZoomChange(); double _getStrokeTolerance(); Handle *_chooseHandle(Node *n, int which); @@ -143,7 +145,7 @@ private: SPPath *_path; ///< can be an SPPath or an Inkscape::LivePathEffect::Effect !!! SPCurve *_spcurve; // in item coordinates SPCanvasItem *_outline; - CurveDragPoint *_dragpoint; // an invisible control point hoverng over curve + CurveDragPoint *_dragpoint; // an invisible control point hovering over curve PathManipulatorObserver *_observer; Geom::Affine _d2i_transform; ///< desktop-to-item transform Geom::Affine _i2d_transform; ///< item-to-desktop transform, inverse of _d2i_transform diff --git a/src/ui/tool/selector.cpp b/src/ui/tool/selector.cpp index e4e701785..051cb41ae 100644 --- a/src/ui/tool/selector.cpp +++ b/src/ui/tool/selector.cpp @@ -129,6 +129,10 @@ bool Selector::event(Inkscape::UI::Tools::ToolBase *event_context, GdkEvent *eve return false; } +bool Selector::doubleClicked() { + return _dragger->doubleClicked(); +} + } // namespace UI } // namespace Inkscape diff --git a/src/ui/tool/selector.h b/src/ui/tool/selector.h index dbe751ede..bd8d3e1aa 100644 --- a/src/ui/tool/selector.h +++ b/src/ui/tool/selector.h @@ -29,6 +29,7 @@ public: Selector(SPDesktop *d); virtual ~Selector(); virtual bool event(Inkscape::UI::Tools::ToolBase *, GdkEvent *); + virtual bool doubleClicked(); sigc::signal signal_area; sigc::signal signal_point; diff --git a/src/ui/tools/node-tool.cpp b/src/ui/tools/node-tool.cpp index ef00eaa40..761492f41 100644 --- a/src/ui/tools/node-tool.cpp +++ b/src/ui/tools/node-tool.cpp @@ -26,6 +26,8 @@ #include "ui/shape-editor.h" // temporary! #include "live_effects/effect.h" #include "display/curve.h" +#include "snap.h" +#include "sp-namedview.h" #include "sp-clippath.h" #include "sp-item-group.h" #include "sp-mask.h" @@ -112,7 +114,7 @@ namespace UI { namespace Tools { const std::string& NodeTool::getPrefsPath() { - return NodeTool::prefsPath; + return NodeTool::prefsPath; } const std::string NodeTool::prefsPath = "/tools/nodes"; @@ -216,7 +218,7 @@ void NodeTool::setup() { Inkscape::UI::ControlPoint::signal_mouseover_change.connect(sigc::mem_fun(this, &NodeTool::mouseover_changed)); this->_sizeUpdatedConn = ControlManager::getManager().connectCtrlSizeChanged( - sigc::mem_fun(this, &NodeTool::handleControlUiStyleChange) + sigc::mem_fun(this, &NodeTool::handleControlUiStyleChange) ); this->_selected_nodes = new Inkscape::UI::ControlPointSelection(this->desktop, this->_transform_handle_group); @@ -236,14 +238,14 @@ void NodeTool::setup() { ); this->_selected_nodes->signal_selection_changed.connect( - // Hide both signal parameters and bind the function parameter to 0 - // sigc::signal - // <=> - // void update_tip(GdkEvent *event) - sigc::hide(sigc::hide(sigc::bind( - sigc::mem_fun(this, &NodeTool::update_tip), - (GdkEvent*)NULL - ))) + // Hide both signal parameters and bind the function parameter to 0 + // sigc::signal + // <=> + // void update_tip(GdkEvent *event) + sigc::hide(sigc::hide(sigc::bind( + sigc::mem_fun(this, &NodeTool::update_tip), + (GdkEvent*)NULL + ))) ); this->helperpath_tmpitem = NULL; @@ -359,7 +361,7 @@ void NodeTool::set(const Inkscape::Preferences::Entry& value) { this->edit_masks = value.getBool(); this->selection_changed(this->desktop->selection); } else { - ToolBase::set(value); + ToolBase::set(value); } } @@ -370,7 +372,7 @@ void gather_items(NodeTool *nt, SPItem *base, SPObject *obj, Inkscape::UI::Shape using namespace Inkscape::UI; if (!obj) { - return; + return; } //XML Tree being used directly here while it shouldn't be. @@ -446,6 +448,9 @@ void NodeTool::selection_changed(Inkscape::Selection *sel) { } } + _previous_selection = _current_selection; + _current_selection = sel->itemList(); + this->_multipath->setItems(shapes); this->update_tip(NULL); this->desktop->updateNow(); @@ -458,31 +463,47 @@ bool NodeTool::root_handler(GdkEvent* event) { * 3. some keybindings */ using namespace Inkscape::UI; // pull in event helpers - + Inkscape::Selection *selection = desktop->selection; static Inkscape::Preferences *prefs = Inkscape::Preferences::get(); if (this->_multipath->event(this, event)) { - return true; + return true; } if (this->_selector->event(this, event)) { - return true; + return true; } if (this->_selected_nodes->event(this, event)) { - return true; + return true; } switch (event->type) { case GDK_MOTION_NOTIFY: { - this->update_helperpath(); + this->update_helperpath(); combine_motion_events(desktop->canvas, event->motion, 0); this->update_helperpath(); SPItem *over_item = sp_event_context_find_item (desktop, event_point(event->button), FALSE, TRUE); + Geom::Point const motion_w(event->motion.x, event->motion.y); + Geom::Point const motion_dt(this->desktop->w2d(motion_w)); + + SnapManager &m = this->desktop->namedview->snap_manager; + + // We will show a pre-snap indication for when the user adds a node through double-clicking + // Adding a node will only work when a path has been selected; if that's not the case then snapping is useless + if (not this->desktop->selection->isEmpty()) { + if (!(event->motion.state & GDK_SHIFT_MASK)) { + m.setup(this->desktop); + Inkscape::SnapCandidatePoint scp(motion_dt, Inkscape::SNAPSOURCE_OTHER_HANDLE); + m.preSnap(scp, true); + m.unSetup(); + } + } + if (over_item != this->_last_over) { this->_last_over = over_item; //ink_node_tool_update_tip(nt, event); @@ -491,11 +512,11 @@ bool NodeTool::root_handler(GdkEvent* event) { // create pathflash outline if (prefs->getBool("/tools/nodes/pathflash_enabled")) { if (over_item == this->flashed_item) { - break; + break; } if (!prefs->getBool("/tools/nodes/pathflash_selected") && selection->includes(over_item)) { - break; + break; } if (this->flash_tempitem) { @@ -505,14 +526,14 @@ bool NodeTool::root_handler(GdkEvent* event) { } if (!SP_IS_SHAPE(over_item)) { - break; // for now, handle only shapes + break; // for now, handle only shapes } this->flashed_item = over_item; SPCurve *c = SP_SHAPE(over_item)->getCurveBeforeLPE(); if (!c) { - break; // break out when curve doesn't exist + break; // break out when curve doesn't exist } c->transform(over_item->i2dt_affine()); @@ -575,11 +596,42 @@ bool NodeTool::root_handler(GdkEvent* event) { case GDK_KEY_RELEASE: //ink_node_tool_update_tip(nt, event); - this->update_tip(event); + this->update_tip(event); + break; + + case GDK_BUTTON_RELEASE: + if (this->_selector->doubleClicked()) { + // If the selector received the doubleclick event, then we're at some distance from + // the path; otherwise, the doubleclick event would have been received by + // CurveDragPoint; we will insert nodes into the path anyway but only if we can snap + // to the path. Otherwise the position would not be very well defined. + if (!(event->motion.state & GDK_SHIFT_MASK)) { + Geom::Point const motion_w(event->motion.x, event->motion.y); + Geom::Point const motion_dt(this->desktop->w2d(motion_w)); + + SnapManager &m = this->desktop->namedview->snap_manager; + m.setup(this->desktop); + Inkscape::SnapCandidatePoint scp(motion_dt, Inkscape::SNAPSOURCE_OTHER_HANDLE); + Inkscape::SnappedPoint sp = m.freeSnap(scp, Geom::OptRect(), true); + m.unSetup(); + + if (sp.getSnapped()) { + // The first click of the double click will have cleared the path selection, because + // we clicked aside of the path. We need to undo this on double click + Inkscape::Selection *selection = desktop->getSelection(); + selection->addList(_previous_selection); + + // The selection has been restored, and the signal selection_changed has been emitted, + // which has again forced a restore of the _mmap variable of the MultiPathManipulator (this->_multipath) + // Now we can insert the new nodes as if nothing has happened! + this->_multipath->insertNode(this->desktop->d2w(sp.getPoint())); + } + } + } break; default: - break; + break; } return ToolBase::root_handler(event); @@ -592,7 +644,7 @@ void NodeTool::update_tip(GdkEvent *event) { unsigned new_state = state_after_event(event); if (new_state == event->key.state) { - return; + return; } if (state_held_shift(new_state)) { @@ -661,7 +713,7 @@ void NodeTool::select_area(Geom::Rect const &sel, GdkEventButton *event) { selection->setList(items); } else { if (!held_shift(*event)) { - this->_selected_nodes->clear(); + this->_selected_nodes->clear(); } this->_selected_nodes->selectArea(sel); @@ -672,11 +724,11 @@ void NodeTool::select_point(Geom::Point const &/*sel*/, GdkEventButton *event) { using namespace Inkscape::UI; // pull in event helpers if (!event) { - return; + return; } if (event->button != 1) { - return; + return; } Inkscape::Selection *selection = this->desktop->selection; diff --git a/src/ui/tools/node-tool.h b/src/ui/tools/node-tool.h index 20375e869..d5a21e0c6 100644 --- a/src/ui/tools/node-tool.h +++ b/src/ui/tools/node-tool.h @@ -85,6 +85,9 @@ private: bool show_transform_handles; bool single_node_transform_handles; + std::vector _current_selection; + std::vector _previous_selection; + void selection_changed(Inkscape::Selection *sel); void select_area(Geom::Rect const &sel, GdkEventButton *event); -- cgit v1.2.3 From 1791eb30ed40414ac83d4bb8cd0c6ce219597e42 Mon Sep 17 00:00:00 2001 From: Diederik van Lierop Date: Sat, 30 May 2015 20:33:03 +0200 Subject: Replace tabs by spaces (bzr r14190) --- src/ui/tools/node-tool.h | 56 ++++++++++++++++++++++++------------------------ 1 file changed, 28 insertions(+), 28 deletions(-) (limited to 'src') diff --git a/src/ui/tools/node-tool.h b/src/ui/tools/node-tool.h index d5a21e0c6..8342d66a6 100644 --- a/src/ui/tools/node-tool.h +++ b/src/ui/tools/node-tool.h @@ -19,18 +19,18 @@ #include "selection.h" namespace Inkscape { - namespace Display { - class TemporaryItem; - } - - namespace UI { - class MultiPathManipulator; - class ControlPointSelection; - class Selector; - class ControlPoint; - - struct PathSharedData; - } + namespace Display { + class TemporaryItem; + } + + namespace UI { + class MultiPathManipulator; + class ControlPointSelection; + class Selector; + class ControlPoint; + + struct PathSharedData; + } } struct SPCanvasGroup; @@ -44,26 +44,26 @@ namespace Tools { class NodeTool : public ToolBase { public: - NodeTool(); - virtual ~NodeTool(); + NodeTool(); + virtual ~NodeTool(); - Inkscape::UI::ControlPointSelection* _selected_nodes; + Inkscape::UI::ControlPointSelection* _selected_nodes; Inkscape::UI::MultiPathManipulator* _multipath; bool edit_clipping_paths; bool edit_masks; - static const std::string prefsPath; + static const std::string prefsPath; - virtual void setup(); - virtual void update_helperpath(); - virtual void set(const Inkscape::Preferences::Entry& val); - virtual bool root_handler(GdkEvent* event); + virtual void setup(); + virtual void update_helperpath(); + virtual void set(const Inkscape::Preferences::Entry& val); + virtual bool root_handler(GdkEvent* event); - virtual const std::string& getPrefsPath(); + virtual const std::string& getPrefsPath(); private: - sigc::connection _selection_changed_connection; + sigc::connection _selection_changed_connection; sigc::connection _mouseover_changed_connection; sigc::connection _sizeUpdatedConn; @@ -88,13 +88,13 @@ private: std::vector _current_selection; std::vector _previous_selection; - void selection_changed(Inkscape::Selection *sel); + void selection_changed(Inkscape::Selection *sel); - void select_area(Geom::Rect const &sel, GdkEventButton *event); - void select_point(Geom::Point const &sel, GdkEventButton *event); - void mouseover_changed(Inkscape::UI::ControlPoint *p); - void update_tip(GdkEvent *event); - void handleControlUiStyleChange(); + void select_area(Geom::Rect const &sel, GdkEventButton *event); + void select_point(Geom::Point const &sel, GdkEventButton *event); + void mouseover_changed(Inkscape::UI::ControlPoint *p); + void update_tip(GdkEvent *event); + void handleControlUiStyleChange(); }; } -- cgit v1.2.3 From 81dfaff00f7f768a52448b62365b7bef52129d5f Mon Sep 17 00:00:00 2001 From: Alexandre Prokoudine Date: Sun, 31 May 2015 16:40:14 +0300 Subject: Mark user-visible messages for translation (bzr r14191) --- src/ui/dialog/objects.cpp | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) (limited to 'src') diff --git a/src/ui/dialog/objects.cpp b/src/ui/dialog/objects.cpp index be04e7149..662cce6e1 100644 --- a/src/ui/dialog/objects.cpp +++ b/src/ui/dialog/objects.cpp @@ -1858,46 +1858,46 @@ ObjectsPanel::ObjectsPanel() : //Set up the pop-up menu // ------------------------------------------------------- { - _watching.push_back( &_addPopupItem( targetDesktop, SP_VERB_LAYER_RENAME, 0, "Rename", (int)BUTTON_RENAME ) ); - _watching.push_back( &_addPopupItem( targetDesktop, SP_VERB_EDIT_DUPLICATE, 0, "Duplicate", (int)BUTTON_DUPLICATE ) ); - _watching.push_back( &_addPopupItem( targetDesktop, SP_VERB_LAYER_NEW, 0, "New", (int)BUTTON_NEW ) ); + _watching.push_back( &_addPopupItem( targetDesktop, SP_VERB_LAYER_RENAME, 0, _("Rename"), (int)BUTTON_RENAME ) ); + _watching.push_back( &_addPopupItem( targetDesktop, SP_VERB_EDIT_DUPLICATE, 0, _("Duplicate"), (int)BUTTON_DUPLICATE ) ); + _watching.push_back( &_addPopupItem( targetDesktop, SP_VERB_LAYER_NEW, 0, _("New"), (int)BUTTON_NEW ) ); _popupMenu.append(*Gtk::manage(new Gtk::SeparatorMenuItem())); - _watching.push_back( &_addPopupItem( targetDesktop, SP_VERB_LAYER_SOLO, 0, "Solo", (int)BUTTON_SOLO ) ); - _watching.push_back( &_addPopupItem( targetDesktop, SP_VERB_LAYER_SHOW_ALL, 0, "Show All", (int)BUTTON_SHOW_ALL ) ); - _watching.push_back( &_addPopupItem( targetDesktop, SP_VERB_LAYER_HIDE_ALL, 0, "Hide All", (int)BUTTON_HIDE_ALL ) ); + _watching.push_back( &_addPopupItem( targetDesktop, SP_VERB_LAYER_SOLO, 0, _("Solo"), (int)BUTTON_SOLO ) ); + _watching.push_back( &_addPopupItem( targetDesktop, SP_VERB_LAYER_SHOW_ALL, 0, _("Show All"), (int)BUTTON_SHOW_ALL ) ); + _watching.push_back( &_addPopupItem( targetDesktop, SP_VERB_LAYER_HIDE_ALL, 0, _("Hide All"), (int)BUTTON_HIDE_ALL ) ); _popupMenu.append(*Gtk::manage(new Gtk::SeparatorMenuItem())); - _watching.push_back( &_addPopupItem( targetDesktop, SP_VERB_LAYER_LOCK_OTHERS, 0, "Lock Others", (int)BUTTON_LOCK_OTHERS ) ); - _watching.push_back( &_addPopupItem( targetDesktop, SP_VERB_LAYER_LOCK_ALL, 0, "Lock All", (int)BUTTON_LOCK_ALL ) ); - _watching.push_back( &_addPopupItem( targetDesktop, SP_VERB_LAYER_UNLOCK_ALL, 0, "Unlock All", (int)BUTTON_UNLOCK_ALL ) ); + _watching.push_back( &_addPopupItem( targetDesktop, SP_VERB_LAYER_LOCK_OTHERS, 0, _("Lock Others"), (int)BUTTON_LOCK_OTHERS ) ); + _watching.push_back( &_addPopupItem( targetDesktop, SP_VERB_LAYER_LOCK_ALL, 0, _("Lock All"), (int)BUTTON_LOCK_ALL ) ); + _watching.push_back( &_addPopupItem( targetDesktop, SP_VERB_LAYER_UNLOCK_ALL, 0, _("Unlock All"), (int)BUTTON_UNLOCK_ALL ) ); _popupMenu.append(*Gtk::manage(new Gtk::SeparatorMenuItem())); - _watchingNonTop.push_back( &_addPopupItem( targetDesktop, SP_VERB_SELECTION_RAISE, GTK_STOCK_GO_UP, "Up", (int)BUTTON_UP ) ); - _watchingNonBottom.push_back( &_addPopupItem( targetDesktop, SP_VERB_SELECTION_LOWER, GTK_STOCK_GO_DOWN, "Down", (int)BUTTON_DOWN ) ); + _watchingNonTop.push_back( &_addPopupItem( targetDesktop, SP_VERB_SELECTION_RAISE, GTK_STOCK_GO_UP, _("Up"), (int)BUTTON_UP ) ); + _watchingNonBottom.push_back( &_addPopupItem( targetDesktop, SP_VERB_SELECTION_LOWER, GTK_STOCK_GO_DOWN, _("Down"), (int)BUTTON_DOWN ) ); _popupMenu.append(*Gtk::manage(new Gtk::SeparatorMenuItem())); - _watching.push_back( &_addPopupItem( targetDesktop, SP_VERB_SELECTION_GROUP, 0, "Group", (int)BUTTON_GROUP ) ); - _watching.push_back( &_addPopupItem( targetDesktop, SP_VERB_SELECTION_UNGROUP, 0, "Ungroup", (int)BUTTON_UNGROUP ) ); + _watching.push_back( &_addPopupItem( targetDesktop, SP_VERB_SELECTION_GROUP, 0, _("Group"), (int)BUTTON_GROUP ) ); + _watching.push_back( &_addPopupItem( targetDesktop, SP_VERB_SELECTION_UNGROUP, 0, _("Ungroup"), (int)BUTTON_UNGROUP ) ); _popupMenu.append(*Gtk::manage(new Gtk::SeparatorMenuItem())); - _watching.push_back( &_addPopupItem( targetDesktop, SP_VERB_OBJECT_SET_CLIPPATH, 0, "Set Clip", (int)BUTTON_SETCLIP ) ); + _watching.push_back( &_addPopupItem( targetDesktop, SP_VERB_OBJECT_SET_CLIPPATH, 0, _("Set Clip"), (int)BUTTON_SETCLIP ) ); - _watching.push_back( &_addPopupItem( targetDesktop, SP_VERB_OBJECT_CREATE_CLIP_GROUP, 0, "Create Clip Group", (int)BUTTON_CLIPGROUP ) ); + _watching.push_back( &_addPopupItem( targetDesktop, SP_VERB_OBJECT_CREATE_CLIP_GROUP, 0, _("Create Clip Group"), (int)BUTTON_CLIPGROUP ) ); //will never be implemented //_watching.push_back( &_addPopupItem( targetDesktop, SP_VERB_OBJECT_SET_INVERSE_CLIPPATH, 0, "Set Inverse Clip", (int)BUTTON_SETINVCLIP ) ); - _watching.push_back( &_addPopupItem( targetDesktop, SP_VERB_OBJECT_UNSET_CLIPPATH, 0, "Unset Clip", (int)BUTTON_UNSETCLIP ) ); + _watching.push_back( &_addPopupItem( targetDesktop, SP_VERB_OBJECT_UNSET_CLIPPATH, 0, _("Unset Clip"), (int)BUTTON_UNSETCLIP ) ); _popupMenu.append(*Gtk::manage(new Gtk::SeparatorMenuItem())); - _watching.push_back( &_addPopupItem( targetDesktop, SP_VERB_OBJECT_SET_MASK, 0, "Set Mask", (int)BUTTON_SETMASK ) ); - _watching.push_back( &_addPopupItem( targetDesktop, SP_VERB_OBJECT_UNSET_MASK, 0, "Unset Mask", (int)BUTTON_UNSETMASK ) ); + _watching.push_back( &_addPopupItem( targetDesktop, SP_VERB_OBJECT_SET_MASK, 0, _("Set Mask"), (int)BUTTON_SETMASK ) ); + _watching.push_back( &_addPopupItem( targetDesktop, SP_VERB_OBJECT_UNSET_MASK, 0, _("Unset Mask"), (int)BUTTON_UNSETMASK ) ); _popupMenu.show_all_children(); } -- cgit v1.2.3 From 3d556ac8b9ff5cb1574f7cc873707e2bc008cc00 Mon Sep 17 00:00:00 2001 From: mathog <> Date: Mon, 1 Jun 2015 16:00:24 -0700 Subject: patch for bug 1283194 (bzr r14192) --- src/display/drawing-text.cpp | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/display/drawing-text.cpp b/src/display/drawing-text.cpp index 3928ad796..a3ca7173a 100644 --- a/src/display/drawing-text.cpp +++ b/src/display/drawing-text.cpp @@ -91,9 +91,24 @@ unsigned DrawingGlyphs::_updateItem(Geom::IntRect const &/*area*/, UpdateContext if (_transform) { scale_bigbox /= _transform->descrim(); } + - Geom::Rect bigbox(Geom::Point(-_width*scale_bigbox*0.1, _asc*scale_bigbox*1.1),Geom::Point(_width*scale_bigbox, -_dsc*scale_bigbox*1.1)); - Geom::Rect b = bigbox * ctx.ctm; + /* Because there can be text decorations the bounding box must correspond in Y to a little above the glyph's ascend + and a little below its descend. This leaves room for overline and underline. The left and right sides + come from the glyph's bounding box. Note that the initial direction of ascender is positive down in Y, and + this flips after the transform is applied. So change the sign on descender. 1.1 provides a little extra space + above and below the max/min y positions of the letters to place the text decorations.*/ + + Geom::Rect b; + if(_drawable){ + Geom::OptRect tiltb = bounds_exact(*_font->PathVector(_glyph)); + Geom::Rect bigbox(Geom::Point(tiltb->left(),-_dsc*scale_bigbox*1.1),Geom::Point(tiltb->right(),_asc*scale_bigbox*1.1)); + b = bigbox * ctx.ctm; + } + else { // Fallback, spaces mostly + Geom::Rect bigbox(Geom::Point(0.0, -_dsc*scale_bigbox*1.1),Geom::Point(_width*scale_bigbox, _asc*scale_bigbox*1.1)); + b = bigbox * ctx.ctm; + } /* The pick box matches the characters as best as it can, leaving no extra space above or below @@ -108,11 +123,11 @@ unsigned DrawingGlyphs::_updateItem(Geom::IntRect const &/*area*/, UpdateContext if(_drawable){ pb = bounds_exact_transformed(*_font->PathVector(_glyph), ctx.ctm); } - if(!pb){ // Fallback + if(!pb){ // Fallback, spaces mostly Geom::Rect pbigbox(Geom::Point(0.0, _asc*scale_bigbox*0.66),Geom::Point(_width*scale_bigbox, 0.0)); pb = pbigbox * ctx.ctm; } - + #if 0 /* FIXME if this is commented out then not even an approximation of pick on decorations */ /* adjust the pick box up or down to include the decorations. @@ -214,7 +229,7 @@ DrawingText::addComponent(font_instance *font, int glyph, Geom::Affine const &tr ng->setGlyph(font, glyph, trans); if(font->PathVector(glyph)){ ng->_drawable = true; } else { ng->_drawable = false; } - ng->_width = width; // only used when _drawable = false + ng->_width = width; // used especially when _drawable = false, otherwise, it is the advance of the font ng->_asc = ascent; // of font, not of this one character ng->_dsc = descent; // of font, not of this one character ng->_pl = phase_length; // used for phase of dots, dashes, and wavy -- cgit v1.2.3 From da9ef35c3022770ba745f02bc2b5af75254c0e98 Mon Sep 17 00:00:00 2001 From: su_v Date: Wed, 3 Jun 2015 06:50:17 +0200 Subject: Fix undo history entry for moving a layer (consistency) (bzr r14194) --- src/ui/dialog/layers.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/ui/dialog/layers.cpp b/src/ui/dialog/layers.cpp index c6888386f..3f5e80f8d 100644 --- a/src/ui/dialog/layers.cpp +++ b/src/ui/dialog/layers.cpp @@ -727,7 +727,7 @@ void LayersPanel::_doTreeMove( ) _selectLayer(_dnd_source); _dnd_source = NULL; DocumentUndo::done( _desktop->doc() , SP_VERB_NONE, - _("Moved layer")); + _("Move layer")); } } -- cgit v1.2.3 From 83ff4841d5b11aed63f1deb9e1b606eee87f30bb Mon Sep 17 00:00:00 2001 From: Alexander Brock Date: Mon, 8 Jun 2015 16:23:08 +0200 Subject: Show angle of selected line segments relative to X-axis (bzr r14195.1.1) --- src/ui/tools/node-tool.cpp | 29 ++++++++++++++++++++++++++--- 1 file changed, 26 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/ui/tools/node-tool.cpp b/src/ui/tools/node-tool.cpp index 761492f41..5c97a4c7f 100644 --- a/src/ui/tools/node-tool.cpp +++ b/src/ui/tools/node-tool.cpp @@ -665,9 +665,32 @@ void NodeTool::update_tip(GdkEvent *event) { unsigned total = this->_selected_nodes->allPoints().size(); if (sz != 0) { - char *nodestring = g_strdup_printf( - ngettext("%u of %u node selected.", "%u of %u nodes selected.", total), - sz, total); + char *nodestring; + if (sz == 2) { + Inkscape::UI::ControlPointSelection::Set &selectionNodes = this->_selected_nodes->allPoints(); + std::vector selectedNodesPositions; + for (Inkscape::UI::ControlPointSelection::Set::iterator i = selectionNodes.begin(); i != selectionNodes.end(); ++i) { + if ((*i)->selected()) { + Inkscape::UI::Node *n = dynamic_cast(*i); + selectedNodesPositions.push_back(n->position()); + } + } + g_assert(selectedNodesPositions.size() == 2); + Geom::Point difference = selectedNodesPositions[0] - selectedNodesPositions[1]; + double angle = Geom::atan2(difference); + if (angle < 0) { + angle += 2*M_PI; + } + angle *= 180.0/M_PI; + nodestring = g_strdup_printf( + "%u of %u nodes selected, angle: %.2f°.", + sz, total, angle); + } + else { + nodestring = g_strdup_printf( + ngettext("%u of %u node selected.", "%u of %u nodes selected.", total), + sz, total); + } if (this->_last_over) { // TRANSLATORS: The %s below is where the "%u of %u nodes selected" sentence gets put -- cgit v1.2.3 From 26236dee0e90bb23678a6b1ec52138c7f6dde32b Mon Sep 17 00:00:00 2001 From: Bryce Harrington Date: Mon, 8 Jun 2015 12:01:23 -0700 Subject: cmake: Add some missing header files to CMakeLists.txt These were found by running cmake_consistency_check.py (bzr r14198) --- src/CMakeLists.txt | 7 +++++++ src/libuemf/CMakeLists.txt | 1 + src/trace/CMakeLists.txt | 1 + src/ui/CMakeLists.txt | 7 +++++++ 4 files changed, 16 insertions(+) (limited to 'src') diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index efb604aca..c416b0dea 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -166,6 +166,9 @@ set(sp_SRC sp-style-elem.h sp-switch.h sp-symbol.h + sp-tag.h + sp-tag-use.h + sp-tag-use-reference.h sp-text.h sp-textpath.h sp-title.h @@ -423,6 +426,10 @@ if(WIN32) #deptool.cpp winconsole.cpp winmain.cpp + + # ------- + # Headers + registrytool.h ) endif() diff --git a/src/libuemf/CMakeLists.txt b/src/libuemf/CMakeLists.txt index 922d404a6..9e6b68994 100644 --- a/src/libuemf/CMakeLists.txt +++ b/src/libuemf/CMakeLists.txt @@ -18,6 +18,7 @@ set(libuemf_SRC uemf.h uemf_endian.h uemf_print.h + uemf_safe.h uemf_utf.h uwmf.h uwmf_endian.h diff --git a/src/trace/CMakeLists.txt b/src/trace/CMakeLists.txt index 958907df6..bf7cfa276 100644 --- a/src/trace/CMakeLists.txt +++ b/src/trace/CMakeLists.txt @@ -28,6 +28,7 @@ set(trace_SRC potrace/auxiliary.h potrace/bitmap.h + potrace/bitops.h potrace/curve.h potrace/decompose.h potrace/greymap.h diff --git a/src/ui/CMakeLists.txt b/src/ui/CMakeLists.txt index fbf25d039..58af7d935 100644 --- a/src/ui/CMakeLists.txt +++ b/src/ui/CMakeLists.txt @@ -226,6 +226,7 @@ set(ui_SRC dialog/livepatheffect-add.h dialog/livepatheffect-editor.h dialog/lpe-fillet-chamfer-properties.h + dialog/lpe-powerstroke-properties.h dialog/memory.h dialog/messages.h dialog/new-from-template.h @@ -242,6 +243,7 @@ set(ui_SRC dialog/svg-fonts-dialog.h dialog/swatches.h dialog/symbols.h + dialog/tags.h dialog/template-load-tab.h dialog/template-widget.h dialog/text-edit.h @@ -293,9 +295,11 @@ set(ui_SRC tools/tweak-tool.h tools/zoom-tool.h + widget/addtoicon.h widget/anchor-selector.h widget/attr-widget.h widget/button.h + widget/clipmaskicon.h widget/color-entry.h widget/color-icc-selector.h widget/color-notebook.h @@ -314,10 +318,13 @@ set(ui_SRC widget/frame.h widget/gimpspinscale.h widget/gimpcolorwheel.h + widget/highlight-picker.h + widget/insertordericon.h widget/imageicon.h widget/imagetoggler.h widget/labelled.h widget/layer-selector.h + widget/layertypeicon.h widget/licensor.h widget/notebook-page.h widget/object-composite-settings.h -- cgit v1.2.3 From 469621748a3321f8b9363a96628f9ec04dd03cb2 Mon Sep 17 00:00:00 2001 From: Alexander Brock Date: Wed, 10 Jun 2015 02:54:16 +0200 Subject: Compute angle in [0,180[ and adhere to style guide (bzr r14195.1.2) --- src/ui/tools/node-tool.cpp | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) (limited to 'src') diff --git a/src/ui/tools/node-tool.cpp b/src/ui/tools/node-tool.cpp index 5c97a4c7f..488d1eb9f 100644 --- a/src/ui/tools/node-tool.cpp +++ b/src/ui/tools/node-tool.cpp @@ -667,21 +667,16 @@ void NodeTool::update_tip(GdkEvent *event) { if (sz != 0) { char *nodestring; if (sz == 2) { - Inkscape::UI::ControlPointSelection::Set &selectionNodes = this->_selected_nodes->allPoints(); - std::vector selectedNodesPositions; - for (Inkscape::UI::ControlPointSelection::Set::iterator i = selectionNodes.begin(); i != selectionNodes.end(); ++i) { + Inkscape::UI::ControlPointSelection::Set &selection_nodes = this->_selected_nodes->allPoints(); + std::vector positions; + for (Inkscape::UI::ControlPointSelection::Set::iterator i = selection_nodes.begin(); i != selection_nodes.end(); ++i) { if ((*i)->selected()) { Inkscape::UI::Node *n = dynamic_cast(*i); - selectedNodesPositions.push_back(n->position()); + positions.push_back(n->position()); } } - g_assert(selectedNodesPositions.size() == 2); - Geom::Point difference = selectedNodesPositions[0] - selectedNodesPositions[1]; - double angle = Geom::atan2(difference); - if (angle < 0) { - angle += 2*M_PI; - } - angle *= 180.0/M_PI; + g_assert(positions.size() == 2); + const double angle = Geom::rad_to_deg(Geom::Line(positions[0], positions[1]).angle()); nodestring = g_strdup_printf( "%u of %u nodes selected, angle: %.2f°.", sz, total, angle); -- cgit v1.2.3 From ea9f79f1b6cb045409140e6190bcbbf768d7fdf7 Mon Sep 17 00:00:00 2001 From: Alexander Brock Date: Wed, 10 Jun 2015 02:55:47 +0200 Subject: Change function call to one line (bzr r14195.1.3) --- src/ui/tools/node-tool.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'src') diff --git a/src/ui/tools/node-tool.cpp b/src/ui/tools/node-tool.cpp index 488d1eb9f..43286615d 100644 --- a/src/ui/tools/node-tool.cpp +++ b/src/ui/tools/node-tool.cpp @@ -677,9 +677,7 @@ void NodeTool::update_tip(GdkEvent *event) { } g_assert(positions.size() == 2); const double angle = Geom::rad_to_deg(Geom::Line(positions[0], positions[1]).angle()); - nodestring = g_strdup_printf( - "%u of %u nodes selected, angle: %.2f°.", - sz, total, angle); + nodestring = g_strdup_printf("%u of %u nodes selected, angle: %.2f°.", sz, total, angle); } else { nodestring = g_strdup_printf( -- cgit v1.2.3 From f0722ae58721f61fedec6d957642dacddf751eec Mon Sep 17 00:00:00 2001 From: "Liam P. White" Date: Wed, 10 Jun 2015 09:56:12 -0400 Subject: 1357805+1227193 revisited Fixed bugs: - https://launchpad.net/bugs/1227193 - https://launchpad.net/bugs/1357805 (bzr r14199) --- src/document-undo.cpp | 22 +++++++++++++++++++++- src/widgets/stroke-style.cpp | 6 +++++- 2 files changed, 26 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/document-undo.cpp b/src/document-undo.cpp index d4015bafb..59e060cd5 100644 --- a/src/document-undo.cpp +++ b/src/document-undo.cpp @@ -217,6 +217,25 @@ static void finish_incomplete_transaction(SPDocument &doc) { } } +static void perform_document_update(SPDocument &doc) { + sp_repr_begin_transaction(doc.rdoc); + doc.ensureUpToDate(); + + Inkscape::XML::Event *update_log=sp_repr_commit_undoable(doc.rdoc); + if (update_log != NULL) { + g_warning("Document was modified while being updated after undo operation"); + sp_repr_debug_print_log(update_log); + + //Coalesce the update changes with the last action performed by user + Inkscape::Event* undo_stack_top = (Inkscape::Event *)doc.priv->undo->data; + if (undo_stack_top) { + undo_stack_top->event = sp_repr_coalesce_log(undo_stack_top->event, update_log); + } else { + sp_repr_free_log(update_log); + } + } +} + gboolean Inkscape::DocumentUndo::undo(SPDocument *doc) { using Inkscape::Debug::EventTracker; @@ -241,7 +260,8 @@ gboolean Inkscape::DocumentUndo::undo(SPDocument *doc) Inkscape::Event *log=(Inkscape::Event *)doc->priv->undo->data; doc->priv->undo = g_slist_remove (doc->priv->undo, log); sp_repr_undo_log (log->event); - //doc->_updateDocument(); + perform_document_update(*doc); + doc->priv->redo = g_slist_prepend (doc->priv->redo, log); doc->setModifiedSinceSave(); diff --git a/src/widgets/stroke-style.cpp b/src/widgets/stroke-style.cpp index 482ca7af4..d05b3b994 100644 --- a/src/widgets/stroke-style.cpp +++ b/src/widgets/stroke-style.cpp @@ -450,7 +450,11 @@ StrokeStyle::makeRadioButton(Gtk::RadioButtonGroup &grp, */ void StrokeStyle::markerSelectCB(MarkerComboBox *marker_combo, StrokeStyle *spw, SPMarkerLoc const /*which*/) { - if (spw->update) { + bool markers_update = spw->startMarkerCombo->update() || + spw->midMarkerCombo->update() || + spw->endMarkerCombo->update(); + + if (spw->update || markers_update) { return; } -- cgit v1.2.3 From 00e579a221eef67f48a82cff71b6733c08015a6a Mon Sep 17 00:00:00 2001 From: "Liam P. White" Date: Wed, 10 Jun 2015 10:10:00 -0400 Subject: "13940 was not a terrible mistake!" (bzr r14200) --- src/Makefile.am | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/Makefile.am b/src/Makefile.am index cfbbd4015..7a37f13e8 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -23,7 +23,6 @@ endif noinst_LIBRARIES = \ - libinkscape.a \ libcroco/libcroco.a \ libavoid/libavoid.a \ $(internal_GDL) \ @@ -36,6 +35,7 @@ noinst_LIBRARIES = \ libdepixelize/libdepixelize.a \ util/libutil.a \ libinkversion.a +# libinkscape.a all_libs = \ $(noinst_LIBRARIES) \ @@ -198,15 +198,15 @@ DISTCLEANFILES = \ # ################################################ # this should speed up the build -libinkscape_a_SOURCES = $(ink_common_sources) +#libinkscape_a_SOURCES = $(ink_common_sources) -inkscape_SOURCES += main.cpp $(win32_sources) +inkscape_SOURCES += main.cpp $(ink_common_sources) $(win32_sources) inkscape_LDADD = $(all_libs) inkscape_LDFLAGS = $(kdeldflags) $(mwindows) -inkview_SOURCES += inkview.cpp $(win32_sources) +inkview_SOURCES += inkview.cpp $(ink_common_sources) $(win32_sources) inkview_LDADD = $(all_libs) -inkview_LDFLAGS = $(mwindows) +inkview_LDFLAGS = $(mwindows) # ################################################ # VERSION REPORTING -- cgit v1.2.3 From e90dafdefd3ea63ca7c4f1e070eb367ec4d54e5c Mon Sep 17 00:00:00 2001 From: Diederik van Lierop Date: Fri, 12 Jun 2015 23:50:13 +0200 Subject: Make the behavior of the snap indicator fully transparent, such that all events are sent to the items or canvas as intended Fixed bugs: - https://launchpad.net/bugs/1420301 (bzr r14201) --- src/display/snap-indicator.cpp | 15 +++++++++++++++ src/display/sp-canvas-item.h | 7 ++++++- src/display/sp-canvas.cpp | 30 ++++++++---------------------- 3 files changed, 29 insertions(+), 23 deletions(-) (limited to 'src') diff --git a/src/display/snap-indicator.cpp b/src/display/snap-indicator.cpp index 8c0c8163f..926b35599 100644 --- a/src/display/snap-indicator.cpp +++ b/src/display/snap-indicator.cpp @@ -258,6 +258,19 @@ SnapIndicator::set_new_snaptarget(Inkscape::SnappedPoint const &p, bool pre_snap const int timeout_val = 4000; + // The snap indicator will be deleted after some time-out, and sp_canvas_item_dispose + // will be called. This will set canvas->current_item to NULL if the snap indicator was + // the current item, after which any events will go to the root handler instead of any + // item handler. Dragging an object which has just snapped might therefore not be possible + // without selecting / repicking it again. To avoid this, we make sure here that the + // snap indicator will never be picked, and will therefore never be the current item. + // Reported bugs: + // - scrolling when hovering above a pre-snap indicator won't work (for example) + // (https://bugs.launchpad.net/inkscape/+bug/522335/comments/8) + // - dragging doesn't work without repicking + // (https://bugs.launchpad.net/inkscape/+bug/1420301/comments/15) + SP_CTRL(canvasitem)->pickable = false; + SP_CTRL(canvasitem)->moveto(p.getPoint()); _snaptarget = _desktop->add_temporary_canvasitem(canvasitem, timeout_val); _snaptarget_is_presnap = pre_snap; @@ -282,6 +295,7 @@ SnapIndicator::set_new_snaptarget(Inkscape::SnappedPoint const &p, bool pre_snap SPCanvasItem *canvas_tooltip = sp_canvastext_new(_desktop->getTempGroup(), _desktop, tooltip_pos, tooltip_str); sp_canvastext_set_fontsize(SP_CANVASTEXT(canvas_tooltip), fontsize); + SP_CANVASTEXT(canvas_tooltip)->pickable = false; // See the extensive comment above SP_CANVASTEXT(canvas_tooltip)->rgba = 0xffffffff; SP_CANVASTEXT(canvas_tooltip)->outline = false; SP_CANVASTEXT(canvas_tooltip)->background = true; @@ -306,6 +320,7 @@ SnapIndicator::set_new_snaptarget(Inkscape::SnappedPoint const &p, bool pre_snap SP_CTRLRECT(box)->setRectangle(*bbox); SP_CTRLRECT(box)->setColor(pre_snap ? 0x7f7f7fff : 0xff0000ff, 0, 0); SP_CTRLRECT(box)->setDashed(true); + SP_CTRLRECT(box)->pickable = false; // See the extensive comment above sp_canvas_item_move_to_z(box, 0); _snaptarget_bbox = _desktop->add_temporary_canvasitem(box, timeout_val); } diff --git a/src/display/sp-canvas-item.h b/src/display/sp-canvas-item.h index 3b7b7bd4f..3e9e085a0 100644 --- a/src/display/sp-canvas-item.h +++ b/src/display/sp-canvas-item.h @@ -69,7 +69,12 @@ struct SPCanvasItem { gboolean visible; gboolean need_update; gboolean need_affine; - + + // If true, then SPCanvasGroup::point() and sp_canvas_item_invoke_point() will calculate + // the distance to the pointer, such that this item can be picked in pickCurrentItem() + // Only if an item can be picked, then it can be set as current_item and receive events! + bool pickable; + bool in_destruction; }; diff --git a/src/display/sp-canvas.cpp b/src/display/sp-canvas.cpp index 305b0950a..5efc4ce86 100644 --- a/src/display/sp-canvas.cpp +++ b/src/display/sp-canvas.cpp @@ -375,6 +375,7 @@ sp_canvas_item_init(SPCanvasItem *item) // used for rubberbanding, path outline, etc. item->visible = TRUE; item->in_destruction = false; + item->pickable = true; } SPCanvasItem *sp_canvas_item_new(SPCanvasGroup *parent, GType type, gchar const *first_arg_name, ...) @@ -728,7 +729,6 @@ bool sp_canvas_item_is_visible(SPCanvasItem *item) return item->visible; } - /** * Sets visible flag on item and requests a redraw. */ @@ -1009,21 +1009,21 @@ double SPCanvasGroup::point(SPCanvasItem *item, Geom::Point p, SPCanvasItem **ac if ((child->x1 <= x2) && (child->y1 <= y2) && (child->x2 >= x1) && (child->y2 >= y1)) { SPCanvasItem *point_item = NULL; // cater for incomplete item implementations - int has_point; - if (child->visible && SP_CANVAS_ITEM_GET_CLASS(child)->point) { + int pickable; + if (child->visible && child->pickable && SP_CANVAS_ITEM_GET_CLASS(child)->point) { dist = sp_canvas_item_invoke_point(child, p, &point_item); - has_point = TRUE; + pickable = TRUE; } else { - has_point = FALSE; + pickable = FALSE; } - // This metric should be improved, because in case of (partly) overlapping items we will now + // TODO: This metric should be improved, because in case of (partly) overlapping items we will now // always select the last one that has been added to the group. We could instead select the one // of which the center is the closest, for example. One can then move to the center // of the item to be focused, and have that one selected. Of course this will only work if the // centers are not coincident, but at least it's better than what we have now. // See the extensive comment in Inkscape::SelTrans::_updateHandles() - if (has_point && point_item && ((int) (dist + 0.5) <= item->canvas->close_enough)) { + if (pickable && point_item && ((int) (dist + 0.5) <= item->canvas->close_enough)) { best = dist; *actual_item = point_item; } @@ -1480,20 +1480,6 @@ int SPCanvasImpl::emitEvent(SPCanvas *canvas, GdkEvent *event) if (canvas->grabbed_item && !is_descendant (canvas->current_item, canvas->grabbed_item)) { item = canvas->grabbed_item; } else { - // Make sure that current_item is up-to-date. If a snap indicator was just deleted, then - // sp_canvas_item_dispose has been called and there is no current_item specified. We need - // that though because otherwise we don't know where to send this event to, leading to a - // lost event. We can't wait for idle events to have current_item updated, we need it now! - // Otherwise, scrolling when hovering above a pre-snap indicator won't work (for example) - // See this bug report: https://bugs.launchpad.net/inkscape/+bug/522335/comments/8 - if (canvas->need_repick && !canvas->in_repick && event->type == GDK_SCROLL) { - // To avoid side effects, we'll only do this for scroll events, because this is the - // only thing we want to fix here. An example of a reported side effect is that - // otherwise selection of nodes in the node editor by dragging a rectangle using a - // tablet will break - canvas->need_repick = FALSE; - pickCurrentItem(canvas, reinterpret_cast(event)); - } item = canvas->current_item; } @@ -1527,7 +1513,7 @@ int SPCanvasImpl::pickCurrentItem(SPCanvas *canvas, GdkEvent *event) { int button_down = 0; - if (!canvas->root) // canvas may have already be destroyed by closing desktop durring interrupted display! + if (!canvas->root) // canvas may have already be destroyed by closing desktop during interrupted display! return FALSE; int retval = FALSE; -- cgit v1.2.3 From f5bc4926b8d0e40e290619f0c3ba177d87abf730 Mon Sep 17 00:00:00 2001 From: Tavmjong Bah Date: Thu, 18 Jun 2015 11:36:24 +0200 Subject: Enable column headers. Add tooltips to headers. (bzr r14204) --- src/ui/dialog/objects.cpp | 31 +++++++++++++++++++++++++++++-- src/ui/dialog/objects.h | 9 ++++++++- 2 files changed, 37 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/ui/dialog/objects.cpp b/src/ui/dialog/objects.cpp index 662cce6e1..835ecf35b 100644 --- a/src/ui/dialog/objects.cpp +++ b/src/ui/dialog/objects.cpp @@ -1614,6 +1614,12 @@ ObjectsPanel::ObjectsPanel() : _pending(0), _toggleEvent(0), _defer_target(), + _visibleHeader(_("V")), + _lockHeader(_("L")), + _typeHeader(_("T")), + _clipmaskHeader(_("CM")), + _highlightHeader(_("HL")), + _nameHeader(_("Label")), _composite_vbox(false, 0), _opacity_vbox(false, 0), _opacity_label(_("Opacity:")), @@ -1641,7 +1647,7 @@ ObjectsPanel::ObjectsPanel() : //Set up the tree _tree.set_model( _store ); - _tree.set_headers_visible(false); + _tree.set_headers_visible(true); _tree.set_reorderable(true); _tree.enable_model_drag_dest (Gdk::ACTION_MOVE); @@ -1654,6 +1660,10 @@ ObjectsPanel::ObjectsPanel() : Gtk::TreeViewColumn* col = _tree.get_column(visibleColNum); if ( col ) { col->add_attribute( eyeRenderer->property_active(), _model->_colVisible ); + // In order to get tooltips on header, we must create our own label. + _visibleHeader.set_tooltip_text(_("Toggle visibility of Layer, Group, or Object.")); + _visibleHeader.show(); + col->set_widget( _visibleHeader ); } //Locked @@ -1664,6 +1674,9 @@ ObjectsPanel::ObjectsPanel() : col = _tree.get_column(lockedColNum); if ( col ) { col->add_attribute( renderer->property_active(), _model->_colLocked ); + _lockHeader.set_tooltip_text(_("Toggle lock of Layer, Group, or Object.")); + _lockHeader.show(); + col->set_widget( _lockHeader ); } //Type @@ -1673,6 +1686,9 @@ ObjectsPanel::ObjectsPanel() : col = _tree.get_column(typeColNum); if ( col ) { col->add_attribute( typeRenderer->property_active(), _model->_colType ); + _typeHeader.set_tooltip_text(_("Type: Layer, Group, or Object. Clicking on Layer or Group icon, toggles between the two types.")); + _typeHeader.show(); + col->set_widget( _typeHeader ); } //Insert order (LiamW: unused) @@ -1689,6 +1705,9 @@ ObjectsPanel::ObjectsPanel() : col = _tree.get_column(clipColNum); if ( col ) { col->add_attribute( clipRenderer->property_active(), _model->_colClipMask ); + _clipmaskHeader.set_tooltip_text(_("Is object clipped and/or masked?")); + _clipmaskHeader.show(); + col->set_widget( _clipmaskHeader ); } //Highlight @@ -1697,13 +1716,21 @@ ObjectsPanel::ObjectsPanel() : col = _tree.get_column(highlightColNum); if ( col ) { col->add_attribute( highlightRenderer->property_active(), _model->_colHighlight ); + _highlightHeader.set_tooltip_text(_("Highlight color of outline in Node tool. Click to set. If alpha is zero, use inherited color.")); + _highlightHeader.show(); + col->set_widget( _highlightHeader ); } //Label _text_renderer = Gtk::manage(new Gtk::CellRendererText()); int nameColNum = _tree.append_column("Name", *_text_renderer) - 1; _name_column = _tree.get_column(nameColNum); - _name_column->add_attribute(_text_renderer->property_text(), _model->_colLabel); + if( _name_column ) { + _name_column->add_attribute(_text_renderer->property_text(), _model->_colLabel); + _nameHeader.set_tooltip_text(_("Layer/Group/Object label (inkscape:label). Double-click to set. Default value is object 'id'.")); + _nameHeader.show(); + _name_column->set_widget( _nameHeader ); + } //Set the expander and search columns _tree.set_expander_column( *_tree.get_column(nameColNum) ); diff --git a/src/ui/dialog/objects.h b/src/ui/dialog/objects.h index 7a826d02e..9b9a6025a 100644 --- a/src/ui/dialog/objects.h +++ b/src/ui/dialog/objects.h @@ -147,7 +147,14 @@ private: Gtk::Menu _popupMenu; Inkscape::UI::Widget::SpinButton _spinBtn; Gtk::VBox _page; - + + Gtk::Label _visibleHeader; + Gtk::Label _lockHeader; + Gtk::Label _typeHeader; + Gtk::Label _clipmaskHeader; + Gtk::Label _highlightHeader; + Gtk::Label _nameHeader; + /* Composite Settings */ Gtk::VBox _composite_vbox; Gtk::VBox _opacity_vbox; -- cgit v1.2.3 From 1219631edb93d78852679a695b904a01c3f8c2ff Mon Sep 17 00:00:00 2001 From: Nicolas Dufour Date: Thu, 18 Jun 2015 15:43:25 +0200 Subject: Spray Tool. Fixing boolean initialization and coding style issues. (bzr r14205) --- src/ui/tools/spray-tool.cpp | 6 +++--- src/ui/tools/spray-tool.h | 16 ++++++++-------- 2 files changed, 11 insertions(+), 11 deletions(-) (limited to 'src') diff --git a/src/ui/tools/spray-tool.cpp b/src/ui/tools/spray-tool.cpp index 26d74733a..e4b5addf8 100644 --- a/src/ui/tools/spray-tool.cpp +++ b/src/ui/tools/spray-tool.cpp @@ -133,8 +133,8 @@ SprayTool::SprayTool() : ToolBase(cursor_spray_xpm, 4, 4, false) , pressure(TC_DEFAULT_PRESSURE) , dragging(false) - , usepressure(0) - , usetilt(0) + , usepressure(false) + , usetilt(false) , usetext(false) , width(0.2) , ratio(0) @@ -542,7 +542,7 @@ static bool sp_spray_dilate(SprayTool *tc, Geom::Point /*event_p*/, Geom::Point double move_standard_deviation = get_move_standard_deviation(tc); { - std::vector const items(selection->itemList()); + std::vector const items(selection->itemList()); for(std::vector::const_iterator i=items.begin();i!=items.end();i++){ SPItem *item = *i; diff --git a/src/ui/tools/spray-tool.h b/src/ui/tools/spray-tool.h index 1a8f98006..fbcd57c8f 100644 --- a/src/ui/tools/spray-tool.h +++ b/src/ui/tools/spray-tool.h @@ -52,8 +52,8 @@ enum { class SprayTool : public ToolBase { public: - SprayTool(); - virtual ~SprayTool(); + SprayTool(); + virtual ~SprayTool(); //ToolBase event_context; //Inkscape::UI::Dialog::Dialog *dialog_option;//Attribut de type SprayOptionClass, localisé dans scr/ui/dialog @@ -90,16 +90,16 @@ public: sigc::connection style_set_connection; - static const std::string prefsPath; + static const std::string prefsPath; - virtual void setup(); - virtual void set(const Inkscape::Preferences::Entry& val); - virtual bool root_handler(GdkEvent* event); + virtual void setup(); + virtual void set(const Inkscape::Preferences::Entry& val); + virtual bool root_handler(GdkEvent* event); - virtual const std::string& getPrefsPath(); + virtual const std::string& getPrefsPath(); - void update_cursor(bool /*with_shift*/); + void update_cursor(bool /*with_shift*/); }; } -- cgit v1.2.3 From 9c5f676d93e36fa9c53fd97f62b178ca1b840969 Mon Sep 17 00:00:00 2001 From: Tavmjong Bah Date: Sun, 21 Jun 2015 22:12:09 +0200 Subject: Render font variants (ligatures, postions, caps, numerics). Requires Pango 1.37.1. (bzr r14206) --- src/libnrtype/Layout-TNG-Compute.cpp | 17 ++++++++++ src/style.cpp | 60 ++++++++++++++++++++++++++++++++++++ src/style.h | 6 ++++ 3 files changed, 83 insertions(+) (limited to 'src') diff --git a/src/libnrtype/Layout-TNG-Compute.cpp b/src/libnrtype/Layout-TNG-Compute.cpp index beff3734b..8c12f235c 100644 --- a/src/libnrtype/Layout-TNG-Compute.cpp +++ b/src/libnrtype/Layout-TNG-Compute.cpp @@ -958,6 +958,10 @@ void Layout::Calculator::ParagraphInfo::free() */ void Layout::Calculator::_buildPangoItemizationForPara(ParagraphInfo *para) const { + TRACE(("pango version string: %s\n", pango_version_string() )); +#if PANGO_VERSION_CHECK(1,37,1) + TRACE((" ... compiled for font features\n")); +#endif Glib::ustring para_text; PangoAttrList *attributes_list; unsigned input_index; @@ -986,9 +990,22 @@ void Layout::Calculator::_buildPangoItemizationForPara(ParagraphInfo *para) con PangoAttribute *attribute_font_description = pango_attr_font_desc_new(font->descr); attribute_font_description->start_index = para_text.bytes(); + +#if PANGO_VERSION_CHECK(1,37,1) + PangoAttribute *attribute_font_features = + pango_attr_font_features_new( text_source->style->getFontFeatureString().c_str()); +// pango_attr_font_features_new( "hlig 1, dlig 1"); + attribute_font_features->start_index = para_text.bytes(); +#endif para_text.append(&*text_source->text_begin.base(), text_source->text_length); // build the combined text attribute_font_description->end_index = para_text.bytes(); pango_attr_list_insert(attributes_list, attribute_font_description); + +#if PANGO_VERSION_CHECK(1,37,1) + attribute_font_features->end_index = para_text.bytes(); + pango_attr_list_insert(attributes_list, attribute_font_features); +#endif + // ownership of attribute is assumed by the list font->Unref(); } diff --git a/src/style.cpp b/src/style.cpp index 1668646b6..e7316525b 100644 --- a/src/style.cpp +++ b/src/style.cpp @@ -1190,6 +1190,66 @@ SPStyle::_mergeObjectStylesheet( SPObject const *const object ) { } } +std::string +SPStyle::getFontFeatureString() { + + std::string feature_string; + + if ( font_variant_ligatures.value & SP_CSS_FONT_VARIANT_LIGATURES_COMMON ) + feature_string += "liga, clig, "; + else + feature_string += "liga 0, clig 0, "; + if ( font_variant_ligatures.value & SP_CSS_FONT_VARIANT_LIGATURES_DISCRETIONARY ) + feature_string += "dlig, "; + if ( font_variant_ligatures.value & SP_CSS_FONT_VARIANT_LIGATURES_HISTORICAL ) + feature_string += "hlig, "; + if ( font_variant_ligatures.value & SP_CSS_FONT_VARIANT_LIGATURES_CONTEXTUAL ) + feature_string += "calt, "; + else + feature_string += "calt 0, "; + + if ( font_variant_position.value & SP_CSS_FONT_VARIANT_POSITION_SUB ) + feature_string += "subs, "; + if ( font_variant_position.value & SP_CSS_FONT_VARIANT_POSITION_SUPER ) + feature_string += "sups, "; + + if ( font_variant_caps.value & SP_CSS_FONT_VARIANT_CAPS_SMALL ) + feature_string += "smcp, "; + if ( font_variant_caps.value & SP_CSS_FONT_VARIANT_CAPS_ALL_SMALL ) + feature_string += "smcp, c2sc, "; + if ( font_variant_caps.value & SP_CSS_FONT_VARIANT_CAPS_PETITE ) + feature_string += "pcap, "; + if ( font_variant_caps.value & SP_CSS_FONT_VARIANT_CAPS_ALL_PETITE ) + feature_string += "pcap, c2pc, "; + if ( font_variant_caps.value & SP_CSS_FONT_VARIANT_CAPS_UNICASE ) + feature_string += "unic, "; + if ( font_variant_caps.value & SP_CSS_FONT_VARIANT_CAPS_TITLING ) + feature_string += "titl, "; + + if ( font_variant_numeric.value & SP_CSS_FONT_VARIANT_NUMERIC_LINING_NUMS ) + feature_string += "lnum, "; + if ( font_variant_numeric.value & SP_CSS_FONT_VARIANT_NUMERIC_OLDSTYLE_NUMS ) + feature_string += "onum, "; + if ( font_variant_numeric.value & SP_CSS_FONT_VARIANT_NUMERIC_PROPORTIONAL_NUMS ) + feature_string += "pnum, "; + if ( font_variant_numeric.value & SP_CSS_FONT_VARIANT_NUMERIC_TABULAR_NUMS ) + feature_string += "tnum, "; + if ( font_variant_numeric.value & SP_CSS_FONT_VARIANT_NUMERIC_DIAGONAL_FRACTIONS ) + feature_string += "frac, "; + if ( font_variant_numeric.value & SP_CSS_FONT_VARIANT_NUMERIC_STACKED_FRACTIONS ) + feature_string += "afrc, "; + if ( font_variant_numeric.value & SP_CSS_FONT_VARIANT_NUMERIC_ORDINAL ) + feature_string += "ordn, "; + if ( font_variant_numeric.value & SP_CSS_FONT_VARIANT_NUMERIC_SLASHED_ZERO ) + feature_string += "zero, "; + + feature_string.erase( feature_string.size() - 1 ); + feature_string.erase( feature_string.size() - 1 ); + + return feature_string; +} + + // Internal /** * Release callback. diff --git a/src/style.h b/src/style.h index 8e22b3121..02432d3e7 100644 --- a/src/style.h +++ b/src/style.h @@ -303,6 +303,12 @@ public: SPPaintServer *getStrokePaintServer() { return (stroke.value.href) ? stroke.value.href->getObject() : NULL; } SPPaintServer const *getStrokePaintServer() const { return (stroke.value.href) ? stroke.value.href->getObject() : NULL; } char const *getStrokeURI() const { return (stroke.value.href) ? stroke.value.href->getURI()->toString() : NULL; } + + /** + * Return a font feature string useful for Pango. + */ + std::string getFontFeatureString(); + }; SPStyle *sp_style_ref(SPStyle *style); // SPStyle::ref(); -- cgit v1.2.3 From dac19399d5e265506e00ea73d2e20fa3c17799a5 Mon Sep 17 00:00:00 2001 From: Tavmjong Bah Date: Mon, 22 Jun 2015 12:10:30 +0200 Subject: Enable rendering of 'font-feature-settings' and 'font-variant-east-asian'. Requires Pango version equal or greater than 1.37.1. (bzr r14207) --- src/libnrtype/Layout-TNG-Compute.cpp | 1 - src/style-enums.h | 22 ++++++++++--------- src/style-internal.h | 10 ++++----- src/style.cpp | 42 +++++++++++++++++++++++++++++------- 4 files changed, 51 insertions(+), 24 deletions(-) (limited to 'src') diff --git a/src/libnrtype/Layout-TNG-Compute.cpp b/src/libnrtype/Layout-TNG-Compute.cpp index 8c12f235c..d81e1b6b4 100644 --- a/src/libnrtype/Layout-TNG-Compute.cpp +++ b/src/libnrtype/Layout-TNG-Compute.cpp @@ -994,7 +994,6 @@ void Layout::Calculator::_buildPangoItemizationForPara(ParagraphInfo *para) con #if PANGO_VERSION_CHECK(1,37,1) PangoAttribute *attribute_font_features = pango_attr_font_features_new( text_source->style->getFontFeatureString().c_str()); -// pango_attr_font_features_new( "hlig 1, dlig 1"); attribute_font_features->start_index = para_text.bytes(); #endif para_text.append(&*text_source->text_begin.base(), text_source->text_length); // build the combined text diff --git a/src/style-enums.h b/src/style-enums.h index 29b8e2130..dfc99282c 100644 --- a/src/style-enums.h +++ b/src/style-enums.h @@ -115,6 +115,7 @@ enum SPCSSFontVariantNumeric { SP_CSS_FONT_VARIANT_NUMERIC_SLASHED_ZERO = 128 }; +// Quite complicated... (see spec) enum SPCSSFontVariantAlternates { SP_CSS_FONT_VARIANT_ALTERNATES_NORMAL, SP_CSS_FONT_VARIANT_ALTERNATES_HISTORICAL_FORMS, @@ -126,17 +127,18 @@ enum SPCSSFontVariantAlternates { SP_CSS_FONT_VARIANT_ALTERNATES_ANNOTATION }; +// Can select more than one (see spec) enum SPCSSFontVariantEastAsian { - SP_CSS_FONT_VARIANT_EAST_ASIAN_NORMAL, - SP_CSS_FONT_VARIANT_EAST_ASIAN_JIS78, - SP_CSS_FONT_VARIANT_EAST_ASIAN_JIS83, - SP_CSS_FONT_VARIANT_EAST_ASIAN_JIS90, - SP_CSS_FONT_VARIANT_EAST_ASIAN_JIS04, - SP_CSS_FONT_VARIANT_EAST_ASIAN_SIMPLIFIED, - SP_CSS_FONT_VARIANT_EAST_ASIAN_TRADITIONAL, - SP_CSS_FONT_VARIANT_EAST_ASIAN_FULL_WIDTH, - SP_CSS_FONT_VARIANT_EAST_ASIAN_PROPORTIONAL_WIDTH, - SP_CSS_FONT_VARIANT_EAST_ASIAN_RUBY + SP_CSS_FONT_VARIANT_EAST_ASIAN_NORMAL = 0, + SP_CSS_FONT_VARIANT_EAST_ASIAN_JIS78 = 1, + SP_CSS_FONT_VARIANT_EAST_ASIAN_JIS83 = 2, + SP_CSS_FONT_VARIANT_EAST_ASIAN_JIS90 = 4, + SP_CSS_FONT_VARIANT_EAST_ASIAN_JIS04 = 8, + SP_CSS_FONT_VARIANT_EAST_ASIAN_SIMPLIFIED = 16, + SP_CSS_FONT_VARIANT_EAST_ASIAN_TRADITIONAL = 32, + SP_CSS_FONT_VARIANT_EAST_ASIAN_FULL_WIDTH = 64, + SP_CSS_FONT_VARIANT_EAST_ASIAN_PROPORTIONAL_WIDTH = 128, + SP_CSS_FONT_VARIANT_EAST_ASIAN_RUBY = 256 }; enum SPCSSTextAlign { diff --git a/src/style-internal.h b/src/style-internal.h index bd2a92c8c..1ddab30f1 100644 --- a/src/style-internal.h +++ b/src/style-internal.h @@ -501,12 +501,12 @@ public: public: SPStyleEnum const *enums; - unsigned value : 8; - unsigned computed: 8; + unsigned value : 16; // 9 bits required for 'font-variant-east-asian' + unsigned computed: 16; private: - unsigned value_default : 8; - unsigned computed_default: 8; // for font-weight + unsigned value_default : 16; + unsigned computed_default: 16; // for font-weight }; @@ -546,7 +546,7 @@ public: {} SPILigatures( Glib::ustring const &name, SPStyleEnum const *enums) : - SPIEnum( name, enums, SP_CSS_FONT_VARIANT_NORMAL ) + SPIEnum( name, enums, SP_CSS_FONT_VARIANT_LIGATURES_NORMAL ) {} virtual ~SPILigatures() diff --git a/src/style.cpp b/src/style.cpp index e7316525b..d8402e08a 100644 --- a/src/style.cpp +++ b/src/style.cpp @@ -1195,17 +1195,13 @@ SPStyle::getFontFeatureString() { std::string feature_string; - if ( font_variant_ligatures.value & SP_CSS_FONT_VARIANT_LIGATURES_COMMON ) - feature_string += "liga, clig, "; - else + if ( !(font_variant_ligatures.value & SP_CSS_FONT_VARIANT_LIGATURES_COMMON) ) feature_string += "liga 0, clig 0, "; if ( font_variant_ligatures.value & SP_CSS_FONT_VARIANT_LIGATURES_DISCRETIONARY ) feature_string += "dlig, "; if ( font_variant_ligatures.value & SP_CSS_FONT_VARIANT_LIGATURES_HISTORICAL ) feature_string += "hlig, "; - if ( font_variant_ligatures.value & SP_CSS_FONT_VARIANT_LIGATURES_CONTEXTUAL ) - feature_string += "calt, "; - else + if ( !(font_variant_ligatures.value & SP_CSS_FONT_VARIANT_LIGATURES_CONTEXTUAL) ) feature_string += "calt 0, "; if ( font_variant_position.value & SP_CSS_FONT_VARIANT_POSITION_SUB ) @@ -1243,8 +1239,38 @@ SPStyle::getFontFeatureString() { if ( font_variant_numeric.value & SP_CSS_FONT_VARIANT_NUMERIC_SLASHED_ZERO ) feature_string += "zero, "; - feature_string.erase( feature_string.size() - 1 ); - feature_string.erase( feature_string.size() - 1 ); + if( font_variant_east_asian.value & SP_CSS_FONT_VARIANT_EAST_ASIAN_JIS78 ) + feature_string += "jp78, "; + if( font_variant_east_asian.value & SP_CSS_FONT_VARIANT_EAST_ASIAN_JIS83 ) + feature_string += "jp83, "; + if( font_variant_east_asian.value & SP_CSS_FONT_VARIANT_EAST_ASIAN_JIS90 ) + feature_string += "jp90, "; + if( font_variant_east_asian.value & SP_CSS_FONT_VARIANT_EAST_ASIAN_JIS04 ) + feature_string += "jp04, "; + if( font_variant_east_asian.value & SP_CSS_FONT_VARIANT_EAST_ASIAN_SIMPLIFIED ) + feature_string += "smpl, "; + if( font_variant_east_asian.value & SP_CSS_FONT_VARIANT_EAST_ASIAN_TRADITIONAL ) + feature_string += "trad, "; + if( font_variant_east_asian.value & SP_CSS_FONT_VARIANT_EAST_ASIAN_FULL_WIDTH ) + feature_string += "fwid, "; + if( font_variant_east_asian.value & SP_CSS_FONT_VARIANT_EAST_ASIAN_PROPORTIONAL_WIDTH ) + feature_string += "pwid, "; + if( font_variant_east_asian.value & SP_CSS_FONT_VARIANT_EAST_ASIAN_RUBY ) + feature_string += "ruby, "; + + if ( strcmp( font_feature_settings.value, "normal") ) { + // We do no sanity checking... + feature_string += font_feature_settings.value; + feature_string += ", "; + } + + if (feature_string.empty()) { + feature_string = "normal"; + } else { + // Remove last ", " + feature_string.erase( feature_string.size() - 1 ); + feature_string.erase( feature_string.size() - 1 ); + } return feature_string; } -- cgit v1.2.3 From 00a70f10f4c5c273a783f87f61e9d98b9d79deca Mon Sep 17 00:00:00 2001 From: Tavmjong Bah Date: Mon, 22 Jun 2015 16:13:38 +0200 Subject: Add simple GUI for 'font-feature-settings'. (bzr r14208) --- src/desktop-style.cpp | 61 ++++++++++++++++++++++++++++++++++++++++- src/desktop-style.h | 1 + src/ui/dialog/text-edit.cpp | 4 ++- src/ui/widget/font-variants.cpp | 46 ++++++++++++++++++++++++++++++- src/ui/widget/font-variants.h | 12 +++++++- 5 files changed, 120 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/desktop-style.cpp b/src/desktop-style.cpp index d2109c03c..02c18339b 100644 --- a/src/desktop-style.cpp +++ b/src/desktop-style.cpp @@ -1179,7 +1179,7 @@ objects_query_fontvariants (const std::vector &objects, SPStyle *style_ SPIEnum* position_res = &(style_res->font_variant_position); SPIEnum* caps_res = &(style_res->font_variant_caps); SPINumeric* numeric_res = &(style_res->font_variant_numeric); - + // Stores 'and' of all values ligatures_res->computed = SP_CSS_FONT_VARIANT_LIGATURES_NORMAL; position_res->computed = SP_CSS_FONT_VARIANT_POSITION_NORMAL; @@ -1256,6 +1256,63 @@ objects_query_fontvariants (const std::vector &objects, SPStyle *style_ } +int +objects_query_fontfeaturesettings (const std::vector &objects, SPStyle *style_res) +{ + bool different = false; + int texts = 0; + + if (style_res->font_feature_settings.value) { + g_free(style_res->font_feature_settings.value); + style_res->font_feature_settings.value = NULL; + } + style_res->font_feature_settings.set = FALSE; + + for (std::vector::const_iterator i = objects.begin(); i != objects.end(); i++) { + SPObject *obj = *i; + + // std::cout << " " << reinterpret_cast(i->data)->getId() << std::endl; + if (!isTextualItem(obj)) { + continue; + } + + SPStyle *style = obj->style; + if (!style) { + continue; + } + + texts ++; + + if (style_res->font_feature_settings.value && style->font_feature_settings.value && + strcmp (style_res->font_feature_settings.value, style->font_feature_settings.value)) { + different = true; // different fonts + } + + if (style_res->font_feature_settings.value) { + g_free(style_res->font_feature_settings.value); + style_res->font_feature_settings.value = NULL; + } + + style_res->font_feature_settings.set = TRUE; + style_res->font_feature_settings.value = g_strdup(style->font_feature_settings.value); + } + + if (texts == 0 || !style_res->font_feature_settings.set) { + return QUERY_STYLE_NOTHING; + } + + if (texts > 1) { + if (different) { + return QUERY_STYLE_MULTIPLE_DIFFERENT; + } else { + return QUERY_STYLE_MULTIPLE_SAME; + } + } else { + return QUERY_STYLE_SINGLE; + } +} + + /** * Write to style_res the baseline numbers. */ @@ -1667,6 +1724,8 @@ sp_desktop_query_style_from_list (const std::vector &list, SPStyle *sty return objects_query_fontstyle (list, style); } else if (property == QUERY_STYLE_PROPERTY_FONTVARIANTS) { return objects_query_fontvariants (list, style); + } else if (property == QUERY_STYLE_PROPERTY_FONTFEATURESETTINGS) { + return objects_query_fontfeaturesettings (list, style); } else if (property == QUERY_STYLE_PROPERTY_FONTNUMBERS) { return objects_query_fontnumbers (list, style); } else if (property == QUERY_STYLE_PROPERTY_BASELINES) { diff --git a/src/desktop-style.h b/src/desktop-style.h index e5fe50440..95c434844 100644 --- a/src/desktop-style.h +++ b/src/desktop-style.h @@ -48,6 +48,7 @@ enum { // which property was queried (add when you need more) QUERY_STYLE_PROPERTY_FONTFAMILY, // font-family QUERY_STYLE_PROPERTY_FONTSTYLE, // font style QUERY_STYLE_PROPERTY_FONTVARIANTS, // font variants (OpenType features) + QUERY_STYLE_PROPERTY_FONTFEATURESETTINGS, // font feature settings (OpenType features) QUERY_STYLE_PROPERTY_FONTNUMBERS, // size, spacings QUERY_STYLE_PROPERTY_BASELINES, // baseline-shift QUERY_STYLE_PROPERTY_MASTEROPACITY, // opacity diff --git a/src/ui/dialog/text-edit.cpp b/src/ui/dialog/text-edit.cpp index 1a696c820..b850b2453 100644 --- a/src/ui/dialog/text-edit.cpp +++ b/src/ui/dialog/text-edit.cpp @@ -391,7 +391,9 @@ void TextEdit::onReadSelection ( gboolean dostyle, gboolean /*docontent*/ ) // Update font variant widget //int result_variants = sp_desktop_query_style (SP_ACTIVE_DESKTOP, &query, QUERY_STYLE_PROPERTY_FONTVARIANTS); - vari_vbox.update( &query ); + int result_features = + sp_desktop_query_style (SP_ACTIVE_DESKTOP, &query, QUERY_STYLE_PROPERTY_FONTFEATURESETTINGS); + vari_vbox.update( &query, result_features == QUERY_STYLE_MULTIPLE_DIFFERENT ); } blocked = false; diff --git a/src/ui/widget/font-variants.cpp b/src/ui/widget/font-variants.cpp index 637631fda..7a1e02839 100644 --- a/src/ui/widget/font-variants.cpp +++ b/src/ui/widget/font-variants.cpp @@ -68,6 +68,9 @@ namespace Widget { _numeric_ordinal ( Glib::ustring(_("Ordinal" )) ), _numeric_slashed_zero ( Glib::ustring(_("Slashed Zero" )) ), + _feature_frame ( Glib::ustring(_("Feature Settings")) ), + _feature_label ( Glib::ustring(_("Selection has different Feature Settings!")) ), + _ligatures_changed( false ), _position_changed( false ), _caps_changed( false ), @@ -231,6 +234,21 @@ namespace Widget { add( _numeric_frame ); + // Feature settings --------------------- + + // Add tooltips + _feature_entry.set_tooltip_text( _("Feature settings in CSS form. No sanity checking is performed.")); + + // Add to frame + _feature_vbox.add( _feature_entry ); + _feature_vbox.add( _feature_label ); + _feature_frame.add( _feature_vbox ); + add( _feature_frame ); + + // Add signals + //_feature_entry.signal_key_press_event().connect ( sigc::mem_fun(*this, &FontVariants::feature_callback) ); + _feature_entry.signal_changed().connect( sigc::mem_fun(*this, &FontVariants::feature_callback) ); + show_all_children(); } @@ -283,9 +301,21 @@ namespace Widget { _changed_signal.emit(); } + void + FontVariants::feature_init() { + // std::cout << "FontVariants::feature_init()" << std::endl; + } + + void + FontVariants::feature_callback() { + // std::cout << "FontVariants::feature_callback()" << std::endl; + _feature_changed = true; + _changed_signal.emit(); + } + // Update GUI based on query. void - FontVariants::update( SPStyle const *query ) { + FontVariants::update( SPStyle const *query, bool different_features ) { _ligatures_all = query->font_variant_ligatures.computed; _ligatures_mix = query->font_variant_ligatures.value; @@ -370,10 +400,19 @@ namespace Widget { _numeric_ordinal.set_inconsistent( _numeric_mix & SP_CSS_FONT_VARIANT_NUMERIC_ORDINAL ); _numeric_slashed_zero.set_inconsistent( _numeric_mix & SP_CSS_FONT_VARIANT_NUMERIC_SLASHED_ZERO ); + if( query->font_feature_settings.value ) + _feature_entry.set_text( query->font_feature_settings.value ); + if( different_features ) { + _feature_label.show(); + } else { + _feature_label.hide(); + } + _ligatures_changed = false; _position_changed = false; _caps_changed = false; _numeric_changed = false; + _feature_changed = false; } void @@ -494,6 +533,11 @@ namespace Widget { sp_repr_css_set_property(css, "font-variant-numeric", css_string.c_str() ); } + // Feature settings + Glib::ustring feature_string = _feature_entry.get_text(); + if( !feature_string.empty() || feature_string.compare( "normal" ) ) { + sp_repr_css_set_property(css, "font-feature-settings", feature_string.c_str()); + } } } // namespace Widget diff --git a/src/ui/widget/font-variants.h b/src/ui/widget/font-variants.h index e6a9dd68b..ca41c050b 100644 --- a/src/ui/widget/font-variants.h +++ b/src/ui/widget/font-variants.h @@ -13,6 +13,7 @@ #include #include #include +#include class SPDesktop; class SPObject; @@ -81,6 +82,11 @@ protected: Gtk::CheckButton _numeric_ordinal; Gtk::CheckButton _numeric_slashed_zero; + Gtk::Expander _feature_frame; + Gtk::VBox _feature_vbox; + Gtk::Entry _feature_entry; + Gtk::Label _feature_label; + private: void ligatures_init(); void ligatures_callback(); @@ -94,6 +100,9 @@ private: void numeric_init(); void numeric_callback(); + void feature_init(); + void feature_callback(); + // To determine if we need to write out property (may not be necessary) unsigned _ligatures_all; unsigned _position_all; @@ -109,6 +118,7 @@ private: bool _position_changed; bool _caps_changed; bool _numeric_changed; + bool _feature_changed; sigc::signal _changed_signal; @@ -117,7 +127,7 @@ public: /** * Update GUI based on query results. */ - void update( SPStyle const *query ); + void update( SPStyle const *query, bool different_features ); /** * Fill SPCSSAttr based on settings of buttons. -- cgit v1.2.3 From 59d0b04b1ab9af5da2df93825580a071afa521bb Mon Sep 17 00:00:00 2001 From: Nicolas Dufour Date: Mon, 22 Jun 2015 21:16:52 +0200 Subject: Tracing. Fix for Bug #1456387 (Trace Bitmap: Multiscan > Brightness steps produces mostly black result). Fixed bugs: - https://launchpad.net/bugs/1456387 (bzr r14209) --- src/trace/potrace/inkscape-potrace.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/trace/potrace/inkscape-potrace.cpp b/src/trace/potrace/inkscape-potrace.cpp index e9e708f52..8f3bb7bdf 100644 --- a/src/trace/potrace/inkscape-potrace.cpp +++ b/src/trace/potrace/inkscape-potrace.cpp @@ -497,7 +497,7 @@ std::vector PotraceTracingEngine::traceBrightnessMulti(GdkP if ( !d.empty() ) { //### get style info int grayVal = (int)(256.0 * brightnessThreshold); - ustring style = ustring::compose("fill-opacity:1.0;fill:%1%2%3", twohex(grayVal), twohex(grayVal), twohex(grayVal) ); + ustring style = ustring::compose("fill-opacity:1.0;fill:#%1%2%3", twohex(grayVal), twohex(grayVal), twohex(grayVal) ); //g_message("### GOT '%s' \n", style.c_str()); TracingEngineResult result(style, d, nodeCount); -- cgit v1.2.3 From 8240bddfef0e1d7a3ba401948678afbd0e69f48e Mon Sep 17 00:00:00 2001 From: Nicolas Dufour Date: Mon, 22 Jun 2015 21:20:23 +0200 Subject: Spray. Fix for Bug #1459845 (Spray tool pressure sensitivity broken?). Fixed bugs: - https://launchpad.net/bugs/1459845 (bzr r14210) --- src/ui/tools/spray-tool.cpp | 47 +++++++++------------------------------------ src/ui/tools/spray-tool.h | 1 - 2 files changed, 9 insertions(+), 39 deletions(-) (limited to 'src') diff --git a/src/ui/tools/spray-tool.cpp b/src/ui/tools/spray-tool.cpp index e4b5addf8..14595740d 100644 --- a/src/ui/tools/spray-tool.cpp +++ b/src/ui/tools/spray-tool.cpp @@ -140,7 +140,6 @@ SprayTool::SprayTool() , ratio(0) , tilt(0) , rotation_variation(0) - , force(0.2) , population(0) , scale_variation(1) , scale(1) @@ -165,14 +164,6 @@ SprayTool::~SprayTool() { } } -static bool is_transform_modes(gint mode) -{ - return (mode == SPRAY_MODE_COPY || - mode == SPRAY_MODE_CLONE || - mode == SPRAY_MODE_SINGLE_PATH || - mode == SPRAY_OPTION); -} - void SprayTool::update_cursor(bool /*with_shift*/) { guint num = 0; gchar *sel_message = NULL; @@ -229,7 +220,6 @@ void SprayTool::setup() { sp_event_context_read(this, "scale_variation"); sp_event_context_read(this, "mode"); sp_event_context_read(this, "population"); - sp_event_context_read(this, "force"); sp_event_context_read(this, "mean"); sp_event_context_read(this, "standard_deviation"); sp_event_context_read(this, "usepressure"); @@ -271,9 +261,7 @@ void SprayTool::set(const Inkscape::Preferences::Entry& val) { this->tilt = CLAMP(val.getDouble(0.1), 0, 1000.0); } else if (path == "ratio") { this->ratio = CLAMP(val.getDouble(), 0.0, 0.9); - } else if (path == "force") { - this->force = CLAMP(val.getDouble(1.0), 0, 1.0); - } + } } static void sp_spray_extinput(SprayTool *tc, GdkEvent *event) @@ -290,16 +278,6 @@ static double get_dilate_radius(SprayTool *tc) return 250 * tc->width/SP_EVENT_CONTEXT(tc)->desktop->current_zoom(); } -static double get_path_force(SprayTool *tc) -{ - double force = 8 * (tc->usepressure? tc->pressure : TC_DEFAULT_PRESSURE) - /sqrt(SP_EVENT_CONTEXT(tc)->desktop->current_zoom()); - if (force > 3) { - force += 4 * (force - 3); - } - return force * tc->force; -} - static double get_path_mean(SprayTool *tc) { return tc->mean; @@ -310,10 +288,11 @@ static double get_path_standard_deviation(SprayTool *tc) return tc->standard_deviation; } -static double get_move_force(SprayTool *tc) +static double get_population(SprayTool *tc) { - double force = (tc->usepressure? tc->pressure : TC_DEFAULT_PRESSURE); - return force * tc->force; + double pressure = (tc->usepressure? tc->pressure / TC_DEFAULT_PRESSURE : 1); + //g_warning("Pressure, population: %f, %f", pressure, pressure * tc->population); + return pressure * tc->population; } static double get_move_mean(SprayTool *tc) @@ -361,7 +340,6 @@ static bool sp_spray_recursive(SPDesktop *desktop, Geom::Point /*vector*/, gint mode, double radius, - double /*force*/, double population, double &scale, double scale_variation, @@ -525,8 +503,8 @@ static bool sp_spray_dilate(SprayTool *tc, Geom::Point /*event_p*/, Geom::Point bool did = false; double radius = get_dilate_radius(tc); - double path_force = get_path_force(tc); - if (radius == 0 || path_force == 0) { + double population = get_population(tc); + if (radius == 0 || population == 0) { return false; } double path_mean = get_path_mean(tc); @@ -537,7 +515,6 @@ static bool sp_spray_dilate(SprayTool *tc, Geom::Point /*event_p*/, Geom::Point if (radius == 0 || path_standard_deviation == 0) { return false; } - double move_force = get_move_force(tc); double move_mean = get_move_mean(tc); double move_standard_deviation = get_move_standard_deviation(tc); @@ -554,14 +531,8 @@ static bool sp_spray_dilate(SprayTool *tc, Geom::Point /*event_p*/, Geom::Point SPItem *item = *i; g_assert(item != NULL); - if (is_transform_modes(tc->mode)) { - if (sp_spray_recursive(desktop, selection, item, p, vector, tc->mode, radius, move_force, tc->population, tc->scale, tc->scale_variation, reverse, move_mean, move_standard_deviation, tc->ratio, tc->tilt, tc->rotation_variation, tc->distrib)) { - did = true; - } - } else { - if (sp_spray_recursive(desktop, selection, item, p, vector, tc->mode, radius, path_force, tc->population, tc->scale, tc->scale_variation, reverse, path_mean, path_standard_deviation, tc->ratio, tc->tilt, tc->rotation_variation, tc->distrib)) { - did = true; - } + if (sp_spray_recursive(desktop, selection, item, p, vector, tc->mode, radius, population, tc->scale, tc->scale_variation, reverse, move_mean, move_standard_deviation, tc->ratio, tc->tilt, tc->rotation_variation, tc->distrib)) { + did = true; } } diff --git a/src/ui/tools/spray-tool.h b/src/ui/tools/spray-tool.h index fbcd57c8f..8df730201 100644 --- a/src/ui/tools/spray-tool.h +++ b/src/ui/tools/spray-tool.h @@ -70,7 +70,6 @@ public: double ratio; double tilt; double rotation_variation; - double force; double population; double scale_variation; double scale; -- cgit v1.2.3 From e64a5c1dfa1b373e7c25378d9a7180cc7a9688b7 Mon Sep 17 00:00:00 2001 From: Nicolas Dufour Date: Tue, 23 Jun 2015 07:26:16 +0200 Subject: Fix for bug #1467601 (Missing undo history label for metadata description). Fixed bugs: - https://launchpad.net/bugs/1467601 (bzr r14211) --- src/ui/widget/entity-entry.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'src') diff --git a/src/ui/widget/entity-entry.cpp b/src/ui/widget/entity-entry.cpp index 69173fa25..a8de2f384 100644 --- a/src/ui/widget/entity-entry.cpp +++ b/src/ui/widget/entity-entry.cpp @@ -188,8 +188,7 @@ EntityMultiLineEntry::on_changed() Gtk::TextView *tv = static_cast(s->get_child()); Glib::ustring text = tv->get_buffer()->get_text(); if (rdf_set_work_entity (doc, _entity, text.c_str())) { - DocumentUndo::done(doc, SP_VERB_NONE, - /* TODO: annotate */ "entity-entry.cpp:146"); + DocumentUndo::done(doc, SP_VERB_NONE, "Document metadata updated"); } _wr->setUpdating (false); } -- cgit v1.2.3 From b8dd2c422d830473e2d609dc1046c90cb51553b3 Mon Sep 17 00:00:00 2001 From: Nicolas Dufour Date: Tue, 23 Jun 2015 07:48:50 +0200 Subject: Libcroco. cr-fonts: Fix a bad copy/paste error (already fixed upstream). Fixed bugs: - https://launchpad.net/bugs/1434203 (bzr r14212) --- src/libcroco/cr-fonts.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/libcroco/cr-fonts.c b/src/libcroco/cr-fonts.c index 3c6896ffd..10f26c99c 100644 --- a/src/libcroco/cr-fonts.c +++ b/src/libcroco/cr-fonts.c @@ -768,7 +768,7 @@ cr_font_weight_get_bolder (enum CRFontWeight a_weight) } else if (a_weight < FONT_WEIGHT_NORMAL) { return FONT_WEIGHT_NORMAL ; } else if (a_weight == FONT_WEIGHT_BOLDER - || a_weight == FONT_WEIGHT_BOLDER) { + || a_weight == FONT_WEIGHT_LIGHTER) { cr_utils_trace_info ("FONT_WEIGHT_BOLDER or FONT_WEIGHT_LIGHTER should not appear here") ; return FONT_WEIGHT_NORMAL ; } else { -- cgit v1.2.3 From 1eaf9e7e7321f8d1ae98be9beb6afaa75a688dff Mon Sep 17 00:00:00 2001 From: Tavmjong Bah Date: Thu, 25 Jun 2015 13:46:43 +0200 Subject: Set sensitivty of font-variant buttons according to available OpenType tables. (bzr r14215) --- src/libnrtype/FontFactory.cpp | 88 +++++++++++++++++++++ src/libnrtype/font-instance.h | 5 ++ src/ui/dialog/text-edit.cpp | 2 +- src/ui/dialog/text-edit.h | 2 +- src/ui/widget/font-variants.cpp | 167 +++++++++++++++++++++++++++++++++++++++- src/ui/widget/font-variants.h | 2 +- 6 files changed, 261 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/libnrtype/FontFactory.cpp b/src/libnrtype/FontFactory.cpp index c8f5e1fef..65eb62dda 100644 --- a/src/libnrtype/FontFactory.cpp +++ b/src/libnrtype/FontFactory.cpp @@ -18,9 +18,11 @@ #include #include +#include #include "libnrtype/FontFactory.h" #include "libnrtype/font-instance.h" #include "util/unordered-containers.h" +#include typedef INK_UNORDERED_MAP FaceMapType; @@ -591,7 +593,23 @@ font_instance* font_factory::FaceFromFontSpecification(char const *fontSpecifica return font; } +void dump_tag( guint32 *tag, Glib::ustring prefix = "" ) { + std::cout << prefix + << ((char)((*tag & 0xff000000)>>24)) + << ((char)((*tag & 0x00ff0000)>>16)) + << ((char)((*tag & 0x0000ff00)>>8)) + << ((char)((*tag & 0x000000ff)>>0)) + << std::endl; +} +Glib::ustring extract_tag( guint32 *tag ) { + Glib::ustring tag_name; + tag_name += ((char)((*tag & 0xff000000)>>24)); + tag_name += ((char)((*tag & 0x00ff0000)>>16)); + tag_name += ((char)((*tag & 0x0000ff00)>>8)); + tag_name += ((char)((*tag & 0x000000ff)>>0)); + return tag_name; +} font_instance *font_factory::Face(PangoFontDescription *descr, bool canFail) { @@ -657,6 +675,76 @@ font_instance *font_factory::Face(PangoFontDescription *descr, bool canFail) pango_font_description_free(descr); } } + + // Extract which OpenType tables are in the font. We'll make a list of all tables + // regardless of which script and langauge they are in. These functions are deprecated but + // will eventually be replaced by newer functions (according to Behdad). + PangoOTInfo* info = pango_ot_info_get( res->theFace ); + + PangoOTTag* scripts = pango_ot_info_list_scripts( info, PANGO_OT_TABLE_GSUB ); + // std::cout << " scripts: " << std::endl; + for( unsigned i = 0; scripts[i] != 0; ++i ) { + // dump_tag( &scripts[i], " " ); + + guint script_index = -1; + if( pango_ot_info_find_script( info, PANGO_OT_TABLE_GSUB, scripts[i], &script_index )) { + + PangoOTTag* languages = + pango_ot_info_list_languages( info, PANGO_OT_TABLE_GSUB, script_index, NULL); + // if( languages[0] != 0 ) + // std::cout << " languages: " << std::endl; + + for( unsigned j = 0; languages[j] != 0; ++j ) { + // dump_tag( &languages[j], " lang: "); + + guint language_index = -1; + if( pango_ot_info_find_language(info, PANGO_OT_TABLE_GSUB, script_index, languages[j], &language_index, NULL)) { + + PangoOTTag* features = + pango_ot_info_list_features( info, PANGO_OT_TABLE_GSUB, 0, i, j ); + if( features[0] != 0 ) + // std::cout << " features: " << std::endl; + + for( unsigned k = 0; features[k] != 0; ++k ) { + // dump_tag( &features[k], " feature: "); + ++(res->openTypeTables[ extract_tag(&features[k])]); + } + g_free( features ); + } else { + // std::cout << " No languages defined" << std::endl; + PangoOTTag* features = + pango_ot_info_list_features( info, PANGO_OT_TABLE_GSUB, 0, i, PANGO_OT_DEFAULT_LANGUAGE ); + // if( features[0] != 0 ) + // std::cout << " default features: " << std::endl; + + for( unsigned k = 0; features[k] != 0; ++k ) { + // dump_tag( &features[k], " feature: " ); + ++(res->openTypeTables[ extract_tag(&features[k])]); + } + g_free( features ); + } + } + g_free( languages ); + } else { + // std::cout << " No scripts defined! " << std::endl; + } + } + g_free( scripts ); + + PangoOTTag* features = + pango_ot_info_list_features( info, PANGO_OT_TABLE_GSUB, 0, 0, PANGO_OT_DEFAULT_LANGUAGE ); + // if( features[0] != 0 ) + // std::cout << " DFTL DFTL features: " << std::endl; + for( unsigned i = 0; features[i] != 0; ++i ) { + // dump_tag( &features[i], " feature: " ); + ++(res->openTypeTables[ extract_tag(&features[i])]); + } + // std::map::iterator it; + // for( it = res->openTypeTables.begin(); it != res->openTypeTables.end(); ++it) { + // std::cout << "Table: " << it->first << " Occurances: " << it->second << std::endl; + // } + g_free( features ); + } else { // already here res = loadedFaces[descr]; diff --git a/src/libnrtype/font-instance.h b/src/libnrtype/font-instance.h index 2c7d1ce46..5a71e353b 100644 --- a/src/libnrtype/font-instance.h +++ b/src/libnrtype/font-instance.h @@ -36,6 +36,9 @@ public: int nbGlyph, maxGlyph; font_glyph* glyphs; + // Map of OpenType tables found in font (convert to std::set?) + std::map openTypeTables; + font_instance(void); virtual ~font_instance(void); @@ -68,6 +71,8 @@ public: private: void FreeTheFace(); + // Temp: make public +public: #ifdef USE_PANGO_WIN32 HFONT theFace; #else diff --git a/src/ui/dialog/text-edit.cpp b/src/ui/dialog/text-edit.cpp index b850b2453..7575cc854 100644 --- a/src/ui/dialog/text-edit.cpp +++ b/src/ui/dialog/text-edit.cpp @@ -393,7 +393,7 @@ void TextEdit::onReadSelection ( gboolean dostyle, gboolean /*docontent*/ ) sp_desktop_query_style (SP_ACTIVE_DESKTOP, &query, QUERY_STYLE_PROPERTY_FONTVARIANTS); int result_features = sp_desktop_query_style (SP_ACTIVE_DESKTOP, &query, QUERY_STYLE_PROPERTY_FONTFEATURESETTINGS); - vari_vbox.update( &query, result_features == QUERY_STYLE_MULTIPLE_DIFFERENT ); + vari_vbox.update( &query, result_features == QUERY_STYLE_MULTIPLE_DIFFERENT, fontspec ); } blocked = false; diff --git a/src/ui/dialog/text-edit.h b/src/ui/dialog/text-edit.h index 41f89b3e7..cfe612268 100644 --- a/src/ui/dialog/text-edit.h +++ b/src/ui/dialog/text-edit.h @@ -36,7 +36,7 @@ class SPItem; struct SPFontSelector; -class FontVariants; +//class FontVariants; class font_instance; class SPCSSAttr; diff --git a/src/ui/widget/font-variants.cpp b/src/ui/widget/font-variants.cpp index 7a1e02839..5d1e40971 100644 --- a/src/ui/widget/font-variants.cpp +++ b/src/ui/widget/font-variants.cpp @@ -13,7 +13,7 @@ #include #include - +#include #include #include "font-variants.h" @@ -315,7 +315,7 @@ namespace Widget { // Update GUI based on query. void - FontVariants::update( SPStyle const *query, bool different_features ) { + FontVariants::update( SPStyle const *query, bool different_features, Glib::ustring& font_spec ) { _ligatures_all = query->font_variant_ligatures.computed; _ligatures_mix = query->font_variant_ligatures.value; @@ -408,6 +408,169 @@ namespace Widget { _feature_label.hide(); } + + // Disable/Enable based on available OpenType tables. + font_instance* res = font_factory::Default()->FaceFromFontSpecification( font_spec.c_str() ); + if( res ) { + + std::map::iterator it; + + if((it = res->openTypeTables.find("liga"))!= res->openTypeTables.end() || + (it = res->openTypeTables.find("clig"))!= res->openTypeTables.end()) { + _ligatures_common.set_sensitive(); + } else { + _ligatures_common.set_sensitive( false ); + } + + if((it = res->openTypeTables.find("dlig"))!= res->openTypeTables.end()) { + _ligatures_discretionary.set_sensitive(); + } else { + _ligatures_discretionary.set_sensitive( false ); + } + + if((it = res->openTypeTables.find("hlig"))!= res->openTypeTables.end()) { + _ligatures_historical.set_sensitive(); + } else { + _ligatures_historical.set_sensitive( false ); + } + + if((it = res->openTypeTables.find("calt"))!= res->openTypeTables.end()) { + _ligatures_contextual.set_sensitive(); + } else { + _ligatures_contextual.set_sensitive( false ); + } + + if((it = res->openTypeTables.find("subs"))!= res->openTypeTables.end()) { + _position_sub.set_sensitive(); + } else { + _position_sub.set_sensitive( false ); + } + + if((it = res->openTypeTables.find("sups"))!= res->openTypeTables.end()) { + _position_super.set_sensitive(); + } else { + _position_super.set_sensitive( false ); + } + + if((it = res->openTypeTables.find("smcp"))!= res->openTypeTables.end()) { + _caps_small.set_sensitive(); + } else { + _caps_small.set_sensitive( false ); + } + + if((it = res->openTypeTables.find("c2sc"))!= res->openTypeTables.end() && + (it = res->openTypeTables.find("smcp"))!= res->openTypeTables.end()) { + _caps_all_small.set_sensitive(); + } else { + _caps_all_small.set_sensitive( false ); + } + + if((it = res->openTypeTables.find("pcap"))!= res->openTypeTables.end()) { + _caps_petite.set_sensitive(); + } else { + _caps_petite.set_sensitive( false ); + } + + if((it = res->openTypeTables.find("c2sc"))!= res->openTypeTables.end() && + (it = res->openTypeTables.find("pcap"))!= res->openTypeTables.end()) { + _caps_all_petite.set_sensitive(); + } else { + _caps_all_petite.set_sensitive( false ); + } + + if((it = res->openTypeTables.find("unic"))!= res->openTypeTables.end()) { + _caps_unicase.set_sensitive(); + } else { + _caps_unicase.set_sensitive( false ); + } + + if((it = res->openTypeTables.find("titl"))!= res->openTypeTables.end()) { + _caps_titling.set_sensitive(); + } else { + _caps_titling.set_sensitive( false ); + } + + if((it = res->openTypeTables.find("lnum"))!= res->openTypeTables.end()) { + _numeric_lining.set_sensitive(); + } else { + _numeric_lining.set_sensitive( false ); + } + + if((it = res->openTypeTables.find("onum"))!= res->openTypeTables.end()) { + _numeric_old_style.set_sensitive(); + } else { + _numeric_old_style.set_sensitive( false ); + } + + if((it = res->openTypeTables.find("pnum"))!= res->openTypeTables.end()) { + _numeric_proportional.set_sensitive(); + } else { + _numeric_proportional.set_sensitive( false ); + } + + if((it = res->openTypeTables.find("tnum"))!= res->openTypeTables.end()) { + _numeric_tabular.set_sensitive(); + } else { + _numeric_tabular.set_sensitive( false ); + } + + if((it = res->openTypeTables.find("frac"))!= res->openTypeTables.end()) { + _numeric_diagonal.set_sensitive(); + } else { + _numeric_diagonal.set_sensitive( false ); + } + + if((it = res->openTypeTables.find("afrac"))!= res->openTypeTables.end()) { + _numeric_stacked.set_sensitive(); + } else { + _numeric_stacked.set_sensitive( false ); + } + + if((it = res->openTypeTables.find("ordn"))!= res->openTypeTables.end()) { + _numeric_ordinal.set_sensitive(); + } else { + _numeric_ordinal.set_sensitive( false ); + } + + if((it = res->openTypeTables.find("zero"))!= res->openTypeTables.end()) { + _numeric_slashed_zero.set_sensitive(); + } else { + _numeric_slashed_zero.set_sensitive( false ); + } + + // Make list of tables not handled above... eventually add Gtk::Label with + // this info. + // std::map table_copy = res->openTypeTables; + // if( (it = table_copy.find("liga")) != table_copy.end() ) table_copy.erase( it ); + // if( (it = table_copy.find("clig")) != table_copy.end() ) table_copy.erase( it ); + // if( (it = table_copy.find("dlig")) != table_copy.end() ) table_copy.erase( it ); + // if( (it = table_copy.find("hlig")) != table_copy.end() ) table_copy.erase( it ); + // if( (it = table_copy.find("calt")) != table_copy.end() ) table_copy.erase( it ); + // if( (it = table_copy.find("subs")) != table_copy.end() ) table_copy.erase( it ); + // if( (it = table_copy.find("sups")) != table_copy.end() ) table_copy.erase( it ); + // if( (it = table_copy.find("smcp")) != table_copy.end() ) table_copy.erase( it ); + // if( (it = table_copy.find("c2sc")) != table_copy.end() ) table_copy.erase( it ); + // if( (it = table_copy.find("pcap")) != table_copy.end() ) table_copy.erase( it ); + // if( (it = table_copy.find("unic")) != table_copy.end() ) table_copy.erase( it ); + // if( (it = table_copy.find("titl")) != table_copy.end() ) table_copy.erase( it ); + // if( (it = table_copy.find("lnum")) != table_copy.end() ) table_copy.erase( it ); + // if( (it = table_copy.find("onum")) != table_copy.end() ) table_copy.erase( it ); + // if( (it = table_copy.find("pnum")) != table_copy.end() ) table_copy.erase( it ); + // if( (it = table_copy.find("tnum")) != table_copy.end() ) table_copy.erase( it ); + // if( (it = table_copy.find("frac")) != table_copy.end() ) table_copy.erase( it ); + // if( (it = table_copy.find("afrc")) != table_copy.end() ) table_copy.erase( it ); + // if( (it = table_copy.find("ordn")) != table_copy.end() ) table_copy.erase( it ); + // if( (it = table_copy.find("zero")) != table_copy.end() ) table_copy.erase( it ); + // for(it = table_copy.begin(); it != table_copy.end(); ++it) { + // std::cout << "Other: " << it->first << " Occurances: " << it->second << std::endl; + // } + + } else { + std::cerr << "FontVariants::update(): Couldn't find font_instance for: " + << font_spec << std::endl; + } + + _ligatures_changed = false; _position_changed = false; _caps_changed = false; diff --git a/src/ui/widget/font-variants.h b/src/ui/widget/font-variants.h index ca41c050b..d4329feff 100644 --- a/src/ui/widget/font-variants.h +++ b/src/ui/widget/font-variants.h @@ -127,7 +127,7 @@ public: /** * Update GUI based on query results. */ - void update( SPStyle const *query, bool different_features ); + void update( SPStyle const *query, bool different_features, Glib::ustring& font_spec ); /** * Fill SPCSSAttr based on settings of buttons. -- cgit v1.2.3 From f914c2572f0e73cba795fb11047cfed056e06616 Mon Sep 17 00:00:00 2001 From: Jabier Arraiza Cenoz Date: Thu, 25 Jun 2015 18:08:54 +0200 Subject: Fix for the bug 1468396 Fixed bugs: - https://launchpad.net/bugs/1468396 (bzr r14217) --- src/live_effects/parameter/filletchamferpointarray.cpp | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'src') diff --git a/src/live_effects/parameter/filletchamferpointarray.cpp b/src/live_effects/parameter/filletchamferpointarray.cpp index 10ded4d9f..c469b5fdd 100644 --- a/src/live_effects/parameter/filletchamferpointarray.cpp +++ b/src/live_effects/parameter/filletchamferpointarray.cpp @@ -491,6 +491,13 @@ std::vector FilletChamferPointArrayParam::get_times(int index, std::vect curve_it1 = subpaths[positions.first][positions.second].duplicate(); Coord it1_length = (*curve_it1).length(tolerance); double time_it1, time_it2, time_it1_B, intpart; + if(_vector.size() <= index){ + std::vector out; + out.push_back(0); + out.push_back(1); + out.push_back(0); + return out; + } time_it1 = modf(to_time(index, _vector[index][X]), &intpart); if (_vector[index][Y] == 0) { time_it1 = 0; -- cgit v1.2.3 From d0da2f213e02d94a8aec40a51a3db32919e9c8e0 Mon Sep 17 00:00:00 2001 From: Jabier Arraiza Cenoz Date: Thu, 25 Jun 2015 18:49:51 +0200 Subject: Improve Tips for BSpline mode (bzr r14218) --- src/ui/tool/curve-drag-point.cpp | 9 +++++++++ src/ui/tool/node.cpp | 5 +++-- 2 files changed, 12 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/ui/tool/curve-drag-point.cpp b/src/ui/tool/curve-drag-point.cpp index d1756fa2c..e460b0fb7 100644 --- a/src/ui/tool/curve-drag-point.cpp +++ b/src/ui/tool/curve-drag-point.cpp @@ -187,6 +187,10 @@ Glib::ustring CurveDragPoint::_getTip(unsigned state) const if (_pm.empty()) return ""; if (!first || !first.next()) return ""; bool linear = first->front()->isDegenerate() && first.next()->back()->isDegenerate(); + if(state_held_shift(state) && _pm._isBSpline()){ + return C_("Path segment tip", + "Shift: drag to open or move BSpline handles"); + } if (state_held_shift(state)) { return C_("Path segment tip", "Shift: click to toggle segment selection"); @@ -195,6 +199,11 @@ Glib::ustring CurveDragPoint::_getTip(unsigned state) const return C_("Path segment tip", "Ctrl+Alt: click to insert a node"); } + if(_pm._isBSpline()){ + return C_("Path segment tip", + "BSpline segment: drag to shape the segment, doubleclick to insert node, " + "click to select (more: Shift, Ctrl+Alt)"); + } if (linear) { return C_("Path segment tip", "Linear segment: drag to convert to a Bezier segment, " diff --git a/src/ui/tool/node.cpp b/src/ui/tool/node.cpp index aa5365265..ef4439242 100644 --- a/src/ui/tool/node.cpp +++ b/src/ui/tool/node.cpp @@ -1464,13 +1464,14 @@ Glib::ustring Node::_getTip(unsigned state) const // No modifiers: assemble tip from node type char const *nodetype = node_type_to_localized_string(_type); + double power = _pm()._bsplineHandlePosition(h,h2); if (_selection.transformHandlesEnabled() && selected()) { if (_selection.size() == 1 && !isBSpline) { return format_tip(C_("Path node tip", "%s: drag to shape the path (more: Shift, Ctrl, Alt)"), nodetype); }else if(_selection.size() == 1){ return format_tip(C_("Path node tip", - "BSpline node: drag to shape the path (more: Shift, Ctrl, Alt). %g power"),_pm()._bsplineHandlePosition(h,h2)); + "BSpline node: drag to shape the path (more: Shift, Ctrl, Alt). %g power"), power); } return format_tip(C_("Path node tip", "%s: drag to shape the path, click to toggle scale/rotation handles (more: Shift, Ctrl, Alt)"), nodetype); @@ -1480,7 +1481,7 @@ Glib::ustring Node::_getTip(unsigned state) const "%s: drag to shape the path, click to select only this node (more: Shift, Ctrl, Alt)"), nodetype); }else{ return format_tip(C_("Path node tip", - "BSpline node: drag to shape the path, click to select only this node (more: Shift, Ctrl, Alt). %g power"),_pm()._bsplineHandlePosition(h,h2)); + "BSpline node: drag to shape the path, click to select only this node (more: Shift, Ctrl, Alt). %g power"), power); } } -- cgit v1.2.3 From d798a62d8347d3191aac351eb7ebef44d9fa64a3 Mon Sep 17 00:00:00 2001 From: Jabier Arraiza Cenoz Date: Thu, 25 Jun 2015 19:52:51 +0200 Subject: Fix for the bug 1468396. Fix the new bug noticed by su_v Fixed bugs: - https://launchpad.net/bugs/1468396 (bzr r14219) --- src/live_effects/parameter/filletchamferpointarray.cpp | 3 +++ 1 file changed, 3 insertions(+) (limited to 'src') diff --git a/src/live_effects/parameter/filletchamferpointarray.cpp b/src/live_effects/parameter/filletchamferpointarray.cpp index c469b5fdd..43352507e 100644 --- a/src/live_effects/parameter/filletchamferpointarray.cpp +++ b/src/live_effects/parameter/filletchamferpointarray.cpp @@ -270,6 +270,9 @@ void FilletChamferPointArrayParam::recalculate_knots( Piecewise > const &pwd2_in) { bool change = false; + if(_vector.size() == 0){ + return; + } PathVector pathv = path_from_piecewise(pwd2_in, 0.001); if (!pathv.empty()) { std::vector result; -- cgit v1.2.3 From 0735cfb906cbfcff254979e99219af75ab0864cc Mon Sep 17 00:00:00 2001 From: jtx Date: Fri, 26 Jun 2015 14:07:24 +0200 Subject: Improve hidding helper path when show outline toogle is on (bzr r14220) --- src/live_effects/lpe-bspline.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/live_effects/lpe-bspline.cpp b/src/live_effects/lpe-bspline.cpp index ecbfef76a..99e2a55fd 100644 --- a/src/live_effects/lpe-bspline.cpp +++ b/src/live_effects/lpe-bspline.cpp @@ -9,6 +9,7 @@ #include "sp-path.h" #include "svg/svg.h" #include "xml/repr.h" +#include "preferences.h" // TODO due to internal breakage in glibmm headers, this must be last: #include @@ -43,7 +44,7 @@ LPEBSpline::LPEBSpline(LivePathEffectObject *lpeobject) steps.param_set_digits(0); helper_size.param_set_range(0.0, 999.0); - helper_size.param_set_increments(5, 5); + helper_size.param_set_increments(1, 1); helper_size.param_set_digits(2); } @@ -76,13 +77,15 @@ void LPEBSpline::doEffect(SPCurve *curve) Geom::PathVector const original_pathv = curve->get_pathvector(); curve->reset(); - + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); for (Geom::PathVector::const_iterator path_it = original_pathv.begin(); path_it != original_pathv.end(); ++path_it) { if (path_it->empty()) { continue; } - hp.push_back(*path_it); + if (!prefs->getBool("/tools/nodes/show_outline", true)){ + hp.push_back(*path_it); + } Geom::Path::const_iterator curve_it1 = path_it->begin(); Geom::Path::const_iterator curve_it2 = ++(path_it->begin()); Geom::Path::const_iterator curve_endit = path_it->end_default(); -- cgit v1.2.3 From a84cc2b2c9b39de293fd0dcba672a7df27be27e3 Mon Sep 17 00:00:00 2001 From: Nicolas Dufour Date: Tue, 30 Jun 2015 10:22:54 +0200 Subject: Templates. Fix for Bug #1402182 (Crash with color widget used in procedural template). Fixed bugs: - https://launchpad.net/bugs/1402182 (bzr r14223) --- src/extension/param/color.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/extension/param/color.cpp b/src/extension/param/color.cpp index 3162e8a40..0b58c5011 100644 --- a/src/extension/param/color.cpp +++ b/src/extension/param/color.cpp @@ -86,9 +86,11 @@ Gtk::Widget *ParamColor::get_widget( SPDocument * /*doc*/, Inkscape::XML::Node * { using Inkscape::UI::Widget::ColorNotebook; - if (_gui_hidden) return NULL; + if (_gui_hidden) return NULL; - _changeSignal = new sigc::signal(*changeSignal); + if (changeSignal) { + _changeSignal = new sigc::signal(*changeSignal); + } if (_color.value() < 1) { _color_changed.block(true); -- cgit v1.2.3 From 3210252c229616a45cdd5c6dcd6ae9860f8627dc Mon Sep 17 00:00:00 2001 From: tavmjong-free <> Date: Tue, 30 Jun 2015 10:40:02 +0200 Subject: Preferences. Fix for Bug #1459944 (self-intersecting shape display and union error). Fixed bugs: - https://launchpad.net/bugs/1459944 (bzr r14224) --- src/preferences-skeleton.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/preferences-skeleton.h b/src/preferences-skeleton.h index 66a3e47d4..f4a08b928 100644 --- a/src/preferences-skeleton.h +++ b/src/preferences-skeleton.h @@ -95,7 +95,7 @@ static char const preferences_skeleton[] = " \n" " \n" " \n" -" \n" " \n" -- cgit v1.2.3 From 60437ac397d41678daba5daece227240e8ddd364 Mon Sep 17 00:00:00 2001 From: Krzysztof Kosi??ski Date: Sat, 4 Jul 2015 17:25:59 +0200 Subject: Upgrade to 2Geom r2413 (bzr r14059.2.18) --- src/2geom/affine.cpp | 88 ++++++--------- src/2geom/angle.h | 232 ++++++++++++++++++++++----------------- src/2geom/bezier-curve.h | 17 ++- src/2geom/circle.cpp | 8 +- src/2geom/circle.h | 11 +- src/2geom/concepts.h | 17 ++- src/2geom/conicsec.cpp | 35 ------ src/2geom/conicsec.h | 9 +- src/2geom/coord.cpp | 4 +- src/2geom/coord.h | 71 ++++++------ src/2geom/curve.h | 12 +- src/2geom/d2.h | 34 +++--- src/2geom/ellipse.cpp | 37 ++++++- src/2geom/ellipse.h | 10 ++ src/2geom/elliptical-arc.cpp | 185 +++++++++++++++---------------- src/2geom/elliptical-arc.h | 185 +++++++++++++++++++------------ src/2geom/intersection-graph.cpp | 137 ++++++++++++++++------- src/2geom/intersection-graph.h | 75 ++++++++----- src/2geom/intersection.h | 12 ++ src/2geom/line.cpp | 38 +++++-- src/2geom/line.h | 26 +++-- src/2geom/linear.h | 2 +- src/2geom/path.cpp | 25 ++--- src/2geom/path.h | 26 ++++- src/2geom/pathvector.h | 5 + src/2geom/piecewise.h | 6 +- src/2geom/polynomial.cpp | 12 +- src/2geom/polynomial.h | 2 + src/2geom/sbasis-curve.h | 3 +- src/2geom/sbasis-math.cpp | 4 +- src/2geom/sweeper.h | 40 ++++++- src/2geom/transforms.h | 2 + 32 files changed, 817 insertions(+), 553 deletions(-) (limited to 'src') diff --git a/src/2geom/affine.cpp b/src/2geom/affine.cpp index e9ca5748e..48179e864 100644 --- a/src/2geom/affine.cpp +++ b/src/2geom/affine.cpp @@ -6,9 +6,10 @@ * This code is in public domain */ -#include <2geom/utils.h> #include <2geom/affine.h> #include <2geom/point.h> +#include <2geom/polynomial.h> +#include <2geom/utils.h> namespace Geom { @@ -36,8 +37,7 @@ Point Affine::yAxis() const { return Point(_c[2], _c[3]); } -/** Gets the translation imparted by the Affine. - */ +/// Gets the translation imparted by the Affine. Point Affine::translation() const { return Point(_c[4], _c[5]); } @@ -52,8 +52,7 @@ void Affine::setYAxis(Point const &vec) { _c[i + 2] = vec[i]; } -/** Sets the translation imparted by the Affine. - */ +/// Sets the translation imparted by the Affine. void Affine::setTranslation(Point const &loc) { for(int i = 0; i < 2; i++) _c[i + 4] = loc[i]; @@ -61,33 +60,35 @@ void Affine::setTranslation(Point const &loc) { /** Calculates the amount of x-scaling imparted by the Affine. This is the scaling applied to * the original x-axis region. It is \emph{not} the overall x-scaling of the transformation. - * Equivalent to L2(m.xAxis()) - */ + * Equivalent to L2(m.xAxis()). */ double Affine::expansionX() const { return sqrt(_c[0] * _c[0] + _c[1] * _c[1]); } /** Calculates the amount of y-scaling imparted by the Affine. This is the scaling applied before * the other transformations. It is \emph{not} the overall y-scaling of the transformation. - * Equivalent to L2(m.yAxis()) - */ + * Equivalent to L2(m.yAxis()). */ double Affine::expansionY() const { return sqrt(_c[2] * _c[2] + _c[3] * _c[3]); } void Affine::setExpansionX(double val) { double exp_x = expansionX(); - if(!are_near(exp_x, 0.0)) { //TODO: best way to deal with it is to skip op? + if (exp_x != 0.0) { //TODO: best way to deal with it is to skip op? double coef = val / expansionX(); - for(unsigned i=0;i<2;i++) _c[i] *= coef; + for (unsigned i = 0; i < 2; ++i) { + _c[i] *= coef; + } } } void Affine::setExpansionY(double val) { double exp_y = expansionY(); - if(!are_near(exp_y, 0.0)) { //TODO: best way to deal with it is to skip op? + if (exp_y != 0.0) { //TODO: best way to deal with it is to skip op? double coef = val / expansionY(); - for(unsigned i=2; i<4; i++) _c[i] *= coef; + for (unsigned i = 2; i < 4; ++i) { + _c[i] *= coef; + } } } @@ -468,55 +469,38 @@ Affine elliptic_quadratic_form(Affine const &m) { Eigen::Eigen(Affine const &m) { double const B = -m[0] - m[3]; double const C = m[0]*m[3] - m[1]*m[2]; - double const center = -B/2.0; - double const delta = sqrt(B*B-4*C)/2.0; - values[0] = center + delta; values[1] = center - delta; - for (int i = 0; i < 2; i++) { - vectors[i] = unit_vector(rot90(Point(m[0]-values[i], m[1]))); - } -} -static void quadratic_roots(const double q0, const double q1, const double q2, int &n, double&r0, double&r1) { - if(q2 == 0) { - if(q1 == 0) { // zero or infinite roots - n = 0; - } else { - n = 1; - r0 = -q0/q1; - } - } else { - double desc = q1*q1 - 4*q2*q0; - if (desc < 0) - n = 0; - else if (desc == 0) { - n = 1; - r0 = -q1/(2*q2); - } else { - n = 2; - desc = std::sqrt(desc); - double t = -0.5*(q1+sgn(q1)*desc); - r0 = t/q2; - r1 = q0/t; - } + std::vector v = solve_quadratic(1, B, C); + + for (unsigned i = 0; i < v.size(); ++i) { + values[i] = v[i]; + vectors[i] = unit_vector(rot90(Point(m[0] - values[i], m[1]))); + } + for (unsigned i = v.size(); i < 2; ++i) { + values[i] = 0; + vectors[i] = Point(0,0); } } Eigen::Eigen(double m[2][2]) { double const B = -m[0][0] - m[1][1]; double const C = m[0][0]*m[1][1] - m[1][0]*m[0][1]; - //double const desc = B*B-4*C; - //double t = -0.5*(B+sgn(B)*desc); - int n; - values[0] = values[1] = 0; - quadratic_roots(C, B, 1, n, values[0], values[1]); - for (int i = 0; i < n; i++) - vectors[i] = unit_vector(rot90(Point(m[0][0]-values[i], m[0][1]))); - for (int i = n; i < 2; i++) + + std::vector v = solve_quadratic(1, B, C); + + for (unsigned i = 0; i < v.size(); ++i) { + values[i] = v[i]; + vectors[i] = unit_vector(rot90(Point(m[0][0] - values[i], m[0][1]))); + } + for (unsigned i = v.size(); i < 2; ++i) { + values[i] = 0; vectors[i] = Point(0,0); + } } -/** @brief Nearness predicate for affine transforms - * @returns True if all entries of matrices are within eps of each other */ +/** @brief Nearness predicate for affine transforms. + * @returns True if all entries of matrices are within eps of each other. + * @relates Affine */ bool are_near(Affine const &a, Affine const &b, Coord eps) { return are_near(a[0], b[0], eps) && are_near(a[1], b[1], eps) && diff --git a/src/2geom/angle.h b/src/2geom/angle.h index 9ece3b9fe..af4442e88 100644 --- a/src/2geom/angle.h +++ b/src/2geom/angle.h @@ -59,6 +59,9 @@ namespace Geom { * to double is in the range \f$[-\pi, \pi)\f$ - the convention used by C's * math library. * + * This class holds only a single floating point value, so passing it by value will generally + * be faster than passing it by const reference. + * * @ingroup Primitives */ class Angle @@ -74,12 +77,12 @@ public: explicit Angle(Point const &p) : _angle(atan2(p)) { _normalize(); } Angle(Point const &a, Point const &b) : _angle(angle_between(a, b)) { _normalize(); } operator Coord() const { return radians(); } - Angle &operator+=(Angle const &o) { + Angle &operator+=(Angle o) { _angle += o._angle; _normalize(); return *this; } - Angle &operator-=(Angle const &o) { + Angle &operator-=(Angle o) { _angle -= o._angle; _normalize(); return *this; @@ -92,7 +95,7 @@ public: *this -= Angle(a); return *this; } - bool operator==(Angle const &o) const { + bool operator==(Angle o) const { return _angle == o._angle; } bool operator==(Coord c) const { @@ -174,36 +177,112 @@ inline Angle distance(Angle const &a, Angle const &b) { * the end angle for 1, and interpolate linearly for other values. Note that such functions * are not continuous if the interval crosses the angle \f$\pi\f$. * - * It is currently not possible to represent the full angle with this class. - * If you specify the same start and end angle, the interval will be treated as empty - * except for that value. - * - * This class is immutable - you cannot change the values of start and end angles - * without creating a new instance of this class. + * This class can represent all directed angular intervals, including empty ones. + * However, not all possible intervals can be created with the constructors. + * For full control, use the setInitial(), setFinal() and setAngles() methods. * * @ingroup Primitives */ -class AngleInterval { +class AngleInterval + : boost::equality_comparable< AngleInterval > +{ public: - /** @brief Create an angular interval. + AngleInterval() {} + /** @brief Create an angular interval from two angles and direction. + * If the initial and final angle are the same, a degenerate interval + * (containing only one angle) will be created. * @param s Starting angle * @param e Ending angle * @param cw Which direction the interval goes. True means that it goes * in the direction of increasing angles, while false means in the direction * of decreasing angles. */ - AngleInterval(Angle const &s, Angle const &e, bool cw = false) - : _start_angle(s), _end_angle(e), _sweep(cw) + AngleInterval(Angle s, Angle e, bool cw = false) + : _start_angle(s), _end_angle(e), _sweep(cw), _full(false) {} AngleInterval(double s, double e, bool cw = false) - : _start_angle(s), _end_angle(e), _sweep(cw) + : _start_angle(s), _end_angle(e), _sweep(cw), _full(false) {} + /** @brief Create an angular interval from three angles. + * If the inner angle is exactly equal to initial or final angle, + * the sweep flag will be set to true, i.e. the interval will go + * in the direction of increasing angles. + * + * If the initial and final angle are the same, but the inner angle + * is different, a full angle in the direction of increasing angles + * will be created. + * + * @param s Initial angle + * @param inner Angle contained in the interval + * @param e Final angle */ + AngleInterval(Angle s, Angle inner, Angle e) + : _start_angle(s) + , _end_angle(e) + , _sweep((inner-s).radians0() <= (e-s).radians0()) + , _full(s == e && s != inner) + { + if (_full) { + _sweep = true; + } + } /// Get the start angle. - Angle const &initialAngle() const { return _start_angle; } + Angle initialAngle() const { return _start_angle; } /// Get the end angle. - Angle const &finalAngle() const { return _end_angle; } + Angle finalAngle() const { return _end_angle; } + /// Check whether the interval goes in the direction of increasing angles. + bool sweep() const { return _sweep; } /// Check whether the interval contains only a single angle. - bool isDegenerate() const { return initialAngle() == finalAngle(); } + bool isDegenerate() const { + return _start_angle == _end_angle && !_full; + } + /// Check whether the interval contains all angles. + bool isFull() const { + return _start_angle == _end_angle && _full; + } + + /** @brief Set the initial angle. + * @param a Angle to set + * @param prefer_full Whether to set a full angular interval when + * the initial angle is set to the final angle */ + void setInitial(Angle a, bool prefer_full = false) { + _start_angle = a; + _full = prefer_full && a == _end_angle; + } + + /** @brief Set the final angle. + * @param a Angle to set + * @param prefer_full Whether to set a full angular interval when + * the initial angle is set to the final angle */ + void setFinal(Angle a, bool prefer_full = false) { + _end_angle = a; + _full = prefer_full && a == _start_angle; + } + /** @brief Set both angles at once. + * The direction (sweep flag) is left unchanged. + * @param s Initial angle + * @param e Final angle + * @param prefer_full Whether to set a full interval when the passed + * initial and final angle are the same */ + void setAngles(Angle s, Angle e, bool prefer_full = false) { + _start_angle = s; + _end_angle = e; + _full = prefer_full && s == e; + } + /// Set whether the interval goes in the direction of increasing angles. + void setSweep(bool s) { _sweep = s; } + + /// Reverse the direction of the interval while keeping contained values the same. + void reverse() { + using std::swap; + swap(_start_angle, _end_angle); + _sweep = !_sweep; + } + /// Get a new interval with reversed direction. + AngleInterval reversed() const { + AngleInterval result(*this); + result.reverse(); + return result; + } /// Get an angle corresponding to the specified time value. Angle angleAt(Coord t) const { @@ -214,8 +293,14 @@ public: Angle operator()(Coord t) const { return angleAt(t); } /** @brief Compute a time value that would evaluate to the given angle. - * If the start and end angle are exactly the same, NaN will be returned. */ - Coord timeAtAngle(Angle const &a) const { + * If the start and end angle are exactly the same, NaN will be returned. + * Negative values will be returned for angles between the initial angle + * and the angle exactly opposite the midpoint of the interval. */ + Coord timeAtAngle(Angle a) const { + if (_full) { + Angle ta = _sweep ? a - _start_angle : _start_angle - a; + return ta.radians0() / (2*M_PI); + } Coord ex = extent(); Coord outex = 2*M_PI - ex; if (_sweep) { @@ -237,8 +322,9 @@ public: } } - /** @brief Check whether the interval includes the given angle. */ - bool contains(Angle const &a) const { + /// Check whether the interval includes the given angle. + bool contains(Angle a) const { + if (_full) return true; Coord s = _start_angle.radians0(); Coord e = _end_angle.radians0(); Coord x = a.radians0(); @@ -254,6 +340,7 @@ public: * Equivalent to the absolute value of the sweep angle. * @return Extent in range \f$[0, 2\pi)\f$. */ Coord extent() const { + if (_full) return 2*M_PI; return _sweep ? (_end_angle - _start_angle).radians0() : (_start_angle - _end_angle).radians0(); @@ -263,16 +350,35 @@ public: * It is positive when sweep is true. Denoted as \f$\Delta\theta\f$ in the SVG * elliptical arc implementation notes. */ Coord sweepAngle() const { + if (_full) return _sweep ? 2*M_PI : -2*M_PI; Coord sa = _end_angle.radians0() - _start_angle.radians0(); if (_sweep && sa < 0) sa += 2*M_PI; if (!_sweep && sa > 0) sa -= 2*M_PI; return sa; } -protected: - AngleInterval() {} + + /// Check another interval for equality. + bool operator==(AngleInterval const &other) const { + if (_start_angle != other._start_angle) return false; + if (_end_angle != other._end_angle) return false; + if (_sweep != other._sweep) return false; + if (_full != other._full) return false; + return true; + } + + static AngleInterval create_full(Angle start, bool sweep = true) { + AngleInterval result; + result._start_angle = result._end_angle = start; + result._sweep = sweep; + result._full = true; + return result; + } + +private: Angle _start_angle; Angle _end_angle; bool _sweep; + bool _full; }; /** @brief Given an angle in degrees, return radians @@ -282,86 +388,6 @@ inline Coord deg_to_rad(Coord deg) { return deg*M_PI/180.0;} * @relates Angle */ inline Coord rad_to_deg(Coord rad) { return rad*180.0/M_PI;} -/* - * start_angle and angle must belong to [0, 2PI[ - * and angle must belong to the cirsular arc defined by - * start_angle, end_angle and with rotation direction cw - */ -inline -double map_circular_arc_on_unit_interval( double angle, double start_angle, double end_angle, bool cw = true ) -{ - double d = end_angle - start_angle; - double t = angle - start_angle; - if ( !cw ) - { - d = -d; - t = -t; - } - d = std::fmod(d, 2*M_PI); - t = std::fmod(t, 2*M_PI); - if ( d < 0 ) d += 2*M_PI; - if ( t < 0 ) t += 2*M_PI; - return t / d; -} - -inline -Coord map_unit_interval_on_circular_arc(Coord t, double start_angle, double end_angle, bool cw = true) -{ - double sweep_angle = end_angle - start_angle; - if ( !cw ) sweep_angle = -sweep_angle; - sweep_angle = std::fmod(sweep_angle, 2*M_PI); - if ( sweep_angle < 0 ) sweep_angle += 2*M_PI; - - Coord angle = start_angle; - if ( cw ) - { - angle += sweep_angle * t; - } - else - { - angle -= sweep_angle * t; - } - angle = std::fmod(angle, 2*M_PI); - if (angle < 0) angle += 2*M_PI; - return angle; -} - -/* - * Return true if the given angle is contained in the circular arc determined - * by the passed angles. - * - * a: the angle to be tested - * sa: the angle the arc start from - * ia: an angle strictly inner to the arc - * ea: the angle the arc end to - * - * prerequisite: the inner angle has to be not equal (mod 2PI) to the start - * or the end angle, except when they are equal each other, too. - * warning: when sa == ea (mod 2PI) they define a whole circle - * if ia != sa (mod 2PI), on the contrary if ia == sa == ea (mod 2PI) - * they define a single point. - */ -inline -bool arc_contains (double a, double sa, double ia, double ea) -{ - a -= sa; - a = std::fmod(a, 2*M_PI); - if (a < 0) a += 2*M_PI; - ia -= sa; - ia = std::fmod(ia, 2*M_PI); - if (ia < 0) ia += 2*M_PI; - ea -= sa; - ea = std::fmod(ea, 2*M_PI); - if (ea < 0) ea += 2*M_PI; - - if (ia == 0 && ea == 0) return (a == 0); - if (ia == 0 || ia == ea) - { - THROW_RANGEERROR ("arc_contains: passed angles do not define an arc"); - } - return (ia < ea && a <= ea) || (ia > ea && (a >= ea || a == 0)); -} - } // end namespace Geom namespace std { diff --git a/src/2geom/bezier-curve.h b/src/2geom/bezier-curve.h index 636a263a7..9ac4d7b4d 100644 --- a/src/2geom/bezier-curve.h +++ b/src/2geom/bezier-curve.h @@ -129,8 +129,21 @@ public: return new BezierCurve(Geom::reverse(inner)); } - virtual void transform(Affine const &m) { - for (unsigned i = 0; i < size(); ++i) { + using Curve::operator*=; + virtual void operator*=(Translate const &tr) { + for (unsigned i = 0; i < size(); ++i) { + inner[X][i] += tr[X]; + inner[Y][i] += tr[Y]; + } + } + virtual void operator*=(Scale const &s) { + for (unsigned i = 0; i < size(); ++i) { + inner[X][i] *= s[X]; + inner[Y][i] *= s[Y]; + } + } + virtual void operator*=(Affine const &m) { + for (unsigned i = 0; i < size(); ++i) { setPoint(i, controlPoint(i) * m); } } diff --git a/src/2geom/circle.cpp b/src/2geom/circle.cpp index ec59bbe4a..553981a72 100644 --- a/src/2geom/circle.cpp +++ b/src/2geom/circle.cpp @@ -101,6 +101,12 @@ Zoom Circle::inverseUnitCircleTransform() const return ret; } +Point Circle::initialPoint() const +{ + Point p(_center); + p[X] += _radius; + return p; +} Point Circle::pointAt(Coord t) const { return _center + Point::polar(t) * _radius; @@ -112,11 +118,11 @@ Coord Circle::valueAt(Coord t, Dim2 d) const { } Coord Circle::timeAt(Point const &p) const { + if (_center == p) return 0; return atan2(p - _center); } Coord Circle::nearestTime(Point const &p) const { - if (_center == p) return 0; return timeAt(p); } diff --git a/src/2geom/circle.h b/src/2geom/circle.h index c42cb7f80..a4d5f2097 100644 --- a/src/2geom/circle.h +++ b/src/2geom/circle.h @@ -76,6 +76,7 @@ public: Coord center(Dim2 d) const { return _center[d]; } Coord radius() const { return _radius; } Coord area() const { return M_PI * _radius * _radius; } + bool isDegenerate() const { return _radius == 0; } void setCenter(Point const &p) { _center = p; } void setRadius(Coord c) { _radius = c; } @@ -83,6 +84,8 @@ public: Rect boundsFast() const; Rect boundsExact() const { return boundsFast(); } + Point initialPoint() const; + Point finalPoint() const { return initialPoint(); } Point pointAt(Coord t) const; Coord valueAt(Coord t, Dim2 d) const; Coord timeAt(Point const &p) const; @@ -138,7 +141,13 @@ bool are_near(Circle const &a, Circle const &b, Coord eps=EPSILON); std::ostream &operator<<(std::ostream &out, Circle const &c); -//bool are_near(Circle const &a, Circle const &b, Coord eps = EPSILON); +template <> +struct ShapeTraits { + typedef Coord TimeType; + typedef Interval IntervalType; + typedef Ellipse AffineClosureType; + typedef Intersection<> IntersectionType; +}; } // end namespace Geom diff --git a/src/2geom/concepts.h b/src/2geom/concepts.h index 7bc1bc0fd..c331f078b 100644 --- a/src/2geom/concepts.h +++ b/src/2geom/concepts.h @@ -39,6 +39,7 @@ #include #include #include <2geom/forward.h> +#include <2geom/transforms.h> namespace Geom { @@ -82,8 +83,8 @@ struct FragmentConcept { o = t.valueAt(d); o = t(d); v = t.valueAndDerivatives(d, u-1); - //Is a pure derivative (ignoring others) accessor ever much faster? - //u = number of values returned. first val is value. + //Is a pure derivative (ignoring others) accessor ever much faster? + //u = number of values returned. first val is value. sb = t.toSBasis(); t = reverse(t); i = bounds_fast(t); @@ -104,26 +105,30 @@ struct ShapeConcept { typedef typename ShapeTraits::TimeType Time; typedef typename ShapeTraits::IntervalType Interval; typedef typename ShapeTraits::AffineClosureType AffineClosure; - //typedef typename ShapeTraits::IntersectionType Isect; + typedef typename ShapeTraits::IntersectionType Isect; - T shape; + T shape, other; Time t; Point p; AffineClosure ac; Affine m; + Translate tr; Coord c; bool bool_; + std::vector ivec; void constraints() { p = shape.pointAt(t); c = shape.valueAt(t, X); - //ivec = shape.intersect(other); + ivec = shape.intersect(other); t = shape.nearestTime(p); + shape *= tr; ac = shape; ac *= m; bool_ = (shape == shape); - bool_ = (shape != shape); + bool_ = (shape != other); bool_ = shape.isDegenerate(); + //bool_ = are_near(shape, other, c); } }; diff --git a/src/2geom/conicsec.cpp b/src/2geom/conicsec.cpp index 889797de3..3b36137be 100644 --- a/src/2geom/conicsec.cpp +++ b/src/2geom/conicsec.cpp @@ -80,41 +80,6 @@ static double boxprod(Point a, Point b, Point c) { return det(a,b) - det(a,c) + det(b,c); } - -/** - * Find the roots of (q2x + q1)x+q0 = 0 - * Tries to be numerically robust. - */ -template -static std::vector quadratic_roots(T q0, T q1, T q2) { - std::vector r; - if(q2 == 0) { - if(q1 == 0) { // zero or infinite roots - return r; - } - r.push_back(-q0/q1); - } else { - double desc = q1*q1 - 4*q2*q0; - /*cout << q2 << ", " - << q1 << ", " - << q0 << "; " - << desc << "\n";*/ - if (desc < 0) - return r; - else if (desc == 0) - r.push_back(-q1/(2*q2)); - else { - desc = std::sqrt(desc); - double t = -0.5*(q1+sgn(q1)*desc); - r.push_back(t/q2); - r.push_back(q0/t); - } - } - return r; -} - - - class BadConversion : public std::runtime_error { public: BadConversion(const std::string& s) diff --git a/src/2geom/conicsec.h b/src/2geom/conicsec.h index e9c466978..dbe564872 100644 --- a/src/2geom/conicsec.h +++ b/src/2geom/conicsec.h @@ -462,13 +462,8 @@ public: bool arc_contains (const Point & _point, const Point & _initial, const Point & _inner, const Point & _final) const { - double pa = angle_at (_point); - double sa = angle_at (_initial); - double ia = angle_at (_inner); - double ea = angle_at (_final); - // we test if _point and _inner have the same position - // wrt _initial and _final - return Geom::arc_contains (pa, sa, ia, ea); + AngleInterval ai(angle_at(_initial), angle_at(_inner), angle_at(_final)); + return ai.contains(angle_at(_point)); } Rect arc_bound (const Point & P1, const Point & Q, const Point & P2) const; diff --git a/src/2geom/coord.cpp b/src/2geom/coord.cpp index 9ee8066f2..8b5e28586 100644 --- a/src/2geom/coord.cpp +++ b/src/2geom/coord.cpp @@ -3656,7 +3656,7 @@ std::string format_coord_nice(Coord x) { static DoubleToStringConverter conv( DoubleToStringConverter::UNIQUE_ZERO, - "Inf", "NaN", 'e', -6, 21, 0, 0); + "inf", "NaN", 'e', -6, 21, 0, 0); std::string ret; ret.reserve(32); conv.ToShortest(x, ret); @@ -3669,7 +3669,7 @@ Coord parse_coord(std::string const &s) StringToDoubleConverter::ALLOW_LEADING_SPACES | StringToDoubleConverter::ALLOW_TRAILING_SPACES | StringToDoubleConverter::ALLOW_SPACES_AFTER_SIGN, - 0.0, nan(""), "Inf", "NaN"); + 0.0, nan(""), "inf", "NaN"); int dummy; return conv.StringToDouble(s.c_str(), s.length(), &dummy); } diff --git a/src/2geom/coord.h b/src/2geom/coord.h index 416e6443d..9cc220db7 100644 --- a/src/2geom/coord.h +++ b/src/2geom/coord.h @@ -1,7 +1,10 @@ /** @file * @brief Integral and real coordinate types and some basic utilities *//* - * Copyright 2006 Nathan Hurst + * Authors: + * Nathan Hurst + * Krzysztof Kosiński + * Copyright 2006-2015 Authors * * This library is free software; you can redistribute it and/or * modify it either under the terms of the GNU Lesser General Public @@ -40,10 +43,12 @@ namespace Geom { -/// 2D axis enumeration (X or Y). +/** @brief 2D axis enumeration (X or Y). + * @ingroup Primitives */ enum Dim2 { X=0, Y=1 }; -/// Get the other (perpendicular) dimension. +/** @brief Get the other (perpendicular) dimension. + * @ingroup Primitives */ inline Dim2 other_dimension(Dim2 d) { return d == Y ? X : Y; } // TODO: make a smarter implementation with C++11 @@ -54,47 +59,48 @@ struct D2Traits { typedef typename T::D1ConstReference D1ConstReference; }; -// for use with things such as transform_iterator -template -struct GetX { - typedef typename D2Traits::D1Value result_type; - typedef T argument_type; - typename D2Traits::D1Value operator()(T const &a) const { - return a[X]; - } -}; -template -struct GetY { +/** @brief Axis extraction functor. + * For use with things such as Boost's transform_iterator. + * @ingroup Utilities */ +template +struct GetAxis { typedef typename D2Traits::D1Value result_type; typedef T argument_type; typename D2Traits::D1Value operator()(T const &a) const { - return a[Y]; + return a[D]; } }; -/** - * @brief Floating point type used to store coordinates. - * - * You may safely assume that double (or even float) provides enough precision for storing - * on-canvas points, and hence that double provides enough precision for dot products of - * differences of on-canvas points. - */ +/** @brief Floating point type used to store coordinates. + * @ingroup Primitives */ typedef double Coord; + +/** @brief Type used for integral coordinates. + * @ingroup Primitives */ typedef int IntCoord; -const Coord EPSILON = 1e-5; //1e-18; +/** @brief Default "acceptably small" value. + * @ingroup Primitives */ +const Coord EPSILON = 1e-6; //1e-18; +/** @brief Get a value representing infinity. + * @ingroup Primitives */ inline Coord infinity() { return std::numeric_limits::infinity(); } -//IMPL: NearConcept +/** @brief Nearness predicate for values. + * @ingroup Primitives */ inline bool are_near(Coord a, Coord b, double eps=EPSILON) { return a-b <= eps && a-b >= -eps; } inline bool rel_error_bound(Coord a, Coord b, double eps=EPSILON) { return a <= eps*b && a >= -eps*b; } -/// Numerically stable linear interpolation. +/** @brief Numerically stable linear interpolation. + * @ingroup Primitives */ inline Coord lerp(Coord t, Coord a, Coord b) { return (1 - t) * a + t * b; } +/** @brief Traits class used with coordinate types. + * Defines point, interval and rectangle types for the given coordinate type. + * @ingroup Utilities */ template struct CoordTraits { typedef D2 PointType; @@ -174,19 +180,22 @@ struct CoordTraits { RectOps; }; -/** @brief Convert coordinate to shortest possible string - * @return The shortest string that parses back to the original value. */ +/** @brief Convert coordinate to shortest possible string. + * @return The shortest string that parses back to the original value. + * @relates Coord */ std::string format_coord_shortest(Coord x); -/** @brief Convert coordinate to human-readable string +/** @brief Convert coordinate to human-readable string. * Unlike format_coord_shortest, this function will not omit a leading zero * before a decimal point or use small negative exponents. The output format - * is similar to Javascript functions. */ + * is similar to Javascript functions. + * @relates Coord */ std::string format_coord_nice(Coord x); -/** @brief Parse coordinate string +/** @brief Parse coordinate string. * When using this function in conjunction with format_coord_shortest() - * or format_coord_nice(), the value is guaranteed to be preserved exactly. */ + * or format_coord_nice(), the value is guaranteed to be preserved exactly. + * @relates Coord */ Coord parse_coord(std::string const &s); } // end namespace Geom diff --git a/src/2geom/curve.h b/src/2geom/curve.h index 7da0d17a0..abbdb1100 100644 --- a/src/2geom/curve.h +++ b/src/2geom/curve.h @@ -184,7 +184,17 @@ public: * Because of this method, all curve types must be closed under affine * transformations. * @param m Affine describing the affine transformation */ - virtual void transform(Affine const &m) = 0; + void transform(Affine const &m) { + *this *= m; + } + + virtual void operator*=(Translate const &tr) { *this *= Affine(tr); } + virtual void operator*=(Scale const &s) { *this *= Affine(s); } + virtual void operator*=(Rotate const &r) { *this *= Affine(r); } + virtual void operator*=(HShear const &hs) { *this *= Affine(hs); } + virtual void operator*=(VShear const &vs) { *this *= Affine(vs); } + virtual void operator*=(Zoom const &z) { *this *= Affine(z); } + virtual void operator*=(Affine const &m) = 0; /** @brief Create a curve transformed by an affine transformation. * This method returns a new curve instead modifying the existing one. diff --git a/src/2geom/d2.h b/src/2geom/d2.h index bf764539d..dca6fa614 100644 --- a/src/2geom/d2.h +++ b/src/2geom/d2.h @@ -43,20 +43,16 @@ namespace Geom { /** - * The D2 class takes two instances of a scalar data type and treats them - * like a point. All operations which make sense on a point are defined for D2. - * A D2 is a Point. A D2 is a standard axis aligned rectangle. - * D2 provides a 2d parametric function which maps t to a point - * x(t), y(t) + * @brief Adaptor that creates 2D functions from 1D ones. + * @ingroup Fragments */ -template -class D2{ - //BOOST_CLASS_REQUIRE(T, boost, AssignableConcept); - private: +template +class D2 +{ +private: T f[2]; - public: - +public: typedef T D1Value; typedef T &D1Reference; typedef T const &D1ConstReference; @@ -74,24 +70,24 @@ class D2{ template D2(Iter first, Iter last) { typedef typename std::iterator_traits::value_type V; - typedef typename boost::transform_iterator, Iter> XIter; - typedef typename boost::transform_iterator, Iter> YIter; + typedef typename boost::transform_iterator, Iter> XIter; + typedef typename boost::transform_iterator, Iter> YIter; - XIter xfirst(first, GetX()), xlast(last, GetX()); + XIter xfirst(first, GetAxis()), xlast(last, GetAxis()); f[X] = T(xfirst, xlast); - YIter yfirst(first, GetY()), ylast(last, GetY()); + YIter yfirst(first, GetAxis()), ylast(last, GetAxis()); f[Y] = T(yfirst, ylast); } D2(std::vector const &vec) { typedef Point V; typedef std::vector::const_iterator Iter; - typedef boost::transform_iterator, Iter> XIter; - typedef boost::transform_iterator, Iter> YIter; + typedef boost::transform_iterator, Iter> XIter; + typedef boost::transform_iterator, Iter> YIter; - XIter xfirst(vec.begin(), GetX()), xlast(vec.end(), GetX()); + XIter xfirst(vec.begin(), GetAxis()), xlast(vec.end(), GetAxis()); f[X] = T(xfirst, xlast); - YIter yfirst(vec.begin(), GetY()), ylast(vec.end(), GetY()); + YIter yfirst(vec.begin(), GetAxis()), ylast(vec.end(), GetAxis()); f[Y] = T(yfirst, ylast); } diff --git a/src/2geom/ellipse.cpp b/src/2geom/ellipse.cpp index 46c60d85d..0264ab4ae 100644 --- a/src/2geom/ellipse.cpp +++ b/src/2geom/ellipse.cpp @@ -97,6 +97,14 @@ void Ellipse::setCoefficients(double A, double B, double C, double D, double E, makeCanonical(); } +Point Ellipse::initialPoint() const +{ + Coord sinrot, cosrot; + sincos(_angle, sinrot, cosrot); + Point p(ray(X) * cosrot + center(X), ray(X) * sinrot + center(Y)); + return p; +} + Affine Ellipse::unitCircleTransform() const { @@ -299,8 +307,19 @@ Point Ellipse::pointAt(Coord t) const Coord Ellipse::valueAt(Coord t, Dim2 d) const { - // TODO: more efficient version. - return pointAt(t)[d]; + Coord sinrot, cosrot, cost, sint; + sincos(rotationAngle(), sinrot, cosrot); + sincos(t, sint, cost); + + if ( d == X ) { + return ray(X) * cosrot * cost + - ray(Y) * sinrot * sint + + center(X); + } else { + return ray(X) * sinrot * cost + + ray(Y) * cosrot * sint + + center(Y); + } } Coord Ellipse::timeAt(Point const &p) const @@ -319,6 +338,20 @@ Coord Ellipse::timeAt(Point const &p) const return Angle(atan2(p * iuct)).radians0(); // return a value in [0, 2pi) } +Point Ellipse::unitTangentAt(Coord t) const +{ + Point p = Point::polar(t + M_PI/2); + p *= unitCircleTransform().withoutTranslation(); + p.normalize(); + return p; +} + +bool Ellipse::contains(Point const &p) const +{ + Point tp = p * inverseUnitCircleTransform(); + return tp.length() <= 1; +} + std::vector Ellipse::intersect(Line const &line) const { diff --git a/src/2geom/ellipse.h b/src/2geom/ellipse.h index 6fb5ed254..4b1701cce 100644 --- a/src/2geom/ellipse.h +++ b/src/2geom/ellipse.h @@ -124,6 +124,10 @@ public: Coord ray(Dim2 d) const { return _rays[d]; } /// Get the angle the X ray makes with the +X axis. Angle rotationAngle() const { return _angle; } + /// Get the point corresponding to the +X ray of the ellipse. + Point initialPoint() const; + /// Get the point corresponding to the +X ray of the ellipse. + Point finalPoint() const { return initialPoint(); } /** @brief Create an ellipse passing through the specified points * At least five points have to be specified. */ @@ -184,6 +188,12 @@ public: * with the ellipse. Note that this is NOT the nearest point on the ellipse. */ Coord timeAt(Point const &p) const; + /// Get the value of the derivative at time t normalized to unit length. + Point unitTangentAt(Coord t) const; + + /// Check whether the ellipse contains the given point. + bool contains(Point const &p) const; + /// Compute intersections with an infinite line. std::vector intersect(Line const &line) const; /// Compute intersections with a line segment. diff --git a/src/2geom/elliptical-arc.cpp b/src/2geom/elliptical-arc.cpp index a04b730b3..25a78b4ad 100644 --- a/src/2geom/elliptical-arc.cpp +++ b/src/2geom/elliptical-arc.cpp @@ -83,9 +83,11 @@ namespace Geom * and the ellipse's rotation. Each set of those parameters corresponds to four different arcs, * with two of them larger than half an ellipse and two of them turning clockwise while traveling * from initial to final point. The two flags disambiguate between them: "large arc flag" selects - * the bigger arc, while the "sweep flag" selects the clockwise arc. + * the bigger arc, while the "sweep flag" selects the arc going in the direction of positive + * angles. Angles always increase when going from the +X axis in the direction of the +Y axis, + * so if Y grows downwards, this means clockwise. * - * @image html elliptical-arc-flags.png "The four possible arcs and the meaning of flags" + * @image html elliptical-arc-flags.png "Meaning of arc flags (Y grows downwards)" * * @ingroup Curves */ @@ -142,31 +144,7 @@ Point EllipticalArc::pointAtAngle(Coord t) const Coord EllipticalArc::valueAtAngle(Coord t, Dim2 d) const { - Coord sinrot, cosrot, cost, sint; - sincos(rotationAngle(), sinrot, cosrot); - sincos(t, sint, cost); - - if ( d == X ) { - return ray(X) * cosrot * cost - - ray(Y) * sinrot * sint - + center(X); - } else { - return ray(X) * sinrot * cost - + ray(Y) * cosrot * sint - + center(Y); - } -} - -Affine EllipticalArc::unitCircleTransform() const -{ - Affine ret = _ellipse.unitCircleTransform(); - return ret; -} - -Affine EllipticalArc::inverseUnitCircleTransform() const -{ - Affine ret = _ellipse.inverseUnitCircleTransform(); - return ret; + return _ellipse.valueAt(t, d); } std::vector EllipticalArc::roots(Coord v, Dim2 d) const @@ -176,6 +154,7 @@ std::vector EllipticalArc::roots(Coord v, Dim2 d) const } std::vector sol; + Interval unit_interval(0, 1); if ( are_near(ray(X), 0) && are_near(ray(Y), 0) ) { if ( center(d) == v ) @@ -251,7 +230,7 @@ std::vector EllipticalArc::roots(Coord v, Dim2 d) const { case X: s = std::asin(s); // return a value in [-PI/2,PI/2] - if ( logical_xor( _sweep, are_near(initialAngle(), M_PI/2) ) ) + if ( logical_xor( sweep(), are_near(initialAngle(), M_PI/2) ) ) { if ( s < 0 ) s += 2*M_PI; } @@ -263,7 +242,7 @@ std::vector EllipticalArc::roots(Coord v, Dim2 d) const break; case Y: s = std::acos(s); // return a value in [0,PI] - if ( logical_xor( _sweep, are_near(initialAngle(), 0) ) ) + if ( logical_xor( sweep(), are_near(initialAngle(), 0) ) ) { s = 2*M_PI - s; if ( !(s < 2*M_PI) ) s -= 2*M_PI; @@ -272,10 +251,11 @@ std::vector EllipticalArc::roots(Coord v, Dim2 d) const } //std::cerr << "s = " << rad_to_deg(s); - s = map_to_01(s); + s = timeAtAngle(s); //std::cerr << " -> t: " << s << std::endl; - if ( !(s < 0 || s > 1) ) + if (unit_interval.contains(s)) { sol.push_back(s); + } return sol; } } @@ -331,13 +311,13 @@ std::vector EllipticalArc::roots(Coord v, Dim2 d) const } std::vector arc_sol; - for (unsigned int i = 0; i < sol.size(); ++i ) - { + for (unsigned int i = 0; i < sol.size(); ++i ) { //std::cerr << "s = " << rad_to_deg(sol[i]); - sol[i] = map_to_01(sol[i]); + sol[i] = timeAtAngle(sol[i]); //std::cerr << " -> t: " << sol[i] << std::endl; - if ( !(sol[i] < 0 || sol[i] > 1) ) + if (unit_interval.contains(sol[i])) { arc_sol.push_back(sol[i]); + } } return arc_sol; } @@ -355,16 +335,8 @@ Curve *EllipticalArc::derivative() const EllipticalArc *result = static_cast(duplicate()); result->_ellipse.setCenter(0, 0); - result->_start_angle += M_PI/2; - if( !( result->_start_angle < 2*M_PI ) ) - { - result->_start_angle -= 2*M_PI; - } - result->_end_angle += M_PI/2; - if( !( result->_end_angle < 2*M_PI ) ) - { - result->_end_angle -= 2*M_PI; - } + result->_angles.setInitial(result->_angles.initialAngle() + M_PI/2); + result->_angles.setFinal(result->_angles.finalAngle() + M_PI/2); result->_initial_point = result->pointAtAngle( result->initialAngle() ); result->_final_point = result->pointAtAngle( result->finalAngle() ); return result; @@ -381,15 +353,14 @@ EllipticalArc::pointAndDerivatives(Coord t, unsigned int n) const unsigned int nn = n+1; // nn represents the size of the result vector. std::vector result; result.reserve(nn); - double angle = map_unit_interval_on_circular_arc(t, initialAngle(), - finalAngle(), _sweep); + double angle = angleAt(t); std::auto_ptr ea( static_cast(duplicate()) ); ea->_ellipse.setCenter(0, 0); unsigned int m = std::min(nn, 4u); for ( unsigned int i = 0; i < m; ++i ) { result.push_back( ea->pointAtAngle(angle) ); - angle += (_sweep ? M_PI/2 : -M_PI/2); + angle += (sweep() ? M_PI/2 : -M_PI/2); if ( !(angle < 2*M_PI) ) angle -= 2*M_PI; } m = nn / 4; @@ -408,17 +379,18 @@ EllipticalArc::pointAndDerivatives(Coord t, unsigned int n) const return result; } -bool EllipticalArc::containsAngle(Coord angle) const -{ - return AngleInterval::contains(angle); -} - Point EllipticalArc::pointAt(Coord t) const { if (isChord()) return chord().pointAt(t); return _ellipse.pointAt(angleAt(t)); } +Coord EllipticalArc::valueAt(Coord t, Dim2 d) const +{ + if (isChord()) return chord().valueAt(t, d); + return valueAtAngle(angleAt(t), d); +} + Curve* EllipticalArc::portion(double f, double t) const { // fix input arguments @@ -427,39 +399,30 @@ Curve* EllipticalArc::portion(double f, double t) const if (t < 0) t = 0; if (t > 1) t = 1; - if (f == t) - { - EllipticalArc *arc = static_cast(duplicate()); + if (f == t) { + EllipticalArc *arc = new EllipticalArc(); arc->_initial_point = arc->_final_point = pointAt(f); - arc->_start_angle = arc->_end_angle = 0; - arc->_ellipse = Ellipse(); - arc->_sweep = false; - arc->_large_arc = false; return arc; } EllipticalArc *arc = static_cast(duplicate()); arc->_initial_point = pointAt(f); arc->_final_point = pointAt(t); - if ( f > t ) arc->_sweep = !_sweep; - if ( _large_arc && fabs(sweepAngle() * (t-f)) < M_PI) { + arc->_angles.setAngles(angleAt(f), angleAt(t)); + if (f > t) arc->_angles.setSweep(!sweep()); + if ( _large_arc && fabs(angularExtent() * (t-f)) <= M_PI) { arc->_large_arc = false; } - //arc->_start_angle = angleAt(f); - //arc->_end_angle = angleAt(t); - arc->_updateCenterAndAngles(); //TODO: be more clever return arc; } // the arc is the same but traversed in the opposite direction Curve *EllipticalArc::reverse() const { + using std::swap; EllipticalArc *rarc = static_cast(duplicate()); - rarc->_sweep = !_sweep; - rarc->_initial_point = _final_point; - rarc->_final_point = _initial_point; - rarc->_start_angle = _end_angle; - rarc->_end_angle = _start_angle; + rarc->_angles.reverse(); + swap(rarc->_initial_point, rarc->_final_point); return rarc; } @@ -625,14 +588,14 @@ std::vector EllipticalArc::allNearestTimes( Point const& p, double from, } } - double t = map_to_01( real_sol[mi1] ); + double t = timeAtAngle(real_sol[mi1]); if ( !(t < from || t > to) ) { result.push_back(t); } bool second_sol = false; - t = map_to_01( real_sol[mi2] ); + t = timeAtAngle(real_sol[mi2]); if ( real_sol.size() == 4 && !(t < from || t > to) ) { if ( result.empty() || are_near(mindistsq1, mindistsq2) ) @@ -757,25 +720,23 @@ void EllipticalArc::_updateCenterAndAngles() // if ip = sp, the arc contains no other points if (initialPoint() == finalPoint()) { - _start_angle = _end_angle = 0; - _ellipse.setRotationAngle(0); + _ellipse = Ellipse(); _ellipse.setCenter(initialPoint()); - _ellipse.setRays(0, 0); - _large_arc = _sweep = false; + _angles = AngleInterval(); + _large_arc = false; return; } // rays should be positive _ellipse.setRays(std::fabs(ray(X)), std::fabs(ray(Y))); - if (ray(X) == 0 || ray(Y) == 0) { - _start_angle = 0; - _end_angle = M_PI; + if (isChord()) { _ellipse.setRays(L2(d) / 2, 0); _ellipse.setRotationAngle(atan2(d)); _ellipse.setCenter(mid); + _angles.setAngles(0, M_PI); + _angles.setSweep(false); _large_arc = false; - _sweep = false; return; } @@ -801,7 +762,7 @@ void EllipticalArc::_updateCenterAndAngles() // normally rad should never be negative, but numerical inaccuracy may cause this if (rad > 0) { rad = std::sqrt(rad); - if (_sweep == _large_arc) { + if (sweep() == _large_arc) { rad = -rad; } c = rad * Point(r[X]*p[Y]/r[Y], -r[Y]*p[X]/r[X]); @@ -816,12 +777,13 @@ void EllipticalArc::_updateCenterAndAngles() Point sp((p[X] - c[X]) / r[X], (p[Y] - c[Y]) / r[Y]); Point ep((-p[X] - c[X]) / r[X], (-p[Y] - c[Y]) / r[Y]); Point v(1, 0); - _start_angle = angle_between(v, sp); - double sweep_angle = angle_between(sp, ep); - if (!_sweep && sweep_angle > 0) sweep_angle -= 2*M_PI; - if (_sweep && sweep_angle < 0) sweep_angle += 2*M_PI; - _end_angle = _start_angle + sweep_angle; + _angles.setInitial(angle_between(v, sp)); + _angles.setFinal(angle_between(v, ep)); + + /*double sweep_angle = angle_between(sp, ep); + if (!sweep() && sweep_angle > 0) sweep_angle -= 2*M_PI; + if (sweep() && sweep_angle < 0) sweep_angle += 2*M_PI;*/ } D2 EllipticalArc::toSBasis() const @@ -852,7 +814,39 @@ D2 EllipticalArc::toSBasis() const return arc; } -void EllipticalArc::transform(Affine const& m) +// All operations that do not contain skew can be evaulated +// without passing through the implicit form of the ellipse, +// which preserves precision. + +void EllipticalArc::operator*=(Translate const &tr) +{ + _initial_point *= tr; + _final_point *= tr; + _ellipse *= tr; +} + +void EllipticalArc::operator*=(Scale const &s) +{ + _initial_point *= s; + _final_point *= s; + _ellipse *= s; +} + +void EllipticalArc::operator*=(Rotate const &r) +{ + _initial_point *= r; + _final_point *= r; + _ellipse *= r; +} + +void EllipticalArc::operator*=(Zoom const &z) +{ + _initial_point *= z; + _final_point *= z; + _ellipse *= z; +} + +void EllipticalArc::operator*=(Affine const& m) { if (isChord()) { _initial_point *= m; @@ -867,14 +861,14 @@ void EllipticalArc::transform(Affine const& m) _final_point *= m; _ellipse *= m; if (m.det() < 0) { - _sweep = !_sweep; + _angles.setSweep(!sweep()); } // ellipse transformation does not preserve its functional form, // i.e. e.pointAt(0.5)*m and (e*m).pointAt(0.5) can be different. // We need to recompute start / end angles. - _start_angle = _ellipse.timeAt(_initial_point); - _end_angle = _ellipse.timeAt(_final_point); + _angles.setInitial(_ellipse.timeAt(_initial_point)); + _angles.setFinal(_ellipse.timeAt(_final_point)); } bool EllipticalArc::operator==(Curve const &c) const @@ -888,7 +882,7 @@ bool EllipticalArc::operator==(Curve const &c) const if (rays() != other->rays()) return false; if (rotationAngle() != other->rotationAngle()) return false; if (_large_arc != other->_large_arc) return false; - if (_sweep != other->_sweep) return false; + if (sweep() != other->sweep()) return false; return true; } @@ -897,16 +891,9 @@ void EllipticalArc::feed(PathSink &sink, bool moveto_initial) const if (moveto_initial) { sink.moveTo(_initial_point); } - sink.arcTo(ray(X), ray(Y), rotationAngle(), _large_arc, _sweep, _final_point); -} - -Coord EllipticalArc::map_to_01(Coord angle) const -{ - return map_circular_arc_on_unit_interval(angle, initialAngle(), - finalAngle(), _sweep); + sink.arcTo(ray(X), ray(Y), rotationAngle(), _large_arc, sweep(), _final_point); } - std::ostream &operator<<(std::ostream &out, EllipticalArc const &ea) { out << "EllipticalArc(" diff --git a/src/2geom/elliptical-arc.h b/src/2geom/elliptical-arc.h index 83909370e..fbb290dca 100644 --- a/src/2geom/elliptical-arc.h +++ b/src/2geom/elliptical-arc.h @@ -49,15 +49,14 @@ namespace Geom { -class EllipticalArc : public Curve, public AngleInterval +class EllipticalArc : public Curve { public: - /** @brief Creates an arc with all variables set to zero, and both flags to true. */ + /** @brief Creates an arc with all variables set to zero. */ EllipticalArc() - : AngleInterval(0, 0, true) - , _initial_point(0,0) + : _initial_point(0,0) , _final_point(0,0) - , _large_arc(true) + , _large_arc(false) {} /** @brief Create a new elliptical arc. * @param ip Initial point of the arc @@ -72,61 +71,73 @@ public: Coord rot_angle, bool large_arc, bool sweep, Point const &fp ) - : AngleInterval(0,0,sweep) - , _initial_point(ip) + : _initial_point(ip) , _final_point(fp) , _ellipse(0, 0, r[X], r[Y], rot_angle) + , _angles(0, 0, sweep) , _large_arc(large_arc) { _updateCenterAndAngles(); } + /// Create a new elliptical arc, giving the ellipse's rays as separate coordinates. EllipticalArc( Point const &ip, Coord rx, Coord ry, Coord rot_angle, bool large_arc, bool sweep, Point const &fp ) - : AngleInterval(0,0,sweep) - , _initial_point(ip) + : _initial_point(ip) , _final_point(fp) , _ellipse(0, 0, rx, ry, rot_angle) + , _angles(0, 0, sweep) , _large_arc(large_arc) { _updateCenterAndAngles(); } - // methods new to EllipticalArc go here - - /// @name Retrieve and modify parameters + /// @name Retrieve basic information /// @{ - /** @brief Get the interval of angles the arc contains - * @return The interval between the final and initial angles of the arc */ - Interval angleInterval() const { return Interval(initialAngle(), finalAngle()); } + /** @brief Get a coordinate of the elliptical arc's center. * @param d The dimension to retrieve * @return The selected coordinate of the center */ - /** @brief Get the defining ellipse's rotation - * @return Angle between the +X ray of the ellipse and the +X axis */ - Angle rotationAngle() const { - return _ellipse.rotationAngle(); - } + Coord center(Dim2 d) const { return _ellipse.center(d); } + + /** @brief Get the arc's center + * @return The arc's center, situated on the intersection of the ellipse's rays */ + Point center() const { return _ellipse.center(); } + /** @brief Get one of the ellipse's rays * @param d Dimension to retrieve * @return The selected ray of the ellipse */ Coord ray(Dim2 d) const { return _ellipse.ray(d); } + /** @brief Get both rays as a point * @return Point with X equal to the X ray and Y to Y ray */ Point rays() const { return _ellipse.rays(); } + + /** @brief Get the defining ellipse's rotation + * @return Angle between the +X ray of the ellipse and the +X axis */ + Angle rotationAngle() const { + return _ellipse.rotationAngle(); + } + /** @brief Whether the arc is larger than half an ellipse. * @return True if the arc is larger than \f$\pi\f$, false otherwise */ bool largeArc() const { return _large_arc; } + /** @brief Whether the arc turns clockwise * @return True if the arc makes a clockwise turn when going from initial to final * point, false otherwise */ - bool sweep() const { return _sweep; } - /** @brief Get the line segment connecting the arc's endpoints. - * @return A linear segment with initial and final point correspoding to those of the arc. */ - LineSegment chord() const { return LineSegment(_initial_point, _final_point); } - /** @brief Change the arc's parameters. */ + bool sweep() const { return _angles.sweep(); } + + Angle initialAngle() const { return _angles.initialAngle(); } + Angle finalAngle() const { return _angles.finalAngle(); } + /// @} + + /// @name Modify parameters + /// @{ + + /// Change all of the arc's parameters. void set( Point const &ip, double rx, double ry, double rot_angle, bool large_arc, bool sweep, Point const &fp @@ -136,10 +147,26 @@ public: _final_point = fp; _ellipse.setRays(rx, ry); _ellipse.setRotationAngle(rot_angle); + _angles.setSweep(sweep); + _large_arc = large_arc; + _updateCenterAndAngles(); + } + + /// Change all of the arc's parameters. + void set( Point const &ip, Point const &r, + Angle rot_angle, bool large_arc, bool sweep, + Point const &fp + ) + { + _initial_point = ip; + _final_point = fp; + _ellipse.setRays(r); + _ellipse.setRotationAngle(rot_angle); + _angles.setSweep(sweep); _large_arc = large_arc; - _sweep = sweep; _updateCenterAndAngles(); } + /** @brief Change the initial and final point in one operation. * This method exists because modifying any of the endpoints causes rather costly * recalculations of the center and extreme angles. @@ -152,52 +179,76 @@ public: } /// @} - /// @name Access computed parameters of the arc - /// @{ - Coord center(Dim2 d) const { return _ellipse.center(d); } - /** @brief Get the arc's center - * @return The arc's center, situated on the intersection of the ellipse's rays */ - Point center() const { return _ellipse.center(); } - /// @} - - /// @name Angular evaluation + /// @name Evaluate the arc as a function /// @{ /** Check whether the arc contains the given angle * @param t The angle to check * @return True if the arc contains the angle, false otherwise */ - bool containsAngle(Coord angle) const; + bool containsAngle(Angle angle) const { return _angles.contains(angle); } + /** @brief Evaluate the arc at the specified angular coordinate * @param t Angle * @return Point corresponding to the given angle */ Point pointAtAngle(Coord t) const; + /** @brief Evaluate one of the arc's coordinates at the specified angle * @param t Angle * @param d The dimension to retrieve * @return Selected coordinate of the arc at the specified angle */ Coord valueAtAngle(Coord t, Dim2 d) const; - /** @brief Retrieve the unit circle transform. + + /// Compute the curve time value corresponding to the given angular value. + Coord timeAtAngle(Angle a) const { return _angles.timeAtAngle(a); } + + /// Compute the angular domain value corresponding to the given time value. + Angle angleAt(Coord t) const { return _angles.angleAt(t); } + + /** @brief Compute the amount by which the angle parameter changes going from start to end. + * This has range \f$(-2\pi, 2\pi)\f$ and thus cannot be represented as instance + * of the class Angle. Add this to the initial angle to obtain the final angle. */ + Coord sweepAngle() const { return _angles.sweepAngle(); } + + /** @brief Get the elliptical angle spanned by the arc. + * This is basically the absolute value of sweepAngle(). */ + Coord angularExtent() const { return _angles.extent(); } + + /// Get the angular interval of the arc. + AngleInterval angularInterval() const { return _angles; } + + /// Evaluate the arc in the curve domain, i.e. \f$[0, 1]\$. + virtual Point pointAt(Coord t) const; + + /// Evaluate a single coordinate on the arc in the curve domain. + virtual Coord valueAt(Coord t, Dim2 d) const; + + /** @brief Compute a transform that maps the unit circle to the arc's ellipse. * Each ellipse can be interpreted as a translated, scaled and rotate unit circle. * This function returns the transform that maps the unit circle to the arc's ellipse. * @return Transform from unit circle to the arc's ellipse */ - Affine unitCircleTransform() const; - Affine inverseUnitCircleTransform() const; + Affine unitCircleTransform() const { + Affine result = _ellipse.unitCircleTransform(); + return result; + } + + /** @brief Compute a transform that maps the arc's ellipse to the unit circle. */ + Affine inverseUnitCircleTransform() const { + Affine result = _ellipse.inverseUnitCircleTransform(); + return result; + } /// @} + /// @name Deal with degenerate ellipses. + /// @{ /** @brief Check whether both rays are nonzero. * If they are not, the arc is represented as a line segment instead. */ bool isChord() const { return ray(X) == 0 || ray(Y) == 0; } - std::pair subdivide(Coord t) const { - EllipticalArc* arc1 = static_cast(portion(0, t)); - EllipticalArc* arc2 = static_cast(portion(t, 1)); - assert( arc1 != NULL && arc2 != NULL); - std::pair arc_pair(*arc1, *arc2); - delete arc1; - delete arc2; - return arc_pair; - } + /** @brief Get the line segment connecting the arc's endpoints. + * @return A linear segment with initial and final point correspoding to those of the arc. */ + LineSegment chord() const { return LineSegment(_initial_point, _final_point); } + /// @} // implementation of overloads goes here virtual Point initialPoint() const { return _initial_point; } @@ -226,58 +277,50 @@ public: virtual std::vector roots(double v, Dim2 d) const; #ifdef HAVE_GSL virtual std::vector allNearestTimes( Point const& p, double from = 0, double to = 1 ) const; -#endif virtual double nearestTime( Point const& p, double from = 0, double to = 1 ) const { if ( are_near(ray(X), ray(Y)) && are_near(center(), p) ) { return from; } return allNearestTimes(p, from, to).front(); } +#endif virtual std::vector intersect(Curve const &other, Coord eps=EPSILON) const; virtual int degreesOfFreedom() const { return 7; } virtual Curve *derivative() const; - virtual void transform(Affine const &m); - virtual Curve &operator*=(Translate const &m) { - _initial_point *= m; - _final_point *= m; - _ellipse *= m; - return *this; - } + using Curve::operator*=; + virtual void operator*=(Translate const &tr); + virtual void operator*=(Scale const &s); + virtual void operator*=(Rotate const &r); + virtual void operator*=(Zoom const &z); + virtual void operator*=(Affine const &m); - /** - * The size of the returned vector equals n+1. - */ virtual std::vector pointAndDerivatives(Coord t, unsigned int n) const; - virtual D2 toSBasis() const; - virtual double valueAt(Coord t, Dim2 d) const { - if (isChord()) return chord().valueAt(t, d); - return valueAtAngle(angleAt(t), d); - } - virtual Point pointAt(Coord t) const; - virtual Curve* portion(double f, double t) const; - virtual Curve* reverse() const; + virtual Curve *portion(double f, double t) const; + virtual Curve *reverse() const; virtual bool operator==(Curve const &c) const; virtual void feed(PathSink &sink, bool moveto_initial) const; -protected: +private: void _updateCenterAndAngles(); void _filterIntersections(std::vector &xs, bool is_first) const; Point _initial_point, _final_point; Ellipse _ellipse; + AngleInterval _angles; bool _large_arc; - -private: - Coord map_to_01(Coord angle) const; }; // end class EllipticalArc // implemented in elliptical-arc-from-sbasis.cpp +/** @brief Fit an elliptical arc to an SBasis fragment. + * @relates EllipticalArc */ bool arc_from_sbasis(EllipticalArc &ea, D2 const &in, double tolerance = EPSILON, unsigned num_samples = 20); +/** @brief Debug output for elliptical arcs. + * @relates EllipticalArc */ std::ostream &operator<<(std::ostream &out, EllipticalArc const &ea); } // end namespace Geom diff --git a/src/2geom/intersection-graph.cpp b/src/2geom/intersection-graph.cpp index ff96c28a8..e18561f67 100644 --- a/src/2geom/intersection-graph.cpp +++ b/src/2geom/intersection-graph.cpp @@ -39,7 +39,7 @@ namespace Geom { -struct IntersectionVertexLess { +struct PathIntersectionGraph::IntersectionVertexLess { bool operator()(IntersectionVertex const &a, IntersectionVertex const &b) const { return a.pos < b.pos; } @@ -49,7 +49,8 @@ struct IntersectionVertexLess { * @brief Intermediate data for computing Boolean operations on paths. * * This class implements the Greiner-Hormann clipping algorithm, - * with improvements by Foster and Overfelt. + * with improvements inspired by Foster and Overfelt as well as some + * original contributions. * * @ingroup Paths */ @@ -69,15 +70,16 @@ PathIntersectionGraph::PathIntersectionGraph(PathVector const &a, PathVector con } std::vector pxs = _a.intersect(_b, precision); + // NOTE: this early return means that the path data structures will not be created + // if there are no intersections at all! if (pxs.empty()) return; - if (pxs.size() % 2) return; // prepare intersection lists for each path component for (std::size_t i = 0; i < _a.size(); ++i) { - _xalists.push_back(new IntersectionList()); + _apaths.push_back(new PathData()); } for (std::size_t i = 0; i < _b.size(); ++i) { - _xblists.push_back(new IntersectionList()); + _bpaths.push_back(new PathData()); } for (std::size_t i = 0; i < pxs.size(); ++i) { @@ -92,30 +94,32 @@ PathIntersectionGraph::PathIntersectionGraph(PathVector const &a, PathVector con xb->neighbor = xa; _xs.push_back(xa); _xs.push_back(xb); - _xalists[xa->pos.path_index].push_back(*xa); - _xblists[xb->pos.path_index].push_back(*xb); + _apaths[xa->pos.path_index].xlist.push_back(*xa); + _bpaths[xb->pos.path_index].xlist.push_back(*xb); } - for (std::size_t i = 0; i < _xalists.size(); ++i) { - _xalists[i].sort(IntersectionVertexLess()); + for (std::size_t i = 0; i < _apaths.size(); ++i) { + _apaths[i].xlist.sort(IntersectionVertexLess()); } - for (std::size_t i = 0; i < _xblists.size(); ++i) { - _xblists[i].sort(IntersectionVertexLess()); + for (std::size_t i = 0; i < _bpaths.size(); ++i) { + _bpaths[i].xlist.sort(IntersectionVertexLess()); } typedef IntersectionList::iterator Iter; // determine in/out/on flags using winding for (unsigned npv = 0; npv < 2; ++npv) { - boost::ptr_vector &ls = npv ? _xblists : _xalists; + boost::ptr_vector &ls = npv ? _bpaths : _apaths; + boost::ptr_vector &ols = npv ? _apaths : _bpaths; PathVector const &pv = npv ? b : a; PathVector const &other = npv ? a : b; for (unsigned li = 0; li < ls.size(); ++li) { - for (Iter i = ls[li].begin(); i != ls[li].end(); ++i) { + IntersectionList &xl = ls[li].xlist; + for (Iter i = xl.begin(); i != xl.end(); ++i) { Iter n = boost::next(i); - if (n == ls[li].end()) { - n = ls[li].begin(); + if (n == xl.end()) { + n = xl.begin(); } std::size_t pi = i->pos.path_index; @@ -123,7 +127,6 @@ PathIntersectionGraph::PathIntersectionGraph(PathVector const &a, PathVector con PathTime mid = ival.inside(precision); // TODO check for degenerate cases - // requires changes in the winding routine int w = other.winding(pv[pi].pointAt(mid)); if (w % 2) { i->next = POINT_INSIDE; @@ -134,9 +137,22 @@ PathIntersectionGraph::PathIntersectionGraph(PathVector const &a, PathVector con } } - // assign exit / entry flags - for (Iter i = ls[li].begin(); i != ls[li].end(); ++i) { - i->entry = ((i->next == POINT_INSIDE) && (i->previous == POINT_OUTSIDE)); + // remove intersections that don't change between in/out + // and assign exit / entry flags + for (Iter i = xl.begin(); i != xl.end();) { + if (i->previous == i->next) { + IntersectionList &oxl = ols[i->neighbor->pos.path_index].xlist; + oxl.erase(oxl.iterator_to(*i->neighbor)); + xl.erase(i++); + if (i->next == POINT_INSIDE) { + ++ls[li].removed_in; + } else { + ++ls[li].removed_out; + } + } else { + i->entry = ((i->next == POINT_INSIDE) && (i->previous == POINT_OUTSIDE)); + ++i; + } } } } @@ -162,6 +178,7 @@ PathVector PathIntersectionGraph::getAminusB() { PathVector result = _getResult(false, true); _handleNonintersectingPaths(result, 0, false); + _handleNonintersectingPaths(result, 1, true); return result; } @@ -169,6 +186,7 @@ PathVector PathIntersectionGraph::getBminusA() { PathVector result = _getResult(true, false); _handleNonintersectingPaths(result, 1, false); + _handleNonintersectingPaths(result, 0, true); return result; } @@ -180,13 +198,22 @@ PathVector PathIntersectionGraph::getXOR() return r1; } +std::size_t PathIntersectionGraph::size() const +{ + std::size_t result = 0; + for (std::size_t i = 0; i < _apaths.size(); ++i) { + result += _apaths[i].xlist.size(); + } + return result; +} + std::vector PathIntersectionGraph::intersectionPoints() const { std::vector result; typedef IntersectionList::const_iterator Iter; - for (std::size_t i = 0; i < _xalists.size(); ++i) { - for (Iter j = _xalists[i].begin(); j != _xalists[i].end(); ++j) { + for (std::size_t i = 0; i < _apaths.size(); ++i) { + for (Iter j = _apaths[i].xlist.begin(); j != _apaths[i].xlist.end(); ++j) { result.push_back(j->p); } } @@ -201,9 +228,9 @@ PathVector PathIntersectionGraph::_getResult(bool enter_a, bool enter_b) // reset processed status for (unsigned npv = 0; npv < 2; ++npv) { - boost::ptr_vector &ls = npv ? _xblists : _xalists; + boost::ptr_vector &ls = npv ? _bpaths : _apaths; for (std::size_t li = 0; li < ls.size(); ++li) { - for (Iter k = ls[li].begin(); k != ls[li].end(); ++k) { + for (Iter k = ls[li].xlist.begin(); k != ls[li].xlist.end(); ++k) { k->processed = false; } } @@ -213,7 +240,7 @@ PathVector PathIntersectionGraph::_getResult(bool enter_a, bool enter_b) while (true) { PathVector const *cur = &_a, *other = &_b; - boost::ptr_vector *lscur = &_xalists, *lsother = &_xblists; + boost::ptr_vector *lscur = &_apaths, *lsother = &_bpaths; // find unprocessed intersection Iter i; @@ -239,14 +266,14 @@ PathVector PathIntersectionGraph::_getResult(bool enter_a, bool enter_b) // get next intersection if (reverse) { - if (i == (*lscur)[pi].begin()) { - i = (*lscur)[pi].end(); + if (i == (*lscur)[pi].xlist.begin()) { + i = (*lscur)[pi].xlist.end(); } --i; } else { ++i; - if (i == (*lscur)[pi].end()) { - i = (*lscur)[pi].begin(); + if (i == (*lscur)[pi].xlist.end()) { + i = (*lscur)[pi].xlist.begin(); } } @@ -263,7 +290,7 @@ PathVector PathIntersectionGraph::_getResult(bool enter_a, bool enter_b) n_processed += 2; // switch to the other path - i = (*lsother)[i->neighbor->pos.path_index].iterator_to(*i->neighbor); + i = (*lsother)[i->neighbor->pos.path_index].xlist.iterator_to(*i->neighbor); std::swap(lscur, lsother); std::swap(cur, other); } @@ -272,7 +299,7 @@ PathVector PathIntersectionGraph::_getResult(bool enter_a, bool enter_b) assert(!result.back().empty()); } - assert(n_processed == _xs.size()); + assert(n_processed == size() * 2); return result; } @@ -285,15 +312,29 @@ void PathIntersectionGraph::_handleNonintersectingPaths(PathVector &result, int * evaluating the winding rule at the initial point. If inside is true and * the path is inside, we add it to the result. */ - boost::ptr_vector const &ls = which ? _xblists : _xalists; + boost::ptr_vector const &ls = which ? _bpaths : _apaths; PathVector const &cur = which ? _b : _a; PathVector const &other = which ? _a : _b; for (std::size_t i = 0; i < cur.size(); ++i) { - if (!ls.empty() && !ls[i].empty()) continue; + // the path data vector might have been left empty if there were no intersections at all + bool has_path_data = !ls.empty(); + // Skip if the path has intersections + if (has_path_data && !ls[i].xlist.empty()) continue; + bool path_inside = false; + + // If the path had any intersections removed, use the result of that, + // since one of those might have been at the initial point. + // Also, it saves time. + if (has_path_data && ls[i].removed_in != 0) { + path_inside = true; + } else if (has_path_data && ls[i].removed_out != 0) { + path_inside = false; + } else { + int w = other.winding(cur[i].initialPoint()); + path_inside = w % 2 != 0; + } - int w = other.winding(cur[i].initialPoint()); - bool path_inside = w % 2 != 0; if (path_inside == inside) { result.push_back(cur[i]); } @@ -304,11 +345,16 @@ bool PathIntersectionGraph::_findUnprocessed(IntersectionList::iterator &result) { typedef IntersectionList::iterator Iter; - Iter it; + Iter it, last; - for (std::size_t k = 0; k < _xalists.size(); ++k) { - it = _xalists[k].begin(); - for (; it != _xalists[k].end(); ++it) { + for (std::size_t k = 0; k < _apaths.size(); ++k) { + it = _apaths[k].xlist.begin(); + last = _apaths[k].xlist.end(); + for (; it != last; ++it) { + if (!it->_hook.is_linked()) { + // this intersection was removed since it did not change inside/outside status + continue; + } if (!it->processed) { result = it; return true; @@ -319,6 +365,21 @@ bool PathIntersectionGraph::_findUnprocessed(IntersectionList::iterator &result) return false; } + +std::ostream &operator<<(std::ostream &os, PathIntersectionGraph const &pig) +{ + os << "Intersection graph:\n" + << pig._xs.size()/2 << " total intersections\n" + << pig.size() << " considered intersections\n"; + for (std::size_t i = 0; i < pig._apaths.size(); ++i) { + typedef PathIntersectionGraph::IntersectionList::const_iterator Iter; + for (Iter j = pig._apaths[i].xlist.begin(); j != pig._apaths[i].xlist.end(); ++j) { + os << j->pos << " - " << j->neighbor->pos << " @ " << j->p << "\n"; + } + } + return os; +} + } // namespace Geom /* diff --git a/src/2geom/intersection-graph.h b/src/2geom/intersection-graph.h index 44beaf46b..bd9aaee81 100644 --- a/src/2geom/intersection-graph.h +++ b/src/2geom/intersection-graph.h @@ -43,33 +43,6 @@ namespace Geom { -enum InOutFlag { - POINT_INSIDE, - POINT_OUTSIDE, - POINT_ON_EDGE -}; - -struct IntersectionVertex { - boost::intrusive::list_member_hook<> _hook; - PathVectorTime pos; - Point p; // guarantees that endpoints are exact - IntersectionVertex *neighbor; - bool entry; // going in +t direction enters the other path - InOutFlag previous; - InOutFlag next; - bool processed; // TODO: use intrusive unprocessed list instead -}; - -typedef boost::intrusive::list - < IntersectionVertex - , boost::intrusive::member_hook - < IntersectionVertex - , boost::intrusive::list_member_hook<> - , &IntersectionVertex::_hook - > - > IntersectionList; - - class PathIntersectionGraph { // this is called PathIntersectionGraph so that we can also have a class for polygons, @@ -83,19 +56,63 @@ public: PathVector getBminusA(); PathVector getXOR(); + /// Returns the number of intersections used when computing Boolean operations. + std::size_t size() const; std::vector intersectionPoints() const; private: + enum InOutFlag { + POINT_INSIDE, + POINT_OUTSIDE + }; + + struct IntersectionVertex { + boost::intrusive::list_member_hook<> _hook; + PathVectorTime pos; + Point p; // guarantees that endpoints are exact + IntersectionVertex *neighbor; + bool entry; // going in +t direction enters the other path + InOutFlag previous; + InOutFlag next; + bool processed; // TODO: use intrusive unprocessed list instead + }; + + typedef boost::intrusive::list + < IntersectionVertex + , boost::intrusive::member_hook + < IntersectionVertex + , boost::intrusive::list_member_hook<> + , &IntersectionVertex::_hook + > + > IntersectionList; + + struct PathData { + IntersectionList xlist; + unsigned removed_in; + unsigned removed_out; + + PathData() + : removed_in(0) + , removed_out(0) + {} + }; + + struct IntersectionVertexLess; + PathVector _getResult(bool enter_a, bool enter_b); void _handleNonintersectingPaths(PathVector &result, int which, bool inside); bool _findUnprocessed(IntersectionList::iterator &result); PathVector _a, _b; boost::ptr_vector _xs; - boost::ptr_vector _xalists; - boost::ptr_vector _xblists; + boost::ptr_vector _apaths; + boost::ptr_vector _bpaths; + + friend std::ostream &operator<<(std::ostream &, PathIntersectionGraph const &); }; +std::ostream &operator<<(std::ostream &os, PathIntersectionGraph const &pig); + } // namespace Geom #endif // SEEN_LIB2GEOM_PATH_GRAPH_H diff --git a/src/2geom/intersection.h b/src/2geom/intersection.h index ae4b50dd1..bbce19947 100644 --- a/src/2geom/intersection.h +++ b/src/2geom/intersection.h @@ -44,6 +44,7 @@ namespace Geom { */ template class Intersection + : boost::totally_ordered< Intersection > { public: /** @brief Construct from shape references and time values. @@ -79,6 +80,17 @@ public: swap(a._point, b._point); } + bool operator==(Intersection const &other) const { + if (first != other.first) return false; + if (second != other.second) return false; + return true; + } + bool operator<(Intersection const &other) const { + if (first < other.first) return true; + if (first == other.first && second < other.second) return true; + return false; + } + public: /// First shape and time value. TimeA first; diff --git a/src/2geom/line.cpp b/src/2geom/line.cpp index 8bea33638..bada8ef38 100644 --- a/src/2geom/line.cpp +++ b/src/2geom/line.cpp @@ -60,6 +60,7 @@ namespace Geom * satisfy the line equation with the given coefficients. */ void Line::setCoefficients (Coord a, Coord b, Coord c) { + // degenerate case if (a == 0 && b == 0) { if (c != 0) { THROW_LOGICALERROR("the passed coefficients give the empty set"); @@ -68,22 +69,36 @@ void Line::setCoefficients (Coord a, Coord b, Coord c) _final = Point(0,0); return; } + + // The way final / initial points are set based on coefficients is somewhat unusual. + // This is done to make sure that calling coefficients() will give back + // (almost) the same values. + + // vertical case if (a == 0) { // b must be nonzero - _initial = Point(0, -c / b); + _initial = Point(-b/2, -c / b); _final = _initial; - _final[X] = 1; + _final[X] = b/2; return; } + + // horizontal case if (b == 0) { - _initial = Point(-c / a, 0); + _initial = Point(-c / a, a/2); _final = _initial; - _final[Y] = 1; + _final[Y] = -a/2; return; } - _initial = Point(-c / a, 0); - _final = Point(0, -c / b); + // This gives reasonable results regardless of the magnitudes of a, b and c. + _initial = Point(-b/2,a/2); + _final = Point(b/2,-a/2); + + Point offset(-c/(2*a), -c/(2*b)); + + _initial += offset; + _final += offset; } void Line::coefficients(Coord &a, Coord &b, Coord &c) const @@ -94,15 +109,18 @@ void Line::coefficients(Coord &a, Coord &b, Coord &c) const c = cross(_initial, _final); } -/** @brief Get the line equation coefficients of this line. +/** @brief Get the implicit line equation coefficients. + * Note that conversion to implicit form always causes loss of + * precision when dealing with lines that start far from the origin + * and end very close to it. It is recommended to normalize the line + * before converting it to implicit form. * @return Vector with three values corresponding to the A, B and C * coefficients of the line equation for this line. */ std::vector Line::coefficients() const { - Coord c[3]; + std::vector c(3); coefficients(c[0], c[1], c[2]); - std::vector coeff(c, c+3); - return coeff; + return c; } /** @brief Find intersection with an axis-aligned line. diff --git a/src/2geom/line.h b/src/2geom/line.h index 5d92c436d..7d4766e12 100644 --- a/src/2geom/line.h +++ b/src/2geom/line.h @@ -49,15 +49,7 @@ namespace Geom // class docs in cpp file class Line - : boost::equality_comparable1< Line - , MultipliableNoncommutative< Line, Translate - , MultipliableNoncommutative< Line, Scale - , MultipliableNoncommutative< Line, Rotate - , MultipliableNoncommutative< Line, HShear - , MultipliableNoncommutative< Line, VShear - , MultipliableNoncommutative< Line, Zoom - , MultipliableNoncommutative< Line, Affine - > > > > > > > > + : boost::equality_comparable< Line > { private: Point _initial; @@ -203,8 +195,14 @@ public: return _initial[X] == _final[X]; } - /** @brief Reparametrize the line so that it has unit speed. */ + /** @brief Reparametrize the line so that it has unit speed. + * Note that the direction of the line may also change. */ void normalize() { + // this helps with the nasty case of a line that starts somewhere far + // and ends very close to the origin + if (L2sq(_final) < L2sq(_initial)) { + std::swap(_initial, _final); + } Point v = _final - _initial; v.normalize(); _final = _initial + v; @@ -380,6 +378,14 @@ public: if (distance(pointAt(nearestTime(other._final)), other._final) != 0) return false; return true; } + + template + friend Line operator*(Line const &l, T const &tr) { + BOOST_CONCEPT_ASSERT((TransformConcept)); + Line result(l); + result *= tr; + return result; + } }; // end class Line /** @brief Removes intersections outside of the unit interval. diff --git a/src/2geom/linear.h b/src/2geom/linear.h index cd7108835..b0306fb9f 100644 --- a/src/2geom/linear.h +++ b/src/2geom/linear.h @@ -51,7 +51,7 @@ namespace Geom { class SBasis; /** - * @brief Linear function fragment + * @brief Function that interpolates linearly between two values. * @ingroup Fragments */ class Linear { diff --git a/src/2geom/path.cpp b/src/2geom/path.cpp index 5fbc65b3e..836e65013 100644 --- a/src/2geom/path.cpp +++ b/src/2geom/path.cpp @@ -380,20 +380,6 @@ bool Path::operator==(Path const &other) const return *_curves == *other._curves; } -Path &Path::operator*=(Affine const &m) -{ - _unshare(); - Sequence::iterator last = _curves->end() - 1; - Sequence::iterator it; - - for (it = _curves->begin(); it != last; ++it) { - it->transform(m); - } - _closing_seg->transform(m); - checkContinuity(); - return *this; -} - void Path::start(Point const &p) { if (_curves->size() > 1) { clear(); @@ -507,7 +493,7 @@ protected: int ib = i->bound.index; if (which == 0) { - cx = record.item->intersect(*i->item); + cx = record.item->intersect(*i->item, _precision); } else { cx = i->item->intersect(*record.item, _precision); std::swap(ia, ib); @@ -535,7 +521,14 @@ std::vector Path::intersect(Path const &other, Coord precision CurveSweeper sweeper(*this, other, result, precision); sweeper.process(); - // TODO: remove multiple intersections within precision of each other? + // preprocessing to remove duplicate intersections at endpoints + for (std::size_t i = 0; i < result.size(); ++i) { + result[i].first.normalizeForward(size()); + result[i].second.normalizeForward(other.size()); + } + std::sort(result.begin(), result.end()); + result.erase(std::unique(result.begin(), result.end()), result.end()); + return result; } diff --git a/src/2geom/path.h b/src/2geom/path.h index a6473e0d2..a2d1e751e 100644 --- a/src/2geom/path.h +++ b/src/2geom/path.h @@ -159,7 +159,7 @@ struct PathTime }; inline std::ostream &operator<<(std::ostream &os, PathTime const &pos) { - os << pos.curve_index << ": " << pos.t; + os << pos.curve_index << ": " << format_coord_nice(pos.t); return os; } @@ -313,9 +313,7 @@ struct ShapeTraits { * * @ingroup Paths */ class Path - : boost::equality_comparable1< Path - , MultipliableNoncommutative< Path, Affine - > > + : boost::equality_comparable< Path > { public: typedef PathInternal::Sequence Sequence; @@ -493,8 +491,24 @@ public: /// Test paths for exact equality. bool operator==(Path const &other) const; - /// Apply an affine transform. - Path &operator*=(Affine const &m); + /// Apply a transform to each curve. + template + Path &operator*=(T const &tr) { + BOOST_CONCEPT_ASSERT((TransformConcept)); + _unshare(); + for (std::size_t i = 0; i < _curves->size(); ++i) { + (*_curves)[i] *= tr; + } + return *this; + } + + template + friend Path operator*(Path const &path, T const &tr) { + BOOST_CONCEPT_ASSERT((TransformConcept)); + Path result(path); + result *= tr; + return result; + } /** @brief Get the allowed range of time values. * @return Values for which pointAt() and valueAt() yield valid results. */ diff --git a/src/2geom/pathvector.h b/src/2geom/pathvector.h index 6636cbf2e..108f2aa05 100644 --- a/src/2geom/pathvector.h +++ b/src/2geom/pathvector.h @@ -81,6 +81,11 @@ struct PathVectorTime } }; +inline std::ostream &operator<<(std::ostream &os, PathVectorTime const &pvt) { + os << pvt.path_index << ": " << pvt.asPathTime(); + return os; +} + typedef Intersection PathVectorIntersection; typedef PathVectorIntersection PVIntersection; ///< Alias to save typing diff --git a/src/2geom/piecewise.h b/src/2geom/piecewise.h index 981d67144..a5a65a9fe 100644 --- a/src/2geom/piecewise.h +++ b/src/2geom/piecewise.h @@ -42,12 +42,14 @@ namespace Geom { /** - * %Piecewise function class. + * @brief Function defined as discrete pieces. + * * The Piecewise class manages a sequence of elements of a type as segments and * the ’cuts’ between them. These cuts are time values which separate the pieces. * This function representation allows for more interesting functions, as it provides * a viable output for operations such as inversion, which may require multiple * SBasis to properly invert the original. + * * As for technical details, while the actual SBasis segments begin on the first * cut and end on the last, the function is defined throughout all inputs by ex- * tending the first and last segments. The exact switching between segments is @@ -62,6 +64,8 @@ namespace Geom { * s_n,& c_n <= t * \end{array}\right. * \f] + * + * @ingroup Fragments */ template class Piecewise { diff --git a/src/2geom/polynomial.cpp b/src/2geom/polynomial.cpp index a0689f0c5..ca2389f80 100644 --- a/src/2geom/polynomial.cpp +++ b/src/2geom/polynomial.cpp @@ -34,6 +34,7 @@ #include #include <2geom/polynomial.h> +#include <2geom/math-utils.h> #include #ifdef HAVE_GSL @@ -235,12 +236,17 @@ std::vector solve_quadratic(Coord a, Coord b, Coord c) if (delta == 0) { // one root - result.push_back(-0.5 * b / a); + result.push_back(-b / (2*a)); } else if (delta > 0) { // two roots Coord delta_sqrt = sqrt(delta); - result.push_back((-b + delta_sqrt)/(2*a)); - result.push_back((-b - delta_sqrt)/(2*a)); + + // Use different formulas depending on sign of b to preserve + // numerical stability. See e.g.: + // http://people.csail.mit.edu/bkph/articles/Quadratics.pdf + Coord t = -0.5 * (b + sgn(b) * delta_sqrt); + result.push_back(t / a); + result.push_back(c / t); } // no roots otherwise diff --git a/src/2geom/polynomial.h b/src/2geom/polynomial.h index aeac2f3fa..5ab2aa4c8 100644 --- a/src/2geom/polynomial.h +++ b/src/2geom/polynomial.h @@ -44,6 +44,8 @@ namespace Geom { +/** @brief Polynomial in canonical (monomial) basis. + * @ingroup Fragments */ class Poly : public std::vector{ public: // coeff; // sum x^i*coeff[i] diff --git a/src/2geom/sbasis-curve.h b/src/2geom/sbasis-curve.h index 17ee8f4c9..affe7edc0 100644 --- a/src/2geom/sbasis-curve.h +++ b/src/2geom/sbasis-curve.h @@ -119,7 +119,8 @@ public: return new SBasisCurve(Geom::portion(inner, f, t)); } - virtual void transform(Affine const &m) { inner = inner * m; } + using Curve::operator*=; + virtual void operator*=(Affine const &m) { inner = inner * m; } virtual Curve *derivative() const { return new SBasisCurve(Geom::derivative(inner)); diff --git a/src/2geom/sbasis-math.cpp b/src/2geom/sbasis-math.cpp index 97cdf45ce..896eb18a7 100644 --- a/src/2geom/sbasis-math.cpp +++ b/src/2geom/sbasis-math.cpp @@ -297,11 +297,11 @@ Piecewise reciprocalOnDomain(Interval range, double tol){ if (a<=tol){ reciprocal_fn.push_cut(0); int i0=(int) floor(std::log(tol)/std::log(R)); - a=pow(R,i0); + a = std::pow(R,i0); reciprocal_fn.push(Linear(1/a),a); }else{ int i0=(int) floor(std::log(a)/std::log(R)); - a=pow(R,i0); + a = std::pow(R,i0); reciprocal_fn.cuts.push_back(a); } diff --git a/src/2geom/sweeper.h b/src/2geom/sweeper.h index 1cbce52b0..8c4e182a6 100644 --- a/src/2geom/sweeper.h +++ b/src/2geom/sweeper.h @@ -41,6 +41,9 @@ namespace Geom { +/** @brief Sweep traits class for interval bounds. + * @relates Sweeper + * @ingroup Utilities */ struct IntervalSweepTraits { typedef Interval Bound; typedef std::less Compare; @@ -48,12 +51,22 @@ struct IntervalSweepTraits { inline static Coord exit_value(Bound const &b) { return b.max(); } }; -template +/** @brief Sweep traits class for rectangle bounds. + * @tparam D Which axis to use for sweeping + * @ingroup Utilities */ +template struct RectSweepTraits { typedef Rect Bound; typedef std::less Compare; - inline static Coord entry_value(Bound const &b) { return b[d].min(); } - inline static Coord exit_value(Bound const &b) { return b[d].max(); } + inline static Coord entry_value(Bound const &b) { return b[D].min(); } + inline static Coord exit_value(Bound const &b) { return b[D].max(); } +}; + +template +struct BoundsFast { + Rect operator()(T const &item) const { + return item.boundsFast(); + } }; /** @brief Generic sweepline algorithm. @@ -66,18 +79,30 @@ struct RectSweepTraits { * * To use this, create a derived class and reimplement the _enter() * and/or _leave() virtual functions, insert all the objects, - * and finally call process(). You can specify the bound type + * and finally call process(). Inside _enter() and _leave(), the items that have + * their bounds intersected by the sweepline are available in a list called + * _active_items. This is an intrusive linked list, so you should access it using + * iterators. Do not add or remove items from it. You can specify the bound type * and how it should be accessed by defining a custom SweepTraits class. * * Look in path.cpp for example usage. + * + * @tparam Item The type of items to sweep + * @tparam SweepTraits Traits class that defines the items' bounds, + * how to interpret them and how to sort the events + * @ingroup Utilities */ template class Sweeper { public: + /// Type of the item's boundary - usually this will be an Interval or Rect. typedef typename SweepTraits::Bound Bound; Sweeper() {} + /** @brief Insert a single item for sweeping. + * @param bound Boundary of the item, as defined in sweep traits + * @param item The item itself */ void insert(Bound const &bound, Item const &item) { assert(!(typename SweepTraits::Compare()( SweepTraits::exit_value(bound), @@ -85,6 +110,11 @@ public: _items.push_back(Record(bound, item)); } + /** @brief Insert a range of items using the supplied bounds functor. + * The bounds are computed from items using the supplied bounds functor. + * @param first Start of range + * @param last End of range (one-past-the-end iterator) + * @param f Bounds functor */ template void insert(Iter first, Iter last, BoundFunc f = BoundFunc()) { for (; first != last; ++first) { @@ -105,6 +135,8 @@ public: typename SweepTraits::Compare cmp; + // we store the events in heaps, which is slightly more efficient + // than sorting them, since a heap requires linear time to construct for (RecordIter i = _items.begin(); i != _items.end(); ++i) { _entry_events.push_back(i); _exit_events.push_back(i); diff --git a/src/2geom/transforms.h b/src/2geom/transforms.h index 7c03c5226..de4e6871f 100644 --- a/src/2geom/transforms.h +++ b/src/2geom/transforms.h @@ -40,6 +40,7 @@ #include <2geom/forward.h> #include <2geom/affine.h> #include <2geom/angle.h> +#include namespace Geom { @@ -95,6 +96,7 @@ public: * @ingroup Transforms */ template T pow(T const &t, int n) { + BOOST_CONCEPT_ASSERT((TransformConcept)); if (n == 0) return T::identity(); T result(T::identity()); T x(n < 0 ? t.inverse() : t); -- cgit v1.2.3 From 009833c1d6be271d611c183aae781e41b71ca927 Mon Sep 17 00:00:00 2001 From: Krzysztof Kosi??ski Date: Sun, 5 Jul 2015 03:47:36 +0200 Subject: Fix compilation failure in make check (bzr r14228) --- ...PLEASE DON'T MAKE CHANGES IN THESE FILES.README | 4 +- src/2geom/forward.h | 2 - src/2geom/path.h | 1 + src/display/curve-test.h | 71 ++++++------ src/display/curve.cpp | 18 +-- src/svg/svg-path-geom-test.h | 121 +-------------------- 6 files changed, 47 insertions(+), 170 deletions(-) (limited to 'src') diff --git a/src/2geom/!PLEASE DON'T MAKE CHANGES IN THESE FILES.README b/src/2geom/!PLEASE DON'T MAKE CHANGES IN THESE FILES.README index 074921de2..e94a549f6 100644 --- a/src/2geom/!PLEASE DON'T MAKE CHANGES IN THESE FILES.README +++ b/src/2geom/!PLEASE DON'T MAKE CHANGES IN THESE FILES.README @@ -2,11 +2,11 @@ This is an in-tree copy of lib2geom, a 2D geometry library started by Inkscape developers. If you want to change code in 2Geom, you should commit it first to upstream repository and then execute this command: -rsync -r --existing /path/to/lib2geom/src/2geom /path/to/inkscape/src/2geom +rsync -r --existing --exclude CMakeLists.txt /path/to/lib2geom/src/2geom/ /path/to/inkscape/src/2geom/ The command above will only update existing files. If you add new files to 2Geom, you'll need to copy the new files manually. Same if you remove -some files. +some files. Note that the trailing slashes are required! 2geom's BZR repo = lp:lib2geom http://lib2geom.sourceforge.net diff --git a/src/2geom/forward.h b/src/2geom/forward.h index cf9c75988..27909242c 100644 --- a/src/2geom/forward.h +++ b/src/2geom/forward.h @@ -72,8 +72,6 @@ class ConvexHull; class Curve; class SBasisCurve; class BezierCurve; -class HLineSegment; -class VLineSegment; template class BezierCurveN; typedef BezierCurveN<1> LineSegment; typedef BezierCurveN<2> QuadraticBezier; diff --git a/src/2geom/path.h b/src/2geom/path.h index a2d1e751e..3ca43e0e5 100644 --- a/src/2geom/path.h +++ b/src/2geom/path.h @@ -389,6 +389,7 @@ public: swap(other._curves, _curves); swap(other._closing_seg, _closing_seg); swap(other._closed, _closed); + swap(other._exception_on_stitch, _exception_on_stitch); } /** @brief Swap contents of two paths. * @relates Path */ diff --git a/src/display/curve-test.h b/src/display/curve-test.h index 34137f3c8..f921a5361 100644 --- a/src/display/curve-test.h +++ b/src/display/curve-test.h @@ -16,15 +16,16 @@ public: CurveTest() : path4(Geom::Point(3,5)) // Just a moveto { // Closed path - path1.append(Geom::HLineSegment(Geom::Point(0,0),1)); - path1.append(Geom::VLineSegment(Geom::Point(1,0),1)); + path1.append(Geom::LineSegment(Geom::Point(0,0),Geom::Point(1,0))); + path1.append(Geom::LineSegment(Geom::Point(1,0),Geom::Point(1,1))); path1.close(); // Closed path (ClosingSegment is zero length) path2.append(Geom::LineSegment(Geom::Point(2,0),Geom::Point(3,0))); - // TODO fix path2.append(Geom::BezierCurve<3>(Geom::Point(3,0),Geom::Point(2,1),Geom::Point(1,1),Geom::Point(2,0))); + path2.append(Geom::CubicBezier(Geom::Point(3,0),Geom::Point(2,1),Geom::Point(1,1),Geom::Point(2,0))); path2.close(); // Open path - path3.append(Geom::SVGEllipticalArc(Geom::Point(4,0),1,2,M_PI,false,false,Geom::Point(5,1))); + path3.setStitching(true); + path3.append(Geom::EllipticalArc(Geom::Point(4,0),1,2,M_PI,false,false,Geom::Point(5,1))); path3.append(Geom::LineSegment(Geom::Point(5,1),Geom::Point(5,2))); path3.append(Geom::LineSegment(Geom::Point(6,4),Geom::Point(2,4))); } @@ -49,17 +50,17 @@ public: TS_ASSERT_EQUALS(curve.get_segment_count() , 0u); } { // Individual paths - Geom::PathVector pv(1, Geom::Path()); + Geom::PathVector pv((Geom::Path())); pv[0] = path1; TS_ASSERT_EQUALS(SPCurve(pv).get_segment_count() , 3u); pv[0] = path2; - TS_ASSERT_EQUALS(SPCurve(pv).get_segment_count() , 3u); + TS_ASSERT_EQUALS(SPCurve(pv).get_segment_count() , 2u); pv[0] = path3; TS_ASSERT_EQUALS(SPCurve(pv).get_segment_count() , 4u); pv[0] = path4; TS_ASSERT_EQUALS(SPCurve(pv).get_segment_count() , 0u); pv[0].close(); - TS_ASSERT_EQUALS(SPCurve(pv).get_segment_count() , 1u); + TS_ASSERT_EQUALS(SPCurve(pv).get_segment_count() , 0u); } { // Combination Geom::PathVector pv; @@ -68,7 +69,7 @@ public: pv.push_back(path3); pv.push_back(path4); SPCurve curve(pv); - TS_ASSERT_EQUALS(curve.get_segment_count() , 10u); + TS_ASSERT_EQUALS(curve.get_segment_count() , 9u); } } @@ -86,7 +87,7 @@ public: TS_ASSERT_EQUALS(curve.nodes_in_path() , 1u); } { // Individual paths - Geom::PathVector pv(1, Geom::Path()); + Geom::PathVector pv((Geom::Path())); pv[0] = path1; TS_ASSERT_EQUALS(SPCurve(pv).nodes_in_path() , 3u); pv[0] = path2; @@ -112,28 +113,28 @@ public: void testIsEmpty() { TS_ASSERT(SPCurve(Geom::PathVector()).is_empty()); - TS_ASSERT(!SPCurve(Geom::PathVector(1, path1)).is_empty()); - TS_ASSERT(!SPCurve(Geom::PathVector(1, path2)).is_empty()); - TS_ASSERT(!SPCurve(Geom::PathVector(1, path3)).is_empty()); - TS_ASSERT(!SPCurve(Geom::PathVector(1, path4)).is_empty()); + TS_ASSERT(!SPCurve(path1).is_empty()); + TS_ASSERT(!SPCurve(path2).is_empty()); + TS_ASSERT(!SPCurve(path3).is_empty()); + TS_ASSERT(!SPCurve(path4).is_empty()); } void testIsClosed() { TS_ASSERT(!SPCurve(Geom::PathVector()).is_closed()); - Geom::PathVector pv(1, Geom::Path()); + Geom::PathVector pv((Geom::Path())); TS_ASSERT(!SPCurve(pv).is_closed()); pv[0].close(); TS_ASSERT(SPCurve(pv).is_closed()); - TS_ASSERT(SPCurve(Geom::PathVector(1, path1)).is_closed()); - TS_ASSERT(SPCurve(Geom::PathVector(1, path2)).is_closed()); - TS_ASSERT(!SPCurve(Geom::PathVector(1, path3)).is_closed()); - TS_ASSERT(!SPCurve(Geom::PathVector(1, path4)).is_closed()); + TS_ASSERT(SPCurve(path1).is_closed()); + TS_ASSERT(SPCurve(path2).is_closed()); + TS_ASSERT(!SPCurve(path3).is_closed()); + TS_ASSERT(!SPCurve(path4).is_closed()); } void testLastFirstSegment() { - Geom::PathVector pv(1, path4); + Geom::PathVector pv(path4); TS_ASSERT_EQUALS(SPCurve(pv).first_segment() , (void*)0); TS_ASSERT_EQUALS(SPCurve(pv).last_segment() , (void*)0); pv[0].close(); @@ -185,10 +186,10 @@ public: void testFirstPoint() { - TS_ASSERT_EQUALS(*(SPCurve(Geom::PathVector(1, path1)).first_point()) , Geom::Point(0,0)); - TS_ASSERT_EQUALS(*(SPCurve(Geom::PathVector(1, path2)).first_point()) , Geom::Point(2,0)); - TS_ASSERT_EQUALS(*(SPCurve(Geom::PathVector(1, path3)).first_point()) , Geom::Point(4,0)); - TS_ASSERT_EQUALS(*(SPCurve(Geom::PathVector(1, path4)).first_point()) , Geom::Point(3,5)); + TS_ASSERT_EQUALS(*(SPCurve(path1).first_point()) , Geom::Point(0,0)); + TS_ASSERT_EQUALS(*(SPCurve(path2).first_point()) , Geom::Point(2,0)); + TS_ASSERT_EQUALS(*(SPCurve(path3).first_point()) , Geom::Point(4,0)); + TS_ASSERT_EQUALS(*(SPCurve(path4).first_point()) , Geom::Point(3,5)); Geom::PathVector pv; TS_ASSERT(!SPCurve(pv).first_point()); pv.push_back(path1); @@ -201,10 +202,10 @@ public: void testLastPoint() { - TS_ASSERT_EQUALS(*(SPCurve(Geom::PathVector(1, path1)).last_point()) , Geom::Point(0,0)); - TS_ASSERT_EQUALS(*(SPCurve(Geom::PathVector(1, path2)).last_point()) , Geom::Point(2,0)); - TS_ASSERT_EQUALS(*(SPCurve(Geom::PathVector(1, path3)).last_point()) , Geom::Point(8,4)); - TS_ASSERT_EQUALS(*(SPCurve(Geom::PathVector(1, path4)).last_point()) , Geom::Point(3,5)); + TS_ASSERT_EQUALS(*(SPCurve(path1).last_point()) , Geom::Point(0,0)); + TS_ASSERT_EQUALS(*(SPCurve(path2).last_point()) , Geom::Point(2,0)); + TS_ASSERT_EQUALS(*(SPCurve(path3).last_point()) , Geom::Point(8,4)); + TS_ASSERT_EQUALS(*(SPCurve(path4).last_point()) , Geom::Point(3,5)); Geom::PathVector pv; TS_ASSERT(!SPCurve(pv).last_point()); pv.push_back(path1); @@ -217,10 +218,10 @@ public: void testSecondPoint() { - TS_ASSERT_EQUALS( *(SPCurve(Geom::PathVector(1, path1)).second_point()) , Geom::Point(1,0)); - TS_ASSERT_EQUALS( *(SPCurve(Geom::PathVector(1, path2)).second_point()) , Geom::Point(3,0)); - TS_ASSERT_EQUALS( *(SPCurve(Geom::PathVector(1, path3)).second_point()) , Geom::Point(5,1)); - TS_ASSERT_EQUALS( *(SPCurve(Geom::PathVector(1, path4)).second_point()) , Geom::Point(3,5)); + TS_ASSERT_EQUALS( *(SPCurve(path1).second_point()) , Geom::Point(1,0)); + TS_ASSERT_EQUALS( *(SPCurve(path2).second_point()) , Geom::Point(3,0)); + TS_ASSERT_EQUALS( *(SPCurve(path3).second_point()) , Geom::Point(5,1)); + TS_ASSERT_EQUALS( *(SPCurve(path4).second_point()) , Geom::Point(3,5)); Geom::PathVector pv; pv.push_back(path1); pv.push_back(path2); @@ -232,10 +233,10 @@ public: void testPenultimatePoint() { - TS_ASSERT_EQUALS( *(SPCurve(Geom::PathVector(1, path1)).penultimate_point()) , Geom::Point(1,1)); - TS_ASSERT_EQUALS( *(SPCurve(Geom::PathVector(1, path2)).penultimate_point()) , Geom::Point(3,0)); - TS_ASSERT_EQUALS( *(SPCurve(Geom::PathVector(1, path3)).penultimate_point()) , Geom::Point(6,4)); - TS_ASSERT_EQUALS( *(SPCurve(Geom::PathVector(1, path4)).penultimate_point()) , Geom::Point(3,5)); + TS_ASSERT_EQUALS( *(SPCurve(Geom::PathVector(path1)).penultimate_point()) , Geom::Point(1,1)); + TS_ASSERT_EQUALS( *(SPCurve(Geom::PathVector(path2)).penultimate_point()) , Geom::Point(3,0)); + TS_ASSERT_EQUALS( *(SPCurve(Geom::PathVector(path3)).penultimate_point()) , Geom::Point(6,4)); + TS_ASSERT_EQUALS( *(SPCurve(Geom::PathVector(path4)).penultimate_point()) , Geom::Point(3,5)); Geom::PathVector pv; pv.push_back(path1); pv.push_back(path2); diff --git a/src/display/curve.cpp b/src/display/curve.cpp index d236d81cf..2f422c151 100644 --- a/src/display/curve.cpp +++ b/src/display/curve.cpp @@ -627,20 +627,10 @@ SPCurve::nodes_in_path() const { size_t nr = 0; for(Geom::PathVector::const_iterator it = _pathv.begin(); it != _pathv.end(); ++it) { - nr += (*it).size(); - - nr++; // count last node (this works also for closed paths because although they don't have a 'last node', they do have an extra segment - - // do not count closing knot double for zero-length closing line segments - // however, if the path is only a moveto, and is closed, do not subtract 1 (otherwise the result will be zero nodes) - if ( it->closed() - && ((*it).size() != 0) ) - { - Geom::Curve const &c = it->back_closed(); - if (are_near(c.initialPoint(), c.finalPoint())) { - nr--; - } - } + // if the path does not have any segments, it is a naked moveto, + // and therefore any path has at least one valid node + size_t psize = std::max(1ul, it->size_closed()); + nr += psize; } return nr; diff --git a/src/svg/svg-path-geom-test.h b/src/svg/svg-path-geom-test.h index 3558b4e55..c3972133d 100644 --- a/src/svg/svg-path-geom-test.h +++ b/src/svg/svg-path-geom-test.h @@ -453,38 +453,6 @@ private: return false; } } - else if(Geom::HLineSegment const *la = dynamic_cast(ca)) - { - Geom::HLineSegment const *lb = dynamic_cast(cb); - if (!Geom::are_near((*la).initialPoint(),(*lb).initialPoint(), eps)) { - char temp[200]; - sprintf(temp, "Different start of segment: (%g,%g) != (%g,%g), subpath: %u, segment: %u", (*la).initialPoint()[Geom::X], (*la).initialPoint()[Geom::Y], (*lb).initialPoint()[Geom::X], (*lb).initialPoint()[Geom::Y], static_cast(i), static_cast(j)); - TS_FAIL(temp); - return false; - } - if (!Geom::are_near((*la).finalPoint(),(*lb).finalPoint(), eps)) { - char temp[200]; - sprintf(temp, "Different end of segment: (%g,%g) != (%g,%g), subpath: %u, segment: %u", (*la).finalPoint()[Geom::X], (*la).finalPoint()[Geom::Y], (*lb).finalPoint()[Geom::X], (*lb).finalPoint()[Geom::Y], static_cast(i), static_cast(j)); - TS_FAIL(temp); - return false; - } - } - else if(Geom::VLineSegment const *la = dynamic_cast(ca)) - { - Geom::VLineSegment const *lb = dynamic_cast(cb); - if (!Geom::are_near((*la).initialPoint(),(*lb).initialPoint(), eps)) { - char temp[200]; - sprintf(temp, "Different start of segment: (%g,%g) != (%g,%g), subpath: %u, segment: %u", (*la).initialPoint()[Geom::X], (*la).initialPoint()[Geom::Y], (*lb).initialPoint()[Geom::X], (*lb).initialPoint()[Geom::Y], static_cast(i), static_cast(j)); - TS_FAIL(temp); - return false; - } - if (!Geom::are_near((*la).finalPoint(),(*lb).finalPoint(), eps)) { - char temp[200]; - sprintf(temp, "Different end of segment: (%g,%g) != (%g,%g), subpath: %u, segment: %u", (*la).finalPoint()[Geom::X], (*la).finalPoint()[Geom::Y], (*lb).finalPoint()[Geom::X], (*lb).finalPoint()[Geom::Y], static_cast(i), static_cast(j)); - TS_FAIL(temp); - return false; - } - } else if(Geom::CubicBezier const *la = dynamic_cast(ca)) { Geom::CubicBezier const *lb = dynamic_cast(cb); @@ -522,91 +490,10 @@ private: } else // not same type { - if(Geom::LineSegment const *la = dynamic_cast(ca)) - { - if (Geom::HLineSegment const *lb = dynamic_cast(cb)) { - if (!Geom::are_near((*la).initialPoint(),(*lb).initialPoint(), eps)) { - char temp[200]; - sprintf(temp, "Different start of segment: (%g,%g) != (%g,%g), subpath: %u, segment: %u", (*la).initialPoint()[Geom::X], (*la).initialPoint()[Geom::Y], (*lb).initialPoint()[Geom::X], (*lb).initialPoint()[Geom::Y], static_cast(i), static_cast(j)); - TS_FAIL(temp); - return false; - } - if (!Geom::are_near((*la).finalPoint(),(*lb).finalPoint(), eps)) { - char temp[200]; - sprintf(temp, "Different end of segment: (%g,%g) != (%g,%g), subpath: %u, segment: %u", (*la).finalPoint()[Geom::X], (*la).finalPoint()[Geom::Y], (*lb).finalPoint()[Geom::X], (*lb).finalPoint()[Geom::Y], static_cast(i), static_cast(j)); - TS_FAIL(temp); - return false; - } - char temp[200]; - sprintf(temp, "A LineSegment and an HLineSegment have been considered equal. Subpath: %u, segment: %u", static_cast(i), static_cast(j)); - TS_TRACE(temp); - } else if (Geom::VLineSegment const *lb = dynamic_cast(cb)) { - if (!Geom::are_near((*la).initialPoint(),(*lb).initialPoint(), eps)) { - char temp[200]; - sprintf(temp, "Different start of segment: (%g,%g) != (%g,%g), subpath: %u, segment: %u", (*la).initialPoint()[Geom::X], (*la).initialPoint()[Geom::Y], (*lb).initialPoint()[Geom::X], (*lb).initialPoint()[Geom::Y], static_cast(i), static_cast(j)); - TS_FAIL(temp); - return false; - } - if (!Geom::are_near((*la).finalPoint(),(*lb).finalPoint(), eps)) { - char temp[200]; - sprintf(temp, "Different end of segment: (%g,%g) != (%g,%g), subpath: %u, segment: %u", (*la).finalPoint()[Geom::X], (*la).finalPoint()[Geom::Y], (*lb).finalPoint()[Geom::X], (*lb).finalPoint()[Geom::Y], static_cast(i), static_cast(j)); - TS_FAIL(temp); - return false; - } - char temp[200]; - sprintf(temp, "A LineSegment and a VLineSegment have been considered equal. Subpath: %u, segment: %u", static_cast(i), static_cast(j)); - TS_TRACE(temp); - } else { - char temp[200]; - sprintf(temp, "Different curve types: %s != %s, subpath: %u, segment: %u", typeid(*ca).name(), typeid(*cb).name(), static_cast(i), static_cast(j)); - TS_FAIL(temp); - } - } - else if(Geom::LineSegment const *lb = dynamic_cast(cb)) - { - if (Geom::HLineSegment const *la = dynamic_cast(ca)) { - if (!Geom::are_near((*la).initialPoint(),(*lb).initialPoint(), eps)) { - char temp[200]; - sprintf(temp, "Different start of segment: (%g,%g) != (%g,%g), subpath: %u, segment: %u", (*la).initialPoint()[Geom::X], (*la).initialPoint()[Geom::Y], (*lb).initialPoint()[Geom::X], (*lb).initialPoint()[Geom::Y], static_cast(i), static_cast(j)); - TS_FAIL(temp); - return false; - } - if (!Geom::are_near((*la).finalPoint(),(*lb).finalPoint(), eps)) { - char temp[200]; - sprintf(temp, "Different end of segment: (%g,%g) != (%g,%g), subpath: %u, segment: %u", (*la).finalPoint()[Geom::X], (*la).finalPoint()[Geom::Y], (*lb).finalPoint()[Geom::X], (*lb).finalPoint()[Geom::Y], static_cast(i), static_cast(j)); - TS_FAIL(temp); - return false; - } - char temp[200]; - sprintf(temp, "An HLineSegment and a LineSegment have been considered equal. Subpath: %u, segment: %u", static_cast(i), static_cast(j)); - TS_TRACE(temp); - } else if (Geom::VLineSegment const *la = dynamic_cast(ca)) { - if (!Geom::are_near((*la).initialPoint(),(*lb).initialPoint(), eps)) { - char temp[200]; - sprintf(temp, "Different start of segment: (%g,%g) != (%g,%g), subpath: %u, segment: %u", (*la).initialPoint()[Geom::X], (*la).initialPoint()[Geom::Y], (*lb).initialPoint()[Geom::X], (*lb).initialPoint()[Geom::Y], static_cast(i), static_cast(j)); - TS_FAIL(temp); - return false; - } - if (!Geom::are_near((*la).finalPoint(),(*lb).finalPoint(), eps)) { - char temp[200]; - sprintf(temp, "Different end of segment: (%g,%g) != (%g,%g), subpath: %u, segment: %u", (*la).finalPoint()[Geom::X], (*la).finalPoint()[Geom::Y], (*lb).finalPoint()[Geom::X], (*lb).finalPoint()[Geom::Y], static_cast(i), static_cast(j)); - TS_FAIL(temp); - return false; - } - char temp[200]; - sprintf(temp, "A VLineSegment and a LineSegment have been considered equal. Subpath: %u, segment: %u", static_cast(i), static_cast(j)); - TS_TRACE(temp); - } else { - char temp[200]; - sprintf(temp, "Different curve types: %s != %s, subpath: %u, segment: %u", typeid(*ca).name(), typeid(*cb).name(), static_cast(i), static_cast(j)); - TS_FAIL(temp); - return false; - } - } else { - char temp[200]; - sprintf(temp, "Different curve types: %s != %s, subpath: %u, segment: %u", typeid(*ca).name(), typeid(*cb).name(), static_cast(i), static_cast(j)); - TS_FAIL(temp); - } + char temp[200]; + sprintf(temp, "Different curve types: %s != %s, subpath: %u, segment: %u", typeid(*ca).name(), typeid(*cb).name(), static_cast(i), static_cast(j)); + TS_FAIL(temp); + return false; } } } -- cgit v1.2.3 From 87e7de3977d4aff931588b894d0c02a4ecdf4dc2 Mon Sep 17 00:00:00 2001 From: Nicolas Dufour Date: Sun, 5 Jul 2015 11:18:18 +0200 Subject: Colors. Fix for Bug #1457069 (ICC profile filename with [] causes a crash). Fixed bugs: - https://launchpad.net/bugs/1457069 (bzr r14229) --- src/color-profile.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/color-profile.cpp b/src/color-profile.cpp index 85a6fa876..690a72654 100644 --- a/src/color-profile.cpp +++ b/src/color-profile.cpp @@ -313,7 +313,7 @@ void ColorProfile::set(unsigned key, gchar const *value) { //# 1. Get complete URI of document gchar const *docbase = doc->getURI(); - gchar* escaped = g_uri_escape_string(this->href, "!*'();:@=+$,/?#[]", TRUE); + gchar* escaped = g_uri_escape_string(this->href, "!*'();:@=+$,/?#", TRUE); //g_message("docbase:%s\n", docbase); //org::w3c::dom::URI docUri(docbase); -- cgit v1.2.3 From 9d3a473d605143b5ebc753c732eb19aeced034b2 Mon Sep 17 00:00:00 2001 From: su_v Date: Sun, 5 Jul 2015 12:27:22 +0200 Subject: SVG font editor: fix defunct Kerning tab (bug #1406543) (bzr r14230) --- src/sp-factory.cpp | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'src') diff --git a/src/sp-factory.cpp b/src/sp-factory.cpp index e48646f8d..55e673c4a 100644 --- a/src/sp-factory.cpp +++ b/src/sp-factory.cpp @@ -27,6 +27,7 @@ #include "sp-font.h" #include "sp-font-face.h" #include "sp-glyph.h" +#include "sp-glyph-kerning.h" #include "sp-guide.h" #include "sp-hatch.h" #include "sp-hatch-path.h" @@ -150,6 +151,10 @@ SPObject *SPFactory::createObject(std::string const& id) ret = new SPFontFace; else if (id == "svg:glyph") ret = new SPGlyph; + else if (id == "svg:hkern") + ret = new SPHkern; + else if (id == "svg:vkern") + ret = new SPVkern; else if (id == "sodipodi:guide") ret = new SPGuide; else if (id == "svg:hatch") -- cgit v1.2.3 From b020354dc251990e7113eb402be5ff9c0e1faa7c Mon Sep 17 00:00:00 2001 From: Krzysztof Kosi??ski Date: Sun, 5 Jul 2015 21:02:33 +0200 Subject: Hopefully fix build failure on i386 (bzr r14232) --- src/display/curve.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/display/curve.cpp b/src/display/curve.cpp index 2f422c151..386c63166 100644 --- a/src/display/curve.cpp +++ b/src/display/curve.cpp @@ -629,7 +629,7 @@ SPCurve::nodes_in_path() const for(Geom::PathVector::const_iterator it = _pathv.begin(); it != _pathv.end(); ++it) { // if the path does not have any segments, it is a naked moveto, // and therefore any path has at least one valid node - size_t psize = std::max(1ul, it->size_closed()); + size_t psize = std::max(1, it->size_closed()); nr += psize; } -- cgit v1.2.3 From ddd25c3640413081276af5af1c81aa2ac81346a1 Mon Sep 17 00:00:00 2001 From: Nicolas Dufour Date: Mon, 6 Jul 2015 10:47:18 +0200 Subject: 2geom. Fixes make distcheck failure. (bzr r14233) --- src/2geom/Makefile_insert | 1 - 1 file changed, 1 deletion(-) (limited to 'src') diff --git a/src/2geom/Makefile_insert b/src/2geom/Makefile_insert index 01f48ab39..e3c6836fd 100644 --- a/src/2geom/Makefile_insert +++ b/src/2geom/Makefile_insert @@ -57,7 +57,6 @@ 2geom/generic-rect.h \ 2geom/geom.cpp \ 2geom/geom.h \ - 2geom/hvlinesegment.h \ 2geom/intersection.h \ 2geom/intersection-graph.cpp \ 2geom/intersection-graph.h \ -- cgit v1.2.3 From 02aedb930177c008f1074fa7b17dd6085825ee1b Mon Sep 17 00:00:00 2001 From: Krzysztof Kosi??ski Date: Tue, 7 Jul 2015 01:29:26 +0200 Subject: Update 2Geom to r2417: make scan-build happy (bzr r14235) --- src/2geom/ellipse.cpp | 4 ++-- src/2geom/nearest-time.cpp | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/2geom/ellipse.cpp b/src/2geom/ellipse.cpp index 0264ab4ae..fed3bf86f 100644 --- a/src/2geom/ellipse.cpp +++ b/src/2geom/ellipse.cpp @@ -499,7 +499,7 @@ std::vector Ellipse::intersect(Ellipse const &other) const Line lines[2]; if (aa != 0) { - bb /= aa; cc /= aa; dd /= aa; ee /= aa; ff /= aa; + bb /= aa; cc /= aa; dd /= aa; ee /= aa; /*ff /= aa;*/ Coord s = (ee + std::sqrt(ee*ee - 4*bb)) / 2; Coord q = ee - s; Coord alpha = (dd - cc*q) / (s - q); @@ -508,7 +508,7 @@ std::vector Ellipse::intersect(Ellipse const &other) const lines[0] = Line(1, q, alpha); lines[1] = Line(1, s, beta); } else if (bb != 0) { - cc /= bb; dd /= bb; ee /= bb; ff /= bb; + cc /= bb; /*dd /= bb;*/ ee /= bb; ff /= bb; Coord s = ee; Coord q = 0; Coord alpha = cc / ee; diff --git a/src/2geom/nearest-time.cpp b/src/2geom/nearest-time.cpp index 0b21e51a2..103921021 100644 --- a/src/2geom/nearest-time.cpp +++ b/src/2geom/nearest-time.cpp @@ -80,7 +80,7 @@ Coord nearest_time(Point const &p, D2 const &input, Coord from, Coord to t = 0; } if (dfinal < mind) { - mind = dfinal; + //mind = dfinal; t = 1; } -- cgit v1.2.3 From 06a9bb45855e6fc4d66de0b58ab66ca5a0822887 Mon Sep 17 00:00:00 2001 From: Tavmjong Bah Date: Tue, 7 Jul 2015 17:29:26 +0200 Subject: Patch from Simon Keller to correct alignment of rotated text in PDF+TEX output. (bzr r14236) --- src/extension/internal/latex-text-renderer.cpp | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/extension/internal/latex-text-renderer.cpp b/src/extension/internal/latex-text-renderer.cpp index 1026f51ad..5933dd526 100644 --- a/src/extension/internal/latex-text-renderer.cpp +++ b/src/extension/internal/latex-text-renderer.cpp @@ -409,7 +409,8 @@ Flowing in rectangle is possible, not in arb shape. return; // don't know how to handle non-rect frames yet. is quite uncommon for latex users i think } - Geom::Rect framebox = frame->getRect() * transform(); + // We will transform the coordinates + Geom::Rect framebox = frame->getRect(); // get position and alignment // Align on topleft corner. @@ -429,7 +430,10 @@ Flowing in rectangle is possible, not in arb shape. // no need to add LaTeX code for standard justified output :) break; } - Geom::Point pos(framebox.corner(3)); //topleft corner + + // The topleft Corner was calculated after rotating the text which results in a wrong Coordinate. + // Now, the topleft Corner is rotated after calculating it + Geom::Point pos(framebox.corner(0) * transform()); //topleft corner // determine color and transparency (for now, use rgb color model as it is most native to Inkscape) bool has_color = false; // if the item has no color set, don't force black color @@ -472,7 +476,9 @@ Flowing in rectangle is possible, not in arb shape. os << "\\rotatebox{" << degrees << "}{"; } os << "\\makebox(0,0)" << alignment << "{"; - os << "\\begin{minipage}{" << framebox.width() << "\\unitlength}"; + + // Scale the x width correctly + os << "\\begin{minipage}{" << framebox.width() * transform().expansionX() << "\\unitlength}"; os << justification; // Walk through all spans in the text object. -- cgit v1.2.3 From 96085240c58b87b7df948b7fa1e928a4432a7cf1 Mon Sep 17 00:00:00 2001 From: Krzysztof Kosi??ski Date: Wed, 8 Jul 2015 23:08:19 +0200 Subject: Fix build failures on some platforms. Correct CMakeLists.txt after 2Geom sync - patch by su_v. (bzr r14237) --- src/2geom/CMakeLists.txt | 7 ------- src/2geom/conicsec.cpp | 1 + src/2geom/point.h | 4 +++- src/live_effects/CMakeLists.txt | 2 -- 4 files changed, 4 insertions(+), 10 deletions(-) (limited to 'src') diff --git a/src/2geom/CMakeLists.txt b/src/2geom/CMakeLists.txt index 8a2884a2a..eb7abb614 100644 --- a/src/2geom/CMakeLists.txt +++ b/src/2geom/CMakeLists.txt @@ -68,8 +68,6 @@ set(2geom_SRC conic_section_clipper_cr.h conic_section_clipper_impl.h conicsec.h - conjugate_gradient.h - convex-cover.h coord.h crossing.h curve.h @@ -83,7 +81,6 @@ set(2geom_SRC generic-interval.h generic-rect.h geom.h - hvlinesegment.h int-interval.h int-point.h int-rect.h @@ -91,19 +88,16 @@ set(2geom_SRC line.h linear.h math-utils.h - nearest-point.h ord.h path-intersection.h path-sink.h path.h pathvector.h piecewise.h - point-ops.h point.h polynomial.h ray.h rect.h - region.h sbasis-2d.h sbasis-curve.h sbasis-geometric.h @@ -111,7 +105,6 @@ set(2geom_SRC sbasis-poly.h sbasis-to-bezier.h sbasis.h - shape.h solver.h svg-path-parser.h svg-path-writer.h diff --git a/src/2geom/conicsec.cpp b/src/2geom/conicsec.cpp index 3b36137be..089db71a4 100644 --- a/src/2geom/conicsec.cpp +++ b/src/2geom/conicsec.cpp @@ -1337,6 +1337,7 @@ bool xAx::decompose (Line& l1, Line& l2) const */ Rect xAx::arc_bound (const Point & P1, const Point & Q, const Point & P2) const { + using std::swap; //std::cout << "BOUND: P1 = " << P1 << std::endl; //std::cout << "BOUND: Q = " << Q << std::endl; //std::cout << "BOUND: P2 = " << P2 << std::endl; diff --git a/src/2geom/point.h b/src/2geom/point.h index f2659d351..a66e64647 100644 --- a/src/2geom/point.h +++ b/src/2geom/point.h @@ -386,7 +386,9 @@ inline Coord distanceSq (Point const &a, Point const &b) { /// Test whether two points are no further apart than some threshold. /// @relates Point inline bool are_near(Point const &a, Point const &b, double eps = EPSILON) { - return are_near(distance(a, b), 0, eps); + // do not use an unqualified calls to distance before the empty + // specialization of iterator_traits is defined - see end of file + return are_near((a - b).length(), 0, eps); } /// Test whether three points lie approximately on the same line. diff --git a/src/live_effects/CMakeLists.txt b/src/live_effects/CMakeLists.txt index c4b92e579..8a097590a 100644 --- a/src/live_effects/CMakeLists.txt +++ b/src/live_effects/CMakeLists.txt @@ -3,7 +3,6 @@ set(live_effects_SRC lpe-angle_bisector.cpp lpe-attach-path.cpp lpe-bendpath.cpp - lpe-boolops.cpp lpe-bounding-box.cpp lpe-bspline.cpp lpe-circle_3pts.cpp @@ -81,7 +80,6 @@ set(live_effects_SRC lpe-angle_bisector.h lpe-attach-path.h lpe-bendpath.h - lpe-boolops.h lpe-bounding-box.h lpe-bspline.h lpe-circle_3pts.h -- cgit v1.2.3 From 99dad514a04e1da213fa0877c15cae5d4ca00ea0 Mon Sep 17 00:00:00 2001 From: Jabier Arraiza Cenoz Date: Fri, 10 Jul 2015 16:50:38 +0200 Subject: Force PNG bitmap export to always write with PNG extension (bzr r14238) --- src/ui/dialog/export.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/ui/dialog/export.cpp b/src/ui/dialog/export.cpp index 384aec415..1edfdfe80 100644 --- a/src/ui/dialog/export.cpp +++ b/src/ui/dialog/export.cpp @@ -945,17 +945,19 @@ Gtk::Dialog * Export::create_progress_dialog (Glib::ustring progress_text) { Glib::ustring Export::filename_add_extension (Glib::ustring filename, Glib::ustring extension) { Glib::ustring::size_type dot; + Glib::ustring::size_type dot_ext; dot = filename.find_last_of("."); - if ( !dot ) + dot_ext = filename.lowercase().rfind("." + extension.lowercase()); + if ( dot == std::string::npos ) { return filename = filename + "." + extension; } else { - if (dot==filename.find_last_of(Glib::ustring::compose(".", extension))) + if (dot == dot_ext) { - return filename; + return filename = filename; } else { -- cgit v1.2.3 From e45d61d03281d9103b3b8daf40b84e6f415eadc4 Mon Sep 17 00:00:00 2001 From: Jabier Arraiza Cenoz Date: Sat, 11 Jul 2015 00:58:49 +0200 Subject: Fix a bug continuing a bezier path whith a LPE one like spiro or bspline (bzr r14239) --- src/ui/tools/freehand-base.cpp | 7 ++++--- src/ui/tools/pen-tool.cpp | 21 ++++++++++++++------- 2 files changed, 18 insertions(+), 10 deletions(-) (limited to 'src') diff --git a/src/ui/tools/freehand-base.cpp b/src/ui/tools/freehand-base.cpp index e8cbfcdbf..4fad06c98 100644 --- a/src/ui/tools/freehand-base.cpp +++ b/src/ui/tools/freehand-base.cpp @@ -598,9 +598,10 @@ void spdc_concat_colors_and_flush(FreehandBase *dc, gboolean forceclosed) if(prefs->getInt(tool_name(dc) + "/freehand-mode", 0) == 1 || prefs->getInt(tool_name(dc) + "/freehand-mode", 0) == 2){ s = dc->overwrite_curve; - } - if (dc->sa->start) { - s = reverse_then_unref(s); + } else { + if (dc->sa->start) { + s = reverse_then_unref(s); + } } s->append_continuous(c, 0.0625); c->unref(); diff --git a/src/ui/tools/pen-tool.cpp b/src/ui/tools/pen-tool.cpp index 38892517d..827dbf5c3 100644 --- a/src/ui/tools/pen-tool.cpp +++ b/src/ui/tools/pen-tool.cpp @@ -1351,8 +1351,9 @@ void PenTool::_bsplineSpiroColor() void PenTool::_bsplineSpiro(bool shift) { - if(!this->spiro && !this->bspline) + if(!this->spiro && !this->bspline){ return; + } shift?this->_bsplineSpiroOff():this->_bsplineSpiroOn(); this->_bsplineSpiroBuild(); @@ -1413,13 +1414,19 @@ void PenTool::_bsplineSpiroStartAnchor(bool shift) }else{ this->spiro = false; } - if(!this->spiro && !this->bspline) + if(!this->spiro && !this->bspline){ + SPCurve *tmp_curve = this->sa->curve->copy(); + if (this->sa->start) { + tmp_curve = tmp_curve ->create_reverse(); + } + this->overwrite_curve = tmp_curve ; return; - - if(shift) + } + if(shift){ this->_bsplineSpiroStartAnchorOff(); - else + } else { this->_bsplineSpiroStartAnchorOn(); + } } void PenTool::_bsplineSpiroStartAnchorOn() @@ -1482,9 +1489,9 @@ void PenTool::_bsplineSpiroStartAnchorOff() } void PenTool::_bsplineSpiroMotion(bool shift){ - if(!this->spiro && !this->bspline) + if(!this->spiro && !this->bspline){ return; - + } using Geom::X; using Geom::Y; if(this->red_curve->is_empty()) return; -- cgit v1.2.3 From 0ea72b9451e2544b4966080e70c9e9689edd3109 Mon Sep 17 00:00:00 2001 From: "Liam P. White" Date: Sat, 11 Jul 2015 14:20:59 -0400 Subject: Shit son, MROE FUCKING DOCS FUCKING EVERYWHERE IT'S A WONDER WE HAVE SPACE FOR A VECTOR GRAPHICS PROGRAM BETWEEN ALL THESE DOCS (bzr r14242) --- src/helper/geom-pathstroke.cpp | 103 +++++++++++++++++++++-------------------- src/helper/geom-pathstroke.h | 50 ++++++++++++++++---- 2 files changed, 94 insertions(+), 59 deletions(-) (limited to 'src') diff --git a/src/helper/geom-pathstroke.cpp b/src/helper/geom-pathstroke.cpp index e1038b03a..e5f207c66 100644 --- a/src/helper/geom-pathstroke.cpp +++ b/src/helper/geom-pathstroke.cpp @@ -1,7 +1,8 @@ -/* Author: +/* Authors: * Liam P. White + * Tavmjong Bah * - * Copyright (C) 2014-2015 Author + * Copyright (C) 2014-2015 Authors * * Released under GNU GPL, read the file 'COPYING' for more information */ @@ -60,14 +61,14 @@ namespace { // Internal data structure -struct join_data -{ +struct join_data { join_data(Geom::Path &_res, Geom::Path const&_outgoing, Geom::Point _in_tang, Geom::Point _out_tang, double _miter, double _width) - : res(_res), outgoing(_outgoing), in_tang(_in_tang) - , out_tang(_out_tang), miter(_miter), width(_width) {} + : res(_res), outgoing(_outgoing), in_tang(_in_tang), out_tang(_out_tang), miter(_miter), width(_width) {}; - // I/O + // contains the current path that is being built on Geom::Path &res; + + // contains the next curve to append Geom::Path const& outgoing; // input tangents @@ -382,47 +383,6 @@ void tangents(Geom::Point tang[2], Geom::Curve const& incoming, Geom::Curve cons tang[0] = tang1, tang[1] = tang2; } -void outline_helper(Geom::Path &res, Geom::Path const& temp, Geom::Point in_tang, Geom::Point out_tang, double width, double miter, Inkscape::LineJoinType join) -{ - if (res.size() == 0 || temp.size() == 0) - return; - - Geom::Curve const& outgoing = temp.front(); - if (Geom::are_near(res.finalPoint(), outgoing.initialPoint())) { - // if the points are /that/ close, just ignore this one - res.setFinal(temp.initialPoint()); - res.append(temp); - return; - } - - join_data jd(res, temp, in_tang, out_tang, miter, width); - - bool on_outside = (Geom::cross(in_tang, out_tang) > 0); - - if (on_outside) { - join_func *jf; - switch (join) { - case Inkscape::JOIN_BEVEL: - jf = &bevel_join; - break; - case Inkscape::JOIN_ROUND: - jf = &round_join; - break; - case Inkscape::JOIN_EXTRAPOLATE: - jf = &extrapolate_join; - break; - case Inkscape::JOIN_MITER_CLIP: - jf = &miter_clip_join; - break; - default: - jf = &miter_join; - } - jf(jd); - } else { - join_inside(jd); - } -} - // Offsetting a line segment is mathematically stable and quick to do Geom::LineSegment offset_line(Geom::LineSegment const& l, double width) { @@ -696,7 +656,7 @@ Geom::Path half_outline(Geom::Path const& input, double width, double miter, Lin res.append(temp); } else { tangents(tang, input[u-1], input[u]); - outline_helper(res, temp, tang[0], tang[1], width, miter, join); + outline_join(res, temp, tang[0], tang[1], width, miter, join); } // odd number of paths @@ -704,7 +664,7 @@ Geom::Path half_outline(Geom::Path const& input, double width, double miter, Lin temp = Geom::Path(); offset_curve(temp, &input[u+1], width); tangents(tang, input[u], input[u+1]); - outline_helper(res, temp, tang[0], tang[1], width, miter, join); + outline_join(res, temp, tang[0], tang[1], width, miter, join); } } @@ -716,7 +676,7 @@ Geom::Path half_outline(Geom::Path const& input, double width, double miter, Lin Geom::Path temp2; temp2.append(c2); tangents(tang, input.back(), input.front()); - outline_helper(temp, temp2, tang[0], tang[1], width, miter, join); + outline_join(temp, temp2, tang[0], tang[1], width, miter, join); res.erase(res.begin()); res.erase_last(); // @@ -727,6 +687,47 @@ Geom::Path half_outline(Geom::Path const& input, double width, double miter, Lin return res; } +void outline_join(Geom::Path &res, Geom::Path const& temp, Geom::Point in_tang, Geom::Point out_tang, double width, double miter, Inkscape::LineJoinType join) +{ + if (res.size() == 0 || temp.size() == 0) + return; + + Geom::Curve const& outgoing = temp.front(); + if (Geom::are_near(res.finalPoint(), outgoing.initialPoint())) { + // if the points are /that/ close, just ignore this one + res.setFinal(temp.initialPoint()); + res.append(temp); + return; + } + + join_data jd(res, temp, in_tang, out_tang, miter, width); + + bool on_outside = (Geom::cross(in_tang, out_tang) > 0); + + if (on_outside) { + join_func *jf; + switch (join) { + case Inkscape::JOIN_BEVEL: + jf = &bevel_join; + break; + case Inkscape::JOIN_ROUND: + jf = &round_join; + break; + case Inkscape::JOIN_EXTRAPOLATE: + jf = &extrapolate_join; + break; + case Inkscape::JOIN_MITER_CLIP: + jf = &miter_clip_join; + break; + default: + jf = &miter_join; + } + jf(jd); + } else { + join_inside(jd); + } +} + } // namespace Inkscape /* diff --git a/src/helper/geom-pathstroke.h b/src/helper/geom-pathstroke.h index 0cfb9f817..6697273cf 100644 --- a/src/helper/geom-pathstroke.h +++ b/src/helper/geom-pathstroke.h @@ -1,10 +1,11 @@ #ifndef INKSCAPE_HELPER_PATH_STROKE_H #define INKSCAPE_HELPER_PATH_STROKE_H -/* Author: +/* Authors: * Liam P. White + * Tavmjong Bah * - * Copyright (C) 2014-2015 Author + * Copyright (C) 2014-2015 Authors * * Released under GNU GPL, read the file 'COPYING' for more information */ @@ -26,21 +27,54 @@ enum LineCapType { BUTT_FLAT, BUTT_ROUND, BUTT_SQUARE, - BUTT_PEAK, // ? + BUTT_PEAK, // This is not a line ending supported by the SVG standard. }; +/** + * Strokes the path given by @a input. + * Joins may behave oddly if the width is negative. + * + * @param[in] input Input path. + * @param[in] width Stroke width. + * @param[in] miter Miter limit. Only used when @a join is one of JOIN_MITER, JOIN_MITER_CLIP, and JOIN_EXTRAPOLATE. + * @param[in] join Line join type used during offset. Member of LineJoinType enum. + * @param[in] cap Line cap type used during stroking. Member of LineCapType enum. + * + * @return Stroked path. + * If the input path is closed, the resultant vector will contain two paths. + * Otherwise, there should be only one in the output. + */ +Geom::PathVector outline(Geom::Path const& input, double width, double miter, LineJoinType join = JOIN_BEVEL, LineCapType cap = BUTT_FLAT); + /** * Offset the input path by @a width. * Joins may behave oddly if the width is negative. * - * @param input - * @param width Amount to offset. - * @param miter Miter limit. Only used with JOIN_MITER, JOIN_MITER_CLIP, and JOIN_EXTRAPOLATE. - * @param join + * @param[in] input Input path. + * @param[in] width Amount to offset. + * @param[in] miter Miter limit. Only used when @a join is one of JOIN_MITER, JOIN_MITER_CLIP, and JOIN_EXTRAPOLATE. + * @param[in] join Line join type used during offset. Member of LineJoinType enum. + * + * @return Offsetted output. */ Geom::Path half_outline(Geom::Path const& input, double width, double miter, LineJoinType join = JOIN_BEVEL); -Geom::PathVector outline(Geom::Path const& input, double width, double miter, LineJoinType join = JOIN_BEVEL, LineCapType cap = BUTT_FLAT); +/** + * Builds a join on the provided path. + * Joins may behave oddly if the width is negative. + * + * @param[inout] res The path to build the join on. + * The outgoing path (or a portion thereof) will be appended after the join is created. + * Previous segments may be modified as an optimization, beware! + * + * @param[in] outgoing The segment to append on the outgoing portion of the join. + * @param[in] in_tang The end tangent to consider on the input path. + * @param[in] out_tang The begin tangent to consider on the output path. + * @param[in] width + * @param[in] miter + * @param[in] join + */ +void outline_join(Geom::Path &res, Geom::Path const& outgoing, Geom::Point in_tang, Geom::Point out_tang, double width, double miter, LineJoinType join); } // namespace Inkscape -- cgit v1.2.3 From e0767cb0f376a7befe269e5eef9fb71d99e02c37 Mon Sep 17 00:00:00 2001 From: Tavmjong Bah Date: Mon, 13 Jul 2015 15:50:02 +0200 Subject: Don't allow zero values for width/height and corresponding viewBox numbers. (bzr r14243) --- src/ui/widget/page-sizer.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/ui/widget/page-sizer.cpp b/src/ui/widget/page-sizer.cpp index 0a5697661..19ab1a280 100644 --- a/src/ui/widget/page-sizer.cpp +++ b/src/ui/widget/page-sizer.cpp @@ -266,12 +266,14 @@ PageSizer::PageSizer(Registry & _wr) _viewboxW.setDigits(2); _viewboxH.setDigits(2); + _dimensionWidth.setRange( 0.00001, 10000000 ); + _dimensionHeight.setRange( 0.00001, 10000000 ); _scaleX.setRange( 0.00001, 100000 ); _scaleY.setRange( 0.00001, 100000 ); _viewboxX.setRange( -100000, 100000 ); _viewboxY.setRange( -100000, 100000 ); - _viewboxW.setRange( 0, 200000 ); - _viewboxH.setRange( 0, 200000 ); + _viewboxW.setRange( 0.01, 200000 ); + _viewboxH.setRange( 0.01, 200000 ); _scaleY.set_sensitive (false); // We only want to display Y scale. -- cgit v1.2.3 From a3d09e2486cf76da1633c15fd40c2c39a0c06a4a Mon Sep 17 00:00:00 2001 From: Marc Jeanmougin Date: Tue, 14 Jul 2015 00:23:14 +0200 Subject: fix "arrange" tool (typo) Fixed bugs: - https://launchpad.net/bugs/1473711 (bzr r14244) --- src/ui/dialog/grid-arrange-tab.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/ui/dialog/grid-arrange-tab.cpp b/src/ui/dialog/grid-arrange-tab.cpp index c44f66a4d..ccd23a572 100644 --- a/src/ui/dialog/grid-arrange-tab.cpp +++ b/src/ui/dialog/grid-arrange-tab.cpp @@ -311,7 +311,7 @@ g_print("\n row = %f col = %f selection x= %f selection y = %f", total_row_h GSList *current_row = NULL; col_cnt = 0; - for(;it!=sorted.end()&&col Date: Tue, 14 Jul 2015 13:04:32 +0200 Subject: Fix for circular references detection in almost all cases, fixing https://bugs.launchpad.net/inkscape/+bug/167247 and a few of its duplicates. This fix is aimed at preventing any sort of circular references with the URIReference::_acceptObject method, checking the absence of loops in the reference+child tree. There can be some performance improvements done if we add a pointer from cloned sub-objects to their origin sub-object. The remaining cases that are not fixed can involve non-trivial loops using one or more "url()" stylesheet references. Being able to take them into account would require a non-obvious style.cpp refactoring making use of URIReference for this kind of reference (and not handling manually the signals in the styling code, which would probably be a good thing to do anyway) (bzr r14245) --- src/live_effects/lpeobject-reference.cpp | 9 +---- src/live_effects/parameter/path-reference.cpp | 2 +- src/persp3d-reference.cpp | 3 +- src/sp-clippath.h | 2 +- src/sp-filter-reference.cpp | 2 +- src/sp-gradient-reference.cpp | 2 +- src/sp-hatch.h | 2 +- src/sp-marker.h | 2 +- src/sp-mask.h | 2 +- src/sp-object.cpp | 5 +-- src/sp-paint-server.cpp | 2 +- src/sp-pattern.h | 5 ++- src/sp-tag-use-reference.cpp | 9 +---- src/sp-tref-reference.cpp | 2 +- src/sp-use-reference.cpp | 13 +------ src/uri-references.cpp | 50 +++++++++++++++++++++++++++ src/uri-references.h | 10 +++--- 17 files changed, 74 insertions(+), 48 deletions(-) (limited to 'src') diff --git a/src/live_effects/lpeobject-reference.cpp b/src/live_effects/lpeobject-reference.cpp index 573c8a2fd..d9de6e77f 100644 --- a/src/live_effects/lpeobject-reference.cpp +++ b/src/live_effects/lpeobject-reference.cpp @@ -43,14 +43,7 @@ LPEObjectReference::~LPEObjectReference(void) bool LPEObjectReference::_acceptObject(SPObject * const obj) const { if (IS_LIVEPATHEFFECT(obj)) { - SPObject * const owner = getOwner(); - /* Refuse references to us or to an ancestor. */ - for ( SPObject *iter = owner ; iter ; iter = iter->parent ) { - if ( iter == obj ) { - return false; - } - } - return true; + return URIReference::_acceptObject(obj); } else { return false; } diff --git a/src/live_effects/parameter/path-reference.cpp b/src/live_effects/parameter/path-reference.cpp index a76fb1b32..42589b050 100644 --- a/src/live_effects/parameter/path-reference.cpp +++ b/src/live_effects/parameter/path-reference.cpp @@ -22,7 +22,7 @@ bool PathReference::_acceptObject(SPObject * const obj) const return false; } // TODO: check whether the referred path has this LPE applied, if so: deny deny deny! - return true; + return URIReference::_acceptObject(obj); } else { return false; } diff --git a/src/persp3d-reference.cpp b/src/persp3d-reference.cpp index 895eac6f2..4526a8d8f 100644 --- a/src/persp3d-reference.cpp +++ b/src/persp3d-reference.cpp @@ -35,7 +35,8 @@ Persp3DReference::~Persp3DReference(void) bool Persp3DReference::_acceptObject(SPObject *obj) const { - return SP_IS_PERSP3D(obj); + return SP_IS_PERSP3D(obj) && URIReference::_acceptObject(obj); +; /* effic: Don't bother making this an inline function: _acceptObject is a virtual function, typically called from a context where the runtime type is not known at compile time. */ } diff --git a/src/sp-clippath.h b/src/sp-clippath.h index 91dcfd625..c9a8c68df 100644 --- a/src/sp-clippath.h +++ b/src/sp-clippath.h @@ -88,7 +88,7 @@ protected: return false; } SPObject * const owner = this->getOwner(); - if (obj->isAncestorOf(owner)) { + if (!URIReference::_acceptObject(obj)) { //XML Tree being used directly here while it shouldn't be... Inkscape::XML::Node * const owner_repr = owner->getRepr(); //XML Tree being used directly here while it shouldn't be... diff --git a/src/sp-filter-reference.cpp b/src/sp-filter-reference.cpp index 57600ad39..afb014820 100644 --- a/src/sp-filter-reference.cpp +++ b/src/sp-filter-reference.cpp @@ -4,7 +4,7 @@ bool SPFilterReference::_acceptObject(SPObject *obj) const { - return SP_IS_FILTER(obj); + return SP_IS_FILTER(obj) && URIReference::_acceptObject(obj); /* effic: Don't bother making this an inline function: _acceptObject is a virtual function, typically called from a context where the runtime type is not known at compile time. */ } diff --git a/src/sp-gradient-reference.cpp b/src/sp-gradient-reference.cpp index d2b8128fb..216ac73de 100644 --- a/src/sp-gradient-reference.cpp +++ b/src/sp-gradient-reference.cpp @@ -4,7 +4,7 @@ bool SPGradientReference::_acceptObject(SPObject *obj) const { - return SP_IS_GRADIENT(obj); + return SP_IS_GRADIENT(obj) && URIReference::_acceptObject(obj); /* effic: Don't bother making this an inline function: _acceptObject is a virtual function, typically called from a context where the runtime type is not known at compile time. */ } diff --git a/src/sp-hatch.h b/src/sp-hatch.h index 5004a611f..546f06a1e 100644 --- a/src/sp-hatch.h +++ b/src/sp-hatch.h @@ -168,7 +168,7 @@ public: protected: virtual bool _acceptObject(SPObject *obj) const { - return dynamic_cast(obj) != NULL; + return dynamic_cast(obj) != NULL && URIReference::_acceptObject(obj); } }; diff --git a/src/sp-marker.h b/src/sp-marker.h index 56cbaf94f..bae13243b 100644 --- a/src/sp-marker.h +++ b/src/sp-marker.h @@ -92,7 +92,7 @@ class SPMarkerReference : public Inkscape::URIReference { } protected: virtual bool _acceptObject(SPObject *obj) const { - return SP_IS_MARKER(obj); + return SP_IS_MARKER(obj) && URIReference::_acceptObject(obj); } }; diff --git a/src/sp-mask.h b/src/sp-mask.h index 3559483bb..74bd4d66e 100644 --- a/src/sp-mask.h +++ b/src/sp-mask.h @@ -81,7 +81,7 @@ protected: return false; } SPObject * const owner = this->getOwner(); - if (obj->isAncestorOf(owner)) { + if (!URIReference::_acceptObject(obj)) { //XML Tree being used directly here while it shouldn't be... Inkscape::XML::Node * const owner_repr = owner->getRepr(); //XML Tree being used directly here while it shouldn't be... diff --git a/src/sp-object.cpp b/src/sp-object.cpp index 0bb8c240f..db66eb3e6 100644 --- a/src/sp-object.cpp +++ b/src/sp-object.cpp @@ -721,6 +721,9 @@ void SPObject::invoke_build(SPDocument *document, Inkscape::XML::Node *repr, uns } this->cloned = cloned; + /* Invoke derived methods, if any */ + this->build(document, repr); + if ( !cloned ) { this->document->bindObjectToRepr(this->repr, this); @@ -754,8 +757,6 @@ void SPObject::invoke_build(SPDocument *document, Inkscape::XML::Node *repr, uns g_assert(this->getId() == NULL); } - /* Invoke derived methods, if any */ - this->build(document, repr); /* Signalling (should be connected AFTER processing derived methods */ sp_repr_add_listener(repr, &object_event_vector, this); diff --git a/src/sp-paint-server.cpp b/src/sp-paint-server.cpp index ae40ad1aa..c3416c6c8 100644 --- a/src/sp-paint-server.cpp +++ b/src/sp-paint-server.cpp @@ -27,7 +27,7 @@ SPPaintServer *SPPaintServerReference::getObject() const bool SPPaintServerReference::_acceptObject(SPObject *obj) const { - return SP_IS_PAINT_SERVER(obj); + return SP_IS_PAINT_SERVER(obj) && URIReference::_acceptObject(obj); } SPPaintServer::SPPaintServer() : SPObject() { diff --git a/src/sp-pattern.h b/src/sp-pattern.h index 145bb934e..a5e7be1d4 100644 --- a/src/sp-pattern.h +++ b/src/sp-pattern.h @@ -129,9 +129,8 @@ public: } protected: - virtual bool _acceptObject(SPObject *obj) const - { - return SP_IS_PATTERN(obj); + virtual bool _acceptObject(SPObject *obj) const { + return SP_IS_PATTERN (obj)&& URIReference::_acceptObject(obj); } }; diff --git a/src/sp-tag-use-reference.cpp b/src/sp-tag-use-reference.cpp index 220cd16d1..9fcb31fd1 100644 --- a/src/sp-tag-use-reference.cpp +++ b/src/sp-tag-use-reference.cpp @@ -24,14 +24,7 @@ bool SPTagUseReference::_acceptObject(SPObject * const obj) const { if (SP_IS_ITEM(obj)) { - SPObject * const owner = getOwner(); - // Refuse references to us or to an ancestor. - for ( SPObject *iter = owner ; iter ; iter = iter->parent ) { - if ( iter == obj ) { - return false; - } - } - return true; + return URIReference::_acceptObject(obj); } else { return false; } diff --git a/src/sp-tref-reference.cpp b/src/sp-tref-reference.cpp index e82f575e0..7c6ff00e7 100644 --- a/src/sp-tref-reference.cpp +++ b/src/sp-tref-reference.cpp @@ -21,7 +21,7 @@ bool SPTRefReference::_acceptObject(SPObject * const obj) const { SPObject *owner = getOwner(); if (SP_IS_TREF(owner)) - return sp_tref_reference_allowed(SP_TREF(getOwner()), obj); + return URIReference::_acceptObject(obj); else return false; } diff --git a/src/sp-use-reference.cpp b/src/sp-use-reference.cpp index 642cfede8..f0b2985d2 100644 --- a/src/sp-use-reference.cpp +++ b/src/sp-use-reference.cpp @@ -25,18 +25,7 @@ bool SPUseReference::_acceptObject(SPObject * const obj) const { - if (SP_IS_ITEM(obj)) { - SPObject * const owner = getOwner(); - // Refuse references to us or to an ancestor. - for ( SPObject *iter = owner ; iter ; iter = iter->parent ) { - if ( iter == obj ) { - return false; - } - } - return true; - } else { - return false; - } + return URIReference::_acceptObject(obj); } diff --git a/src/uri-references.cpp b/src/uri-references.cpp index 2518c173e..04f904d39 100644 --- a/src/uri-references.cpp +++ b/src/uri-references.cpp @@ -43,6 +43,56 @@ URIReference::~URIReference() detach(); } +/* + * The main ideas here are: + * (1) "If we are inside a clone, then we can accept if and only if our "original thing" can accept the reference" + * (this caused problems when there are clones because a change in ids triggers signals for the object hrefing this id, but also its cloned reprs + * (descendants of referencing an ancestor of the href'ing object)). The way it is done here is *atrocious*, but i could not find a better way. + * FIXME: find a better and safer way to find the "original object" of anyone with the flag ->cloned + * + * (2) Once we have an (potential owner) object, it can accept a href to obj, iff the graph of objects where directed edges are + * either parent->child relations , *** or href'ing to href'ed *** relations, stays acyclic. + * We can go either from owner and up in the tree, or from obj and down, in either case this will be in the worst case linear in the number of objects. + * There are no easy objects allowing to do the second proposition, while "hrefList" is a "list of objects href'ing us", so we'll take this. + * Then we keep a set of already visited elements, and do a DFS on this graph. if we find obj, then BOOM. + */ + +bool URIReference::_acceptObject(SPObject *obj) const { + //we go back following hrefList and parent to find if the object already references ourselves indirectly + std::set done; + SPObject * owner = getOwner(); + if(!owner)return true; + while(owner->cloned){ + std::vector positions; + while(owner->cloned){ + int position=0; + SPObject* c = owner->parent->firstChild(); + while(c != owner && dynamic_cast(c) ){position++;c=c->next;} + positions.push_back(position); + owner=owner->parent; + } + owner = ((SPUse*)owner)->get_original(); + for(int i=positions.size()-2;i>=0;i--)owner=owner->childList(false)[positions[i]]; + } + //once we have the "original" object (hopefully) we look at who is referencing it + std::list todo(owner->hrefList); + todo.push_front(owner->parent); + while(!todo.empty()){ + SPObject* e = todo.front(); + todo.pop_front(); + if(!dynamic_cast(e))continue; + if(done.insert(e).second){ + if(e==obj){return false;} + todo.push_front(e->parent); + todo.insert(todo.begin(),e->hrefList.begin(),e->hrefList.end()); + } + } + return true; +} + + + + void URIReference::attach(const URI &uri) throw(BadURIException) { SPDocument *document = NULL; diff --git a/src/uri-references.h b/src/uri-references.h index 0c51481cc..e56ea0612 100644 --- a/src/uri-references.h +++ b/src/uri-references.h @@ -15,11 +15,15 @@ */ #include +#include +#include #include #include #include "bad-uri-exception.h" #include "sp-object.h" +#include "sp-item.h" +#include "sp-use.h" namespace Inkscape { @@ -122,11 +126,7 @@ public: SPObject *getOwnerObject() { return _owner; } protected: - virtual bool _acceptObject(SPObject *obj) const { - (void)obj; - return true; - } - + virtual bool _acceptObject(SPObject *obj) const; private: SPObject *_owner; SPDocument *_owner_document; -- cgit v1.2.3 From e297259e8fb1fafb05019649a87ba030fbc7ad9c Mon Sep 17 00:00:00 2001 From: Krzysztof Kosi??ski Date: Wed, 15 Jul 2015 20:10:34 +0200 Subject: Add a script that simplifies syncing 2Geom changes (bzr r14246) --- src/2geom/sync.sh | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100755 src/2geom/sync.sh (limited to 'src') diff --git a/src/2geom/sync.sh b/src/2geom/sync.sh new file mode 100755 index 000000000..a2c162903 --- /dev/null +++ b/src/2geom/sync.sh @@ -0,0 +1,31 @@ +#!/bin/bash +set -e + +function usage { + echo "2Geom sync to upstream script" + echo "Usage: $0 path/to/2geom/checkout/dir" +} + +if [ "x$(which rsync)" = "x" ]; then + echo "rsync not found on your system, please install it" + exit 1 +fi + +if [ "x$1" = "x" ]; then + usage $0 + exit 64 +fi +if [ ! -d "$1" ]; then + usage $0 + exit 64 +fi +if [ ! -f "$1/src/2geom/path.h" ]; then + usage $0 + exit 64 +fi + +INK_2GEOM="$(dirname $0)/" +UPSTREAM_2GEOM="$1/src/2geom/" +rsync -r --existing \ + --exclude CMakeLists.txt --exclude sync.sh \ + "$UPSTREAM_2GEOM" "$INK_2GEOM" -- cgit v1.2.3 From 8d9336326e52ee6a181c658d57c7c3a3b776fcf8 Mon Sep 17 00:00:00 2001 From: Krzysztof Kosi??ski Date: Wed, 15 Jul 2015 20:18:11 +0200 Subject: Sync 2Geom to revision 2420. Should fix build failure on llvm-gcc 4.2 and an issue with powerstroke. (bzr r14247) --- src/2geom/ellipse.cpp | 52 +++++++++++++++++++++++++++++++++++++++------------ src/2geom/path.cpp | 3 --- 2 files changed, 40 insertions(+), 15 deletions(-) (limited to 'src') diff --git a/src/2geom/ellipse.cpp b/src/2geom/ellipse.cpp index fed3bf86f..4b5ad9762 100644 --- a/src/2geom/ellipse.cpp +++ b/src/2geom/ellipse.cpp @@ -205,22 +205,50 @@ Ellipse::arc(Point const &ip, Point const &inner, Point const &fp) bool sweep_flag = false; // Determination of large arc flag: - // The arc is larger than half of the ellipse if the inner point - // is on the same side of the line going from the initial - // to the final point as the center of the ellipse - Point versor = fp - ip; - double sdist_c = cross(versor, _center - ip); - double sdist_inner = cross(versor, inner - ip); - - // if we have exactly half of an arc, do not set the large flag. - if (sdist_c != 0 && sgn(sdist_c) == sgn(sdist_inner)) { + // large_arc is false when the inner point is on the same side + // of the center---initial point line as the final point, AND + // is on the same side of the center---final point line as the + // initial point. + // Additionally, large_arc is always false when we have exactly + // 1/2 of an arc, i.e. the cross product of the center -> initial point + // and center -> final point vectors is zero. + // Negating the above leads to the condition for large_arc being true. + Point fv = fp - _center; + Point iv = ip - _center; + Point innerv = inner - _center; + double ifcp = cross(fv, iv); + + if (ifcp != 0 && (sgn(cross(fv, innerv)) != sgn(ifcp) || + sgn(cross(iv, innerv)) != sgn(-ifcp))) + { large_arc_flag = true; } + //cross(-iv, fv) && large_arc_flag + + // Determination of sweep flag: - // If the inner point is on the left side of the ip-fp line, - // we go in clockwise direction. - if (sdist_inner < 0) { + // For clarity, let's assume that Y grows up. Then the cross product + // is positive for points on the left side of a vector and negative + // on the right side of a vector. + // + // cross(?, v) > 0 + // o-------------------> + // cross(?, v) < 0 + // + // If the arc is small (large_arc_flag is false) and the final point + // is on the right side of the vector initial point -> center, + // we have to go in the direction of increasing angles + // (counter-clockwise) and the sweep flag is true. + // If the arc is large, the opposite is true, since we have to reach + // the final point going the long way - in the other direction. + // We can express this observation as: + // cross(_center - ip, fp - _center) < 0 xor large_arc flag + // This is equal to: + // cross(-iv, fv) < 0 xor large_arc flag + // But cross(-iv, fv) is equal to cross(fv, iv) due to antisymmetry + // of the cross product, so we end up with the condition below. + if ((ifcp < 0) ^ large_arc_flag) { sweep_flag = true; } diff --git a/src/2geom/path.cpp b/src/2geom/path.cpp index 836e65013..871441751 100644 --- a/src/2geom/path.cpp +++ b/src/2geom/path.cpp @@ -441,7 +441,6 @@ std::vector Path::roots(Coord v, Dim2 d) const // The class below implements sweepline optimization for curve intersection in paths. // Instead of O(N^2), this takes O(N + X), where X is the number of overlaps // between the bounding boxes of curves. -namespace { struct CurveSweepTraits { struct Bound { @@ -512,8 +511,6 @@ private: Coord _precision; }; -} // end anonymous namespace - std::vector Path::intersect(Path const &other, Coord precision) const { std::vector result; -- cgit v1.2.3 From 3767f1ca97ac6dcacce110089fd7247669ab8e5b Mon Sep 17 00:00:00 2001 From: Krzysztof Kosi??ski Date: Wed, 15 Jul 2015 20:47:16 +0200 Subject: Update 2Geom to r2421, fix SBasis derivatives. Fixes LP bug #1473317. Fixed bugs: - https://launchpad.net/bugs/1473317 (bzr r14248) --- src/2geom/sbasis.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/2geom/sbasis.cpp b/src/2geom/sbasis.cpp index 4f1df621e..42d92d7b8 100644 --- a/src/2geom/sbasis.cpp +++ b/src/2geom/sbasis.cpp @@ -328,9 +328,9 @@ SBasis derivative(SBasis const &a) { } int k = a.size()-1; double d = (2*k+1)*(a[k][1] - a[k][0]); - if(d == 0) + if (d == 0 && k > 0) { c.pop_back(); - else { + } else { c[k][0] = d; c[k][1] = d; } @@ -351,9 +351,9 @@ void SBasis::derive() { // in place version } int k = size()-1; double d = (2*k+1)*((*this)[k][1] - (*this)[k][0]); - if(d == 0) + if (d == 0 && k > 0) { pop_back(); - else { + } else { (*this)[k][0] = d; (*this)[k][1] = d; } -- cgit v1.2.3 From b8027c4442f0e93903ff96c49fbd0c0e4d1444e3 Mon Sep 17 00:00:00 2001 From: "Liam P. White" Date: Thu, 16 Jul 2015 07:56:04 -0400 Subject: setStitching(), gajiosdfksdsfd (bzr r14249) --- src/helper/geom-pathstroke.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/helper/geom-pathstroke.cpp b/src/helper/geom-pathstroke.cpp index e5f207c66..c73a9e9e7 100644 --- a/src/helper/geom-pathstroke.cpp +++ b/src/helper/geom-pathstroke.cpp @@ -647,7 +647,7 @@ Geom::Path half_outline(Geom::Path const& input, double width, double miter, Lin const size_t k = (input.back_closed().isDegenerate() && input.closed()) ?input.size_default()-1:input.size_default(); for (size_t u = 0; u < k; u += 2) { - temp = Geom::Path(); + temp.clear(); offset_curve(temp, &input[u], width); @@ -661,7 +661,7 @@ Geom::Path half_outline(Geom::Path const& input, double width, double miter, Lin // odd number of paths if (u < k - 1) { - temp = Geom::Path(); + temp.clear(); offset_curve(temp, &input[u+1], width); tangents(tang, input[u], input[u+1]); outline_join(res, temp, tang[0], tang[1], width, miter, join); @@ -671,7 +671,7 @@ Geom::Path half_outline(Geom::Path const& input, double width, double miter, Lin if (input.closed()) { Geom::Curve const &c1 = res.back(); Geom::Curve const &c2 = res.front(); - temp = Geom::Path(); + temp.clear(); temp.append(c1); Geom::Path temp2; temp2.append(c2); -- cgit v1.2.3 From 1997b7aeecff6a01b3e319cd2a42a6029bc56ae7 Mon Sep 17 00:00:00 2001 From: Krzysztof Kosi??ski Date: Sun, 19 Jul 2015 15:22:31 +0200 Subject: Enable stitching in Spiro and SPCurve to prevent some crashes (bzr r14250) --- src/display/curve.cpp | 5 +++-- src/live_effects/spiro-converters.cpp | 6 +++++- src/live_effects/spiro-converters.h | 6 ++---- src/live_effects/spiro.h | 6 ++---- 4 files changed, 12 insertions(+), 11 deletions(-) (limited to 'src') diff --git a/src/display/curve.cpp b/src/display/curve.cpp index 386c63166..3024d1276 100644 --- a/src/display/curve.cpp +++ b/src/display/curve.cpp @@ -203,8 +203,9 @@ SPCurve::moveto(double x, double y) void SPCurve::moveto(Geom::Point const &p) { - _pathv.push_back( Geom::Path() ); // for some reason Geom::Path(p) does not work... - _pathv.back().start(p); + Geom::Path path(p); + path.setStitching(true); + _pathv.push_back(path); } /** diff --git a/src/live_effects/spiro-converters.cpp b/src/live_effects/spiro-converters.cpp index 3c7bdf99e..f116d5256 100644 --- a/src/live_effects/spiro-converters.cpp +++ b/src/live_effects/spiro-converters.cpp @@ -64,7 +64,11 @@ ConverterSPCurve::curveto(double x1, double y1, double x2, double y2, double x3, } - +ConverterPath::ConverterPath(Geom::Path &path) + : _path(path) +{ + _path.setStitching(true); +} void ConverterPath::moveto(double x, double y, bool is_open) diff --git a/src/live_effects/spiro-converters.h b/src/live_effects/spiro-converters.h index 83f6ebbc3..90855d2d6 100644 --- a/src/live_effects/spiro-converters.h +++ b/src/live_effects/spiro-converters.h @@ -25,7 +25,7 @@ class ConverterSPCurve : public ConverterBase { public: ConverterSPCurve(SPCurve &curve) : _curve(curve) - {} ; + {} virtual void moveto(double x, double y, bool is_open); virtual void lineto(double x, double y); @@ -45,9 +45,7 @@ private: */ class ConverterPath : public ConverterBase { public: - ConverterPath(Geom::Path &path) - : _path(path) - {} ; + ConverterPath(Geom::Path &path); virtual void moveto(double x, double y, bool is_open); virtual void lineto(double x, double y); diff --git a/src/live_effects/spiro.h b/src/live_effects/spiro.h index 0d85da74b..066b44ca8 100644 --- a/src/live_effects/spiro.h +++ b/src/live_effects/spiro.h @@ -25,11 +25,9 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA #define INKSCAPE_SPIRO_H #include "live_effects/spiro-converters.h" +#include <2geom/forward.h> class SPCurve; -namespace Geom { - class Path; -} namespace Spiro { @@ -53,4 +51,4 @@ double get_knot_th(const spiro_seg *s, int i); } // namespace Spiro -#endif // INKSCAPE_SPIRO_H \ No newline at end of file +#endif // INKSCAPE_SPIRO_H -- cgit v1.2.3 From 8417b110e22e3e56862c0deff4ae72e76a9958b1 Mon Sep 17 00:00:00 2001 From: Alvin Penner Date: Sun, 19 Jul 2015 19:27:14 -0400 Subject: fix typo in intersection_point() (Bug 1475097) Fixed bugs: - https://launchpad.net/bugs/1475097 (bzr r14251) --- src/live_effects/lpe-powerstroke.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/live_effects/lpe-powerstroke.cpp b/src/live_effects/lpe-powerstroke.cpp index 6ce912bcb..f90d67d4e 100644 --- a/src/live_effects/lpe-powerstroke.cpp +++ b/src/live_effects/lpe-powerstroke.cpp @@ -49,7 +49,7 @@ static boost::optional intersection_point( Point const & origin_a, Point { Coord denom = cross(vector_a, vector_b); if (!are_near(denom,0.)){ - Coord t = (cross(origin_b, vector_a) + cross(origin_b, vector_b)) / denom; + Coord t = (cross(vector_b, origin_a) + cross(origin_b, vector_b)) / denom; return origin_a + t * vector_a; } return boost::none; -- cgit v1.2.3 From 535ed65a232ae48ed3b107304dc416ec5eba249e Mon Sep 17 00:00:00 2001 From: Jabier Arraiza Cenoz Date: Wed, 22 Jul 2015 22:25:18 +0200 Subject: Fix a bug continuing a bezier path whith a LPE one like spiro or bspline on a start node (bzr r14252) --- src/ui/tools/freehand-base.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/ui/tools/freehand-base.cpp b/src/ui/tools/freehand-base.cpp index 4fad06c98..e8cbfcdbf 100644 --- a/src/ui/tools/freehand-base.cpp +++ b/src/ui/tools/freehand-base.cpp @@ -598,10 +598,9 @@ void spdc_concat_colors_and_flush(FreehandBase *dc, gboolean forceclosed) if(prefs->getInt(tool_name(dc) + "/freehand-mode", 0) == 1 || prefs->getInt(tool_name(dc) + "/freehand-mode", 0) == 2){ s = dc->overwrite_curve; - } else { - if (dc->sa->start) { - s = reverse_then_unref(s); - } + } + if (dc->sa->start) { + s = reverse_then_unref(s); } s->append_continuous(c, 0.0625); c->unref(); -- cgit v1.2.3