From c98c541481381a04f5e04da046d457b05c3ed711 Mon Sep 17 00:00:00 2001 From: Jabiertxof Date: Sat, 27 May 2017 12:23:25 +0200 Subject: Change bad named vars (bzr r15704) --- src/live_effects/effect.cpp | 2 +- src/live_effects/effect.h | 2 +- src/live_effects/lpe-copy_rotate.cpp | 4 ++-- src/live_effects/lpe-fillet-chamfer.cpp | 2 +- src/live_effects/lpe-measure-line.cpp | 4 ++-- src/live_effects/lpe-mirror_symmetry.cpp | 4 ++-- src/live_effects/parameter/bool.cpp | 6 +++--- src/live_effects/parameter/bool.h | 4 ++-- src/live_effects/parameter/hidden.cpp | 6 ++++-- src/live_effects/parameter/hidden.h | 5 +++-- src/live_effects/parameter/parameter.cpp | 6 +++--- src/live_effects/parameter/parameter.h | 4 ++-- src/sp-lpe-item.cpp | 2 +- 13 files changed, 27 insertions(+), 24 deletions(-) (limited to 'src') diff --git a/src/live_effects/effect.cpp b/src/live_effects/effect.cpp index a4b44b1a9..23a4c9f3d 100644 --- a/src/live_effects/effect.cpp +++ b/src/live_effects/effect.cpp @@ -355,7 +355,7 @@ Effect::Effect(LivePathEffectObject *lpeobject) oncanvasedit_it(0), is_visible(_("Is visible?"), _("If unchecked, the effect remains applied to the object but is temporarily disabled on canvas"), "is_visible", &wr, this, true), show_orig_path(false), - erase_extra_objects(true), + keep_paths(false), lpeobj(lpeobject), concatenate_before_pwd2(false), sp_lpe_item(NULL), diff --git a/src/live_effects/effect.h b/src/live_effects/effect.h index 60ee8d98f..cc0d53f12 100644 --- a/src/live_effects/effect.h +++ b/src/live_effects/effect.h @@ -132,7 +132,7 @@ public: void editNextParamOncanvas(SPItem * item, SPDesktop * desktop); bool apply_to_clippath_and_mask; - bool erase_extra_objects; // set this to false allow retain extra generated objects, see measure line LPE + bool keep_paths; // set this to false allow retain extra generated objects, see measure line LPE bool upd_params; BoolParam is_visible; SPCurve * sp_curve; diff --git a/src/live_effects/lpe-copy_rotate.cpp b/src/live_effects/lpe-copy_rotate.cpp index ff24b46da..2364f4f66 100644 --- a/src/live_effects/lpe-copy_rotate.cpp +++ b/src/live_effects/lpe-copy_rotate.cpp @@ -722,8 +722,8 @@ LPECopyRotate::doOnVisibilityToggled(SPLPEItem const* /*lpeitem*/) void LPECopyRotate::doOnRemove (SPLPEItem const* /*lpeitem*/) { - //unset "erase_extra_objects" hook on sp-lpe-item.cpp - if (!erase_extra_objects) { + //set "keep paths" hook on sp-lpe-item.cpp + if (keep_paths) { processObjects(LPE_TO_OBJECTS); return; } diff --git a/src/live_effects/lpe-fillet-chamfer.cpp b/src/live_effects/lpe-fillet-chamfer.cpp index 08ceab3c3..a2f0b829d 100644 --- a/src/live_effects/lpe-fillet-chamfer.cpp +++ b/src/live_effects/lpe-fillet-chamfer.cpp @@ -38,7 +38,7 @@ LPEFilletChamfer::LPEFilletChamfer(LivePathEffectObject *lpeobject) method(_("Method:"), _("Methods to calculate the fillet or chamfer"), "method", FMConverter, &wr, this, FM_AUTO), mode(_("Mode:"), _("Mode, fillet or chamfer"), - "mode", &wr, this, "F"), + "mode", &wr, this, "F", true), radius(_("Radius (unit or %):"), _("Radius, in unit or %"), "radius", &wr, this, 0.0), chamfer_steps(_("Chamfer steps:"), _("Chamfer steps"), "chamfer_steps", diff --git a/src/live_effects/lpe-measure-line.cpp b/src/live_effects/lpe-measure-line.cpp index f7892cbe7..f18ba2dcd 100644 --- a/src/live_effects/lpe-measure-line.cpp +++ b/src/live_effects/lpe-measure-line.cpp @@ -674,8 +674,8 @@ LPEMeasureLine::doOnVisibilityToggled(SPLPEItem const* /*lpeitem*/) void LPEMeasureLine::doOnRemove (SPLPEItem const* /*lpeitem*/) { - //unset "erase_extra_objects" hook on sp-lpe-item.cpp - if (!erase_extra_objects) { + //set "keep paths" hook on sp-lpe-item.cpp + if (keep_paths) { processObjects(LPE_TO_OBJECTS); items.clear(); return; diff --git a/src/live_effects/lpe-mirror_symmetry.cpp b/src/live_effects/lpe-mirror_symmetry.cpp index bd3dedc86..9c2b876db 100644 --- a/src/live_effects/lpe-mirror_symmetry.cpp +++ b/src/live_effects/lpe-mirror_symmetry.cpp @@ -350,8 +350,8 @@ LPEMirrorSymmetry::doOnVisibilityToggled(SPLPEItem const* /*lpeitem*/) void LPEMirrorSymmetry::doOnRemove (SPLPEItem const* /*lpeitem*/) { - //unset "erase_extra_objects" hook on sp-lpe-item.cpp - if (!erase_extra_objects) { + //set "keep paths" hook on sp-lpe-item.cpp + if (keep_paths) { processObjects(LPE_TO_OBJECTS); return; } diff --git a/src/live_effects/parameter/bool.cpp b/src/live_effects/parameter/bool.cpp index 3184bfa80..d9e8ecc90 100644 --- a/src/live_effects/parameter/bool.cpp +++ b/src/live_effects/parameter/bool.cpp @@ -21,8 +21,8 @@ namespace LivePathEffect { BoolParam::BoolParam( const Glib::ustring& label, const Glib::ustring& tip, const Glib::ustring& key, Inkscape::UI::Widget::Registry* wr, - Effect* effect, bool default_value , bool no_widget) - : Parameter(label, tip, key, wr, effect), value(default_value), defvalue(default_value), hide_widget(no_widget) + Effect* effect, bool default_value , bool is_visible) + : Parameter(label, tip, key, wr, effect), value(default_value), defvalue(default_value), widget_is_visible(is_visible) { } @@ -65,7 +65,7 @@ BoolParam::param_getSVGValue() const Gtk::Widget * BoolParam::param_newWidget() { - if(!hide_widget){ + if(widget_is_visible){ Inkscape::UI::Widget::RegisteredCheckButton * checkwdg = Gtk::manage( new Inkscape::UI::Widget::RegisteredCheckButton( param_label, param_tooltip, diff --git a/src/live_effects/parameter/bool.h b/src/live_effects/parameter/bool.h index 39f328eaa..86681e764 100644 --- a/src/live_effects/parameter/bool.h +++ b/src/live_effects/parameter/bool.h @@ -26,7 +26,7 @@ public: Inkscape::UI::Widget::Registry* wr, Effect* effect, bool default_value = false, - bool no_widget = false); + bool widget_is_visible = true); virtual ~BoolParam(); virtual Gtk::Widget * param_newWidget(); @@ -40,6 +40,7 @@ public: virtual void param_update_default(const gchar * default_value); bool get_value() const { return value; }; inline operator bool() const { return value; }; + bool widget_is_visible; private: BoolParam(const BoolParam&); @@ -47,7 +48,6 @@ private: bool value; bool defvalue; - bool hide_widget; }; diff --git a/src/live_effects/parameter/hidden.cpp b/src/live_effects/parameter/hidden.cpp index 2f218847a..95735d50f 100644 --- a/src/live_effects/parameter/hidden.cpp +++ b/src/live_effects/parameter/hidden.cpp @@ -22,10 +22,12 @@ namespace LivePathEffect { HiddenParam::HiddenParam( const Glib::ustring& label, const Glib::ustring& tip, const Glib::ustring& key, Inkscape::UI::Widget::Registry* wr, - Effect* effect, const Glib::ustring default_value ) + Effect* effect, const Glib::ustring default_value, bool is_visible) : Parameter(label, tip, key, wr, effect), value(default_value), - defvalue(default_value) + defvalue(default_value), + //This last is to allow set or unset default parameters on hidden ones + widget_is_visible(is_visible) { } diff --git a/src/live_effects/parameter/hidden.h b/src/live_effects/parameter/hidden.h index d565272b6..f07dd9edc 100644 --- a/src/live_effects/parameter/hidden.h +++ b/src/live_effects/parameter/hidden.h @@ -29,7 +29,8 @@ public: const Glib::ustring& key, Inkscape::UI::Widget::Registry* wr, Effect* effect, - const Glib::ustring default_value = ""); + const Glib::ustring default_value = "", + bool widget_is_visible = false); virtual ~HiddenParam() {} virtual Gtk::Widget * param_newWidget(); @@ -42,7 +43,7 @@ public: virtual void param_update_default(const gchar * default_value); const Glib::ustring get_value() const { return value; }; - + bool widget_is_visible; private: HiddenParam(const HiddenParam&); HiddenParam& operator=(const HiddenParam&); diff --git a/src/live_effects/parameter/parameter.cpp b/src/live_effects/parameter/parameter.cpp index 45f46a0a7..cc7b476d7 100644 --- a/src/live_effects/parameter/parameter.cpp +++ b/src/live_effects/parameter/parameter.cpp @@ -55,7 +55,7 @@ void Parameter::write_to_SVG(void) */ ScalarParam::ScalarParam( const Glib::ustring& label, const Glib::ustring& tip, const Glib::ustring& key, Inkscape::UI::Widget::Registry* wr, - Effect* effect, gdouble default_value, bool no_widget) + Effect* effect, gdouble default_value, bool is_visible) : Parameter(label, tip, key, wr, effect), value(default_value), min(-SCALARPARAM_G_MAXDOUBLE), @@ -67,7 +67,7 @@ ScalarParam::ScalarParam( const Glib::ustring& label, const Glib::ustring& tip, inc_page(1), add_slider(false), overwrite_widget(false), - hide_widget(no_widget) + widget_is_visible(is_visible) { } @@ -172,7 +172,7 @@ ScalarParam::param_overwrite_widget(bool overwrite_widget) Gtk::Widget * ScalarParam::param_newWidget() { - if(!hide_widget){ + if(widget_is_visible){ Inkscape::UI::Widget::RegisteredScalar *rsu = Gtk::manage( new Inkscape::UI::Widget::RegisteredScalar( param_label, param_tooltip, param_key, *param_wr, param_effect->getRepr(), param_effect->getSPDoc() ) ); diff --git a/src/live_effects/parameter/parameter.h b/src/live_effects/parameter/parameter.h index ee1d2d547..bdba9f860 100644 --- a/src/live_effects/parameter/parameter.h +++ b/src/live_effects/parameter/parameter.h @@ -104,7 +104,7 @@ public: Inkscape::UI::Widget::Registry* wr, Effect* effect, gdouble default_value = 1.0, - bool no_widget = false); + bool widget_is_visible = true); virtual ~ScalarParam(); virtual bool param_readSVGValue(const gchar * strvalue); @@ -125,6 +125,7 @@ public: virtual Gtk::Widget * param_newWidget(); inline operator gdouble() const { return value; }; + bool widget_is_visible; protected: gdouble value; @@ -137,7 +138,6 @@ protected: double inc_page; bool add_slider; bool overwrite_widget; - bool hide_widget; private: ScalarParam(const ScalarParam&); diff --git a/src/sp-lpe-item.cpp b/src/sp-lpe-item.cpp index efb1f4353..b08772826 100644 --- a/src/sp-lpe-item.cpp +++ b/src/sp-lpe-item.cpp @@ -519,7 +519,7 @@ void SPLPEItem::removeAllPathEffects(bool keep_paths) LivePathEffectObject *lpeobj = (*it)->lpeobject; if (lpeobj) { Inkscape::LivePathEffect::Effect * lpe = lpeobj->get_lpe(); - lpe->erase_extra_objects = false; + lpe->keep_paths = true; } } } -- cgit v1.2.3 From d77efb0c2c4b6925e87055f2921d35677d1625d5 Mon Sep 17 00:00:00 2001 From: Jabiertxof Date: Sat, 27 May 2017 14:00:01 +0200 Subject: More fixes to LPE (bzr r15705) --- src/live_effects/lpe-bspline.cpp | 4 +-- src/live_effects/lpe-copy_rotate.cpp | 15 +++++----- src/live_effects/lpe-fillet-chamfer.cpp | 2 +- src/live_effects/lpe-measure-line.cpp | 35 ++++++++++++------------ src/live_effects/lpe-mirror_symmetry.cpp | 38 ++------------------------ src/live_effects/lpe-mirror_symmetry.h | 1 - src/live_effects/lpe-transform_2pts.cpp | 4 +-- src/live_effects/parameter/bool.cpp | 4 +-- src/live_effects/parameter/bool.h | 4 +-- src/live_effects/parameter/hidden.cpp | 5 ++-- src/live_effects/parameter/hidden.h | 2 +- src/live_effects/parameter/parameter.cpp | 11 ++++---- src/live_effects/parameter/parameter.h | 9 +++--- src/live_effects/parameter/satellitesarray.cpp | 1 + 14 files changed, 47 insertions(+), 88 deletions(-) (limited to 'src') diff --git a/src/live_effects/lpe-bspline.cpp b/src/live_effects/lpe-bspline.cpp index dbd67beda..721a4ecab 100644 --- a/src/live_effects/lpe-bspline.cpp +++ b/src/live_effects/lpe-bspline.cpp @@ -44,12 +44,12 @@ LPEBSpline::LPEBSpline(LivePathEffectObject *lpeobject) weight.param_set_range(NO_POWER, 100.0); weight.param_set_increments(0.1, 0.1); weight.param_set_digits(4); - weight.param_overwrite_widget(true); + weight.param_set_undo(false); steps.param_set_range(1, 10); steps.param_set_increments(1, 1); steps.param_set_digits(0); - steps.param_overwrite_widget(true); + steps.param_set_undo(false); helper_size.param_set_range(0.0, 999.0); helper_size.param_set_increments(1, 1); diff --git a/src/live_effects/lpe-copy_rotate.cpp b/src/live_effects/lpe-copy_rotate.cpp index 2364f4f66..551cf1bf9 100644 --- a/src/live_effects/lpe-copy_rotate.cpp +++ b/src/live_effects/lpe-copy_rotate.cpp @@ -96,6 +96,7 @@ LPECopyRotate::LPECopyRotate(LivePathEffectObject *lpeobject) : previous_num_copies = num_copies; previous_origin = Geom::Point(0,0); previous_start_point = Geom::Point(0,0); + starting_point.param_widget_is_visible(false); reset = false; } @@ -319,14 +320,12 @@ Gtk::Widget * LPECopyRotate::newWidget() Gtk::Widget *widg = dynamic_cast(param->param_newWidget()); Glib::ustring *tip = param->param_getTooltip(); if (widg) { - if (param->param_key != "starting_point") { - vbox->pack_start(*widg, true, true, 2); - if (tip) { - widg->set_tooltip_text(*tip); - } else { - widg->set_tooltip_text(""); - widg->set_has_tooltip(false); - } + vbox->pack_start(*widg, true, true, 2); + if (tip) { + widg->set_tooltip_text(*tip); + } else { + widg->set_tooltip_text(""); + widg->set_has_tooltip(false); } } } diff --git a/src/live_effects/lpe-fillet-chamfer.cpp b/src/live_effects/lpe-fillet-chamfer.cpp index a2f0b829d..11298bcbe 100644 --- a/src/live_effects/lpe-fillet-chamfer.cpp +++ b/src/live_effects/lpe-fillet-chamfer.cpp @@ -80,7 +80,7 @@ LPEFilletChamfer::LPEFilletChamfer(LivePathEffectObject *lpeobject) radius.param_set_range(0.0, Geom::infinity()); radius.param_set_increments(1, 1); radius.param_set_digits(4); - radius.param_overwrite_widget(true); + radius.param_set_undo(false); chamfer_steps.param_set_range(1, 999); chamfer_steps.param_set_increments(1, 1); chamfer_steps.param_set_digits(0); diff --git a/src/live_effects/lpe-measure-line.cpp b/src/live_effects/lpe-measure-line.cpp index f18ba2dcd..99828aef8 100644 --- a/src/live_effects/lpe-measure-line.cpp +++ b/src/live_effects/lpe-measure-line.cpp @@ -141,6 +141,7 @@ LPEMeasureLine::LPEMeasureLine(LivePathEffectObject *lpeobject) : helpline_overlap.param_set_digits(2); start_stored = Geom::Point(0,0); end_stored = Geom::Point(0,0); + id_origin.param_widget_is_visible(false); } LPEMeasureLine::~LPEMeasureLine() {} @@ -700,24 +701,22 @@ Gtk::Widget *LPEMeasureLine::newWidget() while (it != param_vector.end()) { if ((*it)->widget_is_visible) { Parameter *param = *it; - if (param->param_key != "id_origin") { - Gtk::Widget *widg = dynamic_cast(param->param_newWidget()); - Glib::ustring *tip = param->param_getTooltip(); - if (widg) { - if (param->param_key != "dimline_format" && - param->param_key != "helperlines_format" && - param->param_key != "arrows_format" && - param->param_key != "anotation_format") { - vbox->pack_start(*widg, true, true, 2); - } else { - vbox_expander->pack_start(*widg, true, true, 2); - } - if (tip) { - widg->set_tooltip_text(*tip); - } else { - widg->set_tooltip_text(""); - widg->set_has_tooltip(false); - } + Gtk::Widget *widg = dynamic_cast(param->param_newWidget()); + Glib::ustring *tip = param->param_getTooltip(); + if (widg) { + if (param->param_key != "dimline_format" && + param->param_key != "helperlines_format" && + param->param_key != "arrows_format" && + param->param_key != "anotation_format") { + vbox->pack_start(*widg, true, true, 2); + } else { + vbox_expander->pack_start(*widg, true, true, 2); + } + if (tip) { + widg->set_tooltip_text(*tip); + } else { + widg->set_tooltip_text(""); + widg->set_has_tooltip(false); } } } diff --git a/src/live_effects/lpe-mirror_symmetry.cpp b/src/live_effects/lpe-mirror_symmetry.cpp index 9c2b876db..8e68c483c 100644 --- a/src/live_effects/lpe-mirror_symmetry.cpp +++ b/src/live_effects/lpe-mirror_symmetry.cpp @@ -78,6 +78,8 @@ LPEMirrorSymmetry::LPEMirrorSymmetry(LivePathEffectObject *lpeobject) : split_gap.param_set_digits(5); apply_to_clippath_and_mask = true; previous_center = Geom::Point(0,0); + id_origin.param_widget_is_visible(false); + center_point.param_widget_is_visible(false); } LPEMirrorSymmetry::~LPEMirrorSymmetry() @@ -304,42 +306,6 @@ LPEMirrorSymmetry::toMirror(Geom::Affine transform) } } -Gtk::Widget * -LPEMirrorSymmetry::newWidget() -{ - // use manage here, because after deletion of Effect object, others might - // still be pointing to this widget. - Gtk::VBox *vbox = Gtk::manage(new Gtk::VBox(Effect::newWidget())); - vbox->set_border_width(5); - vbox->set_homogeneous(false); - vbox->set_spacing(2); - - std::vector::iterator it = param_vector.begin(); - while (it != param_vector.end()) { - if ((*it)->widget_is_visible) { - Parameter * param = *it; - if (param->param_key == "id_origin" || param->param_key == "center_point") { - ++it; - continue; - } - Gtk::Widget * widg = param->param_newWidget(); - Glib::ustring * tip = param->param_getTooltip(); - if (widg) { - vbox->pack_start(*widg, true, true, 2); - if (tip) { - widg->set_tooltip_text(*tip); - } else { - widg->set_tooltip_text(""); - widg->set_has_tooltip(false); - } - } - } - - ++it; - } - return dynamic_cast(vbox); -} - //TODO: Migrate the tree next function to effect.cpp/h to avoid duplication void LPEMirrorSymmetry::doOnVisibilityToggled(SPLPEItem const* /*lpeitem*/) diff --git a/src/live_effects/lpe-mirror_symmetry.h b/src/live_effects/lpe-mirror_symmetry.h index 07bb3d4fc..e98c83f2b 100644 --- a/src/live_effects/lpe-mirror_symmetry.h +++ b/src/live_effects/lpe-mirror_symmetry.h @@ -46,7 +46,6 @@ public: virtual Geom::PathVector doEffect_path (Geom::PathVector const & path_in); virtual void doOnRemove (SPLPEItem const* /*lpeitem*/); virtual void doOnVisibilityToggled(SPLPEItem const* /*lpeitem*/); - virtual Gtk::Widget * newWidget(); void toMirror(Geom::Affine transform); // void cloneAttrbutes(Inkscape::XML::Node * origin, Inkscape::XML::Node * dest, const char * first_attribute, ...); void cloneD(SPObject *orig, SPObject *dest, bool live, bool root); diff --git a/src/live_effects/lpe-transform_2pts.cpp b/src/live_effects/lpe-transform_2pts.cpp index f4d233d56..ab05b880c 100644 --- a/src/live_effects/lpe-transform_2pts.cpp +++ b/src/live_effects/lpe-transform_2pts.cpp @@ -64,9 +64,9 @@ LPETransform2Pts::LPETransform2Pts(LivePathEffectObject *lpeobject) : registerParameter(&lock_angle); first_knot.param_make_integer(true); - first_knot.param_overwrite_widget(true); + first_knot.param_set_undo(false); last_knot.param_make_integer(true); - last_knot.param_overwrite_widget(true); + last_knot.param_set_undo(false); helper_size.param_set_range(0, 999); helper_size.param_set_increments(1, 1); helper_size.param_set_digits(0); diff --git a/src/live_effects/parameter/bool.cpp b/src/live_effects/parameter/bool.cpp index d9e8ecc90..954947cf4 100644 --- a/src/live_effects/parameter/bool.cpp +++ b/src/live_effects/parameter/bool.cpp @@ -21,8 +21,8 @@ namespace LivePathEffect { BoolParam::BoolParam( const Glib::ustring& label, const Glib::ustring& tip, const Glib::ustring& key, Inkscape::UI::Widget::Registry* wr, - Effect* effect, bool default_value , bool is_visible) - : Parameter(label, tip, key, wr, effect), value(default_value), defvalue(default_value), widget_is_visible(is_visible) + Effect* effect, bool default_value) + : Parameter(label, tip, key, wr, effect), value(default_value), defvalue(default_value) { } diff --git a/src/live_effects/parameter/bool.h b/src/live_effects/parameter/bool.h index 86681e764..417752050 100644 --- a/src/live_effects/parameter/bool.h +++ b/src/live_effects/parameter/bool.h @@ -25,8 +25,7 @@ public: const Glib::ustring& key, Inkscape::UI::Widget::Registry* wr, Effect* effect, - bool default_value = false, - bool widget_is_visible = true); + bool default_value = false); virtual ~BoolParam(); virtual Gtk::Widget * param_newWidget(); @@ -40,7 +39,6 @@ public: virtual void param_update_default(const gchar * default_value); bool get_value() const { return value; }; inline operator bool() const { return value; }; - bool widget_is_visible; private: BoolParam(const BoolParam&); diff --git a/src/live_effects/parameter/hidden.cpp b/src/live_effects/parameter/hidden.cpp index 95735d50f..6d0e7f58f 100644 --- a/src/live_effects/parameter/hidden.cpp +++ b/src/live_effects/parameter/hidden.cpp @@ -25,10 +25,9 @@ HiddenParam::HiddenParam( const Glib::ustring& label, const Glib::ustring& tip, Effect* effect, const Glib::ustring default_value, bool is_visible) : Parameter(label, tip, key, wr, effect), value(default_value), - defvalue(default_value), - //This last is to allow set or unset default parameters on hidden ones - widget_is_visible(is_visible) + defvalue(default_value) { + param_widget_is_visible(is_visible); } void diff --git a/src/live_effects/parameter/hidden.h b/src/live_effects/parameter/hidden.h index f07dd9edc..387071e53 100644 --- a/src/live_effects/parameter/hidden.h +++ b/src/live_effects/parameter/hidden.h @@ -43,7 +43,7 @@ public: virtual void param_update_default(const gchar * default_value); const Glib::ustring get_value() const { return value; }; - bool widget_is_visible; + private: HiddenParam(const HiddenParam&); HiddenParam& operator=(const HiddenParam&); diff --git a/src/live_effects/parameter/parameter.cpp b/src/live_effects/parameter/parameter.cpp index cc7b476d7..2f73488aa 100644 --- a/src/live_effects/parameter/parameter.cpp +++ b/src/live_effects/parameter/parameter.cpp @@ -55,7 +55,7 @@ void Parameter::write_to_SVG(void) */ ScalarParam::ScalarParam( const Glib::ustring& label, const Glib::ustring& tip, const Glib::ustring& key, Inkscape::UI::Widget::Registry* wr, - Effect* effect, gdouble default_value, bool is_visible) + Effect* effect, gdouble default_value) : Parameter(label, tip, key, wr, effect), value(default_value), min(-SCALARPARAM_G_MAXDOUBLE), @@ -66,8 +66,7 @@ ScalarParam::ScalarParam( const Glib::ustring& label, const Glib::ustring& tip, inc_step(0.1), inc_page(1), add_slider(false), - overwrite_widget(false), - widget_is_visible(is_visible) + _set_undo(true) { } @@ -164,9 +163,9 @@ ScalarParam::param_make_integer(bool yes) } void -ScalarParam::param_overwrite_widget(bool overwrite_widget) +ScalarParam::param_set_undo(bool set_undo) { - this->overwrite_widget = overwrite_widget; + _set_undo = set_undo; } Gtk::Widget * @@ -184,7 +183,7 @@ ScalarParam::param_newWidget() if (add_slider) { rsu->addSlider(); } - if(!overwrite_widget){ + if(_set_undo){ rsu->set_undo_parameters(SP_VERB_DIALOG_LIVE_PATH_EFFECT, _("Change scalar parameter")); } return dynamic_cast (rsu); diff --git a/src/live_effects/parameter/parameter.h b/src/live_effects/parameter/parameter.h index bdba9f860..7ab7e30dd 100644 --- a/src/live_effects/parameter/parameter.h +++ b/src/live_effects/parameter/parameter.h @@ -57,6 +57,7 @@ public: virtual bool param_readSVGValue(const gchar * strvalue) = 0; // returns true if new value is valid / accepted. virtual gchar * param_getSVGValue() const = 0; + virtual void param_widget_is_visible(bool is_visible) {widget_is_visible = is_visible;} void write_to_SVG(); virtual void param_set_default() = 0; @@ -103,8 +104,7 @@ public: const Glib::ustring& key, Inkscape::UI::Widget::Registry* wr, Effect* effect, - gdouble default_value = 1.0, - bool widget_is_visible = true); + gdouble default_value = 1.0); virtual ~ScalarParam(); virtual bool param_readSVGValue(const gchar * strvalue); @@ -121,11 +121,10 @@ public: void addSlider(bool add_slider_widget) { add_slider = add_slider_widget; }; double param_get_max() { return max; }; double param_get_min() { return min; }; - void param_overwrite_widget(bool overwrite_widget); + void param_set_undo(bool set_undo); virtual Gtk::Widget * param_newWidget(); inline operator gdouble() const { return value; }; - bool widget_is_visible; protected: gdouble value; @@ -137,7 +136,7 @@ protected: double inc_step; double inc_page; bool add_slider; - bool overwrite_widget; + bool _set_undo; private: ScalarParam(const ScalarParam&); diff --git a/src/live_effects/parameter/satellitesarray.cpp b/src/live_effects/parameter/satellitesarray.cpp index 7626317a1..ce4da243e 100644 --- a/src/live_effects/parameter/satellitesarray.cpp +++ b/src/live_effects/parameter/satellitesarray.cpp @@ -37,6 +37,7 @@ SatellitesArrayParam::SatellitesArrayParam(const Glib::ustring &label, _current_zoom = 0; _effectType = FILLET_CHAMFER; _last_pathvector_satellites = NULL; + param_widget_is_visible(false); } -- cgit v1.2.3 From 6297a82b81a3ba575bd60ccbc118f3e17d762896 Mon Sep 17 00:00:00 2001 From: Jabiertxof Date: Sat, 27 May 2017 22:26:45 +0200 Subject: Allow LPE clip or mask hasent effect applied (bzr r15706) --- src/sp-lpe-item.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/sp-lpe-item.cpp b/src/sp-lpe-item.cpp index b08772826..68f9843d5 100644 --- a/src/sp-lpe-item.cpp +++ b/src/sp-lpe-item.cpp @@ -220,6 +220,7 @@ bool SPLPEItem::performPathEffect(SPCurve *curve, SPShape *current, bool is_clip if (!curve) { return false; } + bool has_lpe_clipmask = false; if (this->hasPathEffect() && this->pathEffectsEnabled()) { for (PathEffectList::iterator it = this->path_effect_list->begin(); it != this->path_effect_list->end(); ++it) { @@ -245,6 +246,9 @@ bool SPLPEItem::performPathEffect(SPCurve *curve, SPShape *current, bool is_clip // yet, we don't alter the path return false; } + if (lpe->apply_to_clippath_and_mask) { + has_lpe_clipmask = true; + } if (!is_clip_or_mask || (is_clip_or_mask && lpe->apply_to_clippath_and_mask)) { // Groups have their doBeforeEffect called elsewhere if (current) { @@ -272,7 +276,7 @@ bool SPLPEItem::performPathEffect(SPCurve *curve, SPShape *current, bool is_clip } } } - if(!SP_IS_GROUP(this) && !is_clip_or_mask){ + if(!SP_IS_GROUP(this) && !is_clip_or_mask && has_lpe_clipmask){ this->apply_to_clippath(this); this->apply_to_mask(this); } -- cgit v1.2.3 From 5f75967b19b3cc95f249194fa13a2e04ef582c36 Mon Sep 17 00:00:00 2001 From: Jabiertxof Date: Sun, 28 May 2017 07:40:43 +0200 Subject: Force not original-d if the clip-path or mask has not a LPE allowed to change it (bzr r15707) --- src/live_effects/parameter/path.cpp | 104 +++++++++++++++++++++--------------- src/live_effects/parameter/path.h | 6 ++- src/sp-lpe-item.cpp | 92 +++++++++++++++++++++++-------- src/sp-lpe-item.h | 2 + 4 files changed, 140 insertions(+), 64 deletions(-) (limited to 'src') diff --git a/src/live_effects/parameter/path.cpp b/src/live_effects/parameter/path.cpp index 6e90c9279..54f5d93e8 100644 --- a/src/live_effects/parameter/path.cpp +++ b/src/live_effects/parameter/path.cpp @@ -69,7 +69,10 @@ PathParam::PathParam( const Glib::ustring& label, const Glib::ustring& tip, defvalue = g_strdup(default_value); param_readSVGValue(defvalue); oncanvas_editable = true; - + _edit_button = true; + _copy_button = true; + _paste_button = true; + _link_button = true; ref_changed_connection = ref.changedSignal().connect(sigc::mem_fun(*this, &PathParam::ref_changed)); } @@ -167,6 +170,15 @@ PathParam::param_getSVGValue() const } } +void +PathParam::set_buttons(bool edit_button, bool copy_button, bool paste_button, bool link_button) +{ + _edit_button = edit_button; + _copy_button = copy_button; + _paste_button = paste_button; + _link_button = link_button; +} + Gtk::Widget * PathParam::param_newWidget() { @@ -175,47 +187,55 @@ PathParam::param_newWidget() Gtk::Label* pLabel = Gtk::manage(new Gtk::Label(param_label)); static_cast(_widget)->pack_start(*pLabel, true, true); pLabel->set_tooltip_text(param_tooltip); - - Gtk::Widget* pIcon = Gtk::manage( sp_icon_get_icon( INKSCAPE_ICON("tool-node-editor"), Inkscape::ICON_SIZE_BUTTON) ); - Gtk::Button * pButton = Gtk::manage(new Gtk::Button()); - pButton->set_relief(Gtk::RELIEF_NONE); - pIcon->show(); - pButton->add(*pIcon); - pButton->show(); - pButton->signal_clicked().connect(sigc::mem_fun(*this, &PathParam::on_edit_button_click)); - static_cast(_widget)->pack_start(*pButton, true, true); - pButton->set_tooltip_text(_("Edit on-canvas")); - - pIcon = Gtk::manage( sp_icon_get_icon( INKSCAPE_ICON("edit-copy"), Inkscape::ICON_SIZE_BUTTON) ); - pButton = Gtk::manage(new Gtk::Button()); - pButton->set_relief(Gtk::RELIEF_NONE); - pIcon->show(); - pButton->add(*pIcon); - pButton->show(); - pButton->signal_clicked().connect(sigc::mem_fun(*this, &PathParam::on_copy_button_click)); - static_cast(_widget)->pack_start(*pButton, true, true); - pButton->set_tooltip_text(_("Copy path")); - - pIcon = Gtk::manage( sp_icon_get_icon( INKSCAPE_ICON("edit-paste"), Inkscape::ICON_SIZE_BUTTON) ); - pButton = Gtk::manage(new Gtk::Button()); - pButton->set_relief(Gtk::RELIEF_NONE); - pIcon->show(); - pButton->add(*pIcon); - pButton->show(); - pButton->signal_clicked().connect(sigc::mem_fun(*this, &PathParam::on_paste_button_click)); - static_cast(_widget)->pack_start(*pButton, true, true); - pButton->set_tooltip_text(_("Paste path")); - - pIcon = Gtk::manage( sp_icon_get_icon( INKSCAPE_ICON("edit-clone"), Inkscape::ICON_SIZE_BUTTON) ); - pButton = Gtk::manage(new Gtk::Button()); - pButton->set_relief(Gtk::RELIEF_NONE); - pIcon->show(); - pButton->add(*pIcon); - pButton->show(); - pButton->signal_clicked().connect(sigc::mem_fun(*this, &PathParam::on_link_button_click)); - static_cast(_widget)->pack_start(*pButton, true, true); - pButton->set_tooltip_text(_("Link to path on clipboard")); - + Gtk::Widget * pIcon = NULL; + Gtk::Button * pButton = NULL; + if (_edit_button) { + pIcon = Gtk::manage( sp_icon_get_icon( INKSCAPE_ICON("tool-node-editor"), Inkscape::ICON_SIZE_BUTTON) ); + pButton = Gtk::manage(new Gtk::Button()); + pButton->set_relief(Gtk::RELIEF_NONE); + pIcon->show(); + pButton->add(*pIcon); + pButton->show(); + pButton->signal_clicked().connect(sigc::mem_fun(*this, &PathParam::on_edit_button_click)); + static_cast(_widget)->pack_start(*pButton, true, true); + pButton->set_tooltip_text(_("Edit on-canvas")); + } + + if (_copy_button) { + pIcon = Gtk::manage( sp_icon_get_icon( INKSCAPE_ICON("edit-copy"), Inkscape::ICON_SIZE_BUTTON) ); + pButton = Gtk::manage(new Gtk::Button()); + pButton->set_relief(Gtk::RELIEF_NONE); + pIcon->show(); + pButton->add(*pIcon); + pButton->show(); + pButton->signal_clicked().connect(sigc::mem_fun(*this, &PathParam::on_copy_button_click)); + static_cast(_widget)->pack_start(*pButton, true, true); + pButton->set_tooltip_text(_("Copy path")); + } + + if (_paste_button) { + pIcon = Gtk::manage( sp_icon_get_icon( INKSCAPE_ICON("edit-paste"), Inkscape::ICON_SIZE_BUTTON) ); + pButton = Gtk::manage(new Gtk::Button()); + pButton->set_relief(Gtk::RELIEF_NONE); + pIcon->show(); + pButton->add(*pIcon); + pButton->show(); + pButton->signal_clicked().connect(sigc::mem_fun(*this, &PathParam::on_paste_button_click)); + static_cast(_widget)->pack_start(*pButton, true, true); + pButton->set_tooltip_text(_("Paste path")); + } + if (_link_button) { + pIcon = Gtk::manage( sp_icon_get_icon( INKSCAPE_ICON("edit-clone"), Inkscape::ICON_SIZE_BUTTON) ); + pButton = Gtk::manage(new Gtk::Button()); + pButton->set_relief(Gtk::RELIEF_NONE); + pIcon->show(); + pButton->add(*pIcon); + pButton->show(); + pButton->signal_clicked().connect(sigc::mem_fun(*this, &PathParam::on_link_button_click)); + static_cast(_widget)->pack_start(*pButton, true, true); + pButton->set_tooltip_text(_("Link to path on clipboard")); + } + static_cast(_widget)->show_all_children(); return dynamic_cast (_widget); diff --git a/src/live_effects/parameter/path.h b/src/live_effects/parameter/path.h index 5381a6b36..ff5e4f1b8 100644 --- a/src/live_effects/parameter/path.h +++ b/src/live_effects/parameter/path.h @@ -44,7 +44,7 @@ public: void param_set_and_write_default(); void set_new_value (Geom::PathVector const &newpath, bool write_to_svg); void set_new_value (Geom::Piecewise > const &newpath, bool write_to_svg); - + void set_buttons(bool edit_button, bool copy_button, bool paste_button, bool link_button); virtual void param_editOncanvas(SPItem * item, SPDesktop * dt); virtual void param_setup_nodepath(Inkscape::NodePath::Path *np); virtual void addCanvasIndicators(SPLPEItem const* lpeitem, std::vector &hp_vec); @@ -91,6 +91,10 @@ protected: gchar * defvalue; private: + bool _edit_button; + bool _copy_button; + bool _paste_button; + bool _link_button; PathParam(const PathParam&); PathParam& operator=(const PathParam&); }; diff --git a/src/sp-lpe-item.cpp b/src/sp-lpe-item.cpp index 68f9843d5..d1f1697a8 100644 --- a/src/sp-lpe-item.cpp +++ b/src/sp-lpe-item.cpp @@ -212,6 +212,47 @@ Inkscape::XML::Node* SPLPEItem::write(Inkscape::XML::Document *xml_doc, Inkscape return repr; } +/** + * returns true when LPE was successful. + */ +bool SPLPEItem::hasPathEffectOnClipOrMask() const +{ + bool has_clipormask_lpe = false; + if (this->hasPathEffect() && this->pathEffectsEnabled()) { + for (PathEffectList::iterator it = this->path_effect_list->begin(); it != this->path_effect_list->end(); ++it) + { + LivePathEffectObject *lpeobj = (*it)->lpeobject; + if (!lpeobj) { + return false; + } + Inkscape::LivePathEffect::Effect *lpe = lpeobj->get_lpe(); + if (!lpe) { + return false; + } + if (lpe->isVisible()) { + if (lpe->acceptsNumClicks() > 0 && !lpe->isReady()) { + return false; + } + if (lpe->apply_to_clippath_and_mask) { + has_clipormask_lpe = true; + } + } + } + } + std::cout << has_clipormask_lpe << "has_clipormask_lpe\n"; + return has_clipormask_lpe; +} + +bool SPLPEItem::hasPathEffectOnClipOrMaskRecursive() const +{ + if (parent && SP_IS_LPE_ITEM(parent)) { + return hasPathEffectOnClipOrMask() || SP_LPE_ITEM(parent)->hasPathEffectOnClipOrMaskRecursive(); + } + else { + return hasPathEffectOnClipOrMask(); + } +} + /** * returns true when LPE was successful. */ @@ -220,7 +261,7 @@ bool SPLPEItem::performPathEffect(SPCurve *curve, SPShape *current, bool is_clip if (!curve) { return false; } - bool has_lpe_clipmask = false; + bool has_clipormask_lpe = false; if (this->hasPathEffect() && this->pathEffectsEnabled()) { for (PathEffectList::iterator it = this->path_effect_list->begin(); it != this->path_effect_list->end(); ++it) { @@ -247,7 +288,7 @@ bool SPLPEItem::performPathEffect(SPCurve *curve, SPShape *current, bool is_clip return false; } if (lpe->apply_to_clippath_and_mask) { - has_lpe_clipmask = true; + has_clipormask_lpe = true; } if (!is_clip_or_mask || (is_clip_or_mask && lpe->apply_to_clippath_and_mask)) { // Groups have their doBeforeEffect called elsewhere @@ -276,7 +317,7 @@ bool SPLPEItem::performPathEffect(SPCurve *curve, SPShape *current, bool is_clip } } } - if(!SP_IS_GROUP(this) && !is_clip_or_mask && has_lpe_clipmask){ + if(!SP_IS_GROUP(this) && !is_clip_or_mask && has_clipormask_lpe){ this->apply_to_clippath(this); this->apply_to_mask(this); } @@ -370,9 +411,8 @@ static void sp_lpe_item_cleanup_original_path_recursive(SPLPEItem *lpeitem) { g_return_if_fail(lpeitem != NULL); - if (SP_IS_GROUP(lpeitem)) { - if (!lpeitem->hasPathEffectRecursive()) { + if (!lpeitem->hasPathEffectOnClipOrMaskRecursive()) { SPMask * mask = lpeitem->mask_ref->getObject(); if(mask) { @@ -391,24 +431,24 @@ sp_lpe_item_cleanup_original_path_recursive(SPLPEItem *lpeitem) sp_lpe_item_cleanup_original_path_recursive(SP_LPE_ITEM(subitem)); } } - } - else if (SP_IS_PATH(lpeitem)) { + } else if (SP_IS_PATH(lpeitem)) { Inkscape::XML::Node *repr = lpeitem->getRepr(); - if (!lpeitem->hasPathEffectRecursive() && repr->attribute("inkscape:original-d")) { - SPMask * mask = lpeitem->mask_ref->getObject(); - if(mask) - { - sp_lpe_item_cleanup_original_path_recursive(SP_LPE_ITEM(mask->firstChild())); - } - SPClipPath * clip_path = lpeitem->clip_ref->getObject(); - if(clip_path) - { - sp_lpe_item_cleanup_original_path_recursive(SP_LPE_ITEM(clip_path->firstChild())); - } + SPMask * mask = lpeitem->mask_ref->getObject(); + if(mask) { + sp_lpe_item_cleanup_original_path_recursive(SP_LPE_ITEM(mask->firstChild())); + } + SPClipPath * clip_path = lpeitem->clip_ref->getObject(); + if(clip_path) { + sp_lpe_item_cleanup_original_path_recursive(SP_LPE_ITEM(clip_path->firstChild())); + } + mask = dynamic_cast(lpeitem->parent); + clip_path = dynamic_cast(lpeitem->parent); + if ((!lpeitem->hasPathEffectRecursive() && repr->attribute("inkscape:original-d")) || + ((mask || clip_path) && !lpeitem->hasPathEffectOnClipOrMask() && repr->attribute("inkscape:original-d"))) + { repr->setAttribute("d", repr->attribute("inkscape:original-d")); repr->setAttribute("inkscape:original-d", NULL); - } - else { + } else { sp_lpe_item_update_patheffect(lpeitem, true, true); } } @@ -462,7 +502,16 @@ void SPLPEItem::addPathEffect(std::string value, bool reset) // Apply the path effect sp_lpe_item_update_patheffect(this, true, true); - + SPMask * mask = mask_ref->getObject(); + if(mask && !hasPathEffectOnClipOrMask()) + { + sp_lpe_item_cleanup_original_path_recursive(SP_LPE_ITEM(mask->firstChild())); + } + SPClipPath * clip_path = clip_ref->getObject(); + if(clip_path && !hasPathEffectOnClipOrMask()) + { + sp_lpe_item_cleanup_original_path_recursive(SP_LPE_ITEM(clip_path->firstChild())); + } //fix bug 1219324 if (SP_ACTIVE_DESKTOP ) { Inkscape::UI::Tools::ToolBase *ec = SP_ACTIVE_DESKTOP->event_context; @@ -649,6 +698,7 @@ bool SPLPEItem::hasPathEffectRecursive() const return hasPathEffect(); } } + void SPLPEItem::apply_to_clippath(SPItem *item) { diff --git a/src/sp-lpe-item.h b/src/sp-lpe-item.h index 0f198c49c..d5d4e118b 100644 --- a/src/sp-lpe-item.h +++ b/src/sp-lpe-item.h @@ -70,6 +70,8 @@ public: virtual void update_patheffect(bool write); + bool hasPathEffectOnClipOrMask() const; + bool hasPathEffectOnClipOrMaskRecursive() const; bool performPathEffect(SPCurve *curve, SPShape *current = NULL, bool is_clip_or_mask = false); bool pathEffectsEnabled() const; -- cgit v1.2.3 From 926e38a08b20ed9aae1abc0396a8aa120e333e9d Mon Sep 17 00:00:00 2001 From: Jabiertxof Date: Sun, 28 May 2017 08:10:29 +0200 Subject: Remove original-d from clip and mask LPE if keep paths (bzr r15708) --- src/sp-lpe-item.cpp | 40 ++++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 20 deletions(-) (limited to 'src') diff --git a/src/sp-lpe-item.cpp b/src/sp-lpe-item.cpp index d1f1697a8..7dcbc4311 100644 --- a/src/sp-lpe-item.cpp +++ b/src/sp-lpe-item.cpp @@ -50,7 +50,7 @@ static void sp_lpe_item_enable_path_effects(SPLPEItem *lpeitem, bool enable); static void lpeobject_ref_modified(SPObject *href, guint flags, SPLPEItem *lpeitem); static void sp_lpe_item_create_original_path_recursive(SPLPEItem *lpeitem); -static void sp_lpe_item_cleanup_original_path_recursive(SPLPEItem *lpeitem); +static void sp_lpe_item_cleanup_original_path_recursive(SPLPEItem *lpeitem, bool keep_paths); typedef std::list HRefList; static std::string patheffectlist_svg_string(PathEffectList const & list); @@ -408,7 +408,7 @@ sp_lpe_item_create_original_path_recursive(SPLPEItem *lpeitem) } static void -sp_lpe_item_cleanup_original_path_recursive(SPLPEItem *lpeitem) +sp_lpe_item_cleanup_original_path_recursive(SPLPEItem *lpeitem, bool keep_paths) { g_return_if_fail(lpeitem != NULL); if (SP_IS_GROUP(lpeitem)) { @@ -416,37 +416,39 @@ sp_lpe_item_cleanup_original_path_recursive(SPLPEItem *lpeitem) SPMask * mask = lpeitem->mask_ref->getObject(); if(mask) { - sp_lpe_item_cleanup_original_path_recursive(SP_LPE_ITEM(mask->firstChild())); + sp_lpe_item_cleanup_original_path_recursive(SP_LPE_ITEM(mask->firstChild()), keep_paths); } SPClipPath * clip_path = lpeitem->clip_ref->getObject(); if(clip_path) { - sp_lpe_item_cleanup_original_path_recursive(SP_LPE_ITEM(clip_path->firstChild())); + sp_lpe_item_cleanup_original_path_recursive(SP_LPE_ITEM(clip_path->firstChild()), keep_paths); } } 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 = *iter; if (SP_IS_LPE_ITEM(subitem)) { - sp_lpe_item_cleanup_original_path_recursive(SP_LPE_ITEM(subitem)); + sp_lpe_item_cleanup_original_path_recursive(SP_LPE_ITEM(subitem), keep_paths); } } } else if (SP_IS_PATH(lpeitem)) { Inkscape::XML::Node *repr = lpeitem->getRepr(); SPMask * mask = lpeitem->mask_ref->getObject(); if(mask) { - sp_lpe_item_cleanup_original_path_recursive(SP_LPE_ITEM(mask->firstChild())); + sp_lpe_item_cleanup_original_path_recursive(SP_LPE_ITEM(mask->firstChild()), keep_paths); } SPClipPath * clip_path = lpeitem->clip_ref->getObject(); if(clip_path) { - sp_lpe_item_cleanup_original_path_recursive(SP_LPE_ITEM(clip_path->firstChild())); + sp_lpe_item_cleanup_original_path_recursive(SP_LPE_ITEM(clip_path->firstChild()), keep_paths); } mask = dynamic_cast(lpeitem->parent); clip_path = dynamic_cast(lpeitem->parent); if ((!lpeitem->hasPathEffectRecursive() && repr->attribute("inkscape:original-d")) || - ((mask || clip_path) && !lpeitem->hasPathEffectOnClipOrMask() && repr->attribute("inkscape:original-d"))) + ((mask || clip_path) && !lpeitem->hasPathEffectOnClipOrMaskRecursive() && repr->attribute("inkscape:original-d"))) { - repr->setAttribute("d", repr->attribute("inkscape:original-d")); + if (!keep_paths) { + repr->setAttribute("d", repr->attribute("inkscape:original-d")); + } repr->setAttribute("inkscape:original-d", NULL); } else { sp_lpe_item_update_patheffect(lpeitem, true, true); @@ -503,14 +505,14 @@ void SPLPEItem::addPathEffect(std::string value, bool reset) // Apply the path effect sp_lpe_item_update_patheffect(this, true, true); SPMask * mask = mask_ref->getObject(); - if(mask && !hasPathEffectOnClipOrMask()) + if(mask && !hasPathEffectOnClipOrMaskRecursive()) { - sp_lpe_item_cleanup_original_path_recursive(SP_LPE_ITEM(mask->firstChild())); + sp_lpe_item_cleanup_original_path_recursive(SP_LPE_ITEM(mask->firstChild()), false); } SPClipPath * clip_path = clip_ref->getObject(); - if(clip_path && !hasPathEffectOnClipOrMask()) + if(clip_path && !hasPathEffectOnClipOrMaskRecursive()) { - sp_lpe_item_cleanup_original_path_recursive(SP_LPE_ITEM(clip_path->firstChild())); + sp_lpe_item_cleanup_original_path_recursive(SP_LPE_ITEM(clip_path->firstChild()), false); } //fix bug 1219324 if (SP_ACTIVE_DESKTOP ) { @@ -552,9 +554,8 @@ void SPLPEItem::removeCurrentPathEffect(bool keep_paths) if( SP_IS_GENERICELLIPSE(this)) { SP_GENERICELLIPSE(this)->write( this->getRepr()->document(), this->getRepr(), SP_OBJECT_WRITE_EXT ); } - - sp_lpe_item_cleanup_original_path_recursive(this); } + sp_lpe_item_cleanup_original_path_recursive(this, keep_paths); } /** @@ -584,9 +585,8 @@ void SPLPEItem::removeAllPathEffects(bool keep_paths) if (SP_IS_GENERICELLIPSE(this)) { SP_GENERICELLIPSE(this)->write(this->getRepr()->document(), this->getRepr(), SP_OBJECT_WRITE_EXT); } - - sp_lpe_item_cleanup_original_path_recursive(this); } + sp_lpe_item_cleanup_original_path_recursive(this, keep_paths); } void SPLPEItem::downCurrentPathEffect() @@ -607,7 +607,7 @@ void SPLPEItem::downCurrentPathEffect() this->getRepr()->setAttribute("inkscape:path-effect", patheffectlist_svg_string(new_list)); - sp_lpe_item_cleanup_original_path_recursive(this); + sp_lpe_item_cleanup_original_path_recursive(this, false); } void SPLPEItem::upCurrentPathEffect() @@ -626,7 +626,7 @@ void SPLPEItem::upCurrentPathEffect() this->getRepr()->setAttribute("inkscape:path-effect", patheffectlist_svg_string(new_list)); - sp_lpe_item_cleanup_original_path_recursive(this); + sp_lpe_item_cleanup_original_path_recursive(this, false); } /** used for shapes so they can see if they should also disable shape calculation and read from d= */ @@ -854,7 +854,7 @@ void SPLPEItem::remove_child(Inkscape::XML::Node * child) { SPObject *ochild = this->get_child_by_repr(child); if ( ochild && SP_IS_LPE_ITEM(ochild) ) { - sp_lpe_item_cleanup_original_path_recursive(SP_LPE_ITEM(ochild)); + sp_lpe_item_cleanup_original_path_recursive(SP_LPE_ITEM(ochild), false); } } -- cgit v1.2.3 From 84d294a3501c7b5ba70283833e334ecc06328466 Mon Sep 17 00:00:00 2001 From: Jabiertxof Date: Sun, 28 May 2017 08:59:50 +0200 Subject: Remove dabug line (bzr r15709) --- src/sp-lpe-item.cpp | 1 - 1 file changed, 1 deletion(-) (limited to 'src') diff --git a/src/sp-lpe-item.cpp b/src/sp-lpe-item.cpp index 7dcbc4311..d920909f9 100644 --- a/src/sp-lpe-item.cpp +++ b/src/sp-lpe-item.cpp @@ -239,7 +239,6 @@ bool SPLPEItem::hasPathEffectOnClipOrMask() const } } } - std::cout << has_clipormask_lpe << "has_clipormask_lpe\n"; return has_clipormask_lpe; } -- cgit v1.2.3 From 2d6c75e0cdd3e341d4372da0a16c81721dadcc05 Mon Sep 17 00:00:00 2001 From: Jabiertxof Date: Sun, 28 May 2017 09:15:03 +0200 Subject: Allow doOnRemove in all LPE (bzr r15710) --- src/sp-lpe-item.cpp | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) (limited to 'src') diff --git a/src/sp-lpe-item.cpp b/src/sp-lpe-item.cpp index d920909f9..83cf408a4 100644 --- a/src/sp-lpe-item.cpp +++ b/src/sp-lpe-item.cpp @@ -129,12 +129,7 @@ void SPLPEItem::set(unsigned int key, gchar const* value) { if (!value) { LivePathEffectObject *lpeobj = (*it)->lpeobject; Inkscape::LivePathEffect::Effect * lpe = lpeobj->get_lpe(); - if (dynamic_cast(lpe) || - dynamic_cast(lpe) || - dynamic_cast(lpe) ) - { - lpe->doOnRemove(this); - } + lpe->doOnRemove(this); } (*it)->unlink(); delete *it; -- cgit v1.2.3 From 59143c117378ec4a866f34b1ba2e2930bfb17593 Mon Sep 17 00:00:00 2001 From: Jabiertxof Date: Sun, 28 May 2017 12:46:10 +0200 Subject: Add a new value to LPE 'is_load' to know the lpe is just load, no previous values set yet to not LPE stored values when loading a previous file (bzr r15711) --- src/live_effects/effect.cpp | 2 ++ src/live_effects/effect.h | 1 + src/live_effects/lpe-copy_rotate.cpp | 1 + src/live_effects/lpe-mirror_symmetry.cpp | 1 + 4 files changed, 5 insertions(+) (limited to 'src') diff --git a/src/live_effects/effect.cpp b/src/live_effects/effect.cpp index 23a4c9f3d..3a628b243 100644 --- a/src/live_effects/effect.cpp +++ b/src/live_effects/effect.cpp @@ -356,6 +356,7 @@ Effect::Effect(LivePathEffectObject *lpeobject) is_visible(_("Is visible?"), _("If unchecked, the effect remains applied to the object but is temporarily disabled on canvas"), "is_visible", &wr, this, true), show_orig_path(false), keep_paths(false), + is_load(true), lpeobj(lpeobject), concatenate_before_pwd2(false), sp_lpe_item(NULL), @@ -511,6 +512,7 @@ Effect::doBeforeEffect (SPLPEItem const*/*lpeitem*/) void Effect::doAfterEffect (SPLPEItem const* /*lpeitem*/) { + is_load = false; } void Effect::doOnRemove (SPLPEItem const* /*lpeitem*/) diff --git a/src/live_effects/effect.h b/src/live_effects/effect.h index cc0d53f12..e353eba23 100644 --- a/src/live_effects/effect.h +++ b/src/live_effects/effect.h @@ -133,6 +133,7 @@ public: void editNextParamOncanvas(SPItem * item, SPDesktop * desktop); bool apply_to_clippath_and_mask; bool keep_paths; // set this to false allow retain extra generated objects, see measure line LPE + bool is_load; bool upd_params; BoolParam is_visible; SPCurve * sp_curve; diff --git a/src/live_effects/lpe-copy_rotate.cpp b/src/live_effects/lpe-copy_rotate.cpp index 551cf1bf9..b29b5e493 100644 --- a/src/live_effects/lpe-copy_rotate.cpp +++ b/src/live_effects/lpe-copy_rotate.cpp @@ -109,6 +109,7 @@ void LPECopyRotate::doAfterEffect (SPLPEItem const* lpeitem) { if (split_items) { + is_load = false; SPDocument * document = SP_ACTIVE_DOCUMENT; if (!document) { return; diff --git a/src/live_effects/lpe-mirror_symmetry.cpp b/src/live_effects/lpe-mirror_symmetry.cpp index 8e68c483c..3fcc4ae3d 100644 --- a/src/live_effects/lpe-mirror_symmetry.cpp +++ b/src/live_effects/lpe-mirror_symmetry.cpp @@ -89,6 +89,7 @@ LPEMirrorSymmetry::~LPEMirrorSymmetry() void LPEMirrorSymmetry::doAfterEffect (SPLPEItem const* lpeitem) { + is_load = false; SPDocument * document = SP_ACTIVE_DOCUMENT; if (!document) { return; -- cgit v1.2.3 From d5cd99243b4594bd556e4985a4d5dad44f5326f7 Mon Sep 17 00:00:00 2001 From: Jabiertxof Date: Sun, 28 May 2017 12:57:28 +0200 Subject: Fix bug on crash if undefined LPE load (bzr r15712) --- src/sp-lpe-item.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/sp-lpe-item.cpp b/src/sp-lpe-item.cpp index 83cf408a4..35e7dfa3e 100644 --- a/src/sp-lpe-item.cpp +++ b/src/sp-lpe-item.cpp @@ -129,7 +129,9 @@ void SPLPEItem::set(unsigned int key, gchar const* value) { if (!value) { LivePathEffectObject *lpeobj = (*it)->lpeobject; Inkscape::LivePathEffect::Effect * lpe = lpeobj->get_lpe(); - lpe->doOnRemove(this); + if (lpe) { + lpe->doOnRemove(this); + } } (*it)->unlink(); delete *it; -- cgit v1.2.3 From 5151c0569bb266461c3b6a6325c0d4be60b41a67 Mon Sep 17 00:00:00 2001 From: Jabiertxof Date: Mon, 29 May 2017 02:09:29 +0200 Subject: Fix bug #1694111 also fixes noumerous bugfixes on LPE undo. And shapes are improved to only perform path effet one time each Fixed bugs: - https://launchpad.net/bugs/1694111 (bzr r15713) --- src/live_effects/effect.cpp | 11 ++++++++--- src/live_effects/lpe-copy_rotate.cpp | 9 ++++----- src/live_effects/lpe-mirror_symmetry.cpp | 1 + src/live_effects/lpeobject.cpp | 1 + src/sp-ellipse.cpp | 10 ++++++++-- src/sp-ellipse.h | 2 +- src/sp-lpe-item.cpp | 34 +++++++++++++------------------- src/sp-spiral.cpp | 10 ++++++++-- src/sp-spiral.h | 2 +- src/sp-star.cpp | 10 ++++++++-- src/sp-star.h | 2 +- 11 files changed, 55 insertions(+), 37 deletions(-) (limited to 'src') diff --git a/src/live_effects/effect.cpp b/src/live_effects/effect.cpp index 3a628b243..21136353c 100644 --- a/src/live_effects/effect.cpp +++ b/src/live_effects/effect.cpp @@ -452,10 +452,13 @@ Effect::processObjects(LpeAction lpe_action) std::vector item_selected; SPCSSAttr *css; Glib::ustring css_str; + SPItem *item = SP_ITEM(elemref); switch (lpe_action){ case LPE_TO_OBJECTS: - if (SP_ITEM(elemref)->isHidden()) { - elemref->deleteObject(); + if (item->isHidden()) { + sp_object_ref(item, 0 ); + item->deleteObject(true); + sp_object_unref(item); } else { if (elemnode->attribute("inkscape:path-effect")) { sp_item_list_to_curves(item_list, item_selected, item_to_select); @@ -465,7 +468,9 @@ Effect::processObjects(LpeAction lpe_action) break; case LPE_ERASE: - elemref->deleteObject(); + sp_object_ref(item, 0 ); + item->deleteObject(true); + sp_object_unref(item); break; case LPE_VISIBILITY: diff --git a/src/live_effects/lpe-copy_rotate.cpp b/src/live_effects/lpe-copy_rotate.cpp index b29b5e493..3abcbf217 100644 --- a/src/live_effects/lpe-copy_rotate.cpp +++ b/src/live_effects/lpe-copy_rotate.cpp @@ -199,15 +199,13 @@ LPECopyRotate::cloneD(SPObject *orig, SPObject *dest, Geom::Affine transform, bo } } SPShape * shape = SP_SHAPE(orig); - SPPath * path = SP_PATH(dest); - if (shape && !path) { + if (shape && !SP_IS_PATH(dest)) { const char * id = dest->getId(); Inkscape::XML::Node *dest_node = sp_selected_item_to_curved_repr(SP_ITEM(dest), 0); dest->updateRepr(xml_doc, dest_node, SP_OBJECT_WRITE_ALL); dest->getRepr()->setAttribute("d", id); - path = SP_PATH(dest); } - if (path && shape) { + if (SP_IS_PATH(dest) && shape) { SPCurve *c = NULL; if (root) { c = new SPCurve(); @@ -216,7 +214,7 @@ LPECopyRotate::cloneD(SPObject *orig, SPObject *dest, Geom::Affine transform, bo c = shape->getCurve(); } if (c) { - path->setCurve(c, TRUE); + SP_PATH(dest)->setCurve(c, TRUE); c->unref(); } else { dest->getRepr()->setAttribute("d", NULL); @@ -725,6 +723,7 @@ LPECopyRotate::doOnRemove (SPLPEItem const* /*lpeitem*/) //set "keep paths" hook on sp-lpe-item.cpp if (keep_paths) { processObjects(LPE_TO_OBJECTS); + items.clear(); return; } processObjects(LPE_ERASE); diff --git a/src/live_effects/lpe-mirror_symmetry.cpp b/src/live_effects/lpe-mirror_symmetry.cpp index 3fcc4ae3d..5d80d65fe 100644 --- a/src/live_effects/lpe-mirror_symmetry.cpp +++ b/src/live_effects/lpe-mirror_symmetry.cpp @@ -320,6 +320,7 @@ LPEMirrorSymmetry::doOnRemove (SPLPEItem const* /*lpeitem*/) //set "keep paths" hook on sp-lpe-item.cpp if (keep_paths) { processObjects(LPE_TO_OBJECTS); + items.clear(); return; } processObjects(LPE_ERASE); diff --git a/src/live_effects/lpeobject.cpp b/src/live_effects/lpeobject.cpp index b5b27c984..ca3ae46e0 100644 --- a/src/live_effects/lpeobject.cpp +++ b/src/live_effects/lpeobject.cpp @@ -112,6 +112,7 @@ void LivePathEffectObject::set(unsigned key, gchar const *value) { this->effecttype_set = true; } else { this->effecttype = Inkscape::LivePathEffect::INVALID_LPE; + this->lpe = NULL; this->effecttype_set = false; } diff --git a/src/sp-ellipse.cpp b/src/sp-ellipse.cpp index 5dfc60f1a..30c1096ca 100644 --- a/src/sp-ellipse.cpp +++ b/src/sp-ellipse.cpp @@ -408,7 +408,7 @@ const char *SPGenericEllipse::displayName() const } // Create path for rendering shape on screen -void SPGenericEllipse::set_shape() +void SPGenericEllipse::set_shape(bool force) { // std::cout << "SPGenericEllipse::set_shape: Entrance" << std::endl; if (hasBrokenPathEffect()) { @@ -475,6 +475,12 @@ void SPGenericEllipse::set_shape() /* Reset the shape's curve to the "original_curve" * This is very important for LPEs to work properly! (the bbox might be recalculated depending on the curve in shape)*/ + if(this->getCurveBeforeLPE()) { + if(!force && this->getCurveBeforeLPE()->get_pathvector() == curve->get_pathvector()) { + curve->unref(); + return; + } + } this->setCurveInsync(curve, TRUE); this->setCurveBeforeLPE(curve); @@ -617,7 +623,7 @@ void SPGenericEllipse::modified(guint flags) void SPGenericEllipse::update_patheffect(bool write) { - this->set_shape(); + this->set_shape(true); if (write) { Inkscape::XML::Node *repr = this->getRepr(); diff --git a/src/sp-ellipse.h b/src/sp-ellipse.h index dafece625..a879c596d 100644 --- a/src/sp-ellipse.h +++ b/src/sp-ellipse.h @@ -64,7 +64,7 @@ public: virtual Inkscape::XML::Node *write(Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, unsigned int flags); virtual const char *displayName() const; - virtual void set_shape(); + virtual void set_shape(bool force = false); virtual Geom::Affine set_transform(Geom::Affine const &xform); virtual void snappoints(std::vector &p, Inkscape::SnapPreferences const *snapprefs) const; diff --git a/src/sp-lpe-item.cpp b/src/sp-lpe-item.cpp index 35e7dfa3e..be886bdd2 100644 --- a/src/sp-lpe-item.cpp +++ b/src/sp-lpe-item.cpp @@ -122,17 +122,8 @@ void SPLPEItem::set(unsigned int key, gchar const* value) { this->lpe_modified_connection_list->clear(); // Clear the path effect list - PathEffectList::iterator it = this->path_effect_list->begin(); - - while ( it != this->path_effect_list->end() ) - { - if (!value) { - LivePathEffectObject *lpeobj = (*it)->lpeobject; - Inkscape::LivePathEffect::Effect * lpe = lpeobj->get_lpe(); - if (lpe) { - lpe->doOnRemove(this); - } - } + PathEffectList::iterator it = this->path_effect_list->begin(); + while ( it != this->path_effect_list->end()) { (*it)->unlink(); delete *it; it = this->path_effect_list->erase(it); @@ -539,11 +530,11 @@ void SPLPEItem::removeCurrentPathEffect(bool keep_paths) return; if (Inkscape::LivePathEffect::Effect* effect_ = this->getCurrentLPE()) { + effect_->keep_paths = keep_paths; effect_->doOnRemove(this); } PathEffectList new_list = *this->path_effect_list; new_list.remove(lperef); //current lpe ref is always our 'own' pointer from the path_effect_list - *this->path_effect_list = new_list; this->getRepr()->setAttribute("inkscape:path-effect", patheffectlist_svg_string(new_list)); if (!keep_paths) { // Make sure that ellipse is stored as or if possible. @@ -563,15 +554,18 @@ void SPLPEItem::removeAllPathEffects(bool keep_paths) if (path_effect_list->empty()) { return; } - - for (PathEffectList::const_iterator it = path_effect_list->begin(); it != path_effect_list->end(); ++it) - { - LivePathEffectObject *lpeobj = (*it)->lpeobject; - if (lpeobj) { - Inkscape::LivePathEffect::Effect * lpe = lpeobj->get_lpe(); - lpe->keep_paths = true; - } + } + for (PathEffectList::const_iterator it = path_effect_list->begin(); it != path_effect_list->end(); ++it) + { + LivePathEffectObject *lpeobj = (*it)->lpeobject; + if (lpeobj) { + Inkscape::LivePathEffect::Effect * lpe = lpeobj->get_lpe(); + lpe->keep_paths = keep_paths; + lpe->doOnRemove(this); } + (*it)->unlink(); + delete *it; + it = this->path_effect_list->erase(it); } this->getRepr()->setAttribute("inkscape:path-effect", NULL); diff --git a/src/sp-spiral.cpp b/src/sp-spiral.cpp index 57eb918fe..d75db3daa 100644 --- a/src/sp-spiral.cpp +++ b/src/sp-spiral.cpp @@ -197,7 +197,7 @@ void SPSpiral::update(SPCtx *ctx, guint flags) { } void SPSpiral::update_patheffect(bool write) { - this->set_shape(); + this->set_shape(true); if (write) { Inkscape::XML::Node *repr = this->getRepr(); @@ -310,7 +310,7 @@ void SPSpiral::fitAndDraw(SPCurve* c, double dstep, Geom::Point darray[], Geom:: g_assert (is_unit_vector (hat2)); } -void SPSpiral::set_shape() { +void SPSpiral::set_shape(bool force) { if (hasBrokenPathEffect()) { g_warning ("The spiral shape has unknown LPE on it! Convert to path to make it editable preserving the appearance; editing it as spiral will remove the bad LPE"); @@ -365,6 +365,12 @@ void SPSpiral::set_shape() { /* Reset the shape'scurve to the "original_curve" * This is very important for LPEs to work properly! (the bbox might be recalculated depending on the curve in shape)*/ + if(this->getCurveBeforeLPE()) { + if(!force && this->getCurveBeforeLPE()->get_pathvector() == c->get_pathvector()) { + c->unref(); + return; + } + } setCurveInsync( c, TRUE); setCurveBeforeLPE( c ); diff --git a/src/sp-spiral.h b/src/sp-spiral.h index 94724685c..ebf4c9e28 100644 --- a/src/sp-spiral.h +++ b/src/sp-spiral.h @@ -70,7 +70,7 @@ public: virtual const char* displayName() const; virtual char* description() const; - virtual void set_shape(); + virtual void set_shape(bool force = false); virtual void update_patheffect(bool write); private: diff --git a/src/sp-star.cpp b/src/sp-star.cpp index d112962a2..d7ee352c7 100644 --- a/src/sp-star.cpp +++ b/src/sp-star.cpp @@ -223,7 +223,7 @@ void SPStar::update(SPCtx *ctx, guint flags) { } void SPStar::update_patheffect(bool write) { - this->set_shape(); + this->set_shape(true); if (write) { Inkscape::XML::Node *repr = this->getRepr(); @@ -363,7 +363,7 @@ sp_star_get_curvepoint (SPStar *star, SPStarPoint point, gint index, bool previ) #define NEXT false #define PREV true -void SPStar::set_shape() { +void SPStar::set_shape(bool force) { // perhaps we should convert all our shapes into LPEs without source path // and with knotholders for parameters, then this situation will be handled automatically // by disabling the entire stack (including the shape LPE) @@ -446,6 +446,12 @@ void SPStar::set_shape() { /* Reset the shape'scurve to the "original_curve" * This is very important for LPEs to work properly! (the bbox might be recalculated depending on the curve in shape)*/ + if(this->getCurveBeforeLPE()) { + if(!force && this->getCurveBeforeLPE()->get_pathvector() == c->get_pathvector()) { + c->unref(); + return; + } + } this->setCurveInsync( c, TRUE); this->setCurveBeforeLPE( c ); diff --git a/src/sp-star.h b/src/sp-star.h index 1ebe3298a..4519de869 100644 --- a/src/sp-star.h +++ b/src/sp-star.h @@ -55,7 +55,7 @@ public: virtual void snappoints(std::vector &p, Inkscape::SnapPreferences const *snapprefs) const; virtual void update_patheffect(bool write); - virtual void set_shape(); + virtual void set_shape(bool force = false); virtual Geom::Affine set_transform(Geom::Affine const& xform); }; -- cgit v1.2.3 From c3a191e4275ade05cf4bb4aab045ee22d050e703 Mon Sep 17 00:00:00 2001 From: Tavmjong Bah Date: Mon, 29 May 2017 15:09:06 +0200 Subject: Update for CSS 3 'image-rendering'. (bzr r15714) --- src/display/drawing-image.cpp | 10 ++++++++-- src/style-enums.h | 4 ++-- 2 files changed, 10 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/display/drawing-image.cpp b/src/display/drawing-image.cpp index e23c89c59..508fcc503 100644 --- a/src/display/drawing-image.cpp +++ b/src/display/drawing-image.cpp @@ -116,16 +116,22 @@ unsigned DrawingImage::_renderItem(DrawingContext &dc, Geom::IntRect const &/*ar if (_style) { // See: http://www.w3.org/TR/SVG/painting.html#ImageRenderingProperty // http://www.w3.org/TR/css4-images/#the-image-rendering + // It's back in CSS Images 3 now. // style.h/style.cpp switch (_style->image_rendering.computed) { case SP_CSS_IMAGE_RENDERING_AUTO: - // Do nothing - break; case SP_CSS_IMAGE_RENDERING_OPTIMIZEQUALITY: + case SP_CSS_IMAGE_RENDERING_CRISPEDGES: + // CSS 3 defines: + // 'auto' to use smoothing + // 'optimize-quality' as alias for auto + // We don't have special rendering for 'crisp-edges' yet + // so follow what browsers do. // In recent Cairo, BEST used Lanczos3, which is prohibitively slow dc.patternSetFilter( CAIRO_FILTER_GOOD ); break; case SP_CSS_IMAGE_RENDERING_OPTIMIZESPEED: + case SP_CSS_IMAGE_RENDERING_PIXELATED: default: dc.patternSetFilter( CAIRO_FILTER_NEAREST ); break; diff --git a/src/style-enums.h b/src/style-enums.h index a0fcaedef..4ea656794 100644 --- a/src/style-enums.h +++ b/src/style-enums.h @@ -640,8 +640,8 @@ static SPStyleEnum const enum_image_rendering[] = { {"auto", SP_CSS_IMAGE_RENDERING_AUTO}, {"optimizeSpeed", SP_CSS_IMAGE_RENDERING_OPTIMIZESPEED}, {"optimizeQuality", SP_CSS_IMAGE_RENDERING_OPTIMIZEQUALITY}, - {"-inkscape-crisp-edges", SP_CSS_IMAGE_RENDERING_CRISPEDGES}, - {"-inkscape-pixelated", SP_CSS_IMAGE_RENDERING_PIXELATED}, + {"crisp-edges", SP_CSS_IMAGE_RENDERING_CRISPEDGES}, + {"pixelated", SP_CSS_IMAGE_RENDERING_PIXELATED}, {NULL, -1} }; -- cgit v1.2.3 From e8a4f74636bade09da8613a09e80809f6824f944 Mon Sep 17 00:00:00 2001 From: Tavmjong Bah Date: Mon, 29 May 2017 15:26:04 +0200 Subject: Fix PDF export with respect to 'image-rendering'. (bzr r15715) --- src/extension/internal/cairo-render-context.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/extension/internal/cairo-render-context.cpp b/src/extension/internal/cairo-render-context.cpp index 06711bca4..21902db7d 100644 --- a/src/extension/internal/cairo-render-context.cpp +++ b/src/extension/internal/cairo-render-context.cpp @@ -1580,13 +1580,13 @@ bool CairoRenderContext::renderImage(Inkscape::Pixbuf *pb, // http://www.w3.org/TR/css4-images/#the-image-rendering // style.h/style.cpp switch (style->image_rendering.computed) { - case SP_CSS_COLOR_RENDERING_AUTO: - // Do nothing - break; - case SP_CSS_COLOR_RENDERING_OPTIMIZEQUALITY: + case SP_CSS_IMAGE_RENDERING_AUTO: + case SP_CSS_IMAGE_RENDERING_OPTIMIZEQUALITY: + case SP_CSS_IMAGE_RENDERING_CRISPEDGES: cairo_pattern_set_filter(cairo_get_source(_cr), CAIRO_FILTER_BEST ); break; - case SP_CSS_COLOR_RENDERING_OPTIMIZESPEED: + case SP_CSS_IMAGE_RENDERING_OPTIMIZESPEED: + case SP_CSS_IMAGE_RENDERING_PIXELATED: default: cairo_pattern_set_filter(cairo_get_source(_cr), CAIRO_FILTER_NEAREST ); break; -- cgit v1.2.3 From fbb39e2ef01040c3c359bf05eb3094e5c7430565 Mon Sep 17 00:00:00 2001 From: Jabier Arraiza Cenoz Date: Mon, 29 May 2017 17:41:44 +0200 Subject: Alow write to repr on hidden LPE parameters (bzr r15716) --- src/live_effects/parameter/hidden.cpp | 5 ++++- src/live_effects/parameter/hidden.h | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/live_effects/parameter/hidden.cpp b/src/live_effects/parameter/hidden.cpp index 6d0e7f58f..e8c55ebd3 100644 --- a/src/live_effects/parameter/hidden.cpp +++ b/src/live_effects/parameter/hidden.cpp @@ -66,9 +66,12 @@ HiddenParam::param_newWidget() } void -HiddenParam::param_setValue(const Glib::ustring newvalue) +HiddenParam::param_setValue(const Glib::ustring newvalue, bool write) { value = newvalue; + if (write) { + param_write_to_repr(value.c_str()); + } } } /* namespace LivePathEffect */ diff --git a/src/live_effects/parameter/hidden.h b/src/live_effects/parameter/hidden.h index 387071e53..c3fba5575 100644 --- a/src/live_effects/parameter/hidden.h +++ b/src/live_effects/parameter/hidden.h @@ -38,7 +38,7 @@ public: virtual bool param_readSVGValue(const gchar * strvalue); virtual gchar * param_getSVGValue() const; - void param_setValue(Glib::ustring newvalue); + void param_setValue(Glib::ustring newvalue, bool write = false); virtual void param_set_default(); virtual void param_update_default(const gchar * default_value); -- cgit v1.2.3 From 2ed5e722d04f65eea0adfee9cea46ba65abda65b Mon Sep 17 00:00:00 2001 From: Jabier Arraiza Cenoz Date: Tue, 30 May 2017 16:46:49 +0200 Subject: Fix bug pointed by parclytaxel in IRC (bzr r15718) --- src/sp-lpe-item.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/sp-lpe-item.cpp b/src/sp-lpe-item.cpp index be886bdd2..1333642e9 100644 --- a/src/sp-lpe-item.cpp +++ b/src/sp-lpe-item.cpp @@ -555,19 +555,18 @@ void SPLPEItem::removeAllPathEffects(bool keep_paths) return; } } - for (PathEffectList::const_iterator it = path_effect_list->begin(); it != path_effect_list->end(); ++it) - { + while ( it != this->path_effect_list->end() ) { LivePathEffectObject *lpeobj = (*it)->lpeobject; if (lpeobj) { Inkscape::LivePathEffect::Effect * lpe = lpeobj->get_lpe(); lpe->keep_paths = keep_paths; lpe->doOnRemove(this); } + // unlink and delete all references in the list (*it)->unlink(); delete *it; it = this->path_effect_list->erase(it); } - this->getRepr()->setAttribute("inkscape:path-effect", NULL); if (!keep_paths) { -- cgit v1.2.3 From 379acda65c15a5ef67b0ab69be96391975816efb Mon Sep 17 00:00:00 2001 From: Jabier Arraiza Cenoz Date: Tue, 30 May 2017 17:22:35 +0200 Subject: Fix broken fix for bug pointed by parclytaxel in IRC (bzr r15719) --- src/sp-lpe-item.cpp | 3 +++ 1 file changed, 3 insertions(+) (limited to 'src') diff --git a/src/sp-lpe-item.cpp b/src/sp-lpe-item.cpp index 1333642e9..84d318db2 100644 --- a/src/sp-lpe-item.cpp +++ b/src/sp-lpe-item.cpp @@ -555,6 +555,9 @@ void SPLPEItem::removeAllPathEffects(bool keep_paths) return; } } + + PathEffectList::iterator it = this->path_effect_list->begin(); + while ( it != this->path_effect_list->end() ) { LivePathEffectObject *lpeobj = (*it)->lpeobject; if (lpeobj) { -- cgit v1.2.3 From f1d04e193de10384953849721a4d8839b4e6d1e2 Mon Sep 17 00:00:00 2001 From: Tavmjong Bah Date: Wed, 31 May 2017 13:59:57 +0200 Subject: Sort File Save and File Input file type menus. (bzr r15720) --- src/extension/db.cpp | 80 ++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 77 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/extension/db.cpp b/src/extension/db.cpp index f17b784a9..e885d3531 100644 --- a/src/extension/db.cpp +++ b/src/extension/db.cpp @@ -35,6 +35,76 @@ DB db; DB::DB (void) { } + +struct ModuleInputCmp { + bool operator()(Input* module1, Input* module2) const { + + // Ensure SVG files are at top + int n1 = 0; + int n2 = 0; + // 12345678901234567890123456789012 + if (strncmp(module1->get_id(),"org.inkscape.input.svg", 22) == 0) n1 = 1; + if (strncmp(module2->get_id(),"org.inkscape.input.svg", 22) == 0) n2 = 1; + if (strncmp(module1->get_id(),"org.inkscape.input.svgz", 23) == 0) n1 = 2; + if (strncmp(module2->get_id(),"org.inkscape.input.svgz", 23) == 0) n2 = 2; + + if (n1 != 0 && n2 != 0) return (n1 < n2); + if (n1 != 0) return true; + if (n2 != 0) return false; + + // GDK filetypenames begin with lower case letters and thus are sorted at the end. + // Special case "sK1" which starts with a lower case letter to keep it out of GDK region. + if (strncmp(module1->get_id(),"org.inkscape.input.sk1", 22) == 0) { + return ( strcmp("SK1", module2->get_filetypename()) <= 0 ); + } + if (strncmp(module2->get_id(),"org.inkscape.input.sk1", 22) == 0) { + return ( strcmp(module1->get_filetypename(), "SK1" ) <= 0 ); + } + + return ( strcmp(module1->get_filetypename(), module2->get_filetypename()) <= 0 ); + } +}; + + +struct ModuleOutputCmp { + bool operator()(Output* module1, Output* module2) const { + + // Ensure SVG files are at top + int n1 = 0; + int n2 = 0; + // 12345678901234567890123456789012 + if (strncmp(module1->get_id(),"org.inkscape.output.svg.inkscape", 32) == 0) n1 = 1; + if (strncmp(module2->get_id(),"org.inkscape.output.svg.inkscape", 32) == 0) n2 = 1; + if (strncmp(module1->get_id(),"org.inkscape.output.svg.plain", 29) == 0) n1 = 2; + if (strncmp(module2->get_id(),"org.inkscape.output.svg.plain", 29) == 0) n2 = 2; + if (strncmp(module1->get_id(),"org.inkscape.output.svgz.inkscape", 33) == 0) n1 = 3; + if (strncmp(module2->get_id(),"org.inkscape.output.svgz.inkscape", 33) == 0) n2 = 3; + if (strncmp(module1->get_id(),"org.inkscape.output.svgz.plain", 30) == 0) n1 = 4; + if (strncmp(module2->get_id(),"org.inkscape.output.svgz.plain", 30) == 0) n2 = 4; + if (strncmp(module1->get_id(),"org.inkscape.output.scour", 25) == 0) n1 = 5; + if (strncmp(module2->get_id(),"org.inkscape.output.scour", 25) == 0) n2 = 5; + if (strncmp(module1->get_id(),"org.inkscape.output.ZIP", 23) == 0) n1 = 6; + if (strncmp(module2->get_id(),"org.inkscape.output.ZIP", 23) == 0) n2 = 6; + if (strncmp(module1->get_id(),"org.inkscape.output.LAYERS", 26) == 0) n1 = 7; + if (strncmp(module2->get_id(),"org.inkscape.output.LAYERS", 26) == 0) n2 = 7; + + if (n1 != 0 && n2 != 0) return (n1 < n2); + if (n1 != 0) return true; + if (n2 != 0) return false; + + // Special case "sK1" which starts with a lower case letter. + if (strncmp(module1->get_id(),"org.inkscape.output.sk1", 23) == 0) { + return ( strcmp("SK1", module2->get_filetypename()) <= 0 ); + } + if (strncmp(module2->get_id(),"org.inkscape.output.sk1", 23) == 0) { + return ( strcmp(module1->get_filetypename(), "SK1" ) <= 0 ); + } + + return ( strcmp(module1->get_filetypename(), module2->get_filetypename()) <= 0 ); + } +}; + + /** \brief Add a module to the module database \param module The module to be registered. @@ -49,10 +119,12 @@ DB::register_ext (Extension *module) bool add_to_list = ( moduledict.find(module->get_id()) == moduledict.end()); - //printf("Registering: '%s' add:%d\n", module->get_id(), add_to_list); + //printf("Registering: '%s' '%s' add:%d\n", module->get_id(), module->get_name(), add_to_list); moduledict[module->get_id()] = module; - if (add_to_list) modulelist.push_back(module); + if (add_to_list) { + modulelist.push_back( module ); + } } /** @@ -85,7 +157,7 @@ DB::unregister_ext (Extension * module) Extension * DB::get (const gchar *key) { - if (key == NULL) return NULL; + if (key == NULL) return NULL; Extension *mod = moduledict[key]; if ( !mod || mod->deactivated() ) @@ -207,6 +279,7 @@ DB::InputList & DB::get_input_list (DB::InputList &ou_list) { foreach(input_internal, (gpointer)&ou_list); + ou_list.sort( ModuleInputCmp() ); return ou_list; } @@ -220,6 +293,7 @@ DB::OutputList & DB::get_output_list (DB::OutputList &ou_list) { foreach(output_internal, (gpointer)&ou_list); + ou_list.sort( ModuleOutputCmp() ); return ou_list; } -- cgit v1.2.3 From de697807d5fdd8702f49fed8168393215e0b7414 Mon Sep 17 00:00:00 2001 From: Tavmjong Bah Date: Thu, 1 Jun 2017 10:36:34 +0200 Subject: Use uniform name for input and output (and PDF is an ISO standard and no longer tied to Adobe). (bzr r15723) --- src/extension/internal/pdfinput/pdf-input.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/extension/internal/pdfinput/pdf-input.cpp b/src/extension/internal/pdfinput/pdf-input.cpp index a57396b17..2ee713085 100644 --- a/src/extension/internal/pdfinput/pdf-input.cpp +++ b/src/extension/internal/pdfinput/pdf-input.cpp @@ -946,8 +946,8 @@ void PdfInput::init(void) { "\n" ".pdf\n" "application/pdf\n" - "" N_("Adobe PDF (*.pdf)") "\n" - "" N_("Adobe Portable Document Format") "\n" + "" N_("Portable Document Format (*.pdf)") "\n" + "" N_("Portable Document Format") "\n" "\n" "", new PdfInput()); -- cgit v1.2.3 From 038293f7984fa8bfd89a0451d3d77fce3f62610c Mon Sep 17 00:00:00 2001 From: Tavmjong Bah Date: Thu, 1 Jun 2017 11:46:21 +0200 Subject: Avoid name conflict with libwmf (wmf_free). (bzr r15724) --- src/extension/internal/wmf-print.cpp | 2 +- src/libuemf/uwmf.c | 3 ++- src/libuemf/uwmf.h | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/extension/internal/wmf-print.cpp b/src/extension/internal/wmf-print.cpp index 6dd9d895e..29dfa2716 100644 --- a/src/extension/internal/wmf-print.cpp +++ b/src/extension/internal/wmf-print.cpp @@ -312,7 +312,7 @@ unsigned int PrintWmf::finish(Inkscape::Extension::Print * /*mod*/) g_error("Fatal programming error in PrintWmf::finish"); } (void) wmf_finish(wt); // Finalize and write out the WMF - wmf_free(&wt); // clean up + uwmf_free(&wt); // clean up wmf_htable_free(&wht); // clean up return 0; diff --git a/src/libuemf/uwmf.c b/src/libuemf/uwmf.c index 62e3d3c06..50e4075d8 100644 --- a/src/libuemf/uwmf.c +++ b/src/libuemf/uwmf.c @@ -1517,8 +1517,9 @@ int wmf_start( \brief Release memory for an wmf structure in memory. Call this after wmf_finish(). \return 0 on success, >=1 on failure \param wt WMF in memory + Renamed to uwmf_free to avoid conflict with libwmf */ -int wmf_free( +int uwmf_free( WMFTRACK **wt ){ WMFTRACK *wtl; diff --git a/src/libuemf/uwmf.h b/src/libuemf/uwmf.h index 138ffab37..529232ca9 100644 --- a/src/libuemf/uwmf.h +++ b/src/libuemf/uwmf.h @@ -2078,7 +2078,7 @@ typedef struct { // Prototypes (_set first, then _get) char *wmr_dup(const char *wmr); int wmf_start(const char *name, uint32_t initsize, uint32_t chunksize, WMFTRACK **wt); -int wmf_free(WMFTRACK **wt); +int uwmf_free(WMFTRACK **wt); int wmf_finish(WMFTRACK *wt); int wmf_append(U_METARECORD *rec, WMFTRACK *wt, int freerec); int wmf_header_append(U_METARECORD *rec,WMFTRACK *et, int freerec); -- cgit v1.2.3 From f518a2c4a18f90c06cb65800b2df5235aa70a17f Mon Sep 17 00:00:00 2001 From: Tavmjong Bah Date: Sat, 3 Jun 2017 15:20:04 +0200 Subject: Add list of OpenType tables available in selected font. (bzr r15725) --- src/ui/widget/font-variants.cpp | 57 ++++++++++++++++++++++++----------------- src/ui/widget/font-variants.h | 3 ++- 2 files changed, 35 insertions(+), 25 deletions(-) (limited to 'src') diff --git a/src/ui/widget/font-variants.cpp b/src/ui/widget/font-variants.cpp index b386051a6..6753bbc7a 100644 --- a/src/ui/widget/font-variants.cpp +++ b/src/ui/widget/font-variants.cpp @@ -231,9 +231,13 @@ namespace Widget { // Add tooltips _feature_entry.set_tooltip_text( _("Feature settings in CSS form. No sanity checking is performed.")); + _feature_list.set_justify( Gtk::JUSTIFY_LEFT ); + _feature_list.set_line_wrap( true ); + // Add to frame _feature_vbox.add( _feature_entry ); _feature_vbox.add( _feature_label ); + _feature_vbox.add( _feature_list ); _feature_frame.add( _feature_vbox ); add( _feature_frame ); @@ -532,30 +536,35 @@ namespace Widget { // 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; - // } + 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 ); + std::string ott_list = "OpenType tables not included above: "; + for(it = table_copy.begin(); it != table_copy.end(); ++it) { + // std::cout << "Other: " << it->first << " Occurances: " << it->second << std::endl; + ott_list += it->first; + ott_list += ", "; + } + + _feature_list.set_text( ott_list.c_str() ); } else { std::cerr << "FontVariants::update(): Couldn't find font_instance for: " diff --git a/src/ui/widget/font-variants.h b/src/ui/widget/font-variants.h index d4329feff..507e5fb91 100644 --- a/src/ui/widget/font-variants.h +++ b/src/ui/widget/font-variants.h @@ -86,7 +86,8 @@ protected: Gtk::VBox _feature_vbox; Gtk::Entry _feature_entry; Gtk::Label _feature_label; - + Gtk::Label _feature_list; + private: void ligatures_init(); void ligatures_callback(); -- cgit v1.2.3 From a6162e760c7eab68fc65a4ccc879e73ab0c20c1b Mon Sep 17 00:00:00 2001 From: Martin Owens Date: Sun, 4 Jun 2017 18:12:50 -0400 Subject: Add very raw page loading using links (bzr r15727) --- src/document.cpp | 12 +++++++++--- src/sp-anchor.cpp | 42 +++++++++++++++++++++++++++++++++++++++--- src/sp-anchor.h | 4 ++++ 3 files changed, 52 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/document.cpp b/src/document.cpp index c7115f906..4fcc2b098 100644 --- a/src/document.cpp +++ b/src/document.cpp @@ -481,7 +481,7 @@ SPDocument *SPDocument::createChildDoc(std::string const &uri) SPDocument *document = NULL; while(parent != NULL && parent->getURI() != NULL && document == NULL) { - // Check myself and any parents int he chain + // Check myself and any parents in the chain if(uri == parent->getURI()) { document = parent; break; @@ -500,8 +500,14 @@ SPDocument *SPDocument::createChildDoc(std::string const &uri) // Load a fresh document from the svg source. if(!document) { - const char *path = uri.c_str(); - document = createNewDoc(path, false, false, this); + std::string path; + if(uri.find('/') == -1) { + path = this->getBase() + uri; + } else { + path = uri; + } + std::cout << "Added base: '" << path << "'\n"; + document = createNewDoc(path.c_str(), false, false, this); } return document; } diff --git a/src/sp-anchor.cpp b/src/sp-anchor.cpp index 78ba10c13..b40f53ee1 100644 --- a/src/sp-anchor.cpp +++ b/src/sp-anchor.cpp @@ -5,6 +5,7 @@ * Lauris Kaplinski * Abhishek Sharma * + * Copyright (C) 2017 Martin Owens * Copyright (C) 2001-2002 Lauris Kaplinski * Copyright (C) 2001 Ximian, Inc. * @@ -23,6 +24,9 @@ SPAnchor::SPAnchor() : SPGroup() { this->href = NULL; + this->type = NULL; + this->title = NULL; + this->page = NULL; } SPAnchor::~SPAnchor() { @@ -46,6 +50,18 @@ void SPAnchor::release() { g_free(this->href); this->href = NULL; } + if (this->type) { + g_free(this->type); + this->type = NULL; + } + if (this->title) { + g_free(this->title); + this->title = NULL; + } + if (this->page) { + g_free(this->page); + this->page = NULL; + } SPGroup::release(); } @@ -56,12 +72,21 @@ void SPAnchor::set(unsigned int key, const gchar* value) { g_free(this->href); this->href = g_strdup(value); this->requestModified(SP_OBJECT_MODIFIED_FLAG); + this->updatePageAnchor(); break; - case SP_ATTR_XLINK_TYPE: + g_free(this->type); + this->type = g_strdup(value); + this->updatePageAnchor(); + this->requestModified(SP_OBJECT_MODIFIED_FLAG); + break; case SP_ATTR_XLINK_ROLE: case SP_ATTR_XLINK_ARCROLE: case SP_ATTR_XLINK_TITLE: + g_free(this->title); + this->title = g_strdup(value); + this->requestModified(SP_OBJECT_MODIFIED_FLAG); + break; case SP_ATTR_XLINK_SHOW: case SP_ATTR_XLINK_ACTUATE: case SP_ATTR_TARGET: @@ -74,6 +99,17 @@ void SPAnchor::set(unsigned int key, const gchar* value) { } } +/* + * Detect if this anchor qualifies as a page link and append + * the new page document to this document. + */ +void SPAnchor::updatePageAnchor() { + if (this->type && !strcmp(this->type, "page")) { + if (this->href && !this->page) { + this->page = this->document->createChildDoc(this->href); + } + } +} #define COPY_ATTR(rd,rs,key) (rd)->setAttribute((key), rs->attribute(key)); @@ -83,14 +119,14 @@ Inkscape::XML::Node* SPAnchor::write(Inkscape::XML::Document *xml_doc, Inkscape: } repr->setAttribute("xlink:href", this->href); + if (this->type) repr->setAttribute("xlink:type", this->type); + if (this->title) repr->setAttribute("xlink:title", this->title); if (repr != this->getRepr()) { // XML Tree being directly used while it shouldn't be in the // below COPY_ATTR lines - COPY_ATTR(repr, this->getRepr(), "xlink:type"); COPY_ATTR(repr, this->getRepr(), "xlink:role"); COPY_ATTR(repr, this->getRepr(), "xlink:arcrole"); - COPY_ATTR(repr, this->getRepr(), "xlink:title"); COPY_ATTR(repr, this->getRepr(), "xlink:show"); COPY_ATTR(repr, this->getRepr(), "xlink:actuate"); COPY_ATTR(repr, this->getRepr(), "target"); diff --git a/src/sp-anchor.h b/src/sp-anchor.h index d17718344..2dd81f74c 100644 --- a/src/sp-anchor.h +++ b/src/sp-anchor.h @@ -24,10 +24,14 @@ public: virtual ~SPAnchor(); char *href; + char *type; + char *title; + SPDocument *page; virtual void build(SPDocument *document, Inkscape::XML::Node *repr); virtual void release(); virtual void set(unsigned int key, char const* value); + virtual void updatePageAnchor(); virtual Inkscape::XML::Node* write(Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, unsigned int flags); virtual const char* displayName() const; -- cgit v1.2.3 From 99cc870e2202dd3bd4c63be34bb45ba09aa0bd0e Mon Sep 17 00:00:00 2001 From: Marc Jeanmougin Date: Mon, 5 Jun 2017 00:58:45 +0200 Subject: Porting the pre-92 file update message from 0.92.x to trunk: New dialog when opening pre-0.92 files (with 90 dpi). I implemented it mostly based on mizmo's UI proposal (thanks!), with additional inputs from su_v with a few bugfixes from jabiertxof Also adds a commandline option --convert-dpi-method=[none|scale-viewbox|scale-document] to be able to batch convert files. Fixed bugs: - https://launchpad.net/bugs/1659229 (bzr r15729) --- src/document.cpp | 5 + src/file-update.cpp | 443 ++++++++++++++++++++++++++++++++++++++++++- src/file.cpp | 536 +--------------------------------------------------- src/file.h | 3 + src/main.cpp | 23 +++ 5 files changed, 477 insertions(+), 533 deletions(-) (limited to 'src') diff --git a/src/document.cpp b/src/document.cpp index 4fcc2b098..2141f65e9 100644 --- a/src/document.cpp +++ b/src/document.cpp @@ -469,6 +469,11 @@ SPDocument *SPDocument::createDoc(Inkscape::XML::Document *rdoc, sp_file_convert_font_name(document); } + /** Fix dpi (pre-92 files) **/ + if ( !(INKSCAPE.use_gui()) && sp_version_inside_range( document->root->version.inkscape, 0, 1, 0, 92 ) ) { + sp_file_convert_dpi(document); + } + return document; } diff --git a/src/file-update.cpp b/src/file-update.cpp index 8fb3b3111..c9a1b6d62 100644 --- a/src/file-update.cpp +++ b/src/file-update.cpp @@ -8,6 +8,17 @@ * Marc Jeanmougin * su_v */ +#include + +#include "extension/effect.h" +#include "extension/db.h" +#include "extension/input.h" +#include "extension/output.h" +#include "extension/system.h" + +#include "inkscape.h" +#include "preferences.h" + #include "file.h" #include "sp-root.h" #include "sp-text.h" @@ -17,13 +28,33 @@ #include "sp-object.h" #include "sp-item.h" #include "style.h" +#include "sp-defs.h" +#include "dir-util.h" #include "document.h" #include #include #include "text-editing.h" - +#include "document-undo.h" +#include "display/canvas-grid.h" +#include "sp-guide.h" +#include "selection-chemistry.h" +#include "persp3d.h" +#include "proj_pt.h" +#include "ui/shape-editor.h" +#include "io/sys.h" +#include "print.h" +#include "ui/interface.h" +#include "desktop.h" +#include "message.h" +#include "message-stack.h" +#include "verbs.h" +#include "sp-namedview.h" + +using Inkscape::DocumentUndo; using namespace std; +int sp_file_convert_dpi_method_commandline = -1; // Unset + bool is_line(SPObject *i) { if (!(i->getAttribute("sodipodi:role"))) @@ -167,6 +198,416 @@ void sp_file_convert_font_name(SPDocument *doc) sp_file_text_run_recursive(fix_update, doc->getRoot()); } + +// Quick and dirty internal backup function +bool sp_file_save_backup( Glib::ustring uri ) { + + Glib::ustring out = uri; + out.insert(out.find(".svg"),"_backup"); + + FILE *filein = Inkscape::IO::fopen_utf8name(uri.c_str(), "rb"); + if (!filein) { + std::cerr << "sp_file_save_backup: failed to open: " << uri << std::endl; + return false; + } + + FILE *fileout = Inkscape::IO::fopen_utf8name(out.c_str(), "wb"); + if (!fileout) { + std::cerr << "sp_file_save_backup: failed to open: " << out << std::endl; + fclose( filein ); + return false; + } + + int ch; + while ((ch = fgetc(filein)) != EOF) { + fputc(ch, fileout); + } + fflush(fileout); + + bool return_value = true; + if (ferror(fileout)) { + std::cerr << "sp_file_save_backup: error when writing to: " << out << std::endl; + return_value = false; + } + + fclose(filein); + fclose(fileout); + + return return_value; +} + + +void sp_file_convert_dpi(SPDocument *doc) +{ + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + Glib::ustring uri = doc->getURI(); + SPRoot *root = doc->getRoot(); + + // See if we need to offer the user a fix for the 90->96 px per inch change. + // std::cout << "SPFileOpen:" << std::endl; + // std::cout << " Version: " << sp_version_to_string(root->version.inkscape) << std::endl; + // std::cout << " SVG file from old Inkscape version detected: " + // << sp_version_to_string(root->version.inkscape) << std::endl; + static const double ratio = 90.0/96.0; + + bool need_fix_viewbox = false; + bool need_fix_units = false; + bool need_fix_guides = false; + bool need_fix_grid_mm = false; + bool need_fix_box3d = false; + bool did_scaling = false; + + // Check if potentially need viewbox or unit fix + switch (root->width.unit) { + case SP_CSS_UNIT_PC: + case SP_CSS_UNIT_PT: + case SP_CSS_UNIT_MM: + case SP_CSS_UNIT_CM: + case SP_CSS_UNIT_IN: + need_fix_viewbox = true; + break; + case SP_CSS_UNIT_NONE: + case SP_CSS_UNIT_PX: + need_fix_units = true; + break; + case SP_CSS_UNIT_EM: + case SP_CSS_UNIT_EX: + case SP_CSS_UNIT_PERCENT: + // OK + break; + default: + std::cerr << "sp_file_open: Unhandled width unit!" << std::endl; + } + + switch (root->height.unit) { + case SP_CSS_UNIT_PC: + case SP_CSS_UNIT_PT: + case SP_CSS_UNIT_MM: + case SP_CSS_UNIT_CM: + case SP_CSS_UNIT_IN: + need_fix_viewbox = true; + break; + case SP_CSS_UNIT_NONE: + case SP_CSS_UNIT_PX: + need_fix_units = true; + break; + case SP_CSS_UNIT_EM: + case SP_CSS_UNIT_EX: + case SP_CSS_UNIT_PERCENT: + // OK + break; + default: + std::cerr << "sp_file_open: Unhandled height unit!" << std::endl; + } + + if (need_fix_units && need_fix_viewbox) { + std::cerr << "Different units in document size !" << std::endl; + if (root->viewBox_set) + need_fix_viewbox = false; + else + need_fix_units = false; + } + + // std::cout << "Absolute SVG units in root? " << (need_fix_viewbox?"true":"false") << std::endl; + // std::cout << "User units in root? " << (need_fix_units ?"true":"false") << std::endl; + + if ((!root->viewBox_set && need_fix_viewbox) || need_fix_units) { + int response = FILE_DPI_UNCHANGED; // default + + /******** UI *******/ + bool backup = prefs->getBool("/options/dpifixbackup", true); + if (INKSCAPE.use_gui() && sp_file_convert_dpi_method_commandline == -1) { + Gtk::Dialog scale_dialog(_("Convert legacy Inkscape file")); + scale_dialog.set_border_width(10); + scale_dialog.set_resizable(false); + Gtk::Label explanation; + explanation.set_markup(Glib::ustring("") + doc->getName() + "\n" + + _("was created in an older version of Inkscape (90 DPI) and we need " + "to make it compatible with newer versions (96 DPI). Tell us about this file:\n")); + explanation.set_line_wrap(true); + explanation.set_size_request(600,-1); + Gtk::RadioButton::Group c1, c2; + + Gtk::Label choice1_label; + choice1_label.set_markup( + _("This file contains digital artwork for screen display. (Choose if unsure.)")); + Gtk::RadioButton choice1(c1); + choice1.add(choice1_label); + Gtk::RadioButton choice2(c1, _("This file is intended for physical output, such as paper or 3D prints.")); + Gtk::Label choice2_1_label; + choice2_1_label.set_markup(_("The appearance of elements such as clips, masks, filters, and clones\n" + "is most important. (Choose if unsure.)")); + Gtk::RadioButton choice2_1(c2); + choice2_1.add(choice2_1_label); + Gtk::RadioButton choice2_2(c2, _("The accuracy of the physical unit size and position values of objects\n" + "in the file is most important. (Experimental.)")); + Gtk::CheckButton backup_button(_("Create a backup file in same directory.")); + Gtk::Expander moreinfo(_("More details...")); + Gtk::Label moreinfo_text; + moreinfo_text.set_markup( + _("We've updated Inkscape to follow the CSS standard of 96 DPI for better browser " + "compatibility; we used to use 90 DPI. " + "Digital artwork for screen display will be converted to 96 DPI without scaling and should be " + "unaffected. " + "Artwork drawn at 90 DPI for a specific physical size will be too small if converted to 96 DPI " + "without any scaling. There are two scaling methods:\n\n" + "Scaling the whole document: The least error-prone method, this preserves the appearance of " + "the artwork, including filters and the position of masks, etc. " + "The scale of the artwork relative to the document size may not be accurate.\n\n" + "Scaling individual elements in the artwork: This method is less reliable and can result in " + "a changed appearance, " + "but is better for physical output that relies on accurate sizes and positions (for example, for " + "3D printing.)\n\n" + "More information about this change are available in the Inkscape FAQ" + "")); + moreinfo_text.set_line_wrap(true); + moreinfo_text.set_size_request(554,-1); + Gtk::Box b; + b.set_border_width(0); + + b.pack_start(choice2_1, false, false, 4); + b.pack_start(choice2_2, false, false, 4); + choice2_1.show(); + choice2_2.show(); + + Gtk::Alignment balign(0, 0, 0, 0); + balign.set_padding (0, 0, 30, 0); + balign.show(); + balign.add(b); + Gtk::Box *content = scale_dialog.get_content_area(); + content->pack_start(explanation, false, false, 5); + content->pack_start(choice1, false, false, 5); + content->pack_start(choice2, false, false, 5); + content->pack_start(balign, false, false, 5); + content->pack_start(backup_button, false, false, 5); + Gtk::Button *ok_button = scale_dialog.add_button(_("OK"), GTK_RESPONSE_ACCEPT); + backup_button.set_active(backup); + content->pack_start(moreinfo, false, false, 5); + moreinfo.add(moreinfo_text); + scale_dialog.show_all_children(); + b.hide(); + choice1.signal_clicked().connect(sigc::mem_fun(b, &Gtk::Box::hide)); + choice2.signal_clicked().connect(sigc::mem_fun(b, &Gtk::Box::show)); + + response = prefs->getInt("/options/dpiupdatemethod", FILE_DPI_UNCHANGED); + if ( response != FILE_DPI_UNCHANGED ) { + choice2.set_active(); + b.show(); + if ( response == FILE_DPI_DOCUMENT_SCALED) + choice2_2.set_active(); + } + ok_button->grab_focus(); + + int status = scale_dialog.run(); + if ( status == GTK_RESPONSE_ACCEPT ) { + backup = backup_button.get_active(); + prefs->setBool("/options/dpifixbackup", backup); + response = choice1.get_active() ? FILE_DPI_UNCHANGED : choice2_1.get_active() ? FILE_DPI_VIEWBOX_SCALED : FILE_DPI_DOCUMENT_SCALED; + prefs->setInt("/options/dpiupdatemethod", response); + } else if (sp_file_convert_dpi_method_commandline != -1) { + response = sp_file_convert_dpi_method_commandline; + } else { + response = FILE_DPI_UNCHANGED; + } + } else { // GUI with explicit option + response = FILE_DPI_UNCHANGED; + } + + if (backup && (response != FILE_DPI_UNCHANGED)) { + sp_file_save_backup(uri); + } + + if (!(response == FILE_DPI_UNCHANGED && need_fix_units)) { + need_fix_guides = true; // Only fix guides if drawing scaled + need_fix_box3d = true; + } + + if (response == FILE_DPI_VIEWBOX_SCALED) { + double ratio_viewbox = need_fix_units ? 1.0 : ratio; + + doc->setViewBox(Geom::Rect::from_xywh(0, 0, doc->getWidth().value("px") * ratio_viewbox, + doc->getHeight().value("px") * ratio_viewbox)); + Inkscape::Util::Quantity width = // maybe set it to mm ? + Inkscape::Util::Quantity(doc->getWidth().value("px") / ratio, "px"); + Inkscape::Util::Quantity height = Inkscape::Util::Quantity(doc->getHeight().value("px") / ratio, "px"); + if (need_fix_units) + doc->setWidthAndHeight(width, height, false); + + } else if (response == FILE_DPI_DOCUMENT_SCALED) { + + Inkscape::Util::Quantity width = // maybe set it to mm ? + Inkscape::Util::Quantity(doc->getWidth().value("px") / ratio, "px"); + Inkscape::Util::Quantity height = Inkscape::Util::Quantity(doc->getHeight().value("px") / ratio, "px"); + if (need_fix_units) + doc->setWidthAndHeight(width, height, false); + + if (!root->viewBox_set) { + // Save preferences + bool transform_stroke = prefs->getBool("/options/transform/stroke", true); + bool transform_rectcorners = prefs->getBool("/options/transform/rectcorners", true); + bool transform_pattern = prefs->getBool("/options/transform/pattern", true); + bool transform_gradient = prefs->getBool("/options/transform/gradient", true); + + prefs->setBool("/options/transform/stroke", true); + prefs->setBool("/options/transform/rectcorners", true); + prefs->setBool("/options/transform/pattern", true); + prefs->setBool("/options/transform/gradient", true); + + Inkscape::UI::ShapeEditor::blockSetItem(true); + doc->getRoot()->scaleChildItemsRec(Geom::Scale(1 / ratio), Geom::Point(0, 0), false); + Inkscape::UI::ShapeEditor::blockSetItem(false); + + // Restore preferences + prefs->setBool("/options/transform/stroke", transform_stroke); + prefs->setBool("/options/transform/rectcorners", transform_rectcorners); + prefs->setBool("/options/transform/pattern", transform_pattern); + prefs->setBool("/options/transform/gradient", transform_gradient); + + did_scaling = true; +/* + +// There used to be 2 "experimental" scaling methods in trunk. Considering that the method in .92.x appear to work, so I'm commenting those. + + // Save preferences + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + bool onlysensitive = prefs->getBool("/options/kbselection/onlysensitive",true); + bool onlyvisible = prefs->getBool("/options/kbselection/onlyvisible", true); + + prefs->setBool("/options/kbselection/onlysensitive", false); + prefs->setBool("/options/kbselection/onlyvisible", false); + + Inkscape::Selection *selection = desktop->getSelection(); + Inkscape::SelectionHelper::selectAllInAll( desktop ); + +//method 1 ... + selection->group(); + SPItem * group = selection->singleItem(); + if (group) { + group->setAttribute("transform","scale(1.06666667,1.06666667)"); + } else { + std::cerr << "sp_file_open: Failed to get group!" << std::endl; + } + selection->clear(); + selection->add( group ); + selection->ungroup(); + +// OR method 2... + + double height = root->height.computed; + selection->setScaleRelative( Geom::Point(0,height), Geom::Scale(96.0/90.0,96.0/90.0) ); + +... end method 2 + + selection->clear(); + + prefs->setBool("/options/kbselection/onlysensitive", onlysensitive); + prefs->setBool("/options/kbselection/onlyvisible", onlyvisible ); + + did_scaling = true; +*/ + + + + } + } else { // FILE_DPI_UNCHANGED + if (need_fix_units) + need_fix_grid_mm = true; + } + } + + // Fix guides and grids and perspective + for (SPObject *child = root->firstChild(); child; child = child->getNext()) { + SPNamedView *nv = dynamic_cast(child); + if (nv) { + if (need_fix_guides) { + // std::cout << "Fixing guides" << std::endl; + for (SPObject *child2 = nv->firstChild(); child2; child2 = child2->getNext()) { + SPGuide *gd = dynamic_cast(child2); + if (gd) { + gd->moveto(gd->getPoint() / ratio, true); + } + } + } + + for (std::vector::const_iterator it = nv->grids.begin(); it != nv->grids.end(); + ++it) { + Inkscape::CanvasXYGrid *xy = dynamic_cast(*it); + if (xy) { + // std::cout << "A grid: " << xy->getSVGName() << std::endl; + // std::cout << " Origin: " << xy->origin + // << " Spacing: " << xy->spacing << std::endl; + // std::cout << (xy->isLegacy()?" Legacy":" Not Legacy") << std::endl; + Geom::Scale scale = doc->getDocumentScale(); + if (xy->isLegacy()) { + if (xy->isPixel()) { + if (need_fix_grid_mm) { + xy->Scale(Geom::Scale(1, 1)); // See note below + } else { + scale *= Geom::Scale(ratio, ratio); + xy->Scale(scale.inverse()); /* *** */ + } + } else { + if (need_fix_grid_mm) { + xy->Scale(Geom::Scale(ratio, ratio)); + } else { + xy->Scale(scale.inverse()); /* *** */ + } + } + } else { + if (need_fix_guides) { + if (did_scaling) { + xy->Scale(Geom::Scale(ratio, ratio).inverse()); + } else { + // HACK: Scaling the document does not seem to cause + // grids defined in document units to be updated. + // This forces an update. + xy->Scale(Geom::Scale(1, 1)); + } + } + } + } + } + } // If SPNamedView + + SPDefs *defs = dynamic_cast(child); + if (defs && need_fix_box3d) { + for (SPObject *child = defs->firstChild(); child; child = child->getNext()) { + Persp3D *persp3d = dynamic_cast(child); + if (persp3d) { + std::vector tokens; + + const gchar *vp_x = persp3d->getAttribute("inkscape:vp_x"); + const gchar *vp_y = persp3d->getAttribute("inkscape:vp_y"); + const gchar *vp_z = persp3d->getAttribute("inkscape:vp_z"); + const gchar *vp_o = persp3d->getAttribute("inkscape:persp3d-origin"); + // std::cout << "Found Persp3d: " + // << " vp_x: " << vp_x + // << " vp_y: " << vp_y + // << " vp_z: " << vp_z << std::endl; + Proj::Pt2 pt_x(vp_x); + Proj::Pt2 pt_y(vp_y); + Proj::Pt2 pt_z(vp_z); + Proj::Pt2 pt_o(vp_o); + pt_x = pt_x * (1.0 / ratio); + pt_y = pt_y * (1.0 / ratio); + pt_z = pt_z * (1.0 / ratio); + pt_o = pt_o * (1.0 / ratio); + persp3d->setAttribute("inkscape:vp_x", pt_x.coord_string()); + persp3d->setAttribute("inkscape:vp_y", pt_y.coord_string()); + persp3d->setAttribute("inkscape:vp_z", pt_z.coord_string()); + persp3d->setAttribute("inkscape:persp3d-origin", pt_o.coord_string()); + } + } + } + } // Look for SPNamedView and SPDefs loop + + // desktop->getDocument()->ensureUpToDate(); // Does not update box3d! + DocumentUndo::done(doc, SP_VERB_NONE, _("Update Document")); +} + + + /* Local Variables: mode:c++ diff --git a/src/file.cpp b/src/file.cpp index 795df433d..43a9c6f5b 100644 --- a/src/file.cpp +++ b/src/file.cpp @@ -65,13 +65,6 @@ #include "event-log.h" #include "ui/dialog/font-substitution.h" -// For updating old Inkscape SVG files -#include "display/canvas-grid.h" -#include "sp-guide.h" -#include "selection-chemistry.h" -#include "persp3d.h" -#include "proj_pt.h" -#include "ui/shape-editor.h" using Inkscape::DocumentUndo; @@ -240,42 +233,6 @@ sp_file_exit() } -// Quick and dirty internal backup function -bool sp_file_save_backup( Glib::ustring uri ) { - - Glib::ustring out = uri; - out.insert(out.find(".svg"),"_backup"); - - FILE *filein = Inkscape::IO::fopen_utf8name(uri.c_str(), "rb"); - if (!filein) { - std::cerr << "sp_file_save_backup: failed to open: " << uri << std::endl; - return false; - } - - FILE *fileout = Inkscape::IO::fopen_utf8name(out.c_str(), "wb"); - if (!fileout) { - std::cerr << "sp_file_save_backup: failed to open: " << out << std::endl; - fclose( filein ); - return false; - } - - int ch; - while ((ch = fgetc(filein)) != EOF) { - fputc(ch, fileout); - } - fflush(fileout); - - bool return_value = true; - if (ferror(fileout)) { - std::cerr << "sp_file_save_backup: error when writing to: " << out << std::endl; - return_value = false; - } - - fclose(filein); - fclose(fileout); - - return return_value; -} /*###################### ## O P E N @@ -342,497 +299,12 @@ bool sp_file_open(const Glib::ustring &uri, root->original.svg = root->version.svg; if (INKSCAPE.use_gui()) { - - // See if we need to offer the user a fix for the 90->96 px per inch change. - // std::cout << "SPFileOpen:" << std::endl; - // std::cout << " Version: " << sp_version_to_string(root->version.inkscape) << std::endl; - - if ( sp_version_inside_range( root->version.inkscape, 0, 1, 0, 92 ) ) { - - // std::cout << " SVG file from old Inkscape version detected: " - // << sp_version_to_string(root->version.inkscape) << std::endl; - static const double ratio = 90.0/96.0; - - bool need_fix_viewbox = false; - bool need_fix_units = false; - bool need_fix_guides = false; - bool need_fix_grid_mm = false; - bool need_fix_box3d = false; - bool did_scaling = false; - - // Check if potentially need viewbox or unit fix - switch (root->width.unit) { - case SP_CSS_UNIT_PC: - case SP_CSS_UNIT_PT: - case SP_CSS_UNIT_MM: - case SP_CSS_UNIT_CM: - case SP_CSS_UNIT_IN: - need_fix_viewbox = true; - break; - case SP_CSS_UNIT_NONE: - case SP_CSS_UNIT_PX: - need_fix_units = true; - break; - case SP_CSS_UNIT_EM: - case SP_CSS_UNIT_EX: - case SP_CSS_UNIT_PERCENT: - // OK - break; - default: - std::cerr << "sp_file_open: Unhandled width unit!" << std::endl; - } - - switch (root->height.unit) { - case SP_CSS_UNIT_PC: - case SP_CSS_UNIT_PT: - case SP_CSS_UNIT_MM: - case SP_CSS_UNIT_CM: - case SP_CSS_UNIT_IN: - need_fix_viewbox = true; - break; - case SP_CSS_UNIT_NONE: - case SP_CSS_UNIT_PX: - need_fix_units = true; - break; - case SP_CSS_UNIT_EM: - case SP_CSS_UNIT_EX: - case SP_CSS_UNIT_PERCENT: - // OK - break; - default: - std::cerr << "sp_file_open: Unhandled height unit!" << std::endl; - } - - // std::cout << "Absolute SVG units in root? " << (need_fix_viewbox?"true":"false") << std::endl; - // std::cout << "User units in root? " << (need_fix_units ?"true":"false") << std::endl; - - Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - - if (!root->viewBox_set && need_fix_viewbox) { - - Glib::ustring msg = _( - "Old Inkscape files use 1in == 90px. CSS requires 1in == 96px.\n" - "Drawing elements may be too small. This can be corrected by\n" - "either setting the SVG 'viewBox' to compensate or by scaling\n" - "all the elements in the drawing."); - Gtk::Dialog scaleDialog( _("Old Inkscape file detected (90 DPI)"), false); - - Gtk::Label info; - info.set_markup(msg.c_str()); - info.show(); - scaleDialog.get_content_area()->pack_start(info, false, false, 20); - - Gtk::CheckButton backupButton( _("Create backup file (in same directory).") ); - bool backup = prefs->getBool("/options/dpifixbackup", true); - backupButton.set_active( backup ); - backupButton.show(); - scaleDialog.get_content_area()->pack_start(backupButton, false, false, 20); - - scaleDialog.add_button(_("Set 'viewBox'"), 1); - scaleDialog.add_button(_("Scale elements"), 2); - scaleDialog.add_button(_("Ignore"), 3); - scaleDialog.add_button("Scale test - group", 4); - scaleDialog.add_button("Scale test - children", 5); - scaleDialog.add_button("Scale test - all", 6); - - gint response = scaleDialog.run(); - backup = backupButton.get_active(); - prefs->setBool("/options/dpifixbackup", backup); - - if ( backup && response != 3) { - sp_file_save_backup( uri ); - } - - if (response == 1) { - - doc->setViewBox(Geom::Rect::from_xywh( - 0, 0, - doc->getWidth().value("px") * ratio, - doc->getHeight().value("px") * ratio)); - - } else if (response == 2 ) { - - std::list effects; - Inkscape::Extension::db.get_effect_list(effects); - std::list::iterator it = effects.begin(); - bool did = false; - while (it != effects.end()) { - if (strcmp((*it)->get_id(), "org.inkscape.dpi90to96") == 0) { - Inkscape::UI::View::View *view = desktop; - (*it)->effect(view); - did = true; - break; - } - ++it; - } - if (!did) { - std::cerr << "sp_file_open: Failed to find dpi90to96 extension." << std::endl; - } - did_scaling = true; - - } else if (response == 4) { - - // Save preferences - bool onlysensitive = prefs->getBool("/options/kbselection/onlysensitive",true); - bool onlyvisible = prefs->getBool("/options/kbselection/onlyvisible", true); - - prefs->setBool("/options/kbselection/onlysensitive", false); - prefs->setBool("/options/kbselection/onlyvisible", false); - - Inkscape::Selection *selection = desktop->getSelection(); - Inkscape::SelectionHelper::selectAllInAll( desktop ); - selection->group(); - SPItem * group = selection->singleItem(); - if (group) { - group->setAttribute("transform","scale(1.06666667,1.06666667)"); - } else { - std::cerr << "sp_file_open: Failed to get group!" << std::endl; - } - selection->clear(); - selection->add( group ); - selection->ungroup(); - selection->clear(); - - prefs->setBool("/options/kbselection/onlysensitive", onlysensitive); - prefs->setBool("/options/kbselection/onlyvisible", onlyvisible ); - - did_scaling = true; - - } else if (response == 5) { - - // Save preferences - bool transform_stroke = prefs->getBool("/options/transform/stroke", true); - bool transform_rectcorners = prefs->getBool("/options/transform/rectcorners", true); - bool transform_pattern = prefs->getBool("/options/transform/pattern", true); - bool transform_gradient = prefs->getBool("/options/transform/gradient", true); - - prefs->setBool("/options/transform/stroke", true); - prefs->setBool("/options/transform/rectcorners", true); - prefs->setBool("/options/transform/pattern", true); - prefs->setBool("/options/transform/gradient", true); - - Inkscape::UI::ShapeEditor::blockSetItem(true); - doc->getRoot()->scaleChildItemsRec(Geom::Scale(1/ratio),Geom::Point(0, 0), false); - Inkscape::UI::ShapeEditor::blockSetItem(false); - - // Restore preferences - prefs->setBool("/options/transform/stroke", transform_stroke); - prefs->setBool("/options/transform/rectcorners", transform_rectcorners); - prefs->setBool("/options/transform/pattern", transform_pattern); - prefs->setBool("/options/transform/gradient", transform_gradient); - - } else if (response == 6) { - - // Save preferences - bool onlysensitive = prefs->getBool("/options/kbselection/onlysensitive",true); - bool onlyvisible = prefs->getBool("/options/kbselection/onlyvisible", true); - - prefs->setBool("/options/kbselection/onlysensitive", false); - prefs->setBool("/options/kbselection/onlyvisible", false); - - Inkscape::Selection *selection = desktop->getSelection(); - Inkscape::SelectionHelper::selectAllInAll( desktop ); - - double height = root->height.computed; - selection->setScaleRelative( Geom::Point(0,height), Geom::Scale(96.0/90.0,96.0/90.0) ); - selection->clear(); - - prefs->setBool("/options/kbselection/onlysensitive", onlysensitive); - prefs->setBool("/options/kbselection/onlyvisible", onlyvisible ); - - did_scaling = true; - - } - - need_fix_box3d = false; // setScaleRelative() handles box3d - need_fix_guides = true; // Always fix guides - } - - else if (need_fix_units) { - Glib::ustring msg = _( - "Old Inkscape files use 1in == 90px. CSS requires 1in == 96px.\n" - "Drawings meant to match a physical size (e.g. Letter or A4)\n" - "will be too small. Scaling the drawing can correct for this.\n" - "Internal scaling can be handled either by setting the SVG 'viewBox'\n" - "attribute to compensate or by scaling all objects in the drawing."); - Gtk::Dialog scaleDialog( _("Old Inkscape file detected (90 DPI)"), false); - - Gtk::Label info; - info.set_markup(msg.c_str()); - info.show(); - scaleDialog.get_content_area()->pack_start(info, false, false, 20); - - Gtk::CheckButton backupButton( _("Create backup file (in same directory).") ); - bool backup = prefs->getBool("/options/dpifixbackup", true); - backupButton.set_active( backup ); - backupButton.show(); - scaleDialog.get_content_area()->pack_start(backupButton, false, false, 20); - - scaleDialog.add_button(_("Set 'viewBox'"), 1); - scaleDialog.add_button(_("Scale elements"), 2); - scaleDialog.add_button(_("Ignore"), 3); - scaleDialog.add_button("Scale test - group", 4); - scaleDialog.add_button("Scale test - children", 5); - scaleDialog.add_button("Scale test - all", 6); - - gint response = scaleDialog.run(); - backup = backupButton.get_active(); - prefs->setBool("/options/dpifixbackup", backup); - - if ( backup && response != 3) { - sp_file_save_backup( uri ); - } - - if (response == 1) { - - if (!root->viewBox_set) { - doc->setViewBox(Geom::Rect::from_xywh( - 0, 0, - doc->getWidth().value("px"), - doc->getHeight().value("px"))); - } - Inkscape::Util::Quantity width = - Inkscape::Util::Quantity(doc->getWidth().value("px")/ratio, "px" ); - Inkscape::Util::Quantity height = - Inkscape::Util::Quantity(doc->getHeight().value("px")/ratio,"px" ); - doc->setWidthAndHeight( width, height, false ); - - need_fix_guides = true; // Only fix guides if drawing scaled - need_fix_box3d = true; - - } else if (response == 2) { - - std::list effects; - Inkscape::Extension::db.get_effect_list(effects); - std::list::iterator it = effects.begin(); - bool did = false; - while (it != effects.end()){ - if (strcmp((*it)->get_id(), "org.inkscape.dpi90to96") == 0) { - Inkscape::UI::View::View *view = desktop; - (*it)->effect(view); - did = true; - break; - } - ++it; - } - if (!did) { - std::cerr << "sp_file_open: Failed to find dpi90to96 extension." << std::endl; - } - need_fix_guides = true; // Only fix guides if drawing scaled - did_scaling = true; - - } else if (response == 4) { - - Inkscape::Util::Quantity width = - Inkscape::Util::Quantity(doc->getWidth().value("px")/ratio, "px" ); - Inkscape::Util::Quantity height = - Inkscape::Util::Quantity(doc->getHeight().value("px")/ratio,"px" ); - doc->setWidthAndHeight( width, height, false ); - - if (!root->viewBox_set) { - - // Save preferences - Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - bool onlysensitive = prefs->getBool("/options/kbselection/onlysensitive",true); - bool onlyvisible = prefs->getBool("/options/kbselection/onlyvisible", true); - - prefs->setBool("/options/kbselection/onlysensitive", false); - prefs->setBool("/options/kbselection/onlyvisible", false); - - Inkscape::Selection *selection = desktop->getSelection(); - Inkscape::SelectionHelper::selectAllInAll( desktop ); - selection->group(); - SPItem * group = selection->singleItem(); - if (group) { - group->setAttribute("transform","scale(1.06666667,1.06666667)"); - } else { - std::cerr << "sp_file_open: Failed to get group!" << std::endl; - } - selection->clear(); - selection->add( group ); - selection->ungroup(); - selection->clear(); - - prefs->setBool("/options/kbselection/onlysensitive", onlysensitive); - prefs->setBool("/options/kbselection/onlyvisible", onlyvisible ); - - did_scaling = true; - } - - need_fix_box3d = true; - need_fix_guides = true; // Only fix guides if drawing scaled - - } else if (response == 5) { - - Inkscape::Util::Quantity width = - Inkscape::Util::Quantity(doc->getWidth().value("px")/ratio, "px" ); - Inkscape::Util::Quantity height = - Inkscape::Util::Quantity(doc->getHeight().value("px")/ratio,"px" ); - doc->setWidthAndHeight( width, height, false ); - - if (!root->viewBox_set) { - - // Save preferences - Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - bool transform_stroke = prefs->getBool("/options/transform/stroke", true); - bool transform_rectcorners = prefs->getBool("/options/transform/rectcorners", true); - bool transform_pattern = prefs->getBool("/options/transform/pattern", true); - bool transform_gradient = prefs->getBool("/options/transform/gradient", true); - - prefs->setBool("/options/transform/stroke", true); - prefs->setBool("/options/transform/rectcorners", true); - prefs->setBool("/options/transform/pattern", true); - prefs->setBool("/options/transform/gradient", true); - - Inkscape::UI::ShapeEditor::blockSetItem(true); - doc->getRoot()->scaleChildItemsRec(Geom::Scale(1/ratio),Geom::Point(0, 0), false); - Inkscape::UI::ShapeEditor::blockSetItem(false); - - // Restore preferences - prefs->setBool("/options/transform/stroke", transform_stroke); - prefs->setBool("/options/transform/rectcorners", transform_rectcorners); - prefs->setBool("/options/transform/pattern", transform_pattern); - prefs->setBool("/options/transform/gradient", transform_gradient); - - did_scaling = true; - - } - - } else if (response == 6) { - - double old_height = root->height.computed; - Inkscape::Util::Quantity width = - Inkscape::Util::Quantity(doc->getWidth().value("px")/ratio, "px" ); - Inkscape::Util::Quantity height = - Inkscape::Util::Quantity(doc->getHeight().value("px")/ratio,"px" ); - doc->setWidthAndHeight( width, height, false ); - - if (!root->viewBox_set) { - - // Save preferences - Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - bool onlysensitive = prefs->getBool("/options/kbselection/onlysensitive",true); - bool onlyvisible = prefs->getBool("/options/kbselection/onlyvisible", true); - - prefs->setBool("/options/kbselection/onlysensitive", false); - prefs->setBool("/options/kbselection/onlyvisible", false); - - Inkscape::Selection *selection = desktop->getSelection(); - Inkscape::SelectionHelper::selectAllInAll( desktop ); - double height = root->height.computed; - - // So far we have just enlarged the drawing but due to the - // inverted coordinate system we must scale around the old - // height position. - selection->setScaleRelative( Geom::Point(0,old_height), Geom::Scale(96.0/90.0,96.0/90.0) ); - selection->clear(); - - prefs->setBool("/options/kbselection/onlysensitive", onlysensitive); - prefs->setBool("/options/kbselection/onlyvisible", onlyvisible ); - - did_scaling = true; - } - - need_fix_box3d = false; // setScaleRelative() handls box3s - need_fix_guides = true; // Only fix guides if drawing scaled - - } else { - // Ignore - need_fix_grid_mm = true; - } - } - - // Fix guides and grids and perspective - for (SPObject *child = root->firstChild() ; child; child = child->getNext() ) { - SPNamedView *nv = dynamic_cast(child); - if (nv) { - if (need_fix_guides) { - // std::cout << "Fixing guides" << std::endl; - for (SPObject *child2 = nv->firstChild() ; child2; child2 = child2->getNext() ) { - SPGuide *gd = dynamic_cast(child2); - if (gd) { - gd->moveto( gd->getPoint() / ratio, true ); - } - } - } - - for(std::vector::const_iterator it=nv->grids.begin();it!=nv->grids.end();++it ) { - Inkscape::CanvasXYGrid *xy = dynamic_cast(*it); - if (xy) { - // std::cout << "A grid: " << xy->getSVGName() << std::endl; - // std::cout << " Origin: " << xy->origin - // << " Spacing: " << xy->spacing << std::endl; - // std::cout << (xy->isLegacy()?" Legacy":" Not Legacy") << std::endl; - Geom::Scale scale = doc->getDocumentScale(); - if (xy->isLegacy()) { - if (xy->isPixel()) { - if (need_fix_grid_mm) { - xy->Scale( Geom::Scale(1,1) ); // See note below - } else { - scale *= Geom::Scale(ratio,ratio); - xy->Scale( scale.inverse() ); /* *** */ - } - } else { - if (need_fix_grid_mm) { - xy->Scale( Geom::Scale(ratio,ratio) ); - } else { - xy->Scale( scale.inverse() ); /* *** */ - } - } - } else { - if (need_fix_guides) { - if(did_scaling){ - xy->Scale( Geom::Scale(ratio,ratio).inverse() ); - } else { - // HACK: Scaling the document does not seem to cause - // grids defined in document units to be updated. - // This forces an update. - xy->Scale( Geom::Scale(1,1) ); - } - } - } - } - } - } // If SPNamedView - - SPDefs *defs = dynamic_cast(child); - if (defs && need_fix_box3d) { - for (SPObject *child = defs->firstChild() ; child; child = child->getNext() ) { - Persp3D* persp3d = dynamic_cast(child); - if (persp3d) { - std::vector tokens; - - const gchar* vp_x = persp3d->getAttribute("inkscape:vp_x"); - const gchar* vp_y = persp3d->getAttribute("inkscape:vp_y"); - const gchar* vp_z = persp3d->getAttribute("inkscape:vp_z"); - const gchar* vp_o = persp3d->getAttribute("inkscape:persp3d-origin"); - // std::cout << "Found Persp3d: " - // << " vp_x: " << vp_x - // << " vp_y: " << vp_y - // << " vp_z: " << vp_z << std::endl; - Proj::Pt2 pt_x (vp_x); - Proj::Pt2 pt_y (vp_y); - Proj::Pt2 pt_z (vp_z); - Proj::Pt2 pt_o (vp_o); - pt_x = pt_x * (1.0/ratio); - pt_y = pt_y * (1.0/ratio); - pt_z = pt_z * (1.0/ratio); - pt_o = pt_o * (1.0/ratio); - persp3d->setAttribute("inkscape:vp_x",pt_x.coord_string()); - persp3d->setAttribute("inkscape:vp_y",pt_y.coord_string()); - persp3d->setAttribute("inkscape:vp_z",pt_z.coord_string()); - persp3d->setAttribute("inkscape:persp3d-origin",pt_o.coord_string()); - } - } - } - } // Look for SPNamedView and SPDefs loop - - // desktop->getDocument()->ensureUpToDate(); // Does not update box3d! - DocumentUndo::done(desktop->getDocument(), SP_VERB_NONE, _("Update Document")); - - } // If old Inkscape version + if (sp_version_inside_range(root->version.inkscape, 0, 1, 0, 92)) { + sp_file_convert_dpi(doc); + } } // If use_gui + // resize the window to match the document properties sp_namedview_window_from_document(desktop); sp_namedview_update_layers_from_document(desktop); diff --git a/src/file.h b/src/file.h index 2fc4ea910..c6ff61c25 100644 --- a/src/file.h +++ b/src/file.h @@ -205,6 +205,9 @@ void sp_file_print (Gtk::Window& parentWindow); void sp_file_vacuum (SPDocument *doc); void sp_file_convert_text_baseline_spacing(SPDocument *doc); void sp_file_convert_font_name(SPDocument *doc); +void sp_file_convert_dpi(SPDocument *doc); +enum File_DPI_Fix { FILE_DPI_UNCHANGED = 0, FILE_DPI_VIEWBOX_SCALED, FILE_DPI_DOCUMENT_SCALED }; +extern int sp_file_convert_dpi_method_commandline; #endif // SEEN_SP_FILE_H diff --git a/src/main.cpp b/src/main.cpp index 4c63402fb..7a786234e 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -15,6 +15,7 @@ * ... and various people who have worked with various projects * Jon A. Cruz * Abhishek Sharma + * Marc Jeanmougin * * Copyright (C) 1999-2004 authors * Copyright (C) 2001-2002 Ximian, Inc. @@ -167,6 +168,7 @@ enum { SP_ARG_VERSION, SP_ARG_VACUUM_DEFS, SP_ARG_NO_CONVERT_TEXT_BASELINE_SPACING, + SP_ARG_CONVERT_DPI_METHOD, #ifdef WITH_DBUS SP_ARG_DBUS_LISTEN, SP_ARG_DBUS_NAME, @@ -278,6 +280,7 @@ static void resetCommandlineGlobals() { sp_query_id = NULL; sp_vacuum_defs = FALSE; sp_no_convert_text_baseline_spacing = FALSE; + sp_file_convert_dpi_method_commandline = -1; #ifdef WITH_DBUS sp_dbus_listen = FALSE; sp_dbus_name = NULL; @@ -539,6 +542,11 @@ struct poptOption options[] = { N_("Do not fix legacy (pre-0.92) files' text baseline spacing on opening."), NULL}, + {"convert-dpi-method", 0, + POPT_ARG_STRING, NULL, SP_ARG_CONVERT_DPI_METHOD, + N_("Method used to convert pre-.92 document dpi, if needed."), + "[none|scale-viewbox|scale-document]"}, + POPT_AUTOHELP POPT_TABLEEND }; @@ -2180,6 +2188,21 @@ sp_process_args(poptContext ctx) } break; } + case SP_ARG_CONVERT_DPI_METHOD: { + gchar const *arg = poptGetOptArg(ctx); + if (arg != NULL) { + if (!strcmp(arg,"none")) { + sp_file_convert_dpi_method_commandline = FILE_DPI_UNCHANGED; + } else if (!strcmp(arg,"scale-viewbox")) { + sp_file_convert_dpi_method_commandline = FILE_DPI_VIEWBOX_SCALED; + } else if (!strcmp(arg,"scale-document")) { + sp_file_convert_dpi_method_commandline = FILE_DPI_DOCUMENT_SCALED; + } else { + g_warning("Invalid update option"); + } + } + break; + } case POPT_ERROR_BADOPT: { g_warning ("Invalid option %s", poptBadOption(ctx, 0)); exit(1); -- cgit v1.2.3 From 48dd012cb96343f14f3b32b9f7be0751bc458f6a Mon Sep 17 00:00:00 2001 From: Michael Soegtrop Date: Mon, 5 Jun 2017 20:59:36 +0200 Subject: fixed enum order + added cpp files to POFILES.in (bzr r14862.2.4) --- src/live_effects/effect-enum.h | 4 ++-- src/live_effects/effect.cpp | 6 ++---- 2 files changed, 4 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/live_effects/effect-enum.h b/src/live_effects/effect-enum.h index 0ad9c5230..5cc4d58e5 100644 --- a/src/live_effects/effect-enum.h +++ b/src/live_effects/effect-enum.h @@ -42,8 +42,6 @@ enum EffectType { TAPER_STROKE, MIRROR_SYMMETRY, COPY_ROTATE, - EMBRODERY_STITCH, - BOOL_OP, ATTACH_PATH, FILL_BETWEEN_STROKES, FILL_BETWEEN_MANY, @@ -51,6 +49,8 @@ enum EffectType { BOUNDING_BOX, MEASURE_LINE, FILLET_CHAMFER, + BOOL_OP, + EMBRODERY_STITCH, DOEFFECTSTACK_TEST, ANGLE_BISECTOR, CIRCLE_WITH_RADIUS, diff --git a/src/live_effects/effect.cpp b/src/live_effects/effect.cpp index 44580b9b2..e5a879241 100644 --- a/src/live_effects/effect.cpp +++ b/src/live_effects/effect.cpp @@ -118,8 +118,6 @@ const Util::EnumData LPETypeData[] = { {MIRROR_SYMMETRY, N_("Mirror symmetry"), "mirror_symmetry"}, {COPY_ROTATE, N_("Rotate copies"), "copy_rotate"}, /* Ponyscape -> Inkscape 0.92*/ - {EMBRODERY_STITCH, N_("Embrodery stitch"), "embrodery_stitch"}, - {BOOL_OP, N_("Boolean operation"), "bool_op"}, {ATTACH_PATH, N_("Attach path"), "attach_path"}, {FILL_BETWEEN_STROKES, N_("Fill between strokes"), "fill_between_strokes"}, {FILL_BETWEEN_MANY, N_("Fill between many"), "fill_between_many"}, @@ -128,6 +126,8 @@ const Util::EnumData LPETypeData[] = { /* 9.93 */ {MEASURE_LINE, N_("Measure Line"), "measure_line"}, {FILLET_CHAMFER, N_("Fillet/Chamfer"), "fillet_chamfer"}, + {BOOL_OP, N_("Boolean operation"), "bool_op"}, + {EMBRODERY_STITCH, N_("Embrodery stitch"), "embrodery_stitch"}, #ifdef LPE_ENABLE_TEST_EFFECTS {DOEFFECTSTACK_TEST, N_("doEffect stack test"), "doeffectstacktest"}, {ANGLE_BISECTOR, N_("Angle bisector"), "angle_bisector"}, @@ -171,11 +171,9 @@ Effect::New(EffectType lpenr, LivePathEffectObject *lpeobj) case EMBRODERY_STITCH: neweffect = static_cast ( new LPEEmbroderyStitch(lpeobj) ); break; - case BOOL_OP: neweffect = static_cast ( new LPEBool(lpeobj) ); break; - case PATTERN_ALONG_PATH: neweffect = static_cast ( new LPEPatternAlongPath(lpeobj) ); break; -- cgit v1.2.3 From eeec983b8b3a888a5ab0fabbc7897759ab715126 Mon Sep 17 00:00:00 2001 From: Michael Soegtrop Date: Mon, 5 Jun 2017 21:00:41 +0200 Subject: fixed enum order + added cpp files to POFILES.in (bzr r14876.2.5) --- src/live_effects/effect-enum.h | 2 +- src/live_effects/effect.cpp | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/live_effects/effect-enum.h b/src/live_effects/effect-enum.h index 71d669bf6..ed9fb2c9d 100644 --- a/src/live_effects/effect-enum.h +++ b/src/live_effects/effect-enum.h @@ -42,7 +42,6 @@ enum EffectType { TAPER_STROKE, MIRROR_SYMMETRY, COPY_ROTATE, - BOOL_OP, ATTACH_PATH, FILL_BETWEEN_STROKES, FILL_BETWEEN_MANY, @@ -50,6 +49,7 @@ enum EffectType { BOUNDING_BOX, MEASURE_LINE, FILLET_CHAMFER, + BOOL_OP, DOEFFECTSTACK_TEST, ANGLE_BISECTOR, CIRCLE_WITH_RADIUS, diff --git a/src/live_effects/effect.cpp b/src/live_effects/effect.cpp index fe40920e3..9e1555c26 100644 --- a/src/live_effects/effect.cpp +++ b/src/live_effects/effect.cpp @@ -117,7 +117,6 @@ const Util::EnumData LPETypeData[] = { {MIRROR_SYMMETRY, N_("Mirror symmetry"), "mirror_symmetry"}, {COPY_ROTATE, N_("Rotate copies"), "copy_rotate"}, /* Ponyscape -> Inkscape 0.92*/ - {BOOL_OP, N_("Boolean operation"), "bool_op"}, {ATTACH_PATH, N_("Attach path"), "attach_path"}, {FILL_BETWEEN_STROKES, N_("Fill between strokes"), "fill_between_strokes"}, {FILL_BETWEEN_MANY, N_("Fill between many"), "fill_between_many"}, @@ -126,6 +125,7 @@ const Util::EnumData LPETypeData[] = { /* 9.93 */ {MEASURE_LINE, N_("Measure Line"), "measure_line"}, {FILLET_CHAMFER, N_("Fillet/Chamfer"), "fillet_chamfer"}, + {BOOL_OP, N_("Boolean operation"), "bool_op"}, #ifdef LPE_ENABLE_TEST_EFFECTS {DOEFFECTSTACK_TEST, N_("doEffect stack test"), "doeffectstacktest"}, {ANGLE_BISECTOR, N_("Angle bisector"), "angle_bisector"}, @@ -169,7 +169,6 @@ Effect::New(EffectType lpenr, LivePathEffectObject *lpeobj) case BOOL_OP: neweffect = static_cast ( new LPEBool(lpeobj) ); break; - case PATTERN_ALONG_PATH: neweffect = static_cast ( new LPEPatternAlongPath(lpeobj) ); break; -- cgit v1.2.3 From cb200b0eff43b9f9afb14d9a7fcedb7f8ee7c3a9 Mon Sep 17 00:00:00 2001 From: Tavmjong Bah Date: Mon, 5 Jun 2017 21:32:59 +0200 Subject: Show glyphs with alternative styles in "Feature Settings" section of "Variants" tab of "Text and Font" dialog. (bzr r15731) --- src/libnrtype/FontFactory.cpp | 97 +++++++++++++++++++++++++++++++++++++---- src/libnrtype/font-instance.h | 3 ++ src/ui/widget/font-variants.cpp | 34 +++++++++++++++ src/ui/widget/font-variants.h | 1 + 4 files changed, 126 insertions(+), 9 deletions(-) (limited to 'src') diff --git a/src/libnrtype/FontFactory.cpp b/src/libnrtype/FontFactory.cpp index 770616ae7..8d66904e0 100644 --- a/src/libnrtype/FontFactory.cpp +++ b/src/libnrtype/FontFactory.cpp @@ -699,26 +699,26 @@ font_instance *font_factory::Face(PangoFontDescription *descr, bool canFail) // Empty map... bitmap fonts seem to be loaded multiple times. res->openTypeTables.clear(); - auto const hb_face = hb_ft_face_create(res->theFace, NULL); + auto const face = hb_ft_face_create(res->theFace, NULL); // First time to get size of array - auto script_count = hb_ot_layout_table_get_script_tags(hb_face, HB_OT_TAG_GSUB, 0, NULL, NULL); + auto script_count = hb_ot_layout_table_get_script_tags(face, HB_OT_TAG_GSUB, 0, NULL, NULL); auto const scripts_hb = g_new(hb_tag_t, script_count + 1); // Second time to fill array (this two step process was not necessary with Pango). - hb_ot_layout_table_get_script_tags(hb_face, HB_OT_TAG_GSUB, 0, &script_count, scripts_hb); + hb_ot_layout_table_get_script_tags(face, HB_OT_TAG_GSUB, 0, &script_count, scripts_hb); for(unsigned int i = 0; i < script_count; ++i) { - auto language_count = hb_ot_layout_script_get_language_tags(hb_face, HB_OT_TAG_GSUB, i, 0, NULL, NULL); + auto language_count = hb_ot_layout_script_get_language_tags(face, HB_OT_TAG_GSUB, i, 0, NULL, NULL); if(language_count > 0) { auto const languages_hb = g_new(hb_tag_t, language_count + 1); - hb_ot_layout_script_get_language_tags(hb_face, HB_OT_TAG_GSUB, i, 0, &language_count, languages_hb); + hb_ot_layout_script_get_language_tags(face, HB_OT_TAG_GSUB, i, 0, &language_count, languages_hb); for(unsigned int j = 0; j < language_count; ++j) { - auto feature_count = hb_ot_layout_language_get_feature_tags(hb_face, HB_OT_TAG_GSUB, i, j, 0, NULL, NULL); + auto feature_count = hb_ot_layout_language_get_feature_tags(face, HB_OT_TAG_GSUB, i, j, 0, NULL, NULL); auto const features_hb = g_new(hb_tag_t, feature_count + 1); - hb_ot_layout_language_get_feature_tags(hb_face, HB_OT_TAG_GSUB, i, j, 0, &feature_count, features_hb); + hb_ot_layout_language_get_feature_tags(face, HB_OT_TAG_GSUB, i, j, 0, &feature_count, features_hb); for(unsigned int k = 0; k < feature_count; ++k) { ++(res->openTypeTables[ extract_tag(&features_hb[k])]); @@ -731,11 +731,11 @@ font_instance *font_factory::Face(PangoFontDescription *descr, bool canFail) } else { // Even if no languages are present there is still the default. - auto feature_count = hb_ot_layout_language_get_feature_tags(hb_face, HB_OT_TAG_GSUB, i, + auto feature_count = hb_ot_layout_language_get_feature_tags(face, HB_OT_TAG_GSUB, i, HB_OT_LAYOUT_DEFAULT_LANGUAGE_INDEX, 0, NULL, NULL); auto const features_hb = g_new(hb_tag_t, feature_count + 1); - hb_ot_layout_language_get_feature_tags(hb_face, HB_OT_TAG_GSUB, i, + hb_ot_layout_language_get_feature_tags(face, HB_OT_TAG_GSUB, i, HB_OT_LAYOUT_DEFAULT_LANGUAGE_INDEX, 0, &feature_count, features_hb); @@ -747,6 +747,85 @@ font_instance *font_factory::Face(PangoFontDescription *descr, bool canFail) } } + // Find glyphs in OpenType substitution tables ('gsub'). + // Note that pango's functions are just dummies. Must use harfbuzz. + + // Loop over all tables + for (auto table: res->openTypeTables) { + + // Only look at style substitution tables ('salt', 'ss01', etc. but not 'ssty'). + if (table.first == "salt" || + (table.first[0] == 's' && table.first[1] == 's' && !(table.first[2] == 't') ) ) { + // std::cout << " Table: " << table.first << std::endl; + + Glib::ustring unicode_characters; + + unsigned int feature_index; + if ( hb_ot_layout_language_find_feature (face, HB_OT_TAG_GSUB, + 0, // Assume one script exists with index 0 + HB_OT_LAYOUT_DEFAULT_LANGUAGE_INDEX, + HB_TAG(table.first[0], + table.first[1], + table.first[2], + table.first[3]), + &feature_index ) ) { + + // std::cout << " Found feature, number: " << feature_index << std::endl; + unsigned int lookup_indexes[32]; + unsigned int lookup_count = 32; + int count = hb_ot_layout_feature_get_lookups (face, HB_OT_TAG_GSUB, + feature_index, + 0, // Start + &lookup_count, + lookup_indexes ); + // std::cout << " Lookup count: " << count << " total: " << lookup_count << std::endl; + + if (count > 0) { + hb_set_t* glyphs_before = NULL; // hb_set_create(); + hb_set_t* glyphs_input = hb_set_create(); + hb_set_t* glyphs_after = NULL; // hb_set_create(); + hb_set_t* glyphs_output = NULL; // hb_set_create(); + + // For now, just look at first index + hb_ot_layout_lookup_collect_glyphs (face, HB_OT_TAG_GSUB, + lookup_indexes[0], + glyphs_before, + glyphs_input, + glyphs_after, + glyphs_output ); + + hb_font_t *font = hb_font_create (face); + + // Without this, all functions return 0, etc. + hb_ft_font_set_funcs (font); + + hb_codepoint_t codepoint = -1; + while (hb_set_next (glyphs_input, &codepoint)) { + + // There is a unicode to glyph mapping function but not the inverse! + for (hb_codepoint_t unicode_i = 0; unicode_i < 0xffff; ++unicode_i) { + hb_codepoint_t glyph = 0; + hb_font_get_nominal_glyph (font, unicode_i, &glyph); + if ( glyph == codepoint) { + unicode_characters += (gunichar)unicode_i; + continue; + } + } + } + res->openTypeSubstitutions[table.first] = unicode_characters; + + hb_set_destroy (glyphs_input); + hb_font_destroy (font); + } + } else { + // std::cout << " Did not find '" << table.first << "'!" << std::endl; + } + } + } + // for (auto table: res->openTypeSubstitutions) { + // std::cout << table.first << ": " << table.second << std::endl; + // } + hb_face_destroy (face); g_free(scripts_hb); } else { // already here diff --git a/src/libnrtype/font-instance.h b/src/libnrtype/font-instance.h index 2fac7c19b..52c921403 100644 --- a/src/libnrtype/font-instance.h +++ b/src/libnrtype/font-instance.h @@ -39,6 +39,9 @@ public: // Map of OpenType tables found in font (convert to std::set?) std::map openTypeTables; + // Map of substitutions indexed by table + std::map openTypeSubstitutions; + font_instance(void); virtual ~font_instance(void); diff --git a/src/ui/widget/font-variants.cpp b/src/ui/widget/font-variants.cpp index 6753bbc7a..e7645b620 100644 --- a/src/ui/widget/font-variants.cpp +++ b/src/ui/widget/font-variants.cpp @@ -234,10 +234,14 @@ namespace Widget { _feature_list.set_justify( Gtk::JUSTIFY_LEFT ); _feature_list.set_line_wrap( true ); + _feature_substitutions.set_justify( Gtk::JUSTIFY_LEFT ); + _feature_substitutions.set_line_wrap( true ); + // Add to frame _feature_vbox.add( _feature_entry ); _feature_vbox.add( _feature_label ); _feature_vbox.add( _feature_list ); + _feature_vbox.add( _feature_substitutions ); _feature_frame.add( _feature_vbox ); add( _feature_frame ); @@ -566,6 +570,36 @@ namespace Widget { _feature_list.set_text( ott_list.c_str() ); + // ""; + Glib::ustring markup; + + for (auto table: res->openTypeSubstitutions) { + + markup += table.first; + markup += ": "; + + markup += ""; + markup += Glib::Markup::escape_text(table.second); + markup += ""; + + markup += " → "; + + markup += ""; + markup += ""; + markup += Glib::Markup::escape_text(table.second); + markup += ""; + markup += "\n"; + + } + + _feature_substitutions.set_markup ( markup.c_str() ); + } else { std::cerr << "FontVariants::update(): Couldn't find font_instance for: " << font_spec << std::endl; diff --git a/src/ui/widget/font-variants.h b/src/ui/widget/font-variants.h index 507e5fb91..cf8e476a9 100644 --- a/src/ui/widget/font-variants.h +++ b/src/ui/widget/font-variants.h @@ -87,6 +87,7 @@ protected: Gtk::Entry _feature_entry; Gtk::Label _feature_label; Gtk::Label _feature_list; + Gtk::Label _feature_substitutions; private: void ligatures_init(); -- cgit v1.2.3 From 6fecef42f41d5641cbadf34bc640e796635da7c5 Mon Sep 17 00:00:00 2001 From: Jabiertxof Date: Tue, 6 Jun 2017 02:27:41 +0200 Subject: Add contextual buttons to Hide/lock and Unhide/unlock items (bzr r15732) --- src/document.cpp | 8 ++-- src/document.h | 4 +- src/ui/interface.cpp | 85 ++++++++++++++++++++++++++++++++++++++++++- src/ui/interface.h | 4 ++ src/ui/tools/measure-tool.cpp | 2 +- 5 files changed, 95 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/src/document.cpp b/src/document.cpp index 2141f65e9..3a7d4408f 100644 --- a/src/document.cpp +++ b/src/document.cpp @@ -1553,11 +1553,11 @@ static SPItem *find_group_at_point(unsigned int dkey, SPGroup *group, Geom::Poin * Assumes box is normalized (and g_asserts it!) * */ -std::vector SPDocument::getItemsInBox(unsigned int dkey, Geom::Rect const &box, bool into_groups) const +std::vector SPDocument::getItemsInBox(unsigned int dkey, Geom::Rect const &box, bool take_insensitive, bool into_groups) const { 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, false, into_groups); + return find_items_in_area(x, SP_GROUP(this->root), dkey, box, is_within, take_insensitive, into_groups); } /* @@ -1567,11 +1567,11 @@ std::vector SPDocument::getItemsInBox(unsigned int dkey, Geom::Rect con * */ -std::vector SPDocument::getItemsPartiallyInBox(unsigned int dkey, Geom::Rect const &box, bool into_groups) const +std::vector SPDocument::getItemsPartiallyInBox(unsigned int dkey, Geom::Rect const &box, bool take_insensitive, bool into_groups) const { 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, false, into_groups); + return find_items_in_area(x, SP_GROUP(this->root), dkey, box, overlaps, take_insensitive, into_groups); } std::vector SPDocument::getItemsAtPoints(unsigned const key, std::vector points, bool all_layers, size_t limit) const diff --git a/src/document.h b/src/document.h index db50f1717..92f53559f 100644 --- a/src/document.h +++ b/src/document.h @@ -282,8 +282,8 @@ public: bool addResource(char const *key, SPObject *object); bool removeResource(char const *key, SPObject *object); const std::vector getResourceList(char const *key) const; - std::vector getItemsInBox(unsigned int dkey, Geom::Rect const &box, bool into_groups = false) const; - std::vector getItemsPartiallyInBox(unsigned int dkey, Geom::Rect const &box, bool into_groups = false) const; + std::vector getItemsInBox(unsigned int dkey, Geom::Rect const &box, bool take_insensitive = false, bool into_groups = false) const; + std::vector getItemsPartiallyInBox(unsigned int dkey, Geom::Rect const &box, bool take_insensitive = false, bool into_groups = false) const; SPItem *getItemAtPoint(unsigned int key, Geom::Point const &p, bool into_groups, SPItem *upto = NULL) const; std::vector getItemsAtPoints(unsigned const key, std::vector points, bool all_layers = true, size_t limit = 0) const ; SPItem *getGroupAtPoint(unsigned int key, Geom::Point const &p) const; diff --git a/src/ui/interface.cpp b/src/ui/interface.cpp index 5e85065d1..33e98a81c 100644 --- a/src/ui/interface.cpp +++ b/src/ui/interface.cpp @@ -1438,13 +1438,58 @@ ContextMenu::ContextMenu(SPDesktop *desktop, SPItem *item) : AppendItemFromVerb(Inkscape::Verb::get(SP_VERB_EDIT_DELETE)); positionOfLastDialog = 10; // 9 in front + 1 for the separator in the next if; used to position the dialog menu entries below each other + Geom::Rect b(_desktop->point(),_desktop->point() + Geom::Point(1,1)); + std::vector< SPItem * > down_items = _desktop->getDocument()->getItemsPartiallyInBox( _desktop->dkey, b, true, true); + bool has_down_hidden = false; + bool has_down_locked = false; + for(std::vector< SPItem * >::iterator down = down_items.begin(); down != down_items.end(); ++down){ + if((*down)->isHidden()) { + has_down_hidden = true; + } + if((*down)->isLocked()) { + has_down_locked = true; + } + } + AddSeparator(); + Gtk::MenuItem* mi; + + mi = Gtk::manage(new Gtk::MenuItem(_("Hide selected objects"),1)); + mi->signal_activate().connect(sigc::mem_fun(*this, &ContextMenu::HideSelected)); + if (_desktop->selection->isEmpty()) { + mi->set_sensitive(false); + } + mi->show(); + append(*mi);//insert(*mi,positionOfLastDialog++); + + mi = Gtk::manage(new Gtk::MenuItem(_("Unhide objects below"),1)); + mi->signal_activate().connect(sigc::bind >(sigc::mem_fun(*this, &ContextMenu::UnHideBelow), down_items)); + if (!has_down_hidden) { + mi->set_sensitive(false); + } + mi->show(); + append(*mi);//insert(*mi,positionOfLastDialog++); + mi = Gtk::manage(new Gtk::MenuItem(_("Lock selected objects"),1)); + mi->signal_activate().connect(sigc::mem_fun(*this, &ContextMenu::LockSelected)); + if (_desktop->selection->isEmpty()) { + mi->set_sensitive(false); + } + mi->show(); + append(*mi);//insert(*mi,positionOfLastDialog++); + + mi = Gtk::manage(new Gtk::MenuItem(_("Unlock objects below"),1)); + mi->signal_activate().connect(sigc::bind >(sigc::mem_fun(*this, &ContextMenu::UnLockBelow), down_items)); + if (!has_down_locked) { + mi->set_sensitive(false); + } + mi->show(); + append(*mi);//insert(*mi,positionOfLastDialog++); /* Item menu */ if (item!=NULL) { AddSeparator(); MakeObjectMenu(); } - + AddSeparator(); /* layer menu */ SPGroup *group=NULL; if (item) { @@ -1507,6 +1552,44 @@ void ContextMenu::LeaveGroup(void) _desktop->setCurrentLayer(_desktop->currentLayer()->parent); } +void ContextMenu::LockSelected(void) +{ + auto itemlist = _desktop->selection->items(); + for(auto i=itemlist.begin();i!=itemlist.end(); ++i) { + (*i)->setLocked(true); + } +} + +void ContextMenu::HideSelected(void) +{ + auto itemlist =_desktop->selection->items(); + for(auto i=itemlist.begin();i!=itemlist.end(); ++i) { + (*i)->setHidden(true); + } +} + +void ContextMenu::UnLockBelow(std::vector items) +{ + _desktop->selection->clear(); + for(auto i=items.begin();i!=items.end(); ++i) { + if ((*i)->isLocked()) { + (*i)->setLocked(false); + _desktop->selection->add(*i); + } + } +} + +void ContextMenu::UnHideBelow(std::vector items) +{ + _desktop->selection->clear(); + for(auto i=items.begin();i!=items.end(); ++i) { + if ((*i)->isHidden()) { + (*i)->setHidden(false); + _desktop->selection->add(*i); + } + } +} + void ContextMenu::AppendItemFromVerb(Inkscape::Verb *verb)//, SPDesktop *view)//, bool radio, GSList *group) { SPAction *action; diff --git a/src/ui/interface.h b/src/ui/interface.h index 52074f0f0..a41c36cc3 100644 --- a/src/ui/interface.h +++ b/src/ui/interface.h @@ -172,6 +172,10 @@ class ContextMenu : public Gtk::Menu void EnterGroup(Gtk::MenuItem* mi); void LeaveGroup(void); + void LockSelected(void); + void HideSelected(void); + void UnLockBelow(std::vector items); + void UnHideBelow(std::vector items); ////////////////////////////////////////// //callbacks for the context menu entries of an SP_TYPE_ITEM object void ItemProperties(void); diff --git a/src/ui/tools/measure-tool.cpp b/src/ui/tools/measure-tool.cpp index f3185649b..98b2c7d03 100644 --- a/src/ui/tools/measure-tool.cpp +++ b/src/ui/tools/measure-tool.cpp @@ -1260,7 +1260,7 @@ void MeasureTool::showCanvasItems(bool to_guides, bool to_item, bool to_phantom, std::vector items; SPDocument *doc = desktop->getDocument(); Geom::Rect rect(start_p, end_p); - items = doc->getItemsPartiallyInBox(desktop->dkey, rect, true); + items = doc->getItemsPartiallyInBox(desktop->dkey, rect, false, true); Inkscape::LayerModel *layer_model = NULL; SPObject *current_layer = NULL; if(desktop){ -- cgit v1.2.3 From 840a38b13e01c5782d88cef336fe10352cf0c212 Mon Sep 17 00:00:00 2001 From: Tavmjong Bah Date: Tue, 6 Jun 2017 10:13:53 +0200 Subject: Fix build with versions of Harfbuzz prior to 1.2.3. (Visualization of alternative glyphs requires 1.2.3.) (bzr r15733) --- src/libnrtype/FontFactory.cpp | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'src') diff --git a/src/libnrtype/FontFactory.cpp b/src/libnrtype/FontFactory.cpp index 8d66904e0..6c0999f2d 100644 --- a/src/libnrtype/FontFactory.cpp +++ b/src/libnrtype/FontFactory.cpp @@ -747,6 +747,7 @@ font_instance *font_factory::Face(PangoFontDescription *descr, bool canFail) } } +#if HB_VERSION_ATLEAST(1,2,3) // Find glyphs in OpenType substitution tables ('gsub'). // Note that pango's functions are just dummies. Must use harfbuzz. @@ -825,6 +826,11 @@ font_instance *font_factory::Face(PangoFontDescription *descr, bool canFail) // for (auto table: res->openTypeSubstitutions) { // std::cout << table.first << ": " << table.second << std::endl; // } +#else + std::cerr << "Requires Harfbuzz 1.2.3 for visualizing alternative glyph OpenType tables. " + << "Compiled with: " << HB_VERSION_STRING << "." << std::endl; +#endif + hb_face_destroy (face); g_free(scripts_hb); } else { -- cgit v1.2.3 From 8b1a5c84ba61d2a356e9e3295958712b78fb1ff2 Mon Sep 17 00:00:00 2001 From: Tavmjong Bah Date: Wed, 7 Jun 2017 11:29:09 +0200 Subject: Strip comments when parsing CSS. Allow no space after an element name if followed by '+', '>', or '~' when entering new selector. (bzr r15735) --- src/ui/dialog/styledialog.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/ui/dialog/styledialog.cpp b/src/ui/dialog/styledialog.cpp index 4576671e7..b1bcddd45 100644 --- a/src/ui/dialog/styledialog.cpp +++ b/src/ui/dialog/styledialog.cpp @@ -355,6 +355,12 @@ void StyleDialog::_readStyleElement() // Remove end-of-lines (check it works on Windoze). content.erase(std::remove(content.begin(), content.end(), '\n'), content.end()); + // Remove comments (/* xxx */) + while(content.find("/*") != std::string::npos) { + size_t start = content.find("/*"); + content.erase(start, (content.find("*/", start) - start) +2); + } + // First split into selector/value chunks. // An attempt to use Glib::Regex failed. A C++11 version worked but // reportedly has problems on Windows. Using split_simple() is simpler @@ -787,7 +793,7 @@ void StyleDialog::_addSelector() * set to ".Class1" */ selectorValue = textEditPtr->get_text(); - Glib::ustring firstWord = selectorValue.substr(0, selectorValue.find(" ")); + Glib::ustring firstWord = selectorValue.substr(0, selectorValue.find_first_of(" >+~")); del->set_sensitive(true); -- cgit v1.2.3 From 4fb9b588f89948e1d8b392f9560510bc05e6f5b9 Mon Sep 17 00:00:00 2001 From: Jabier Arraiza Cenoz Date: Wed, 7 Jun 2017 12:52:19 +0200 Subject: Reorder hide and lock from context menu (bzr r15736) --- src/ui/interface.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/ui/interface.cpp b/src/ui/interface.cpp index 33e98a81c..7e80c1a2f 100644 --- a/src/ui/interface.cpp +++ b/src/ui/interface.cpp @@ -1438,6 +1438,13 @@ ContextMenu::ContextMenu(SPDesktop *desktop, SPItem *item) : AppendItemFromVerb(Inkscape::Verb::get(SP_VERB_EDIT_DELETE)); positionOfLastDialog = 10; // 9 in front + 1 for the separator in the next if; used to position the dialog menu entries below each other + /* Item menu */ + if (item!=NULL) { + AddSeparator(); + MakeObjectMenu(); + } + AddSeparator(); + /* Lock/Unock Hide/Unhide*/ Geom::Rect b(_desktop->point(),_desktop->point() + Geom::Point(1,1)); std::vector< SPItem * > down_items = _desktop->getDocument()->getItemsPartiallyInBox( _desktop->dkey, b, true, true); bool has_down_hidden = false; @@ -1450,7 +1457,6 @@ ContextMenu::ContextMenu(SPDesktop *desktop, SPItem *item) : has_down_locked = true; } } - AddSeparator(); Gtk::MenuItem* mi; mi = Gtk::manage(new Gtk::MenuItem(_("Hide selected objects"),1)); @@ -1484,12 +1490,6 @@ ContextMenu::ContextMenu(SPDesktop *desktop, SPItem *item) : } mi->show(); append(*mi);//insert(*mi,positionOfLastDialog++); - /* Item menu */ - if (item!=NULL) { - AddSeparator(); - MakeObjectMenu(); - } - AddSeparator(); /* layer menu */ SPGroup *group=NULL; if (item) { -- cgit v1.2.3 From 01eb013ee6bf17c8d330385a5db614aa40758dee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felipe=20Corr=C3=AAa=20da=20Silva=20Sanches?= Date: Fri, 9 Jun 2017 18:04:28 -0300 Subject: Disable debugging code on libnrtype Layout-TNG-Compute at compile-time. --- src/libnrtype/Layout-TNG-Compute.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/libnrtype/Layout-TNG-Compute.cpp b/src/libnrtype/Layout-TNG-Compute.cpp index 8e173a7c7..79fdadb54 100644 --- a/src/libnrtype/Layout-TNG-Compute.cpp +++ b/src/libnrtype/Layout-TNG-Compute.cpp @@ -19,6 +19,8 @@ namespace Inkscape { namespace Text { +//#define DEBUG_LAYOUT_TNG_COMPUTE + //#define IFTRACE(_code) _code #define IFTRACE(_code) @@ -203,6 +205,8 @@ class Layout::Calculator /* *********************************************************************************************************/ // Per-line functions + +#ifdef DEBUG_LAYOUT_TNG_COMPUTE /** * For debugging, not called in distributed code * @@ -241,7 +245,7 @@ static void dumpUnbrokenSpans(ParagraphInfo *para){ << std::endl; } } - +#endif //DEBUG_LAYOUT_TNG_COMPUTE bool _goToNextWrapShape(); -- cgit v1.2.3 From 8268b0b9173f87ac10995139b28b68908392abb6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felipe=20Corr=C3=AAa=20da=20Silva=20Sanches?= Date: Sat, 10 Jun 2017 01:20:07 -0300 Subject: libnrtype/Layout-TNG refactoring for better code legibility --- src/libnrtype/Layout-TNG-Input.cpp | 113 ++++++++++++++++++++++++------------ src/libnrtype/Layout-TNG-Output.cpp | 12 +++- src/libnrtype/Layout-TNG.h | 4 ++ src/sp-flowtext.cpp | 4 +- src/sp-text.cpp | 8 ++- 5 files changed, 101 insertions(+), 40 deletions(-) (limited to 'src') diff --git a/src/libnrtype/Layout-TNG-Input.cpp b/src/libnrtype/Layout-TNG-Input.cpp index 6f5d4e5f8..98ce7d526 100644 --- a/src/libnrtype/Layout-TNG-Input.cpp +++ b/src/libnrtype/Layout-TNG-Input.cpp @@ -40,7 +40,13 @@ void Layout::_clearInputObjects() } // this function does nothing more than store all its parameters for future reference -void Layout::appendText(Glib::ustring const &text, SPStyle *style, void *source_cookie, OptionalTextTagAttrs const *optional_attributes, unsigned optional_attributes_offset, Glib::ustring::const_iterator text_begin, Glib::ustring::const_iterator text_end) +void Layout::appendText(Glib::ustring const &text, + SPStyle *style, + void *source_cookie, + OptionalTextTagAttrs const *optional_attributes, + unsigned optional_attributes_offset, + Glib::ustring::const_iterator text_begin, + Glib::ustring::const_iterator text_end) { if (style == NULL) return; @@ -120,40 +126,40 @@ void Layout::appendWrapShape(Shape const *shape, DisplayAlign display_align) int Layout::_enum_converter(int input, EnumConversionItem const *conversion_table, unsigned conversion_table_size) { - for (unsigned i = 0 ; i < conversion_table_size ; i++) + for (unsigned i = 0 ; i < conversion_table_size ; i++) { if (conversion_table[i].input == input) return conversion_table[i].output; + } return conversion_table[0].output; } Layout::Direction Layout::InputStreamTextSource::styleGetBlockProgression() const { - switch( style->writing_mode.computed ) { + switch( style->writing_mode.computed ) { + case SP_CSS_WRITING_MODE_LR_TB: + case SP_CSS_WRITING_MODE_RL_TB: + return TOP_TO_BOTTOM; - case SP_CSS_WRITING_MODE_LR_TB: - case SP_CSS_WRITING_MODE_RL_TB: - return TOP_TO_BOTTOM; - - case SP_CSS_WRITING_MODE_TB_RL: - return RIGHT_TO_LEFT; + case SP_CSS_WRITING_MODE_TB_RL: + return RIGHT_TO_LEFT; - case SP_CSS_WRITING_MODE_TB_LR: - return LEFT_TO_RIGHT; + case SP_CSS_WRITING_MODE_TB_LR: + return LEFT_TO_RIGHT; - default: - std::cerr << "Layout::InputTextStream::styleGetBlockProgression: invalid writing mode." << std::endl; - } - return TOP_TO_BOTTOM; + default: + std::cerr << "Layout::InputTextStream::styleGetBlockProgression: invalid writing mode." << std::endl; + } + return TOP_TO_BOTTOM; } SPCSSTextOrientation Layout::InputStreamTextSource::styleGetTextOrientation() const { - return ((SPCSSTextOrientation)style->text_orientation.computed); + return ((SPCSSTextOrientation)style->text_orientation.computed); } SPCSSBaseline Layout::InputStreamTextSource::styleGetDominantBaseline() const { - return ((SPCSSBaseline)style->dominant_baseline.computed); + return ((SPCSSBaseline)style->dominant_baseline.computed); } static Layout::Alignment text_anchor_to_alignment(unsigned anchor, Layout::Direction para_direction) @@ -202,22 +208,24 @@ Layout::Alignment Layout::InputStreamTextSource::styleGetAlignment(Layout::Direc static const Layout::EnumConversionItem enum_convert_spstyle_style_to_pango_style[] = { {SP_CSS_FONT_STYLE_NORMAL, PANGO_STYLE_NORMAL}, {SP_CSS_FONT_STYLE_ITALIC, PANGO_STYLE_ITALIC}, - {SP_CSS_FONT_STYLE_OBLIQUE, PANGO_STYLE_OBLIQUE}}; + {SP_CSS_FONT_STYLE_OBLIQUE, PANGO_STYLE_OBLIQUE} +}; static const Layout::EnumConversionItem enum_convert_spstyle_weight_to_pango_weight[] = { // NB: The Pango web page calls 500 "the normal font" but both CSS2 and the Pango // enumeration define 400 as normal. {SP_CSS_FONT_WEIGHT_NORMAL, PANGO_WEIGHT_NORMAL}, - {SP_CSS_FONT_WEIGHT_BOLD,PANGO_WEIGHT_BOLD}, - {SP_CSS_FONT_WEIGHT_100, PANGO_WEIGHT_THIN}, - {SP_CSS_FONT_WEIGHT_200, PANGO_WEIGHT_ULTRALIGHT}, - {SP_CSS_FONT_WEIGHT_300, PANGO_WEIGHT_LIGHT}, - {SP_CSS_FONT_WEIGHT_400, PANGO_WEIGHT_NORMAL}, - {SP_CSS_FONT_WEIGHT_500, PANGO_WEIGHT_MEDIUM}, - {SP_CSS_FONT_WEIGHT_600, PANGO_WEIGHT_SEMIBOLD}, - {SP_CSS_FONT_WEIGHT_700, PANGO_WEIGHT_BOLD}, - {SP_CSS_FONT_WEIGHT_800, PANGO_WEIGHT_ULTRABOLD}, - {SP_CSS_FONT_WEIGHT_900, PANGO_WEIGHT_HEAVY}}; + {SP_CSS_FONT_WEIGHT_BOLD, PANGO_WEIGHT_BOLD}, + {SP_CSS_FONT_WEIGHT_100, PANGO_WEIGHT_THIN}, + {SP_CSS_FONT_WEIGHT_200, PANGO_WEIGHT_ULTRALIGHT}, + {SP_CSS_FONT_WEIGHT_300, PANGO_WEIGHT_LIGHT}, + {SP_CSS_FONT_WEIGHT_400, PANGO_WEIGHT_NORMAL}, + {SP_CSS_FONT_WEIGHT_500, PANGO_WEIGHT_MEDIUM}, + {SP_CSS_FONT_WEIGHT_600, PANGO_WEIGHT_SEMIBOLD}, + {SP_CSS_FONT_WEIGHT_700, PANGO_WEIGHT_BOLD}, + {SP_CSS_FONT_WEIGHT_800, PANGO_WEIGHT_ULTRABOLD}, + {SP_CSS_FONT_WEIGHT_900, PANGO_WEIGHT_HEAVY} +}; static const Layout::EnumConversionItem enum_convert_spstyle_stretch_to_pango_stretch[] = { {SP_CSS_FONT_STRETCH_NORMAL, PANGO_STRETCH_NORMAL}, @@ -228,11 +236,13 @@ static const Layout::EnumConversionItem enum_convert_spstyle_stretch_to_pango_st {SP_CSS_FONT_STRETCH_SEMI_EXPANDED, PANGO_STRETCH_SEMI_EXPANDED}, {SP_CSS_FONT_STRETCH_EXPANDED, PANGO_STRETCH_EXPANDED}, {SP_CSS_FONT_STRETCH_EXTRA_EXPANDED, PANGO_STRETCH_EXTRA_EXPANDED}, - {SP_CSS_FONT_STRETCH_ULTRA_EXPANDED, PANGO_STRETCH_ULTRA_EXPANDED}}; + {SP_CSS_FONT_STRETCH_ULTRA_EXPANDED, PANGO_STRETCH_ULTRA_EXPANDED} +}; static const Layout::EnumConversionItem enum_convert_spstyle_variant_to_pango_variant[] = { {SP_CSS_FONT_VARIANT_NORMAL, PANGO_VARIANT_NORMAL}, - {SP_CSS_FONT_VARIANT_SMALL_CAPS, PANGO_VARIANT_SMALL_CAPS}}; + {SP_CSS_FONT_VARIANT_SMALL_CAPS, PANGO_VARIANT_SMALL_CAPS} +}; font_instance *Layout::InputStreamTextSource::styleGetFontInstance() const { @@ -265,26 +275,57 @@ PangoFontDescription *Layout::InputStreamTextSource::styleGetFontDescription() c } pango_font_description_set_family(descr,family.c_str()); - pango_font_description_set_weight(descr,(PangoWeight)_enum_converter(style->font_weight.computed, enum_convert_spstyle_weight_to_pango_weight, sizeof(enum_convert_spstyle_weight_to_pango_weight)/sizeof(enum_convert_spstyle_weight_to_pango_weight[0]))); - pango_font_description_set_style(descr,(PangoStyle)_enum_converter(style->font_style.computed, enum_convert_spstyle_style_to_pango_style, sizeof(enum_convert_spstyle_style_to_pango_style)/sizeof(enum_convert_spstyle_style_to_pango_style[0]))); - pango_font_description_set_variant(descr,(PangoVariant)_enum_converter(style->font_variant.computed, enum_convert_spstyle_variant_to_pango_variant, sizeof(enum_convert_spstyle_variant_to_pango_variant)/sizeof(enum_convert_spstyle_variant_to_pango_variant[0]))); + pango_font_description_set_weight( + descr, + (PangoWeight)_enum_converter( + style->font_weight.computed, + enum_convert_spstyle_weight_to_pango_weight, + sizeof(enum_convert_spstyle_weight_to_pango_weight) / sizeof(enum_convert_spstyle_weight_to_pango_weight[0]) + ) + ); + pango_font_description_set_style( + descr, + (PangoStyle)_enum_converter( + style->font_style.computed, + enum_convert_spstyle_style_to_pango_style, + sizeof(enum_convert_spstyle_style_to_pango_style) / sizeof(enum_convert_spstyle_style_to_pango_style[0]) + ) + ); + pango_font_description_set_variant( + descr, + (PangoVariant)_enum_converter( + style->font_variant.computed, + enum_convert_spstyle_variant_to_pango_variant, + sizeof(enum_convert_spstyle_variant_to_pango_variant) / sizeof(enum_convert_spstyle_variant_to_pango_variant[0]) + ) + ); #ifdef USE_PANGO_WIN32 // damn Pango fudges the size, so we need to unfudge. See source of pango_win32_font_map_init() - pango_font_description_set_size(descr, (int) ((font_factory::Default())->fontSize*PANGO_SCALE*72/GetDeviceCaps(pango_win32_get_dc(),LOGPIXELSY))); // mandatory huge size (hinting workaround) + pango_font_description_set_size( + descr, + (int) ((font_factory::Default())->fontSize*PANGO_SCALE*72 / GetDeviceCaps(pango_win32_get_dc(),LOGPIXELSY)) // mandatory huge size (hinting workaround) + ); // we don't set stretch on Win32, because pango-win32 has no concept of it // (Windows doesn't really provide any useful field it could use). // If we did set stretch, then any text with a font-stretch attribute would // end up falling back to Arial. #else pango_font_description_set_size(descr, (int) ((font_factory::Default())->fontSize*PANGO_SCALE)); // mandatory huge size (hinting workaround) - pango_font_description_set_stretch(descr,(PangoStretch)_enum_converter(style->font_stretch.computed, enum_convert_spstyle_stretch_to_pango_stretch, sizeof(enum_convert_spstyle_stretch_to_pango_stretch)/sizeof(enum_convert_spstyle_stretch_to_pango_stretch[0]))); + pango_font_description_set_stretch( + descr, + (PangoStretch)_enum_converter( + style->font_stretch.computed, + enum_convert_spstyle_stretch_to_pango_stretch, + sizeof(enum_convert_spstyle_stretch_to_pango_stretch) / sizeof(enum_convert_spstyle_stretch_to_pango_stretch[0]) + ) + ); #endif return descr; } Layout::InputStreamTextSource::~InputStreamTextSource() { - sp_style_unref(style); + sp_style_unref(style); } }//namespace Text diff --git a/src/libnrtype/Layout-TNG-Output.cpp b/src/libnrtype/Layout-TNG-Output.cpp index a1a19f2b3..7f20dee95 100644 --- a/src/libnrtype/Layout-TNG-Output.cpp +++ b/src/libnrtype/Layout-TNG-Output.cpp @@ -515,6 +515,7 @@ void Layout::showGlyphs(CairoRenderContext *ctx) const } #endif +#if DEBUG_TEXTLAYOUT_DUMPASTEXT // these functions are for dumpAsText() only. No need to translate static char const *direction_to_text(Layout::Direction d) { @@ -557,6 +558,7 @@ static char const *weight_to_text(PangoWeight w) } return "???"; } +#endif //DEBUG_TEXTLAYOUT_DUMPASTEXT Glib::ustring Layout::getFontFamily(unsigned span_index) const { @@ -570,6 +572,7 @@ Glib::ustring Layout::getFontFamily(unsigned span_index) const return ""; } +#if DEBUG_TEXTLAYOUT_DUMPASTEXT Glib::ustring Layout::dumpAsText() const { Glib::ustring result; @@ -609,7 +612,13 @@ Glib::ustring Layout::dumpAsText() const _lines[_chunks[_spans[span_index].in_chunk].in_line].in_shape) + Glib::ustring::compose(" in chunk %1 (x=%2, baselineshift=%3)\n", _spans[span_index].in_chunk, _chunks[_spans[span_index].in_chunk].left_x, _spans[span_index].baseline_shift); if (_spans[span_index].font) { - result += Glib::ustring::compose(" font '%1' %2 %3 %4\n", sp_font_description_get_family(_spans[span_index].font->descr), _spans[span_index].font_size, style_to_text(pango_font_description_get_style(_spans[span_index].font->descr)), weight_to_text(pango_font_description_get_weight(_spans[span_index].font->descr))); + result += Glib::ustring::compose( + " font '%1' %2 %3 %4\n", + sp_font_description_get_family(_spans[span_index].font->descr), + _spans[span_index].font_size, + style_to_text( pango_font_description_get_style(_spans[span_index].font->descr) ), + weight_to_text( pango_font_description_get_weight(_spans[span_index].font->descr) ) + ); } result += Glib::ustring::compose(" x_start = %1, x_end = %2\n", _spans[span_index].x_start, _spans[span_index].x_end) + Glib::ustring::compose(" line height: ascent %1, descent %2\n", _spans[span_index].line_height.ascent, _spans[span_index].line_height.descent) @@ -640,6 +649,7 @@ Glib::ustring Layout::dumpAsText() const result += "EOT\n"; return result; } +#endif //DEBUG_TEXTLAYOUT_DUMPASTEXT void Layout::fitToPathAlign(SVGLength const &startOffset, Path const &path) { diff --git a/src/libnrtype/Layout-TNG.h b/src/libnrtype/Layout-TNG.h index c39315106..878c76af8 100644 --- a/src/libnrtype/Layout-TNG.h +++ b/src/libnrtype/Layout-TNG.h @@ -11,6 +11,8 @@ #ifndef __LAYOUT_TNG_H__ #define __LAYOUT_TNG_H__ +//#define DEBUG_TEXTLAYOUT_DUMPASTEXT + #ifdef HAVE_CONFIG_H # include "config.h" #endif @@ -402,10 +404,12 @@ public: /** Returns the font family of the indexed span */ Glib::ustring getFontFamily(unsigned span_index) const; +#if DEBUG_TEXTLAYOUT_DUMPASTEXT /** debug and unit test method. Creates a textual representation of the contents of this object. The output is designed to be both human-readable and comprehensible when diffed with a known-good dump. */ Glib::ustring dumpAsText() const; +#endif /** Moves all the glyphs in the structure so that the baseline of all the characters sits neatly along the path specified. If the text has diff --git a/src/sp-flowtext.cpp b/src/sp-flowtext.cpp index d79652bf4..741ca7886 100644 --- a/src/sp-flowtext.cpp +++ b/src/sp-flowtext.cpp @@ -463,7 +463,9 @@ void SPFlowtext::rebuildLayout() _buildLayoutInput(this, exclusion_shape, &shapes, &pending_line_break_object); delete exclusion_shape; layout.calculateFlow(); - //g_print("%s", layout.dumpAsText().c_str()); +#if DEBUG_TEXTLAYOUT_DUMPASTEXT + g_print("%s", layout.dumpAsText().c_str()); +#endif } void SPFlowtext::_clearFlow(Inkscape::DrawingGroup *in_arena) diff --git a/src/sp-text.cpp b/src/sp-text.cpp index b066ca3de..2a88c5009 100644 --- a/src/sp-text.cpp +++ b/src/sp-text.cpp @@ -620,12 +620,16 @@ void SPText::rebuildLayout() if (SP_IS_TEXTPATH(&child)) { SPTextPath const *textpath = SP_TEXTPATH(&child); if (textpath->originalPath != NULL) { - //g_print("%s", layout.dumpAsText().c_str()); +#if DEBUG_TEXTLAYOUT_DUMPASTEXT + g_print("%s", layout.dumpAsText().c_str()); +#endif layout.fitToPathAlign(textpath->startOffset, *textpath->originalPath); } } } - //g_print("%s", layout.dumpAsText().c_str()); +#if DEBUG_TEXTLAYOUT_DUMPASTEXT + g_print("%s", layout.dumpAsText().c_str()); +#endif // set the x,y attributes on role:line spans for (auto& child: children) { -- cgit v1.2.3 From 0ddf7f86b0157cd45bde038d462e47f62dca0d70 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felipe=20Corr=C3=AAa=20da=20Silva=20Sanches?= Date: Sat, 10 Jun 2017 01:57:16 -0300 Subject: Group all of the ParagraphInfo class implementation --- src/libnrtype/Layout-TNG-Compute.cpp | 38 +++++++++++++++--------------------- 1 file changed, 16 insertions(+), 22 deletions(-) (limited to 'src') diff --git a/src/libnrtype/Layout-TNG-Compute.cpp b/src/libnrtype/Layout-TNG-Compute.cpp index 79fdadb54..c3f634897 100644 --- a/src/libnrtype/Layout-TNG-Compute.cpp +++ b/src/libnrtype/Layout-TNG-Compute.cpp @@ -183,17 +183,26 @@ class Layout::Calculator std::vector char_attributes; ///< For every character in the paragraph. std::vector unbroken_spans; - template static void free_sequence(T &seq); - void free(); + template static void free_sequence(T &seq) + { + for (typename T::iterator it(seq.begin()); it != seq.end(); ++it) { + it->free(); + } + seq.clear(); + } + + void free() + { + free_sequence(input_items); + free_sequence(pango_items); + free_sequence(unbroken_spans); + } }; -/* *********************************************************************************************************/ -// Initialisation of ParagraphInfo structure -#if 0 /* unused */ - void _initialiseInputItems(ParagraphInfo *para) const; -#endif +/* *********************************************************************************************************/ +// Initialisation of ParagraphInfo structure void _buildPangoItemizationForPara(ParagraphInfo *para) const; @@ -953,21 +962,6 @@ void Layout::Calculator::BrokenSpan::setZero() word_spacing = 0.0; } -template void Layout::Calculator::ParagraphInfo::free_sequence(T &seq) -{ - for (typename T::iterator it(seq.begin()); it != seq.end(); ++it) { - it->free(); - } - seq.clear(); -} - -void Layout::Calculator::ParagraphInfo::free() -{ - free_sequence(input_items); - free_sequence(pango_items); - free_sequence(unbroken_spans); -} - ///** // * For sections of text with a block-progression different to the rest // * of the flow, the best thing to do is to detect them in advance and -- cgit v1.2.3 From f6a336e4b622cd668ea7ef6177369a0ef9026db8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felipe=20Corr=C3=AAa=20da=20Silva=20Sanches?= Date: Sat, 10 Jun 2017 02:00:41 -0300 Subject: A bit more massaging of codestyle on src/libnrtype/Layout... --- src/libnrtype/Layout-TNG-Compute.cpp | 1417 +++++++++++++++++----------------- 1 file changed, 723 insertions(+), 694 deletions(-) (limited to 'src') diff --git a/src/libnrtype/Layout-TNG-Compute.cpp b/src/libnrtype/Layout-TNG-Compute.cpp index c3f634897..63364ab34 100644 --- a/src/libnrtype/Layout-TNG-Compute.cpp +++ b/src/libnrtype/Layout-TNG-Compute.cpp @@ -55,27 +55,22 @@ class Layout::Calculator { class SpanPosition; friend class SpanPosition; - Layout &_flow; - ScanlineMaker *_scanline_maker; - unsigned _current_shape_index; /// index into Layout::_input_wrap_shapes - PangoContext *_pango_context; - Direction _block_progression; - /** for y= attributes in tspan elements et al, we do the adjustment by moving each - glyph individually by this number. The spec means that this is maintained across - paragraphs. - - To do non-flow text layout, only the first "y" attribute is normally used. If there is only one - "y" attribute in a other than the first , it is ignored. This allows Inkscape to - insert a new line anywhere. On output, the Inkscape determined "y" is written out so other SVG - viewers know where to place the . - */ - + /** + * For y= attributes in tspan elements et al, we do the adjustment by moving each + * glyph individually by this number. The spec means that this is maintained across + * paragraphs. + * + * To do non-flow text layout, only the first "y" attribute is normally used. If there is only one + * "y" attribute in a other than the first , it is ignored. This allows Inkscape to + * insert a new line anywhere. On output, the Inkscape determined "y" is written out so other SVG + * viewers know where to place the . + */ double _y_offset; /** to stop pango from hinting its output, the font factory creates all fonts very large. @@ -89,7 +84,20 @@ class Layout::Calculator Layout *sub_flow; // this is only set for the first input item in a sub-flow InputItemInfo() : in_sub_flow(false), sub_flow(NULL) {} - void free(); + + /* fixme: I don't like the fact that InputItemInfo etc. use the default copy constructor and + * operator= (and thus don't involve incrementing reference counts), yet they provide a free method + * that does delete or Unref. + * + * I suggest using the garbage collector to manage deletion. + */ + void free() + { + if (sub_flow) { + delete sub_flow; + sub_flow = NULL; + } + } }; /** Temporary storage associated with each item returned by the call to @@ -99,17 +107,36 @@ class Layout::Calculator font_instance *font; PangoItemInfo() : item(NULL), font(NULL) {} - void free(); + + /* fixme: I don't like the fact that InputItemInfo etc. use the default copy constructor and + * operator= (and thus don't involve incrementing reference counts), yet they provide a free method + * that does delete or Unref. + * + * I suggest using the garbage collector to manage deletion. + */ + void free() + { + if (item) { + pango_item_free(item); + item = NULL; + } + if (font) { + font->Unref(); + font = NULL; + } + } }; + /** These spans have approximately the same definition as that used for - Layout::Span (constant font, direction, etc), except that they are from - before we have located the line breaks, so bear no relation to chunks. - They are guaranteed to be in at most one PangoItem (spans with no text in - them will not have an associated PangoItem), exactly one input source and - will only have one change of x, y, dx, dy or rotate attribute, which will - be at the beginning. An UnbrokenSpan can cross a chunk boundary, c.f. - BrokenSpan. */ + * Layout::Span (constant font, direction, etc), except that they are from + * before we have located the line breaks, so bear no relation to chunks. + * They are guaranteed to be in at most one PangoItem (spans with no text in + * them will not have an associated PangoItem), exactly one input source and + * will only have one change of x, y, dx, dy or rotate attribute, which will + * be at the beginning. An UnbrokenSpan can cross a chunk boundary, c.f. + * BrokenSpan. + */ struct UnbrokenSpan { PangoGlyphString *glyph_string; int pango_item_index; /// index into _para.pango_items, or -1 if this is style only @@ -125,10 +152,48 @@ class Layout::Calculator SVGLength x, y, dx, dy, rotate; // these are reoriented copies of the attributes. We change span when we encounter one. UnbrokenSpan() : glyph_string(NULL) {} - void free() {if (glyph_string) pango_glyph_string_free(glyph_string); glyph_string = NULL;} + void free() + { + if (glyph_string) + pango_glyph_string_free(glyph_string); + glyph_string = NULL; + } + }; + + + /** Used to provide storage for anything that applies to the current + paragraph only. Since we're only processing one paragraph at a time, + there's only one instantiation of this struct, on the stack of + calculate(). */ + struct ParagraphInfo { + unsigned first_input_index; ///< Index into Layout::_input_stream. + Direction direction; + Alignment alignment; + std::vector input_items; + std::vector pango_items; + std::vector char_attributes; ///< For every character in the paragraph. + std::vector unbroken_spans; + + template static void free_sequence(T &seq) + { + for (typename T::iterator it(seq.begin()); it != seq.end(); ++it) { + it->free(); + } + seq.clear(); + } + + void free() + { + free_sequence(input_items); + free_sequence(pango_items); + free_sequence(unbroken_spans); + } }; - /** a useful little iterator for moving char-by-char across spans. */ + + /** + * A useful little iterator for moving char-by-char across spans. + */ struct UnbrokenSpanPosition { std::vector::iterator iter_span; unsigned char_byte; @@ -142,9 +207,11 @@ class Layout::Calculator {return char_byte != other.char_byte || iter_span != other.iter_span;} }; - /** The line breaking algorithm will convert each UnbrokenSpan into one - or more of these. A BrokenSpan will never cross a chunk boundary, c.f. - UnbrokenSpan. */ + /** + * The line breaking algorithm will convert each UnbrokenSpan into one + * or more of these. A BrokenSpan will never cross a chunk boundary, + * c.f. UnbrokenSpan. + */ struct BrokenSpan { UnbrokenSpanPosition start; UnbrokenSpanPosition end; // the end of this will always be the same as the start of the next @@ -170,94 +237,11 @@ class Layout::Calculator int whitespace_count; }; - /** Used to provide storage for anything that applies to the current - paragraph only. Since we're only processing one paragraph at a time, - there's only one instantiation of this struct, on the stack of - calculate(). */ - struct ParagraphInfo { - unsigned first_input_index; ///< Index into Layout::_input_stream. - Direction direction; - Alignment alignment; - std::vector input_items; - std::vector pango_items; - std::vector char_attributes; ///< For every character in the paragraph. - std::vector unbroken_spans; - - template static void free_sequence(T &seq) - { - for (typename T::iterator it(seq.begin()); it != seq.end(); ++it) { - it->free(); - } - seq.clear(); - } - - void free() - { - free_sequence(input_items); - free_sequence(pango_items); - free_sequence(unbroken_spans); - } - }; - - - -/* *********************************************************************************************************/ -// Initialisation of ParagraphInfo structure - void _buildPangoItemizationForPara(ParagraphInfo *para) const; - - // Returns line_height_multiplier - static double _computeFontLineHeight( SPStyle const *style ); - + static double _computeFontLineHeight( SPStyle const *style ); // Returns line_height_multiplier unsigned _buildSpansForPara(ParagraphInfo *para) const; - -/* *********************************************************************************************************/ -// Per-line functions - - -#ifdef DEBUG_LAYOUT_TNG_COMPUTE -/** - * For debugging, not called in distributed code - * - * Input: para->first_input_index, para->pango_items - */ -static void dumpPangoItemsOut(ParagraphInfo *para){ - std::cout << "Pango items: " << para->pango_items.size() << std::endl; - font_factory * factory = font_factory::Default(); - for(unsigned pidx = 0 ; pidx < para->pango_items.size(); pidx++){ - std::cout - << "idx: " << pidx - << " offset: " - << para->pango_items[pidx].item->offset - << " length: " - << para->pango_items[pidx].item->length - << " font: " - << factory->ConstructFontSpecification( para->pango_items[pidx].font ) - << std::endl; - } -} - -/** - * For debugging, not called in distributed code - * - * Input: para->first_input_index, para->pango_items - */ -static void dumpUnbrokenSpans(ParagraphInfo *para){ - std::cout << "Unbroken Spans: " << para->unbroken_spans.size() << std::endl; - for(unsigned uidx = 0 ; uidx < para->unbroken_spans.size(); uidx++){ - std::cout - << "idx: " << uidx - << " pango_item_index: " << para->unbroken_spans[uidx].pango_item_index - << " input_index: " << para->unbroken_spans[uidx].input_index - << " char_index_in_para: " << para->unbroken_spans[uidx].char_index_in_para - << " text_bytes: " << para->unbroken_spans[uidx].text_bytes - << std::endl; - } -} -#endif //DEBUG_LAYOUT_TNG_COMPUTE - - bool _goToNextWrapShape(); + void _createFirstScanlineMaker(); bool _findChunksForLine(ParagraphInfo const ¶, UnbrokenSpanPosition *start_span_pos, @@ -265,12 +249,6 @@ static void dumpUnbrokenSpans(ParagraphInfo *para){ FontMetrics *line_box_height, FontMetrics const *strut_height); - static inline PangoLogAttr const &_charAttributes(ParagraphInfo const ¶, - UnbrokenSpanPosition const &span_pos) - { - return para.char_attributes[span_pos.iter_span->char_index_in_para + span_pos.char_index]; - } - bool _buildChunksInScanRun(ParagraphInfo const ¶, UnbrokenSpanPosition const &start_span_pos, ScanlineMaker::ScanRun const &scan_run, @@ -278,664 +256,675 @@ static void dumpUnbrokenSpans(ParagraphInfo *para){ FontMetrics *line_height, FontMetrics const *strut_height) const; - /** computes the width of a single UnbrokenSpan (pointed to by span->start.iter_span) - and outputs its vital statistics into the other fields of \a span. - Measuring will stop if maximum_width is reached and in that case the - function will return false. In other cases where a line break must be - done immediately the function will also return false. On return - \a last_break_span will contain the vital statistics for the span only - up to the last line breaking change. If there are no line breaking - characters in the span then \a last_break_span will not be altered. - Similarly, \a last_emergency_break_span will contain the vital - statistics for the span up to the last inter-character boundary, - or will be unaltered if there is none. */ - bool _measureUnbrokenSpan(ParagraphInfo const ¶, BrokenSpan *span, BrokenSpan *last_break_span, BrokenSpan *last_emergency_break_span, double maximum_width) const + bool _measureUnbrokenSpan(ParagraphInfo const ¶, + BrokenSpan *span, + BrokenSpan *last_break_span, + BrokenSpan *last_emergency_break_span, + double maximum_width) const; + + double _getChunkLeftWithAlignment(ParagraphInfo const ¶, + std::vector::const_iterator it_chunk, + double *add_to_each_whitespace) const; + + void _outputLine(ParagraphInfo const ¶, + FontMetrics const &line_height, + std::vector const &chunk_info); + + static inline PangoLogAttr const &_charAttributes(ParagraphInfo const ¶, + UnbrokenSpanPosition const &span_pos) { - TRACE((" start _measureUnbrokenSpan %g\n", maximum_width)); - span->setZero(); + return para.char_attributes[span_pos.iter_span->char_index_in_para + span_pos.char_index]; + } - if (span->start.iter_span->dx._set && span->start.char_byte == 0){ - if(para.direction == RIGHT_TO_LEFT){ - span->width -= span->start.iter_span->dx.computed; - } else { - span->width += span->start.iter_span->dx.computed; - } - } +#ifdef DEBUG_LAYOUT_TNG_COMPUTE + static void dumpPangoItemsOut(ParagraphInfo *para); + static void dumpUnbrokenSpans(ParagraphInfo *para){ +#endif //DEBUG_LAYOUT_TNG_COMPUTE - if (span->start.iter_span->pango_item_index == -1) { - // if this is a style-only span there's no text in it - // so we don't need to do very much at all - span->end.iter_span++; - return true; +public: + Calculator(Layout *text_flow) + : _flow(*text_flow) {} + + bool calculate(); +}; + + +/** + * Computes the width of a single UnbrokenSpan (pointed to by span->start.iter_span) + * and outputs its vital statistics into the other fields of \a span. + * Measuring will stop if maximum_width is reached and in that case the + * function will return false. In other cases where a line break must be + * done immediately the function will also return false. On return + * \a last_break_span will contain the vital statistics for the span only + * up to the last line breaking change. If there are no line breaking + * characters in the span then \a last_break_span will not be altered. + * Similarly, \a last_emergency_break_span will contain the vital + * statistics for the span up to the last inter-character boundary, + * or will be unaltered if there is none. + */ +bool Layout::Calculator::_measureUnbrokenSpan(ParagraphInfo const ¶, + BrokenSpan *span, + BrokenSpan *last_break_span, + BrokenSpan *last_emergency_break_span, + double maximum_width) const +{ + TRACE((" start _measureUnbrokenSpan %g\n", maximum_width)); + span->setZero(); + + if (span->start.iter_span->dx._set && span->start.char_byte == 0){ + if(para.direction == RIGHT_TO_LEFT){ + span->width -= span->start.iter_span->dx.computed; + } else { + span->width += span->start.iter_span->dx.computed; } + } - if (_flow._input_stream[span->start.iter_span->input_index]->Type() == CONTROL_CODE) { - InputStreamControlCode const *control_code = static_cast(_flow._input_stream[span->start.iter_span->input_index]); - if (control_code->code == SHAPE_BREAK || control_code->code == PARAGRAPH_BREAK) { - *last_emergency_break_span = *last_break_span = *span; - return false; - } - if (control_code->code == ARBITRARY_GAP) { - if (span->width + control_code->width > maximum_width) - return false; - TRACE((" fitted control code, width = %f\n", control_code->width)); - span->width += control_code->width; - span->end.increment(); - } - return true; + if (span->start.iter_span->pango_item_index == -1) { + // if this is a style-only span there's no text in it + // so we don't need to do very much at all + span->end.iter_span++; + return true; + } + if (_flow._input_stream[span->start.iter_span->input_index]->Type() == CONTROL_CODE) { + InputStreamControlCode const *control_code = static_cast(_flow._input_stream[span->start.iter_span->input_index]); + if (control_code->code == SHAPE_BREAK || control_code->code == PARAGRAPH_BREAK) { + *last_emergency_break_span = *last_break_span = *span; + return false; + } + if (control_code->code == ARBITRARY_GAP) { + if (span->width + control_code->width > maximum_width) + return false; + TRACE((" fitted control code, width = %f\n", control_code->width)); + span->width += control_code->width; + span->end.increment(); } + return true; - if (_flow._input_stream[span->start.iter_span->input_index]->Type() != TEXT_SOURCE) - return true; // never happens + } - InputStreamTextSource const *text_source = static_cast(_flow._input_stream[span->start.iter_span->input_index]); + if (_flow._input_stream[span->start.iter_span->input_index]->Type() != TEXT_SOURCE) + return true; // never happens - if (_directions_are_orthogonal(_block_progression, text_source->styleGetBlockProgression())) { - // TODO: block-progression altered in the middle - // Measure the precomputed flow from para.input_items - span->end.iter_span++; // for now, skip to the next span - return true; - } + InputStreamTextSource const *text_source = static_cast(_flow._input_stream[span->start.iter_span->input_index]); - // a normal span going with a normal block-progression - double font_size_multiplier = span->start.iter_span->font_size / (PANGO_SCALE * _font_factory_size_multiplier); - double soft_hyphen_glyph_width = 0.0; - bool soft_hyphen_in_word = false; - bool is_soft_hyphen = false; - IFTRACE(int char_count = 0); - - // if we're not at the start of the span we need to pre-init glyph_index - span->start_glyph_index = 0; - while (span->start_glyph_index < (unsigned)span->start.iter_span->glyph_string->num_glyphs - && span->start.iter_span->glyph_string->log_clusters[span->start_glyph_index] < (int)span->start.char_byte) - span->start_glyph_index++; - span->end_glyph_index = span->start_glyph_index; - - // go char-by-char summing the width, while keeping track of the previous break point - do { - PangoLogAttr const &char_attributes = _charAttributes(para, span->end); - - if (char_attributes.is_mandatory_break && span->end != span->start) { - TRACE((" is_mandatory_break ************\n")); - *last_emergency_break_span = *last_break_span = *span; - TRACE((" span %ld end of para; width = %f chars = %d\n", span->start.iter_span - para.unbroken_spans.begin(), span->width, char_count)); - return false; - } + if (_directions_are_orthogonal(_block_progression, text_source->styleGetBlockProgression())) { + // TODO: block-progression altered in the middle + // Measure the precomputed flow from para.input_items + span->end.iter_span++; // for now, skip to the next span + return true; + } - if (char_attributes.is_line_break) { - TRACE((" is_line_break ************\n")); - // a suitable position to break at, record where we are - *last_emergency_break_span = *last_break_span = *span; - if (soft_hyphen_in_word) { - // if there was a previous soft hyphen we're not going to need it any more so we can remove it - span->width -= soft_hyphen_glyph_width; - if (!is_soft_hyphen) - soft_hyphen_in_word = false; - } - } else if (char_attributes.is_char_break) { - *last_emergency_break_span = *span; + // a normal span going with a normal block-progression + double font_size_multiplier = span->start.iter_span->font_size / (PANGO_SCALE * _font_factory_size_multiplier); + double soft_hyphen_glyph_width = 0.0; + bool soft_hyphen_in_word = false; + bool is_soft_hyphen = false; + IFTRACE(int char_count = 0); + + // if we're not at the start of the span we need to pre-init glyph_index + span->start_glyph_index = 0; + while (span->start_glyph_index < (unsigned)span->start.iter_span->glyph_string->num_glyphs + && span->start.iter_span->glyph_string->log_clusters[span->start_glyph_index] < (int)span->start.char_byte) + span->start_glyph_index++; + span->end_glyph_index = span->start_glyph_index; + + // go char-by-char summing the width, while keeping track of the previous break point + do { + PangoLogAttr const &char_attributes = _charAttributes(para, span->end); + + if (char_attributes.is_mandatory_break && span->end != span->start) { + TRACE((" is_mandatory_break ************\n")); + *last_emergency_break_span = *last_break_span = *span; + TRACE((" span %ld end of para; width = %f chars = %d\n", span->start.iter_span - para.unbroken_spans.begin(), span->width, char_count)); + return false; + } + + if (char_attributes.is_line_break) { + TRACE((" is_line_break ************\n")); + // a suitable position to break at, record where we are + *last_emergency_break_span = *last_break_span = *span; + if (soft_hyphen_in_word) { + // if there was a previous soft hyphen we're not going to need it any more so we can remove it + span->width -= soft_hyphen_glyph_width; + if (!is_soft_hyphen) + soft_hyphen_in_word = false; } - // todo: break between chars if necessary (ie no word breaks present) when doing rectangular flowing + } else if (char_attributes.is_char_break) { + *last_emergency_break_span = *span; + } + // todo: break between chars if necessary (ie no word breaks present) when doing rectangular flowing - // sum the glyph widths, letter spacing, word spacing, and textLength adjustment to get the character width - double char_width = 0.0; - while (span->end_glyph_index < (unsigned)span->end.iter_span->glyph_string->num_glyphs - && span->end.iter_span->glyph_string->log_clusters[span->end_glyph_index] <= (int)span->end.char_byte) { - if (_block_progression == LEFT_TO_RIGHT || _block_progression == RIGHT_TO_LEFT) { - // Vertical text + // sum the glyph widths, letter spacing, word spacing, and textLength adjustment to get the character width + double char_width = 0.0; + while (span->end_glyph_index < (unsigned)span->end.iter_span->glyph_string->num_glyphs + && span->end.iter_span->glyph_string->log_clusters[span->end_glyph_index] <= (int)span->end.char_byte) { + if (_block_progression == LEFT_TO_RIGHT || _block_progression == RIGHT_TO_LEFT) { + // Vertical text - if( text_source->style->text_orientation.computed == SP_CSS_TEXT_ORIENTATION_SIDEWAYS || - (text_source->style->text_orientation.computed == SP_CSS_TEXT_ORIENTATION_MIXED && - para.pango_items[span->end.iter_span->pango_item_index].item->analysis.gravity == 0) ) { - // Sideways orientation - char_width += span->start.iter_span->font_size * para.pango_items[span->end.iter_span->pango_item_index].font->Advance(span->end.iter_span->glyph_string->glyphs[span->end_glyph_index].glyph, false); - } else { - // Upright orientation - char_width += span->start.iter_span->font_size * para.pango_items[span->end.iter_span->pango_item_index].font->Advance(span->end.iter_span->glyph_string->glyphs[span->end_glyph_index].glyph, true); - } + if( text_source->style->text_orientation.computed == SP_CSS_TEXT_ORIENTATION_SIDEWAYS || + (text_source->style->text_orientation.computed == SP_CSS_TEXT_ORIENTATION_MIXED && + para.pango_items[span->end.iter_span->pango_item_index].item->analysis.gravity == 0) ) { + // Sideways orientation + char_width += span->start.iter_span->font_size * para.pango_items[span->end.iter_span->pango_item_index].font->Advance(span->end.iter_span->glyph_string->glyphs[span->end_glyph_index].glyph, false); } else { - // Horizontal text - char_width += font_size_multiplier * span->end.iter_span->glyph_string->glyphs[span->end_glyph_index].geometry.width; + // Upright orientation + char_width += span->start.iter_span->font_size * para.pango_items[span->end.iter_span->pango_item_index].font->Advance(span->end.iter_span->glyph_string->glyphs[span->end_glyph_index].glyph, true); } - span->end_glyph_index++; - } - if (char_attributes.is_cursor_position) - char_width += text_source->style->letter_spacing.computed * _flow.getTextLengthMultiplierDue(); - if (char_attributes.is_white) - char_width += text_source->style->word_spacing.computed * _flow.getTextLengthMultiplierDue(); - char_width += _flow.getTextLengthIncrementDue(); - span->width += char_width; - IFTRACE(char_count++); - - if (char_attributes.is_white) { - span->whitespace_count++; - span->each_whitespace_width = char_width; + } else { + // Horizontal text + char_width += font_size_multiplier * span->end.iter_span->glyph_string->glyphs[span->end_glyph_index].geometry.width; } - span->ends_with_whitespace = char_attributes.is_white; + span->end_glyph_index++; + } + if (char_attributes.is_cursor_position) + char_width += text_source->style->letter_spacing.computed * _flow.getTextLengthMultiplierDue(); + if (char_attributes.is_white) + char_width += text_source->style->word_spacing.computed * _flow.getTextLengthMultiplierDue(); + char_width += _flow.getTextLengthIncrementDue(); + span->width += char_width; + IFTRACE(char_count++); + + if (char_attributes.is_white) { + span->whitespace_count++; + span->each_whitespace_width = char_width; + } + span->ends_with_whitespace = char_attributes.is_white; - is_soft_hyphen = (UNICODE_SOFT_HYPHEN == *Glib::ustring::const_iterator(span->end.iter_span->input_stream_first_character.base() + span->end.char_byte)); - if (is_soft_hyphen) - soft_hyphen_glyph_width = char_width; + is_soft_hyphen = (UNICODE_SOFT_HYPHEN == *Glib::ustring::const_iterator(span->end.iter_span->input_stream_first_character.base() + span->end.char_byte)); + if (is_soft_hyphen) + soft_hyphen_glyph_width = char_width; - span->end.increment(); + span->end.increment(); - // Width should not include letter_spacing (or word_spacing) after last letter at end of line. - // word_spacing is attached to white space that is already removed from line end (?) - double test_width = span->width - text_source->style->letter_spacing.computed; + // Width should not include letter_spacing (or word_spacing) after last letter at end of line. + // word_spacing is attached to white space that is already removed from line end (?) + double test_width = span->width - text_source->style->letter_spacing.computed; - // Save letter_spacing and word_spacing for subtraction later if span is last span in line. - span->letter_spacing = text_source->style->letter_spacing.computed; - span->word_spacing = text_source->style->word_spacing.computed; + // Save letter_spacing and word_spacing for subtraction later if span is last span in line. + span->letter_spacing = text_source->style->letter_spacing.computed; + span->word_spacing = text_source->style->word_spacing.computed; - if (test_width > maximum_width && !char_attributes.is_white) { // whitespaces don't matter, we can put as many as we want at eol - TRACE((" span %ld exceeded scanrun; width = %f chars = %d\n", span->start.iter_span - para.unbroken_spans.begin(), span->width, char_count)); - return false; - } + if (test_width > maximum_width && !char_attributes.is_white) { // whitespaces don't matter, we can put as many as we want at eol + TRACE((" span %ld exceeded scanrun; width = %f chars = %d\n", span->start.iter_span - para.unbroken_spans.begin(), span->width, char_count)); + return false; + } - } while (span->end.char_byte != 0); // while we haven't wrapped to the next span + } while (span->end.char_byte != 0); // while we haven't wrapped to the next span - TRACE((" fitted span %ld width = %f chars = %d\n", span->start.iter_span - para.unbroken_spans.begin(), span->width, char_count)); - TRACE((" end _measureUnbrokenSpan %g\n", maximum_width)); - return true; - } + TRACE((" fitted span %ld width = %f chars = %d\n", span->start.iter_span - para.unbroken_spans.begin(), span->width, char_count)); + TRACE((" end _measureUnbrokenSpan %g\n", maximum_width)); + return true; +} /* *********************************************************************************************************/ // Per-line functions (output) - /** Uses the paragraph alignment and the chunk information to work out - where the actual left of the final chunk must be. Also sets - \a add_to_each_whitespace to be the amount of x to add at each - whitespace character to make full justification work. */ - double _getChunkLeftWithAlignment(ParagraphInfo const ¶, std::vector::const_iterator it_chunk, double *add_to_each_whitespace) const - { - *add_to_each_whitespace = 0.0; - if (_flow._input_wrap_shapes.empty()) { - switch (para.alignment) { - case FULL: - case LEFT: - default: - return it_chunk->x; - case RIGHT: - return it_chunk->x - it_chunk->text_width; - case CENTER: - return it_chunk->x - it_chunk->text_width/ 2; - } - } - +/** Uses the paragraph alignment and the chunk information to work out + * where the actual left of the final chunk must be. Also sets + * \a add_to_each_whitespace to be the amount of x to add at each + * whitespace character to make full justification work. + */ +double Layout::Calculator::_getChunkLeftWithAlignment(ParagraphInfo const ¶, + std::vector::const_iterator it_chunk, + double *add_to_each_whitespace) const +{ + *add_to_each_whitespace = 0.0; + if (_flow._input_wrap_shapes.empty()) { switch (para.alignment) { case FULL: - if (!it_chunk->broken_spans.empty() - && it_chunk->broken_spans.back().end.iter_span != para.unbroken_spans.end()) { // don't justify the last chunk in the para - if (it_chunk->whitespace_count) - *add_to_each_whitespace = (it_chunk->scanrun_width - it_chunk->text_width) / it_chunk->whitespace_count; - //else - //add_to_each_charspace = something - } - return it_chunk->x; case LEFT: default: return it_chunk->x; case RIGHT: - return it_chunk->x + it_chunk->scanrun_width - it_chunk->text_width; + return it_chunk->x - it_chunk->text_width; case CENTER: - return it_chunk->x + (it_chunk->scanrun_width - it_chunk->text_width) / 2; + return it_chunk->x - it_chunk->text_width/ 2; } } - /** Once we've got here we have finished making changes to the line and - are ready to output the final result to #_flow. This method takes its - input parameters and does that. - */ - void _outputLine(ParagraphInfo const ¶, FontMetrics const &line_height, std::vector const &chunk_info) - { - TRACE((" Start _outputLine: ascent %f, descent %f, top of box %f\n", line_height.ascent, line_height.descent, _scanline_maker->yCoordinate() )); - if (chunk_info.empty()) { - TRACE((" line too short to fit anything on it, go to next\n")); - return; - } + switch (para.alignment) { + case FULL: + if (!it_chunk->broken_spans.empty() + && it_chunk->broken_spans.back().end.iter_span != para.unbroken_spans.end()) { // don't justify the last chunk in the para + if (it_chunk->whitespace_count) + *add_to_each_whitespace = (it_chunk->scanrun_width - it_chunk->text_width) / it_chunk->whitespace_count; + //else + //add_to_each_charspace = something + } + return it_chunk->x; + case LEFT: + default: + return it_chunk->x; + case RIGHT: + return it_chunk->x + it_chunk->scanrun_width - it_chunk->text_width; + case CENTER: + return it_chunk->x + (it_chunk->scanrun_width - it_chunk->text_width) / 2; + } +} - // we've finished fiddling about with ascents and descents: create the output - TRACE((" found line fit; creating output\n")); - Layout::Line new_line; - new_line.in_paragraph = _flow._paragraphs.size() - 1; - new_line.baseline_y = _scanline_maker->yCoordinate(); - - // The y coordinate is at the beginning edge of the line box (top for horizontal text, left - // edge for vertical lr text, right edge for vertical rl text. We align, by default to the - // alphabetic baseline for horizontal text and the central baseline for vertical text. - if( _block_progression == RIGHT_TO_LEFT ) { - // Vertical text, use em box center as baseline - new_line.baseline_y -= 0.5 * line_height.emSize(); - } else if ( _block_progression == LEFT_TO_RIGHT ) { - // Vertical text, use em box center as baseline - new_line.baseline_y += 0.5 * line_height.emSize(); - } else { - new_line.baseline_y += line_height.getTypoAscent(); - } +/** + * Once we've got here we have finished making changes to the line + * and are ready to output the final result to #_flow. + * This method takes its input parameters and does that. + */ +void Layout::Calculator::_outputLine(ParagraphInfo const ¶, + FontMetrics const &line_height, + std::vector const &chunk_info) +{ + TRACE((" Start _outputLine: ascent %f, descent %f, top of box %f\n", line_height.ascent, line_height.descent, _scanline_maker->yCoordinate() )); + if (chunk_info.empty()) { + TRACE((" line too short to fit anything on it, go to next\n")); + return; + } - new_line.in_shape = _current_shape_index; - _flow._lines.push_back(new_line); - - for (std::vector::const_iterator it_chunk = chunk_info.begin() ; it_chunk != chunk_info.end() ; it_chunk++) { - - double add_to_each_whitespace; - // add the chunk to the list - Layout::Chunk new_chunk; - new_chunk.in_line = _flow._lines.size() - 1; - TRACE((" New chunk: in_line: %d\n", new_chunk.in_line)); - new_chunk.left_x = _getChunkLeftWithAlignment(para, it_chunk, &add_to_each_whitespace); - - // we may also have y move orders to deal with here (dx, dy and rotate are done per span) - - // Comment updated: 23 July 2010: - // We must handle two cases: - // - // 1. Inkscape SVG where the first line is placed by the read-in "y" value and the - // rest are determined by 'font-size' and 'line-height' (and not by any - // y-kerning). s in this case are marked by sodipodi:role="line". This - // allows new lines to be inserted in the middle of a object. On output, - // new "y" values are calculated for each that represents a new line. Line - // spacing is already handled by the calling routine. - // - // 2. Plain SVG where each or is placed by its own "x" and "y" values. - // Note that in this case Inkscape treats each object with any included - // s as a single line of text. This can be confusing in the code below. - - if (!it_chunk->broken_spans.empty() // Not empty paragraph - && it_chunk->broken_spans.front().start.char_byte == 0 ) { // Beginning of unbroken span - - // If empty or new line (sodipode:role="line") - if( _flow._characters.empty() || - _flow._characters.back().chunk(&_flow).in_line != _flow._lines.size() - 1) { - - // This is the Inkscape SVG case. - // - // If "y" attribute is set, use it (initial "y" attributes in - // other than the first have already been stripped for - // marked with role="line", see sp-text.cpp: SPText::_buildLayoutInput). - // NOTE: for vertical text, "y" is the user-space "x" value. - if( it_chunk->broken_spans.front().start.iter_span->y._set ) { - - // Use set "y" attribute - new_line.baseline_y = it_chunk->broken_spans.front().start.iter_span->y.computed; - // Save baseline - _flow._lines.back().baseline_y = new_line.baseline_y; - - double top_of_line_box = new_line.baseline_y; - if( _block_progression == RIGHT_TO_LEFT ) { - // Vertical text, use em box center as baseline - top_of_line_box += 0.5 * line_height.emSize(); - } else if (_block_progression == LEFT_TO_RIGHT ) { - // Vertical text, use em box center as baseline - top_of_line_box -= 0.5 * line_height.emSize(); - } else { - top_of_line_box -= line_height.getTypoAscent(); - } - TRACE((" y attribute set, next line top_of_line_box: %f\n", top_of_line_box )); - // Set the initial y coordinate of the next line (see above). - _scanline_maker->setNewYCoordinate(top_of_line_box); + // we've finished fiddling about with ascents and descents: create the output + TRACE((" found line fit; creating output\n")); + Layout::Line new_line; + new_line.in_paragraph = _flow._paragraphs.size() - 1; + new_line.baseline_y = _scanline_maker->yCoordinate(); + + // The y coordinate is at the beginning edge of the line box (top for horizontal text, left + // edge for vertical lr text, right edge for vertical rl text. We align, by default to the + // alphabetic baseline for horizontal text and the central baseline for vertical text. + if( _block_progression == RIGHT_TO_LEFT ) { + // Vertical text, use em box center as baseline + new_line.baseline_y -= 0.5 * line_height.emSize(); + } else if ( _block_progression == LEFT_TO_RIGHT ) { + // Vertical text, use em box center as baseline + new_line.baseline_y += 0.5 * line_height.emSize(); + } else { + new_line.baseline_y += line_height.getTypoAscent(); + } + + new_line.in_shape = _current_shape_index; + _flow._lines.push_back(new_line); + + for (std::vector::const_iterator it_chunk = chunk_info.begin() ; it_chunk != chunk_info.end() ; it_chunk++) { + + double add_to_each_whitespace; + // add the chunk to the list + Layout::Chunk new_chunk; + new_chunk.in_line = _flow._lines.size() - 1; + TRACE((" New chunk: in_line: %d\n", new_chunk.in_line)); + new_chunk.left_x = _getChunkLeftWithAlignment(para, it_chunk, &add_to_each_whitespace); + + // we may also have y move orders to deal with here (dx, dy and rotate are done per span) + + // Comment updated: 23 July 2010: + // We must handle two cases: + // + // 1. Inkscape SVG where the first line is placed by the read-in "y" value and the + // rest are determined by 'font-size' and 'line-height' (and not by any + // y-kerning). s in this case are marked by sodipodi:role="line". This + // allows new lines to be inserted in the middle of a object. On output, + // new "y" values are calculated for each that represents a new line. Line + // spacing is already handled by the calling routine. + // + // 2. Plain SVG where each or is placed by its own "x" and "y" values. + // Note that in this case Inkscape treats each object with any included + // s as a single line of text. This can be confusing in the code below. + + if (!it_chunk->broken_spans.empty() // Not empty paragraph + && it_chunk->broken_spans.front().start.char_byte == 0 ) { // Beginning of unbroken span + + // If empty or new line (sodipode:role="line") + if( _flow._characters.empty() || + _flow._characters.back().chunk(&_flow).in_line != _flow._lines.size() - 1) { + + // This is the Inkscape SVG case. + // + // If "y" attribute is set, use it (initial "y" attributes in + // other than the first have already been stripped for + // marked with role="line", see sp-text.cpp: SPText::_buildLayoutInput). + // NOTE: for vertical text, "y" is the user-space "x" value. + if( it_chunk->broken_spans.front().start.iter_span->y._set ) { + + // Use set "y" attribute + new_line.baseline_y = it_chunk->broken_spans.front().start.iter_span->y.computed; + // Save baseline + _flow._lines.back().baseline_y = new_line.baseline_y; + + double top_of_line_box = new_line.baseline_y; + if( _block_progression == RIGHT_TO_LEFT ) { + // Vertical text, use em box center as baseline + top_of_line_box += 0.5 * line_height.emSize(); + } else if (_block_progression == LEFT_TO_RIGHT ) { + // Vertical text, use em box center as baseline + top_of_line_box -= 0.5 * line_height.emSize(); + } else { + top_of_line_box -= line_height.getTypoAscent(); } + TRACE((" y attribute set, next line top_of_line_box: %f\n", top_of_line_box )); + // Set the initial y coordinate of the next line (see above). + _scanline_maker->setNewYCoordinate(top_of_line_box); + } - // Reset relative y_offset ("dy" attribute is relative but should be reset at - // the beginning of each line since each line will have a new "y" written out.) - _y_offset = 0.0; + // Reset relative y_offset ("dy" attribute is relative but should be reset at + // the beginning of each line since each line will have a new "y" written out.) + _y_offset = 0.0; - } else { + } else { - // This is the plain SVG case - // - // "x" and "y" are used to place text, simulating lines as necessary - if( it_chunk->broken_spans.front().start.iter_span->y._set ) { - _y_offset = it_chunk->broken_spans.front().start.iter_span->y.computed - new_line.baseline_y; - } + // This is the plain SVG case + // + // "x" and "y" are used to place text, simulating lines as necessary + if( it_chunk->broken_spans.front().start.iter_span->y._set ) { + _y_offset = it_chunk->broken_spans.front().start.iter_span->y.computed - new_line.baseline_y; } } - _flow._chunks.push_back(new_chunk); - - double current_x; - double direction_sign; - Direction previous_direction = para.direction; - double counter_directional_width_remaining = 0.0; - float glyph_rotate = 0.0; - if (para.direction == LEFT_TO_RIGHT) { - direction_sign = +1.0; - current_x = 0.0; - } else { - direction_sign = -1.0; - if (para.alignment == FULL && !_flow._input_wrap_shapes.empty()){ - current_x = it_chunk->scanrun_width; - } - else { - current_x = it_chunk->text_width; - } + } + _flow._chunks.push_back(new_chunk); + + double current_x; + double direction_sign; + Direction previous_direction = para.direction; + double counter_directional_width_remaining = 0.0; + float glyph_rotate = 0.0; + if (para.direction == LEFT_TO_RIGHT) { + direction_sign = +1.0; + current_x = 0.0; + } else { + direction_sign = -1.0; + if (para.alignment == FULL && !_flow._input_wrap_shapes.empty()){ + current_x = it_chunk->scanrun_width; } + else { + current_x = it_chunk->text_width; + } + } - for (std::vector::const_iterator it_span = it_chunk->broken_spans.begin() ; it_span != it_chunk->broken_spans.end() ; it_span++) { - // begin adding spans to the list - UnbrokenSpan const &unbroken_span = *it_span->start.iter_span; - double x_in_span_last = 0.0; // set at the END when a new cluster starts - double x_in_span = 0.0; // set from the preceding at the START when a new cluster starts. - - if (it_span->start.char_byte == 0) { - // Start of an unbroken span, we might have dx, dy or rotate still to process - // (x and y are done per chunk) - if (unbroken_span.dx._set) current_x += unbroken_span.dx.computed; - if (unbroken_span.dy._set) _y_offset += unbroken_span.dy.computed; - if (unbroken_span.rotate._set) glyph_rotate = unbroken_span.rotate.computed * (M_PI/180); - } - - if (_flow._input_stream[unbroken_span.input_index]->Type() == TEXT_SOURCE - && unbroken_span.pango_item_index == -1) { - // style only, nothing to output - continue; - } + for (std::vector::const_iterator it_span = it_chunk->broken_spans.begin() ; it_span != it_chunk->broken_spans.end() ; it_span++) { + // begin adding spans to the list + UnbrokenSpan const &unbroken_span = *it_span->start.iter_span; + double x_in_span_last = 0.0; // set at the END when a new cluster starts + double x_in_span = 0.0; // set from the preceding at the START when a new cluster starts. + + if (it_span->start.char_byte == 0) { + // Start of an unbroken span, we might have dx, dy or rotate still to process + // (x and y are done per chunk) + if (unbroken_span.dx._set) current_x += unbroken_span.dx.computed; + if (unbroken_span.dy._set) _y_offset += unbroken_span.dy.computed; + if (unbroken_span.rotate._set) glyph_rotate = unbroken_span.rotate.computed * (M_PI/180); + } - Layout::Span new_span; + if (_flow._input_stream[unbroken_span.input_index]->Type() == TEXT_SOURCE + && unbroken_span.pango_item_index == -1) { + // style only, nothing to output + continue; + } - new_span.in_chunk = _flow._chunks.size() - 1; - new_span.line_height = unbroken_span.line_height; - new_span.in_input_stream_item = unbroken_span.input_index; - new_span.baseline_shift = 0.0; - new_span.block_progression = _block_progression; - new_span.text_orientation = unbroken_span.text_orientation; - if ((_flow._input_stream[unbroken_span.input_index]->Type() == TEXT_SOURCE) && (new_span.font = para.pango_items[unbroken_span.pango_item_index].font)) - { - new_span.font->Ref(); - new_span.font_size = unbroken_span.font_size; - new_span.direction = para.pango_items[unbroken_span.pango_item_index].item->analysis.level & 1 ? RIGHT_TO_LEFT : LEFT_TO_RIGHT; - new_span.input_stream_first_character = Glib::ustring::const_iterator(unbroken_span.input_stream_first_character.base() + it_span->start.char_byte); - } else { // a control code - new_span.font = NULL; - new_span.font_size = new_span.line_height.emSize(); - new_span.direction = para.direction; - } + Layout::Span new_span; + + new_span.in_chunk = _flow._chunks.size() - 1; + new_span.line_height = unbroken_span.line_height; + new_span.in_input_stream_item = unbroken_span.input_index; + new_span.baseline_shift = 0.0; + new_span.block_progression = _block_progression; + new_span.text_orientation = unbroken_span.text_orientation; + if ((_flow._input_stream[unbroken_span.input_index]->Type() == TEXT_SOURCE) && (new_span.font = para.pango_items[unbroken_span.pango_item_index].font)) + { + new_span.font->Ref(); + new_span.font_size = unbroken_span.font_size; + new_span.direction = para.pango_items[unbroken_span.pango_item_index].item->analysis.level & 1 ? RIGHT_TO_LEFT : LEFT_TO_RIGHT; + new_span.input_stream_first_character = Glib::ustring::const_iterator(unbroken_span.input_stream_first_character.base() + it_span->start.char_byte); + } else { // a control code + new_span.font = NULL; + new_span.font_size = new_span.line_height.emSize(); + new_span.direction = para.direction; + } - if (new_span.direction == para.direction) { - current_x -= counter_directional_width_remaining; - counter_directional_width_remaining = 0.0; - } else if (new_span.direction != previous_direction) { - // measure width of spans we need to switch round - counter_directional_width_remaining = 0.0; - std::vector::const_iterator it_following_span; - for (it_following_span = it_span ; it_following_span != it_chunk->broken_spans.end() ; it_following_span++) { - Layout::Direction following_span_progression = static_cast(_flow._input_stream[it_following_span->start.iter_span->input_index])->styleGetBlockProgression(); - if (!Layout::_directions_are_orthogonal(following_span_progression, _block_progression)) { - if (it_following_span->start.iter_span->pango_item_index == -1) { // when the span came from a control code - if (new_span.direction != para.direction) break; - } else - if (new_span.direction != (para.pango_items[it_following_span->start.iter_span->pango_item_index].item->analysis.level & 1 ? RIGHT_TO_LEFT : LEFT_TO_RIGHT)) break; - } - counter_directional_width_remaining += direction_sign * (it_following_span->width + it_following_span->whitespace_count * add_to_each_whitespace); + if (new_span.direction == para.direction) { + current_x -= counter_directional_width_remaining; + counter_directional_width_remaining = 0.0; + } else if (new_span.direction != previous_direction) { + // measure width of spans we need to switch round + counter_directional_width_remaining = 0.0; + std::vector::const_iterator it_following_span; + for (it_following_span = it_span ; it_following_span != it_chunk->broken_spans.end() ; it_following_span++) { + Layout::Direction following_span_progression = static_cast(_flow._input_stream[it_following_span->start.iter_span->input_index])->styleGetBlockProgression(); + if (!Layout::_directions_are_orthogonal(following_span_progression, _block_progression)) { + if (it_following_span->start.iter_span->pango_item_index == -1) { // when the span came from a control code + if (new_span.direction != para.direction) break; + } else + if (new_span.direction != (para.pango_items[it_following_span->start.iter_span->pango_item_index].item->analysis.level & 1 ? RIGHT_TO_LEFT : LEFT_TO_RIGHT)) break; } - current_x += counter_directional_width_remaining; - counter_directional_width_remaining = 0.0; // we want to go increasingly negative + counter_directional_width_remaining += direction_sign * (it_following_span->width + it_following_span->whitespace_count * add_to_each_whitespace); } - new_span.x_start = current_x; - - if (_flow._input_stream[unbroken_span.input_index]->Type() == TEXT_SOURCE) { - // the span is set up, push the glyphs and chars - InputStreamTextSource const *text_source = static_cast(_flow._input_stream[unbroken_span.input_index]); - Glib::ustring::const_iterator iter_source_text = Glib::ustring::const_iterator(unbroken_span.input_stream_first_character.base() + it_span->start.char_byte) ; - unsigned char_index_in_unbroken_span = it_span->start.char_index; - double font_size_multiplier = new_span.font_size / (PANGO_SCALE * _font_factory_size_multiplier); - int log_cluster_size_glyphs = 0; // Number of glyphs in this log_cluster - int log_cluster_size_chars = 0; // Number of characters in this log_cluster - unsigned end_byte = 0; - - for (unsigned glyph_index = it_span->start_glyph_index ; glyph_index < it_span->end_glyph_index ; glyph_index++) { - unsigned char_byte = iter_source_text.base() - unbroken_span.input_stream_first_character.base(); - int newcluster = 0; - if (unbroken_span.glyph_string->glyphs[glyph_index].attr.is_cluster_start){ - newcluster = 1; - x_in_span = x_in_span_last; - } - - if (unbroken_span.glyph_string->log_clusters[glyph_index] < (int)unbroken_span.text_bytes - && *iter_source_text == UNICODE_SOFT_HYPHEN - && glyph_index + 1 != it_span->end_glyph_index) { - // if we're looking at a soft hyphen and it's not the last glyph in the - // chunk we don't draw the glyph but we still need to add to _characters - Layout::Character new_character; - new_character.in_span = _flow._spans.size(); // the span hasn't been added yet, so no -1 - new_character.char_attributes = para.char_attributes[unbroken_span.char_index_in_para + char_index_in_unbroken_span]; - new_character.in_glyph = -1; - _flow._characters.push_back(new_character); - iter_source_text++; - char_index_in_unbroken_span++; - while (glyph_index < (unsigned)unbroken_span.glyph_string->num_glyphs - && unbroken_span.glyph_string->log_clusters[glyph_index] == (int)char_byte) - glyph_index++; - glyph_index--; - continue; - } + current_x += counter_directional_width_remaining; + counter_directional_width_remaining = 0.0; // we want to go increasingly negative + } + new_span.x_start = current_x; + + if (_flow._input_stream[unbroken_span.input_index]->Type() == TEXT_SOURCE) { + // the span is set up, push the glyphs and chars + InputStreamTextSource const *text_source = static_cast(_flow._input_stream[unbroken_span.input_index]); + Glib::ustring::const_iterator iter_source_text = Glib::ustring::const_iterator(unbroken_span.input_stream_first_character.base() + it_span->start.char_byte) ; + unsigned char_index_in_unbroken_span = it_span->start.char_index; + double font_size_multiplier = new_span.font_size / (PANGO_SCALE * _font_factory_size_multiplier); + int log_cluster_size_glyphs = 0; // Number of glyphs in this log_cluster + int log_cluster_size_chars = 0; // Number of characters in this log_cluster + unsigned end_byte = 0; + + for (unsigned glyph_index = it_span->start_glyph_index ; glyph_index < it_span->end_glyph_index ; glyph_index++) { + unsigned char_byte = iter_source_text.base() - unbroken_span.input_stream_first_character.base(); + int newcluster = 0; + if (unbroken_span.glyph_string->glyphs[glyph_index].attr.is_cluster_start){ + newcluster = 1; + x_in_span = x_in_span_last; + } - // create the Layout::Glyph - PangoGlyphInfo *unbroken_span_glyph_info = &unbroken_span.glyph_string->glyphs[glyph_index]; - Layout::Glyph new_glyph; - new_glyph.glyph = unbroken_span_glyph_info->glyph; - new_glyph.in_character = _flow._characters.size(); - new_glyph.rotation = glyph_rotate; - new_glyph.orientation = ORIENTATION_UPRIGHT; // Only effects vertical text - - // We may have scaled font size to fit textLength; now, if - // @lengthAdjust=spacingAndGlyphs, this scaling must be only horizontal, - // not vertical, so we unscale it back vertically during output - if (_flow.lengthAdjust == Inkscape::Text::Layout::LENGTHADJUST_SPACINGANDGLYPHS) - new_glyph.vertical_scale = 1.0 / _flow.getTextLengthMultiplierDue(); - else - new_glyph.vertical_scale = 1.0; - - // Position glyph -------------------- - new_glyph.x = current_x + unbroken_span_glyph_info->geometry.x_offset * font_size_multiplier; - new_glyph.y =_y_offset; - - // y-coordinate is flipped between vertical and horizontal text... delta_y is common offset but applied with opposite sign - double delta_y = unbroken_span_glyph_info->geometry.y_offset * font_size_multiplier + unbroken_span.baseline_shift; - SPCSSBaseline dominant_baseline = _flow._blockBaseline(); - - if (_block_progression == LEFT_TO_RIGHT || _block_progression == RIGHT_TO_LEFT) { - // Vertical text - - // Default dominant baseline is determined by overall block (i.e. ) 'text-orientation' value. - if( _flow._blockTextOrientation() != SP_CSS_TEXT_ORIENTATION_SIDEWAYS ) { - if( dominant_baseline == SP_CSS_BASELINE_AUTO ) dominant_baseline = SP_CSS_BASELINE_CENTRAL; - } else { - if( dominant_baseline == SP_CSS_BASELINE_AUTO ) dominant_baseline = SP_CSS_BASELINE_ALPHABETIC; - } + if (unbroken_span.glyph_string->log_clusters[glyph_index] < (int)unbroken_span.text_bytes + && *iter_source_text == UNICODE_SOFT_HYPHEN + && glyph_index + 1 != it_span->end_glyph_index) { + // if we're looking at a soft hyphen and it's not the last glyph in the + // chunk we don't draw the glyph but we still need to add to _characters + Layout::Character new_character; + new_character.in_span = _flow._spans.size(); // the span hasn't been added yet, so no -1 + new_character.char_attributes = para.char_attributes[unbroken_span.char_index_in_para + char_index_in_unbroken_span]; + new_character.in_glyph = -1; + _flow._characters.push_back(new_character); + iter_source_text++; + char_index_in_unbroken_span++; + while (glyph_index < (unsigned)unbroken_span.glyph_string->num_glyphs + && unbroken_span.glyph_string->log_clusters[glyph_index] == (int)char_byte) + glyph_index++; + glyph_index--; + continue; + } - new_glyph.y += delta_y; + // create the Layout::Glyph + PangoGlyphInfo *unbroken_span_glyph_info = &unbroken_span.glyph_string->glyphs[glyph_index]; + Layout::Glyph new_glyph; + new_glyph.glyph = unbroken_span_glyph_info->glyph; + new_glyph.in_character = _flow._characters.size(); + new_glyph.rotation = glyph_rotate; + new_glyph.orientation = ORIENTATION_UPRIGHT; // Only effects vertical text + + // We may have scaled font size to fit textLength; now, if + // @lengthAdjust=spacingAndGlyphs, this scaling must be only horizontal, + // not vertical, so we unscale it back vertically during output + if (_flow.lengthAdjust == Inkscape::Text::Layout::LENGTHADJUST_SPACINGANDGLYPHS) + new_glyph.vertical_scale = 1.0 / _flow.getTextLengthMultiplierDue(); + else + new_glyph.vertical_scale = 1.0; + + // Position glyph -------------------- + new_glyph.x = current_x + unbroken_span_glyph_info->geometry.x_offset * font_size_multiplier; + new_glyph.y =_y_offset; + + // y-coordinate is flipped between vertical and horizontal text... delta_y is common offset but applied with opposite sign + double delta_y = unbroken_span_glyph_info->geometry.y_offset * font_size_multiplier + unbroken_span.baseline_shift; + SPCSSBaseline dominant_baseline = _flow._blockBaseline(); + + if (_block_progression == LEFT_TO_RIGHT || _block_progression == RIGHT_TO_LEFT) { + // Vertical text + + // Default dominant baseline is determined by overall block (i.e. ) 'text-orientation' value. + if( _flow._blockTextOrientation() != SP_CSS_TEXT_ORIENTATION_SIDEWAYS ) { + if( dominant_baseline == SP_CSS_BASELINE_AUTO ) dominant_baseline = SP_CSS_BASELINE_CENTRAL; + } else { + if( dominant_baseline == SP_CSS_BASELINE_AUTO ) dominant_baseline = SP_CSS_BASELINE_ALPHABETIC; + } - // TODO: Should also check 'glyph_orientation_vertical' if 'text-orientation' is unset... - if( new_span.text_orientation == SP_CSS_TEXT_ORIENTATION_SIDEWAYS || - (new_span.text_orientation == SP_CSS_TEXT_ORIENTATION_MIXED && - para.pango_items[unbroken_span.pango_item_index].item->analysis.gravity == 0) ) { + new_glyph.y += delta_y; - // Sideways orientation (Latin characters, CJK punctuation), 90deg rotation done at output stage. zzzzzzz - new_glyph.orientation = ORIENTATION_SIDEWAYS; + // TODO: Should also check 'glyph_orientation_vertical' if 'text-orientation' is unset... + if( new_span.text_orientation == SP_CSS_TEXT_ORIENTATION_SIDEWAYS || + (new_span.text_orientation == SP_CSS_TEXT_ORIENTATION_MIXED && + para.pango_items[unbroken_span.pango_item_index].item->analysis.gravity == 0) ) { - new_glyph.y -= new_span.font_size * para.pango_items[unbroken_span.pango_item_index].font->GetBaselines()[ dominant_baseline ]; - new_glyph.width = new_span.font_size * para.pango_items[unbroken_span.pango_item_index].font->Advance(unbroken_span_glyph_info->glyph, false); + // Sideways orientation (Latin characters, CJK punctuation), 90deg rotation done at output stage. zzzzzzz + new_glyph.orientation = ORIENTATION_SIDEWAYS; - } else { - // Upright orientation + new_glyph.y -= new_span.font_size * para.pango_items[unbroken_span.pango_item_index].font->GetBaselines()[ dominant_baseline ]; + new_glyph.width = new_span.font_size * para.pango_items[unbroken_span.pango_item_index].font->Advance(unbroken_span_glyph_info->glyph, false); - new_glyph.x += new_span.line_height.ascent; + } else { + // Upright orientation - // Glyph reference point is center (shift: left edge to center glyph) - new_glyph.y -= unbroken_span_glyph_info->geometry.width * 0.5 * font_size_multiplier; - new_glyph.y -= new_span.font_size * (para.pango_items[unbroken_span.pango_item_index].font->GetBaselines()[ dominant_baseline ] - - para.pango_items[unbroken_span.pango_item_index].font->GetBaselines()[ SP_CSS_BASELINE_CENTRAL ] ); + new_glyph.x += new_span.line_height.ascent; - new_glyph.width = new_span.font_size * para.pango_items[unbroken_span.pango_item_index].font->Advance(unbroken_span_glyph_info->glyph, true); - if( new_glyph.width == 0 ) { - new_glyph.width = unbroken_span_glyph_info->geometry.width * font_size_multiplier; - } + // Glyph reference point is center (shift: left edge to center glyph) + new_glyph.y -= unbroken_span_glyph_info->geometry.width * 0.5 * font_size_multiplier; + new_glyph.y -= new_span.font_size * (para.pango_items[unbroken_span.pango_item_index].font->GetBaselines()[ dominant_baseline ] - + para.pango_items[unbroken_span.pango_item_index].font->GetBaselines()[ SP_CSS_BASELINE_CENTRAL ] ); + new_glyph.width = new_span.font_size * para.pango_items[unbroken_span.pango_item_index].font->Advance(unbroken_span_glyph_info->glyph, true); + if( new_glyph.width == 0 ) { + new_glyph.width = unbroken_span_glyph_info->geometry.width * font_size_multiplier; } - } else { - // Horizontal text - if( dominant_baseline == SP_CSS_BASELINE_AUTO ) dominant_baseline = SP_CSS_BASELINE_ALPHABETIC; - - new_glyph.y -= delta_y; - new_glyph.y += new_span.font_size * para.pango_items[unbroken_span.pango_item_index].font->GetBaselines()[ dominant_baseline ]; - - new_glyph.width = unbroken_span_glyph_info->geometry.width * font_size_multiplier; - if ((new_glyph.width == 0) && (para.pango_items[unbroken_span.pango_item_index].font)) - new_glyph.width = new_span.font_size * para.pango_items[unbroken_span.pango_item_index].font->Advance(unbroken_span_glyph_info->glyph, false); - // for some reason pango returns zero width for invalid glyph characters (those empty boxes), so go to freetype for the info } + } else { + // Horizontal text + if( dominant_baseline == SP_CSS_BASELINE_AUTO ) dominant_baseline = SP_CSS_BASELINE_ALPHABETIC; - if (new_span.direction == RIGHT_TO_LEFT) { - // pango wanted to give us glyphs in visual order but we refused, so we need to work - // out where the cluster start is ourselves - double cluster_width = 0.0; - for (unsigned rtl_index = glyph_index; rtl_index < it_span->end_glyph_index ; rtl_index++) { - if (unbroken_span.glyph_string->glyphs[rtl_index].attr.is_cluster_start && rtl_index != glyph_index) - break; - if (_block_progression == LEFT_TO_RIGHT || _block_progression == RIGHT_TO_LEFT) - // Vertical text - cluster_width += new_span.font_size * para.pango_items[unbroken_span.pango_item_index].font->Advance(unbroken_span.glyph_string->glyphs[rtl_index].glyph, true); - else - // Horizontal text - cluster_width += font_size_multiplier * unbroken_span.glyph_string->glyphs[rtl_index].geometry.width; - } - new_glyph.x -= cluster_width; + new_glyph.y -= delta_y; + new_glyph.y += new_span.font_size * para.pango_items[unbroken_span.pango_item_index].font->GetBaselines()[ dominant_baseline ]; + + new_glyph.width = unbroken_span_glyph_info->geometry.width * font_size_multiplier; + if ((new_glyph.width == 0) && (para.pango_items[unbroken_span.pango_item_index].font)) + new_glyph.width = new_span.font_size * para.pango_items[unbroken_span.pango_item_index].font->Advance(unbroken_span_glyph_info->glyph, false); + // for some reason pango returns zero width for invalid glyph characters (those empty boxes), so go to freetype for the info + } + + + if (new_span.direction == RIGHT_TO_LEFT) { + // pango wanted to give us glyphs in visual order but we refused, so we need to work + // out where the cluster start is ourselves + double cluster_width = 0.0; + for (unsigned rtl_index = glyph_index; rtl_index < it_span->end_glyph_index ; rtl_index++) { + if (unbroken_span.glyph_string->glyphs[rtl_index].attr.is_cluster_start && rtl_index != glyph_index) + break; + if (_block_progression == LEFT_TO_RIGHT || _block_progression == RIGHT_TO_LEFT) + // Vertical text + cluster_width += new_span.font_size * para.pango_items[unbroken_span.pango_item_index].font->Advance(unbroken_span.glyph_string->glyphs[rtl_index].glyph, true); + else + // Horizontal text + cluster_width += font_size_multiplier * unbroken_span.glyph_string->glyphs[rtl_index].geometry.width; } - _flow._glyphs.push_back(new_glyph); - - // create the Layout::Character(s) - double advance_width = new_glyph.width; - if (newcluster){ - newcluster = 0; - // find where the text ends for this log_cluster - end_byte = it_span->start.iter_span->text_bytes; // Upper limit - for(int next_glyph_index = glyph_index+1; next_glyph_index < unbroken_span.glyph_string->num_glyphs; next_glyph_index++){ - if(unbroken_span.glyph_string->glyphs[next_glyph_index].attr.is_cluster_start){ - end_byte = unbroken_span.glyph_string->log_clusters[next_glyph_index]; - break; - } - } - // Figure out how many glyphs and characters are in the log_cluster. - log_cluster_size_glyphs = 0; - log_cluster_size_chars = 0; - for(; log_cluster_size_glyphs + glyph_index < it_span->end_glyph_index; log_cluster_size_glyphs++){ - if(unbroken_span.glyph_string->log_clusters[glyph_index ] != - unbroken_span.glyph_string->log_clusters[glyph_index + log_cluster_size_glyphs])break; - } - Glib::ustring::const_iterator lclist = iter_source_text; - unsigned lcb = char_byte; - while(lcb < end_byte){ - log_cluster_size_chars++; - lclist++; - lcb = lclist.base() - unbroken_span.input_stream_first_character.base(); + new_glyph.x -= cluster_width; + } + _flow._glyphs.push_back(new_glyph); + + // create the Layout::Character(s) + double advance_width = new_glyph.width; + if (newcluster){ + newcluster = 0; + // find where the text ends for this log_cluster + end_byte = it_span->start.iter_span->text_bytes; // Upper limit + for(int next_glyph_index = glyph_index+1; next_glyph_index < unbroken_span.glyph_string->num_glyphs; next_glyph_index++){ + if(unbroken_span.glyph_string->glyphs[next_glyph_index].attr.is_cluster_start){ + end_byte = unbroken_span.glyph_string->log_clusters[next_glyph_index]; + break; } } - while (char_byte < end_byte) { - /* Hack to survive ligatures: in log_cluster keep the number of available chars >= number of glyphs remaining. - When there are no ligatures these two sizes are always the same. - */ - if(log_cluster_size_chars < log_cluster_size_glyphs){ - log_cluster_size_glyphs--; - break; - } - Layout::Character new_character; - new_character.in_span = _flow._spans.size(); - new_character.x = x_in_span; - new_character.char_attributes = para.char_attributes[unbroken_span.char_index_in_para + char_index_in_unbroken_span]; - new_character.in_glyph = _flow._glyphs.size() - 1; - _flow._characters.push_back(new_character); - if (new_character.char_attributes.is_white) - advance_width += text_source->style->word_spacing.computed * _flow.getTextLengthMultiplierDue() + add_to_each_whitespace; // justification - if (new_character.char_attributes.is_cursor_position) - advance_width += text_source->style->letter_spacing.computed * _flow.getTextLengthMultiplierDue(); - advance_width += _flow.getTextLengthIncrementDue(); - iter_source_text++; - char_index_in_unbroken_span++; - char_byte = iter_source_text.base() - unbroken_span.input_stream_first_character.base(); - log_cluster_size_chars--; + // Figure out how many glyphs and characters are in the log_cluster. + log_cluster_size_glyphs = 0; + log_cluster_size_chars = 0; + for(; log_cluster_size_glyphs + glyph_index < it_span->end_glyph_index; log_cluster_size_glyphs++){ + if(unbroken_span.glyph_string->log_clusters[glyph_index ] != + unbroken_span.glyph_string->log_clusters[glyph_index + log_cluster_size_glyphs])break; } - - advance_width *= direction_sign; - if (new_span.direction != para.direction) { - counter_directional_width_remaining -= advance_width; - current_x -= advance_width; - x_in_span_last -= advance_width; - } else { - current_x += advance_width; - x_in_span_last += advance_width; + Glib::ustring::const_iterator lclist = iter_source_text; + unsigned lcb = char_byte; + while(lcb < end_byte){ + log_cluster_size_chars++; + lclist++; + lcb = lclist.base() - unbroken_span.input_stream_first_character.base(); } } - } else if (_flow._input_stream[unbroken_span.input_index]->Type() == CONTROL_CODE) { - current_x += static_cast(_flow._input_stream[unbroken_span.input_index])->width; - } + while (char_byte < end_byte) { + /* Hack to survive ligatures: in log_cluster keep the number of available chars >= number of glyphs remaining. + When there are no ligatures these two sizes are always the same. + */ + if(log_cluster_size_chars < log_cluster_size_glyphs){ + log_cluster_size_glyphs--; + break; + } + Layout::Character new_character; + new_character.in_span = _flow._spans.size(); + new_character.x = x_in_span; + new_character.char_attributes = para.char_attributes[unbroken_span.char_index_in_para + char_index_in_unbroken_span]; + new_character.in_glyph = _flow._glyphs.size() - 1; + _flow._characters.push_back(new_character); + if (new_character.char_attributes.is_white) + advance_width += text_source->style->word_spacing.computed * _flow.getTextLengthMultiplierDue() + add_to_each_whitespace; // justification + if (new_character.char_attributes.is_cursor_position) + advance_width += text_source->style->letter_spacing.computed * _flow.getTextLengthMultiplierDue(); + advance_width += _flow.getTextLengthIncrementDue(); + iter_source_text++; + char_index_in_unbroken_span++; + char_byte = iter_source_text.base() - unbroken_span.input_stream_first_character.base(); + log_cluster_size_chars--; + } - new_span.x_end = new_span.x_start + x_in_span_last; - _flow._spans.push_back(new_span); - previous_direction = new_span.direction; + advance_width *= direction_sign; + if (new_span.direction != para.direction) { + counter_directional_width_remaining -= advance_width; + current_x -= advance_width; + x_in_span_last -= advance_width; + } else { + current_x += advance_width; + x_in_span_last += advance_width; + } + } + } else if (_flow._input_stream[unbroken_span.input_index]->Type() == CONTROL_CODE) { + current_x += static_cast(_flow._input_stream[unbroken_span.input_index])->width; } - // end adding spans to the list, on to the next chunk... - } - TRACE((" End _outputLine\n")); - } -/* *********************************************************************************************************/ -// Setup and top-level functions - - /** initialises the ScanlineMaker for the first shape in the flow, or - the infinite version if we're not doing wrapping. */ - void _createFirstScanlineMaker() - { - _current_shape_index = 0; - if (_flow._input_wrap_shapes.empty()) { - // create the special no-wrapping infinite scanline maker - double initial_x = 0, initial_y = 0; - InputStreamTextSource const *text_source = static_cast(_flow._input_stream.front()); - if (!text_source->x.empty()) - initial_x = text_source->x.front().computed; - if (!text_source->y.empty()) - initial_y = text_source->y.front().computed; - _scanline_maker = new InfiniteScanlineMaker(initial_x, initial_y, _block_progression); - TRACE((" wrapping disabled\n")); + new_span.x_end = new_span.x_start + x_in_span_last; + _flow._spans.push_back(new_span); + previous_direction = new_span.direction; } - else { - _scanline_maker = new ShapeScanlineMaker(_flow._input_wrap_shapes[_current_shape_index].shape, _block_progression); - TRACE((" begin wrap shape 0\n")); - } - } - -public: - Calculator(Layout *text_flow) - : _flow(*text_flow) {} - - bool calculate(); -}; - -/* fixme: I don't like the fact that InputItemInfo etc. use the default copy constructor and - * operator= (and thus don't involve incrementing reference counts), yet they provide a free method - * that does delete or Unref. - * - * I suggest using the garbage collector to manage deletion. - */ -void Layout::Calculator::InputItemInfo::free() -{ - if (sub_flow) { - delete sub_flow; - sub_flow = NULL; + // end adding spans to the list, on to the next chunk... } + TRACE((" End _outputLine\n")); } -void Layout::Calculator::PangoItemInfo::free() +/** + * Initialises the ScanlineMaker for the first shape in the flow, + * or the infinite version if we're not doing wrapping. + */ +void Layout::Calculator::_createFirstScanlineMaker() { - if (item) { - pango_item_free(item); - item = NULL; + _current_shape_index = 0; + if (_flow._input_wrap_shapes.empty()) { + // create the special no-wrapping infinite scanline maker + double initial_x = 0, initial_y = 0; + InputStreamTextSource const *text_source = static_cast(_flow._input_stream.front()); + if (!text_source->x.empty()) + initial_x = text_source->x.front().computed; + if (!text_source->y.empty()) + initial_y = text_source->y.front().computed; + _scanline_maker = new InfiniteScanlineMaker(initial_x, initial_y, _block_progression); + TRACE((" wrapping disabled\n")); } - if (font) { - font->Unref(); - font = NULL; + else { + _scanline_maker = new ShapeScanlineMaker(_flow._input_wrap_shapes[_current_shape_index].shape, _block_progression); + TRACE((" begin wrap shape 0\n")); } } @@ -1690,6 +1679,46 @@ bool Layout::Calculator::_buildChunksInScanRun(ParagraphInfo const ¶, return true; } +#ifdef DEBUG_LAYOUT_TNG_COMPUTE +/** + * For debugging, not called in distributed code + * + * Input: para->first_input_index, para->pango_items + */ +static void Layout::Calculator::dumpPangoItemsOut(ParagraphInfo *para){ + std::cout << "Pango items: " << para->pango_items.size() << std::endl; + font_factory * factory = font_factory::Default(); + for(unsigned pidx = 0 ; pidx < para->pango_items.size(); pidx++){ + std::cout + << "idx: " << pidx + << " offset: " + << para->pango_items[pidx].item->offset + << " length: " + << para->pango_items[pidx].item->length + << " font: " + << factory->ConstructFontSpecification( para->pango_items[pidx].font ) + << std::endl; + } +} + +/** + * For debugging, not called in distributed code + * + * Input: para->first_input_index, para->pango_items + */ +static void Layout::Calculator::dumpUnbrokenSpans(ParagraphInfo *para){ + std::cout << "Unbroken Spans: " << para->unbroken_spans.size() << std::endl; + for(unsigned uidx = 0 ; uidx < para->unbroken_spans.size(); uidx++){ + std::cout + << "idx: " << uidx + << " pango_item_index: " << para->unbroken_spans[uidx].pango_item_index + << " input_index: " << para->unbroken_spans[uidx].input_index + << " char_index_in_para: " << para->unbroken_spans[uidx].char_index_in_para + << " text_bytes: " << para->unbroken_spans[uidx].text_bytes + << std::endl; + } +} +#endif //DEBUG_LAYOUT_TNG_COMPUTE /** The management function to start the whole thing off. */ bool Layout::Calculator::calculate() -- cgit v1.2.3 From 74bbf0973bb755dd058867dee6fc59ab3cc88974 Mon Sep 17 00:00:00 2001 From: Michael Soegtrop Date: Sun, 11 Jun 2017 16:14:52 +0000 Subject: Lpe bool fix --- src/live_effects/lpe-bool.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/live_effects/lpe-bool.h b/src/live_effects/lpe-bool.h index 1c0aa0243..ce46f14d1 100644 --- a/src/live_effects/lpe-bool.h +++ b/src/live_effects/lpe-bool.h @@ -42,7 +42,7 @@ public: inline friend bool_op to_bool_op(bool_op_ex val) { assert(val <= bool_op_ex_slice); - (bool_op) val; + return (bool_op) val; } private: -- cgit v1.2.3