diff options
| author | su_v <suv-sf@users.sourceforge.net> | 2014-06-15 09:08:03 +0000 |
|---|---|---|
| committer | ~suv <suv-sf@users.sourceforge.net> | 2014-06-15 09:08:03 +0000 |
| commit | ccacefacda584c206625b7759001d3d8c531cfed (patch) | |
| tree | 8c00cc50f5bb400b62639c06c234d11fa982502b /src | |
| parent | update to trunk (r13407) (diff) | |
| parent | Allow symbol zooming independent of icon screen size. (diff) | |
| download | inkscape-ccacefacda584c206625b7759001d3d8c531cfed.tar.gz inkscape-ccacefacda584c206625b7759001d3d8c531cfed.zip | |
update to trunk (r13425)
(bzr r13398.1.3)
Diffstat (limited to 'src')
40 files changed, 949 insertions, 1392 deletions
diff --git a/src/box3d-side.cpp b/src/box3d-side.cpp index dfccb63bf..a5e7eaa94 100644 --- a/src/box3d-side.cpp +++ b/src/box3d-side.cpp @@ -213,6 +213,8 @@ void Box3DSide::set_shape() { bool success = this->performPathEffect(c_lpe); if (success) { + sp_lpe_item_apply_to_mask(this); + sp_lpe_item_apply_to_clippath(this); this->setCurveInsync(c_lpe, TRUE); } diff --git a/src/desktop-style.cpp b/src/desktop-style.cpp index 37f537cc5..f6347e5c0 100644 --- a/src/desktop-style.cpp +++ b/src/desktop-style.cpp @@ -211,11 +211,17 @@ sp_desktop_set_style(SPDesktop *desktop, SPCSSAttr *css, bool change, bool write for (GSList const *i = desktop->selection->itemList(); i != NULL; i = i->next) { - // If not text, don't apply text attributes (can a group have text attributes?) + // If not text, don't apply text attributes (can a group have text attributes? Yes! FIXME) if ( SP_IS_TEXT(i->data) || SP_IS_FLOWTEXT(i->data) || SP_IS_TSPAN(i->data) || SP_IS_TREF(i->data) || SP_IS_TEXTPATH(i->data) || SP_IS_FLOWDIV(i->data) || SP_IS_FLOWPARA(i->data) || SP_IS_FLOWTSPAN(i->data)) { + // If any font property has changed, then we have written out the font + // properties in longhand and we need to remove the 'font' shorthand. + if( !sp_repr_css_property_is_unset(css, "font-family") ) { + sp_repr_css_unset_property(css, "font"); + } + sp_desktop_apply_css_recursive(SP_OBJECT(i->data), css, true); } else { diff --git a/src/document.cpp b/src/document.cpp index dc7ed254c..f79a00178 100644 --- a/src/document.cpp +++ b/src/document.cpp @@ -1529,7 +1529,7 @@ void SPDocument::setModifiedSinceSave(bool modified) { /** - * Paste SVG defs from the document retrieved from the clipboard into the active document. + * Paste SVG defs from the document retrieved from the clipboard or imported document into the active document. * @param clipdoc The document to paste. * @pre @c clipdoc != NULL and pasting into the active document is possible. */ @@ -1540,27 +1540,117 @@ void SPDocument::importDefs(SPDocument *source) Inkscape::XML::Node *target_defs = this->getDefs()->getRepr(); prevent_id_clashes(source, this); + + int stagger=0; + /* Note, "clipboard" throughout the comments means "the document that is either the clipboard + or an imported document", as importDefs is called in both contexts. + + The order of the records in the clipboard is unpredictable and there may be both + forward and backwards references to other records within it. There may be definitions in + the clipboard that duplicate definitions in the present document OR that duplicate other + definitions in the clipboard. (Inkscape will not have created these, but they may be read + in from other SVG sources.) + + There are 3 passes to clean this up: + + In the first find and mark definitions in the clipboard that are duplicates of those in the + present document. Change the ID to "RESERVED_FOR_INKSCAPE_DUPLICATE_DEF_XXXXXXXXX". + (Inkscape will not reuse an ID, and the XXXXXXXXX keeps it from automatically creating new ones.) + References in the clipboard to the old clipboard name are converted to the name used + in the current document. + + In the second find and mark definitions in the clipboard that are duplicates of earlier + definitions in the clipbard. Unfortunately this is O(n^2) and could be very slow for a large + SVG with thousands of definitions. As before, references are adjusted to reflect the name + going forward. + + In the final cycle copy over those records not marked with that ID. + + If an SVG file uses the special ID it will cause problems! + + If this function is called because of the paste of a true clipboard the caller will have passed in a + COPY of the clipboard items. That is good, because this routine modifies that document. If the calling + behavior ever changes, so that the same document is passed in on multiple pastes, this routine will break + as in the following example: + 1. Paste clipboard containing B same as A into document containing A. Result, B is dropped + and all references to it will point to A. + 2. Paste same clipboard into a new document. It will not contain A, so there will be unsatisfied + references in that window. + */ + + std::string DuplicateDefString = "RESERVED_FOR_INKSCAPE_DUPLICATE_DEF"; + + /* First pass: remove duplicates in clipboard of definitions in document */ for (Inkscape::XML::Node *def = defs->firstChild() ; def ; def = def->next()) { - gboolean duplicate = false; + /* If this clipboard has been pasted into one document, and is now being pasted into another, + or pasted again into the same, it will already have been processed. If we detect that then + skip the rest of this pass. */ + + Glib::ustring defid = def->attribute("id"); + if( defid.find( DuplicateDefString ) != Glib::ustring::npos )break; + SPObject *src = source->getObjectByRepr(def); // Prevent duplicates of solid swatches by checking if equivalent swatch already exists if (src && SP_IS_GRADIENT(src)) { - SPGradient *gr = SP_GRADIENT(src); + SPGradient *s_gr = SP_GRADIENT(src); for (SPObject *trg = this->getDefs()->firstChild() ; trg ; trg = trg->getNext()) { - if (trg && SP_IS_GRADIENT(trg) && src != trg) { - if (gr->isEquivalent(SP_GRADIENT(trg)) && - gr->isAligned(SP_GRADIENT(trg))) { - // Change object references to the existing equivalent gradient - change_def_references(src, trg); - duplicate = true; - break; + if (trg && (src != trg) && SP_IS_GRADIENT(trg)) { + SPGradient *t_gr = SP_GRADIENT(trg); + if (t_gr && s_gr->isEquivalent(t_gr)) { + // Change object references to the existing equivalent gradient + Glib::ustring newid = trg->getId(); + if(newid != defid){ // id could be the same if it is a second paste into the same document + change_def_references(src, trg); + } + gchar *longid = g_strdup_printf("%s_%9.9d", DuplicateDefString.c_str(), stagger++); + def->setAttribute("id", longid ); + g_free(longid); + // do NOT break here, there could be more than 1 duplicate! } } } } + } + + /* Second pass: remove duplicates in clipboard of earlier definitions in clipboard */ + for (Inkscape::XML::Node *def = defs->firstChild() ; def ; def = def->next()) { + Glib::ustring defid = def->attribute("id"); + if( defid.find( DuplicateDefString ) != Glib::ustring::npos )continue; // this one already handled + SPObject *src = source->getObjectByRepr(def); + if (src && SP_IS_GRADIENT(src)) { + SPGradient *s_gr = SP_GRADIENT(src); + for (Inkscape::XML::Node *laterDef = def->next() ; laterDef ; laterDef = laterDef->next()) { + SPObject *trg = source->getObjectByRepr(laterDef); + if(trg && (src != trg) && SP_IS_GRADIENT(trg)) { + Glib::ustring newid = trg->getId(); + if( newid.find( DuplicateDefString ) != Glib::ustring::npos )continue; // this one already handled + SPGradient *t_gr = SP_GRADIENT(trg); + if (t_gr && s_gr->isEquivalent(t_gr)) { + // Change object references to the existing equivalent gradient + // two id's in the clipboard should never be the same, so always change references + change_def_references(trg, src); + gchar *longid = g_strdup_printf("%s_%9.9d", DuplicateDefString.c_str(), stagger++); + laterDef->setAttribute("id", longid ); + g_free(longid); + // do NOT break here, there could be more than 1 duplicate! + } + } + } + } + } + + /* Final pass: copy over those parts which are not duplicates */ + for (Inkscape::XML::Node *def = defs->firstChild() ; def ; def = def->next()) { + + /* Ignore duplicate defs marked in the first pass */ + Glib::ustring defid = def->attribute("id"); + if( defid.find( DuplicateDefString ) != Glib::ustring::npos )continue; + + bool duplicate = false; + SPObject *src = source->getObjectByRepr(def); // Prevent duplication of symbols... could be more clever. // The tag "_inkscape_duplicate" is added to "id" by ClipboardManagerImpl::copySymbol(). @@ -1597,7 +1687,6 @@ void SPDocument::importDefs(SPDocument *source) Inkscape::GC::release(dup); } } - } /* diff --git a/src/extension/CMakeLists.txt b/src/extension/CMakeLists.txt index 759c704f0..47292fd97 100644 --- a/src/extension/CMakeLists.txt +++ b/src/extension/CMakeLists.txt @@ -49,7 +49,6 @@ set(extension_SRC internal/metafile-print.cpp internal/odf.cpp internal/latex-text-renderer.cpp - internal/pdf-input-cairo.cpp internal/pov-out.cpp internal/javafx-out.cpp internal/svg.cpp @@ -133,7 +132,6 @@ set(extension_SRC internal/metafile-inout.h internal/metafile-print.h internal/odf.h - internal/pdf-input-cairo.h internal/pdfinput/pdf-input.h internal/pdfinput/pdf-parser.h internal/pdfinput/svg-builder.h diff --git a/src/extension/dependency.cpp b/src/extension/dependency.cpp index 78012ccc8..e46b6fbd2 100644 --- a/src/extension/dependency.cpp +++ b/src/extension/dependency.cpp @@ -57,14 +57,22 @@ Dependency::Dependency (Inkscape::XML::Node * in_repr) Inkscape::GC::anchor(_repr); - const gchar * location = _repr->attribute("location"); - for (int i = 0; i < LOCATION_CNT && location != NULL; i++) { - if (!strcmp(location, _location_str[i])) { - _location = (location_t)i; - break; + if (const gchar * location = _repr->attribute("location")) { + for (int i = 0; i < LOCATION_CNT && location != NULL; i++) { + if (!strcmp(location, _location_str[i])) { + _location = (location_t)i; + break; + } + } + } else if (const gchar * location = _repr->attribute("reldir")) { + for (int i = 0; i < LOCATION_CNT && location != NULL; i++) { + if (!strcmp(location, _location_str[i])) { + _location = (location_t)i; + break; + } } } - + const gchar * type = _repr->attribute("type"); for (int i = 0; i < TYPE_CNT && type != NULL; i++) { if (!strcmp(type, _type_str[i])) { diff --git a/src/extension/extension.cpp b/src/extension/extension.cpp index 588efb521..06e35ff3e 100644 --- a/src/extension/extension.cpp +++ b/src/extension/extension.cpp @@ -111,6 +111,9 @@ Extension::Extension (Inkscape::XML::Node * in_repr, Implementation::Implementat if (!strcmp(chname, "dependency")) { _deps.push_back(new Dependency(child_repr)); } /* dependency */ + if (!strcmp(chname, "script")) { + _deps.push_back(new Dependency(child_repr->firstChild())); + } /* check command as a dependency (see LP #505920) */ if (!strcmp(chname, "options")) { silent = !strcmp( child_repr->attribute("silent"), "true" ); } diff --git a/src/extension/init.cpp b/src/extension/init.cpp index 0ff4b79c4..912d58a13 100644 --- a/src/extension/init.cpp +++ b/src/extension/init.cpp @@ -19,9 +19,6 @@ #ifdef HAVE_POPPLER # include "internal/pdfinput/pdf-input.h" #endif -#ifdef HAVE_POPPLER_GLIB -# include "internal/pdf-input-cairo.h" -#endif #include "path-prefix.h" @@ -174,11 +171,6 @@ init() #ifdef HAVE_POPPLER Internal::PdfInput::init(); #endif -#ifdef HAVE_POPPLER_GLIB - if (1) { - Internal::PdfInputCairo::init(); - } -#endif Internal::PrintEmf::init(); Internal::Emf::init(); Internal::PrintWmf::init(); diff --git a/src/extension/internal/Makefile_insert b/src/extension/internal/Makefile_insert index a31843114..125776d41 100644 --- a/src/extension/internal/Makefile_insert +++ b/src/extension/internal/Makefile_insert @@ -106,8 +106,6 @@ ink_common_sources += \ extension/internal/svg.cpp \ extension/internal/svgz.h \ extension/internal/svgz.cpp \ - extension/internal/pdf-input-cairo.cpp \ - extension/internal/pdf-input-cairo.h \ extension/internal/cairo-ps-out.h \ extension/internal/cairo-ps-out.cpp \ extension/internal/cairo-render-context.h \ diff --git a/src/extension/internal/cairo-ps-out.cpp b/src/extension/internal/cairo-ps-out.cpp index 055a30add..4defc2ab9 100644 --- a/src/extension/internal/cairo-ps-out.cpp +++ b/src/extension/internal/cairo-ps-out.cpp @@ -5,7 +5,7 @@ * Authors: * Ted Gould <ted@gould.cx> * Ulf Erikson <ulferikson@users.sf.net> - * Adib Taraben <theAdib@yahoo.com> + * Adib Taraben <theAdib@gmail.com> * Jon A. Cruz <jon@joncruz.org> * Abhishek Sharma * diff --git a/src/extension/internal/cairo-ps-out.h b/src/extension/internal/cairo-ps-out.h index 7eda3c510..b438b55b4 100644 --- a/src/extension/internal/cairo-ps-out.h +++ b/src/extension/internal/cairo-ps-out.h @@ -5,7 +5,7 @@ * Authors: * Ted Gould <ted@gould.cx> * Ulf Erikson <ulferikson@users.sf.net> - * Adib Taraben <theAdib@yahoo.com> + * Adib Taraben <theAdib@gmail.com> * Abhishek Sharma * * Copyright (C) 2004-2006 Authors diff --git a/src/extension/internal/pdf-input-cairo.cpp b/src/extension/internal/pdf-input-cairo.cpp deleted file mode 100644 index 9ce73c260..000000000 --- a/src/extension/internal/pdf-input-cairo.cpp +++ /dev/null @@ -1,680 +0,0 @@ - /* - * Simple PDF import extension using libpoppler and Cairo's SVG surface. - * - * Authors: - * miklos erdelyi - * Abhishek Sharma - * - * Copyright (C) 2007 Authors - * - * Released under GNU GPL, read the file 'COPYING' for more information - * - */ - -#ifdef HAVE_CONFIG_H -# include <config.h> -#endif - -#ifdef HAVE_POPPLER_GLIB -#ifdef HAVE_POPPLER_CAIRO - -#include "pdf-input-cairo.h" -#include "extension/system.h" -#include "extension/input.h" -#include "dialogs/dialog-events.h" -#include "document.h" -#include "sp-root.h" -#include "util/units.h" - -#include <2geom/rect.h> - -#include "inkscape.h" - -#include <cairo-svg.h> -#include <poppler/glib/poppler.h> -#include <poppler/glib/poppler-document.h> -#include <poppler/glib/poppler-page.h> - -#include "ui/widget/spinbutton.h" -#include "ui/widget/frame.h" - -#include <gdkmm/general.h> - -namespace Inkscape { -namespace Extension { -namespace Internal { - - -/** - * \brief The PDF import dialog - * FIXME: Probably this should be placed into src/ui/dialog - */ - -static const gchar * crop_setting_choices[] = { - //TRANSLATORS: The following are document crop settings for PDF import - // more info: http://www.acrobatusers.com/tech_corners/javascript_corner/tips/2006/page_bounds/ - N_("media box"), - N_("crop box"), - N_("trim box"), - N_("bleed box"), - N_("art box") -}; - -PdfImportCairoDialog::PdfImportCairoDialog(PopplerDocument *doc) -{ - if(doc == NULL) { - // if there is no document, throw exception here - throw; - } - - _poppler_doc = doc; - - cancelbutton = Gtk::manage(new class Gtk::Button(Gtk::StockID("gtk-cancel"))); - okbutton = Gtk::manage(new class Gtk::Button(Gtk::StockID("gtk-ok"))); - _labelSelect = Gtk::manage(new class Gtk::Label(_("Select page:"))); - - // Page number - int num_pages = poppler_document_get_n_pages(_poppler_doc); -#if WITH_GTKMM_3_0 - Glib::RefPtr<Gtk::Adjustment> _pageNumberSpin_adj( Gtk::Adjustment::create(1, 1, num_pages, 1, 10, 0) ); - _pageNumberSpin = Gtk::manage(new class Inkscape::UI::Widget::SpinButton(_pageNumberSpin_adj, 1, 1)); -#else - Gtk::Adjustment *_pageNumberSpin_adj = Gtk::manage(new class Gtk::Adjustment(1, 1, num_pages, 1, 10, 0)); - _pageNumberSpin = Gtk::manage(new class Inkscape::UI::Widget::SpinButton(*_pageNumberSpin_adj, 1, 1)); -#endif - _labelTotalPages = Gtk::manage(new class Gtk::Label()); - hbox2 = Gtk::manage(new class Gtk::HBox(false, 0)); - // Disable the page selector when there's only one page - if ( num_pages == 1 ) { - _pageNumberSpin->set_sensitive(false); - } else { - // Display total number of pages - gchar *label_text = g_strdup_printf(_("out of %i"), num_pages); - _labelTotalPages->set_label(label_text); - g_free(label_text); - } - - // Crop settings - _cropCheck = Gtk::manage(new class Gtk::CheckButton(_("Clip to:"))); - _cropTypeCombo = Gtk::manage(new class Gtk::ComboBoxText()); - int num_crop_choices = sizeof(crop_setting_choices) / sizeof(crop_setting_choices[0]); - for ( int i = 0 ; i < num_crop_choices ; i++ ) { - _cropTypeCombo->append(_(crop_setting_choices[i])); - } - _cropTypeCombo->set_active_text(_(crop_setting_choices[0])); - _cropTypeCombo->set_sensitive(false); - - hbox3 = Gtk::manage(new class Gtk::HBox(false, 4)); - vbox2 = Gtk::manage(new class Gtk::VBox(false, 4)); - _pageSettingsFrame = Gtk::manage(new class Inkscape::UI::Widget::Frame(_("Page settings"))); - _labelPrecision = Gtk::manage(new class Gtk::Label(_("Precision of approximating gradient meshes:"))); - _labelPrecisionWarning = Gtk::manage(new class Gtk::Label(_("<b>Note</b>: setting the precision too high may result in a large SVG file and slow performance."))); - -#if WITH_GTKMM_3_0 - _fallbackPrecisionSlider_adj = Gtk::Adjustment::create(2, 1, 256, 1, 10, 10); - _fallbackPrecisionSlider = Gtk::manage(new Gtk::Scale(_fallbackPrecisionSlider_adj)); -#else - _fallbackPrecisionSlider_adj = Gtk::manage(new class Gtk::Adjustment(2, 1, 256, 1, 10, 10)); - _fallbackPrecisionSlider = Gtk::manage(new class Gtk::HScale(*_fallbackPrecisionSlider_adj)); -#endif - _fallbackPrecisionSlider->set_value(2.0); - _labelPrecisionComment = Gtk::manage(new class Gtk::Label(_("rough"))); - hbox6 = Gtk::manage(new class Gtk::HBox(false, 4)); - - // Text options - _labelText = Gtk::manage(new class Gtk::Label(_("Text handling:"))); - _textHandlingCombo = Gtk::manage(new class Gtk::ComboBoxText()); - _textHandlingCombo->append(_("Import text as text")); - _textHandlingCombo->set_active_text(_("Import text as text")); - _localFontsCheck = Gtk::manage(new class Gtk::CheckButton(_("Replace PDF fonts by closest-named installed fonts"))); - - hbox5 = Gtk::manage(new class Gtk::HBox(false, 4)); - _embedImagesCheck = Gtk::manage(new class Gtk::CheckButton(_("Embed images"))); - vbox3 = Gtk::manage(new class Gtk::VBox(false, 4)); - _importSettingsFrame = Gtk::manage(new class Inkscape::UI::Widget::Frame(_("Import settings"))); - vbox1 = Gtk::manage(new class Gtk::VBox(false, 4)); - _previewArea = Gtk::manage(new class Gtk::DrawingArea()); - hbox1 = Gtk::manage(new class Gtk::HBox(false, 4)); - cancelbutton->set_can_focus(); - cancelbutton->set_can_default(); - cancelbutton->set_relief(Gtk::RELIEF_NORMAL); - okbutton->set_can_focus(); - okbutton->set_can_default(); - okbutton->set_relief(Gtk::RELIEF_NORMAL); - this->get_action_area()->property_layout_style().set_value(Gtk::BUTTONBOX_END); - _labelSelect->set_alignment(0.5,0.5); - _labelSelect->set_padding(4,0); - _labelSelect->set_justify(Gtk::JUSTIFY_LEFT); - _labelSelect->set_line_wrap(false); - _labelSelect->set_use_markup(false); - _labelSelect->set_selectable(false); - _pageNumberSpin->set_can_focus(); - _pageNumberSpin->set_update_policy(Gtk::UPDATE_ALWAYS); - _pageNumberSpin->set_numeric(true); - _pageNumberSpin->set_digits(0); - _pageNumberSpin->set_wrap(false); - _labelTotalPages->set_alignment(0.5,0.5); - _labelTotalPages->set_padding(4,0); - _labelTotalPages->set_justify(Gtk::JUSTIFY_LEFT); - _labelTotalPages->set_line_wrap(false); - _labelTotalPages->set_use_markup(false); - _labelTotalPages->set_selectable(false); - hbox2->pack_start(*_labelSelect, Gtk::PACK_SHRINK, 4); - hbox2->pack_start(*_pageNumberSpin, Gtk::PACK_SHRINK, 4); - hbox2->pack_start(*_labelTotalPages, Gtk::PACK_SHRINK, 4); - _cropCheck->set_can_focus(); - _cropCheck->set_relief(Gtk::RELIEF_NORMAL); - _cropCheck->set_mode(true); - _cropCheck->set_active(false); - _cropTypeCombo->set_border_width(1); - hbox3->pack_start(*_cropCheck, Gtk::PACK_SHRINK, 4); - hbox3->pack_start(*_cropTypeCombo, Gtk::PACK_SHRINK, 0); - vbox2->pack_start(*hbox2); - vbox2->pack_start(*hbox3); - _pageSettingsFrame->add(*vbox2); - _pageSettingsFrame->set_border_width(4); - _labelPrecision->set_alignment(0,0.5); - _labelPrecision->set_padding(4,0); - _labelPrecision->set_justify(Gtk::JUSTIFY_LEFT); - _labelPrecision->set_line_wrap(true); - _labelPrecision->set_use_markup(false); - _labelPrecision->set_selectable(false); - _labelPrecisionWarning->set_alignment(0,0.5); - _labelPrecisionWarning->set_padding(4,0); - _labelPrecisionWarning->set_justify(Gtk::JUSTIFY_LEFT); - _labelPrecisionWarning->set_line_wrap(true); - _labelPrecisionWarning->set_use_markup(true); - _labelPrecisionWarning->set_selectable(false); - _fallbackPrecisionSlider->set_size_request(180,-1); - _fallbackPrecisionSlider->set_can_focus(); - _fallbackPrecisionSlider->set_inverted(false); - _fallbackPrecisionSlider->set_digits(1); - _fallbackPrecisionSlider->set_draw_value(true); - _fallbackPrecisionSlider->set_value_pos(Gtk::POS_TOP); - _labelPrecisionComment->set_size_request(90,-1); - _labelPrecisionComment->set_alignment(0.5,0.5); - _labelPrecisionComment->set_padding(4,0); - _labelPrecisionComment->set_justify(Gtk::JUSTIFY_LEFT); - _labelPrecisionComment->set_line_wrap(false); - _labelPrecisionComment->set_use_markup(false); - _labelPrecisionComment->set_selectable(false); - hbox6->pack_start(*_fallbackPrecisionSlider, Gtk::PACK_SHRINK, 4); - hbox6->pack_start(*_labelPrecisionComment, Gtk::PACK_SHRINK, 0); - _labelText->set_alignment(0.5,0.5); - _labelText->set_padding(4,0); - _labelText->set_justify(Gtk::JUSTIFY_LEFT); - _labelText->set_line_wrap(false); - _labelText->set_use_markup(false); - _labelText->set_selectable(false); - hbox5->pack_start(*_labelText, Gtk::PACK_SHRINK, 0); - hbox5->pack_start(*_textHandlingCombo, Gtk::PACK_SHRINK, 0); - _localFontsCheck->set_can_focus(); - _localFontsCheck->set_relief(Gtk::RELIEF_NORMAL); - _localFontsCheck->set_mode(true); - _localFontsCheck->set_active(true); - _embedImagesCheck->set_can_focus(); - _embedImagesCheck->set_relief(Gtk::RELIEF_NORMAL); - _embedImagesCheck->set_mode(true); - _embedImagesCheck->set_active(true); - vbox3->pack_start(*_labelPrecision, Gtk::PACK_SHRINK, 0); - vbox3->pack_start(*hbox6, Gtk::PACK_SHRINK, 0); - vbox3->pack_start(*_labelPrecisionWarning, Gtk::PACK_SHRINK, 0); - vbox3->pack_start(*hbox5, Gtk::PACK_SHRINK, 4); - vbox3->pack_start(*_localFontsCheck, Gtk::PACK_SHRINK, 0); - vbox3->pack_start(*_embedImagesCheck, Gtk::PACK_SHRINK, 0); - _importSettingsFrame->add(*vbox3); - _importSettingsFrame->set_border_width(4); - vbox1->pack_start(*_pageSettingsFrame, Gtk::PACK_EXPAND_PADDING, 0); - vbox1->pack_start(*_importSettingsFrame, Gtk::PACK_EXPAND_PADDING, 0); - hbox1->pack_start(*vbox1); - hbox1->pack_start(*_previewArea, Gtk::PACK_EXPAND_WIDGET, 4); - -#if WITH_GTKMM_3_0 - get_content_area()->set_homogeneous(false); - get_content_area()->set_spacing(0); - get_content_area()->pack_start(*hbox1); -#else - this->get_vbox()->set_homogeneous(false); - this->get_vbox()->set_spacing(0); - this->get_vbox()->pack_start(*hbox1); -#endif - - this->set_title(_("PDF Import Settings")); - this->set_modal(true); - sp_transientize(GTK_WIDGET(this->gobj())); //Make transient - this->property_window_position().set_value(Gtk::WIN_POS_NONE); - this->set_resizable(true); - this->property_destroy_with_parent().set_value(false); - this->add_action_widget(*cancelbutton, -6); - this->add_action_widget(*okbutton, -5); - cancelbutton->show(); - okbutton->show(); - _labelSelect->show(); - _pageNumberSpin->show(); - _labelTotalPages->show(); - hbox2->show(); - _cropCheck->show(); - _cropTypeCombo->show(); - hbox3->show(); - vbox2->show(); - _pageSettingsFrame->show(); - _labelPrecision->show(); - _labelPrecisionWarning->show(); - _fallbackPrecisionSlider->show(); - _labelPrecisionComment->show(); - hbox6->show(); - _labelText->show(); - _textHandlingCombo->show(); - hbox5->show(); - _localFontsCheck->show(); - _embedImagesCheck->show(); - vbox3->show(); - _importSettingsFrame->show(); - vbox1->show(); - _previewArea->show(); - hbox1->show(); - - // Connect signals -#if WITH_GTKMM_3_0 - _previewArea->signal_draw().connect(sigc::mem_fun(*this, &PdfImportCairoDialog::_onDraw)); -#else - _previewArea->signal_expose_event().connect(sigc::mem_fun(*this, &PdfImportCairoDialog::_onExposePreview)); -#endif - _pageNumberSpin_adj->signal_value_changed().connect(sigc::mem_fun(*this, &PdfImportCairoDialog::_onPageNumberChanged)); - _cropCheck->signal_toggled().connect(sigc::mem_fun(*this, &PdfImportCairoDialog::_onToggleCropping)); - _fallbackPrecisionSlider_adj->signal_value_changed().connect(sigc::mem_fun(*this, &PdfImportCairoDialog::_onPrecisionChanged)); - - _render_thumb = false; - _cairo_surface = NULL; - _render_thumb = true; - - // Set default preview size - _preview_width = 200; - _preview_height = 300; - - // Init preview - _thumb_data = NULL; - _pageNumberSpin_adj->set_value(1.0); - _current_page = 1; - _setPreviewPage(_current_page); - - set_default (*okbutton); - set_focus (*okbutton); -} - -PdfImportCairoDialog::~PdfImportCairoDialog() { - if (_cairo_surface) { - cairo_surface_destroy(_cairo_surface); - } - if (_thumb_data) { - if (_render_thumb) { - delete _thumb_data; - } else { - // -->gfree(_thumb_data); - delete _thumb_data; - } - } -} - -bool PdfImportCairoDialog::showDialog() { - show(); - gint b = run(); - hide(); - if ( b == Gtk::RESPONSE_OK ) { - return TRUE; - } else { - return FALSE; - } -} - -int PdfImportCairoDialog::getSelectedPage() { - return _current_page; -} - -/** - * \brief Retrieves the current settings into a repr which SvgBuilder will use - * for determining the behaviour desired by the user - */ -void PdfImportCairoDialog::getImportSettings(Inkscape::XML::Node *prefs) { - sp_repr_set_svg_double(prefs, "selectedPage", (double)_current_page); - if (_cropCheck->get_active()) { - Glib::ustring current_choice = _cropTypeCombo->get_active_text(); - int num_crop_choices = sizeof(crop_setting_choices) / sizeof(crop_setting_choices[0]); - int i = 0; - for ( ; i < num_crop_choices ; i++ ) { - if ( current_choice == _(crop_setting_choices[i]) ) { - break; - } - } - sp_repr_set_svg_double(prefs, "cropTo", (double)i); - } else { - sp_repr_set_svg_double(prefs, "cropTo", -1.0); - } - sp_repr_set_svg_double(prefs, "approximationPrecision", - _fallbackPrecisionSlider->get_value()); - if (_localFontsCheck->get_active()) { - prefs->setAttribute("localFonts", "1"); - } else { - prefs->setAttribute("localFonts", "0"); - } - if (_embedImagesCheck->get_active()) { - prefs->setAttribute("embedImages", "1"); - } else { - prefs->setAttribute("embedImages", "0"); - } -} - -/** - * \brief Redisplay the comment on the current approximation precision setting - * Evenly divides the interval of possible values between the available labels. - */ -void PdfImportCairoDialog::_onPrecisionChanged() { - - static Glib::ustring precision_comments[] = { - Glib::ustring(C_("PDF input precision", "rough")), - Glib::ustring(C_("PDF input precision", "medium")), - Glib::ustring(C_("PDF input precision", "fine")), - Glib::ustring(C_("PDF input precision", "very fine")) - }; - - double min = _fallbackPrecisionSlider_adj->get_lower(); - double max = _fallbackPrecisionSlider_adj->get_upper(); - int num_intervals = sizeof(precision_comments) / sizeof(precision_comments[0]); - double interval_len = ( max - min ) / (double)num_intervals; - double value = _fallbackPrecisionSlider_adj->get_value(); - int comment_idx = (int)floor( ( value - min ) / interval_len ); - _labelPrecisionComment->set_label(precision_comments[comment_idx]); -} - -void PdfImportCairoDialog::_onToggleCropping() { - _cropTypeCombo->set_sensitive(_cropCheck->get_active()); -} - -void PdfImportCairoDialog::_onPageNumberChanged() { - int page = _pageNumberSpin->get_value_as_int(); - _current_page = CLAMP(page, 1, poppler_document_get_n_pages(_poppler_doc)); - _setPreviewPage(_current_page); -} - -/** - * \brief Copies image data from a Cairo surface to a pixbuf - * - * Borrowed from libpoppler, from the file poppler-page.cc - * Copyright (C) 2005, Red Hat, Inc. - * - */ -static void copy_cairo_surface_to_pixbuf (cairo_surface_t *surface, - unsigned char *data, - GdkPixbuf *pixbuf) -{ - int cairo_width, cairo_height, cairo_rowstride; - unsigned char *pixbuf_data, *dst, *cairo_data; - int pixbuf_rowstride, pixbuf_n_channels; - unsigned int *src; - int x, y; - - cairo_width = cairo_image_surface_get_width (surface); - cairo_height = cairo_image_surface_get_height (surface); - cairo_rowstride = cairo_width * 4; - cairo_data = data; - - pixbuf_data = gdk_pixbuf_get_pixels (pixbuf); - pixbuf_rowstride = gdk_pixbuf_get_rowstride (pixbuf); - pixbuf_n_channels = gdk_pixbuf_get_n_channels (pixbuf); - - if (cairo_width > gdk_pixbuf_get_width (pixbuf)) - cairo_width = gdk_pixbuf_get_width (pixbuf); - if (cairo_height > gdk_pixbuf_get_height (pixbuf)) - cairo_height = gdk_pixbuf_get_height (pixbuf); - for (y = 0; y < cairo_height; y++) - { - src = reinterpret_cast<unsigned int *>(cairo_data + y * cairo_rowstride); - dst = pixbuf_data + y * pixbuf_rowstride; - for (x = 0; x < cairo_width; x++) - { - dst[0] = (*src >> 16) & 0xff; - dst[1] = (*src >> 8) & 0xff; - dst[2] = (*src >> 0) & 0xff; - if (pixbuf_n_channels == 4) - dst[3] = (*src >> 24) & 0xff; - dst += pixbuf_n_channels; - src++; - } - } -} - -/** - * \brief Updates the preview area with the previously rendered thumbnail - */ -#if !WITH_GTKMM_3_0 -bool PdfImportCairoDialog::_onExposePreview(GdkEventExpose * /*event*/) { - Cairo::RefPtr<Cairo::Context> cr = _previewArea->get_window()->create_cairo_context(); - return _onDraw(cr); -} -#endif - - -bool PdfImportCairoDialog::_onDraw(const Cairo::RefPtr<Cairo::Context>& cr) { - // Check if we have a thumbnail at all - if (!_thumb_data) { - return true; - } - - // Create the pixbuf for the thumbnail - Glib::RefPtr<Gdk::Pixbuf> thumb; - if (_render_thumb) { - thumb = Gdk::Pixbuf::create(Gdk::COLORSPACE_RGB, true, - 8, _thumb_width, _thumb_height); - } else { - thumb = Gdk::Pixbuf::create_from_data(_thumb_data, Gdk::COLORSPACE_RGB, - false, 8, _thumb_width, _thumb_height, _thumb_rowstride); - } - if (!thumb) { - return true; - } - - // Set background to white - if (_render_thumb) { - thumb->fill(0xffffffff); - Gdk::Cairo::set_source_pixbuf(cr, thumb, 0, 0); - cr->paint(); - } - - // Copy the thumbnail image from the Cairo surface - if (_render_thumb) { - copy_cairo_surface_to_pixbuf(_cairo_surface, _thumb_data, thumb->gobj()); - } - Gdk::Cairo::set_source_pixbuf(cr, thumb, 0, _render_thumb ? 0 : 20); - cr->paint(); - - return true; -} - -/** - * \brief Renders the given page's thumbnail using Cairo - */ -void PdfImportCairoDialog::_setPreviewPage(int page) { - - PopplerPage *_previewed_page = poppler_document_get_page(_poppler_doc, page-1); - - // Try to get a thumbnail from the PDF if possible - if (!_render_thumb) { - if (_thumb_data) { - // --> gfree(_thumb_data); - free(_thumb_data); - _thumb_data = NULL; - } - -/* ---> if (!_previewed_page->loadThumb(&_thumb_data, - &_thumb_width, &_thumb_height, &_thumb_rowstride)) { - return; - } -*/ - // Redraw preview area - _previewArea->set_size_request(_thumb_width, _thumb_height + 20); - _previewArea->queue_draw(); - return; - } - - // Get page size by accounting for rotation - double width, height; - // --> int rotate = _previewed_page->getRotate(); - int rotate = 0; - if ( rotate == 90 || rotate == 270 ) { -// --> height = _previewed_page->getCropWidth(); -// --> width = _previewed_page->getCropHeight(); - } else { - poppler_page_get_size (_previewed_page, &width, &height); -// --> width = _previewed_page->getCropWidth(); -// --> height = _previewed_page->getCropHeight(); - } - // Calculate the needed scaling for the page - double scale_x = (double)_preview_width / width; - double scale_y = (double)_preview_height / height; - double scale_factor = ( scale_x > scale_y ) ? scale_y : scale_x; - // Create new Cairo surface - _thumb_width = (int)ceil( width * scale_factor ); - _thumb_height = (int)ceil( height * scale_factor ); - _thumb_rowstride = _thumb_width * 4; - if (_thumb_data) { - delete _thumb_data; - } - _thumb_data = new unsigned char[ _thumb_rowstride * _thumb_height ]; - if (_cairo_surface) { - cairo_surface_destroy(_cairo_surface); - } - _cairo_surface = cairo_image_surface_create_for_data(_thumb_data, - CAIRO_FORMAT_ARGB32, _thumb_width, _thumb_height, _thumb_rowstride); - cairo_t *cr = cairo_create(_cairo_surface); - cairo_set_source_rgba(cr, 1.0, 1.0, 1.0, 1.0); // Set fill color to white - cairo_paint(cr); // Clear it - cairo_scale(cr, scale_factor, scale_factor); // Use Cairo for resizing the image - // Render page - if (_poppler_doc != NULL) { - PopplerPage *poppler_page = poppler_document_get_page(_poppler_doc, page - 1); - poppler_page_render(poppler_page, cr); - g_object_unref(G_OBJECT(poppler_page)); - } - // Clean up - cairo_destroy(cr); - // Redraw preview area - _previewArea->set_size_request(_preview_width, _preview_height); - _previewArea->queue_draw(); - -} - - -static cairo_status_t _write_ustring_cb(void *closure, const unsigned char *data, unsigned int length); - -SPDocument * -PdfInputCairo::open(Inkscape::Extension::Input * /*mod*/, const gchar * uri) { - - g_message("Attempting to open using PdfInputCairo\n"); - - gchar* filename_uri = g_filename_to_uri(uri, NULL, NULL); - - GError *error = NULL; - /// @todo handle passwort - /// @todo check if win32 unicode needs special attention - PopplerDocument* document = poppler_document_new_from_file(filename_uri, NULL, &error); - - if(error != NULL) { - g_message("Unable to read file: %s\n", error->message); - g_error_free (error); - } - - if (document == NULL) { - return NULL; - } - - // create and show the import dialog - PdfImportCairoDialog *dlg = NULL; - if (inkscape_use_gui()) { - dlg = new PdfImportCairoDialog(document); - if (!dlg->showDialog()) { - delete dlg; - return NULL; - } - } - - // Get needed page - int page_num; - if (dlg) { - page_num = dlg->getSelectedPage(); - delete dlg; - } - else - page_num = 1; - - double width, height; - PopplerPage* page = poppler_document_get_page(document, page_num - 1); - poppler_page_get_size(page, &width, &height); - - Glib::ustring* output = new Glib::ustring(""); - cairo_surface_t* surface = cairo_svg_surface_create_for_stream(Inkscape::Extension::Internal::_write_ustring_cb, - output, width, height); - cairo_t* cr = cairo_create(surface); - - poppler_page_render_for_printing(page, cr); - cairo_show_page(cr); - - cairo_destroy(cr); - cairo_surface_destroy(surface); - - SPDocument * doc = SPDocument::createNewDocFromMem(output->c_str(), output->length(), TRUE); - - // Set viewBox if it doesn't exist - if (doc && !doc->getRoot()->viewBox_set) { - doc->setViewBox(Geom::Rect::from_xywh(0, 0, doc->getWidth().value(doc->getDefaultUnit()), doc->getHeight().value(doc->getDefaultUnit()))); - } - - delete output; - g_object_unref(page); - g_object_unref(document); - - return doc; -} - -static cairo_status_t - _write_ustring_cb(void *closure, const unsigned char *data, unsigned int length) -{ - Glib::ustring* stream = static_cast<Glib::ustring*>(closure); - stream->append(reinterpret_cast<const char*>(data), length); - - return CAIRO_STATUS_SUCCESS; -} - - -#include "clear-n_.h" - -void -PdfInputCairo::init(void) { - Inkscape::Extension::build_from_mem( - "<inkscape-extension xmlns=\"" INKSCAPE_EXTENSION_URI "\">\n" - "<name>" N_("PDF Input") "</name>\n" - "<id>org.inkscape.input.cairo-pdf</id>\n" - "<input>\n" - "<extension>.pdf</extension>\n" - "<mimetype>application/pdf</mimetype>\n" - "<filetypename>" N_("Adobe PDF via poppler-cairo (*.pdf)") "</filetypename>\n" - "<filetypetooltip>" N_("PDF Document") "</filetypetooltip>\n" - "</input>\n" - "</inkscape-extension>", new PdfInputCairo()); -} // init - -} } } /* namespace Inkscape, Extension, Implementation */ - -#endif /* HAVE_POPPLER_CAIRO */ -#endif /* HAVE_POPPLER_GLIB */ - -/* - Local Variables: - mode:c++ - c-file-style:"stroustrup" - c-file-offsets:((innamespace . 0)(inline-open . 0)) - indent-tabs-mode:nil - fill-column:99 - End: -*/ -// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 : diff --git a/src/extension/internal/pdf-input-cairo.h b/src/extension/internal/pdf-input-cairo.h deleted file mode 100644 index b65d22f48..000000000 --- a/src/extension/internal/pdf-input-cairo.h +++ /dev/null @@ -1,157 +0,0 @@ -#ifndef __EXTENSION_INTERNAL_PDFINPUTCAIRO_H__ -#define __EXTENSION_INTERNAL_PDFINPUTCAIRO_H__ - -/* - * PDF input using libpoppler and Cairo's SVG surface. - * - * Authors: - * miklos erdelyi - * - * Copyright (C) 2007 Authors - * - * Released under GNU GPL, read the file 'COPYING' for more information - */ - -#ifdef HAVE_CONFIG_H -# include <config.h> -#endif - -#if GLIBMM_DISABLE_DEPRECATED && HAVE_GLIBMM_THREADS_H -#include <glibmm/threads.h> -#endif - -#include <gtkmm/dialog.h> -#include <gtkmm/button.h> -#include <gtkmm/buttonbox.h> -#include <gtkmm/label.h> -#include <gtkmm/box.h> -#include <gtkmm/checkbutton.h> -#include <gtkmm/comboboxtext.h> -#include <gtkmm/drawingarea.h> -#include <gtkmm/alignment.h> -#include <gtkmm/frame.h> -#include <gtkmm/scale.h> -#include <glibmm/i18n.h> -#include <gdk/gdk.h> - -#ifdef HAVE_POPPLER_GLIB -#ifdef HAVE_POPPLER_CAIRO - -#include <poppler/glib/poppler.h> - -#include "../implementation/implementation.h" - -namespace Gtk { -#if WITH_GTKMM_3_0 - class Scale; -#else - class HScale; -#endif -} - -namespace Inkscape { - -namespace UI { -namespace Widget { - class SpinButton; - class Frame; -} -} - -namespace Extension { -namespace Internal { - -class PdfImportCairoDialog : public Gtk::Dialog -{ -public: - PdfImportCairoDialog(PopplerDocument* doc); - virtual ~PdfImportCairoDialog(); - - bool showDialog(); - int getSelectedPage(); - void getImportSettings(Inkscape::XML::Node *prefs); - -private: - void _setPreviewPage(int page); - - // Signal handlers -#if !WITH_GTKMM_3_0 - bool _onExposePreview(GdkEventExpose *event); -#endif - - bool _onDraw(const Cairo::RefPtr<Cairo::Context>& cr); - void _onPageNumberChanged(); - void _onToggleCropping(); - void _onPrecisionChanged(); - - class Gtk::Button * cancelbutton; - class Gtk::Button * okbutton; - class Gtk::Label * _labelSelect; - class Inkscape::UI::Widget::SpinButton * _pageNumberSpin; - class Gtk::Label * _labelTotalPages; - class Gtk::HBox * hbox2; - class Gtk::CheckButton * _cropCheck; - class Gtk::ComboBoxText * _cropTypeCombo; - class Gtk::HBox * hbox3; - class Gtk::VBox * vbox2; - class Inkscape::UI::Widget::Frame * _pageSettingsFrame; - class Gtk::Label * _labelPrecision; - class Gtk::Label * _labelPrecisionWarning; -#if WITH_GTKMM_3_0 - class Gtk::Scale * _fallbackPrecisionSlider; - Glib::RefPtr<Gtk::Adjustment> _fallbackPrecisionSlider_adj; -#else - class Gtk::HScale * _fallbackPrecisionSlider; - class Gtk::Adjustment *_fallbackPrecisionSlider_adj; -#endif - class Gtk::Label * _labelPrecisionComment; - class Gtk::HBox * hbox6; - class Gtk::Label * _labelText; - class Gtk::ComboBoxText * _textHandlingCombo; - class Gtk::HBox * hbox5; - class Gtk::CheckButton * _localFontsCheck; - class Gtk::CheckButton * _embedImagesCheck; - class Gtk::VBox * vbox3; - class Inkscape::UI::Widget::Frame * _importSettingsFrame; - class Gtk::VBox * vbox1; - class Gtk::DrawingArea * _previewArea; - class Gtk::HBox * hbox1; - - PopplerDocument *_poppler_doc; - // PopplerPage *_previewed_page; - int _current_page; // Current selected page - unsigned char *_thumb_data; // Thumbnail image data - int _thumb_width, _thumb_height; // Thumbnail size - int _thumb_rowstride; - int _preview_width, _preview_height; // Size of the preview area - bool _render_thumb; // Whether we can/shall render thumbnails - cairo_surface_t *_cairo_surface; // this cairo surface is used for preview -}; - - -class PdfInputCairo: public Inkscape::Extension::Implementation::Implementation { - PdfInputCairo () { }; -public: - SPDocument *open( Inkscape::Extension::Input *mod, - const gchar *uri ); - static void init( void ); - -}; - -} } } /* namespace Inkscape, Extension, Implementation */ - -#endif /* HAVE_POPPLER_CAIRO */ -#endif /* HAVE_POPPLER_GLIB */ - -#endif /* __EXTENSION_INTERNAL_PDFINPUTCAIRO_H__ */ - -/* - Local Variables: - mode:c++ - c-file-style:"stroustrup" - c-file-offsets:((innamespace . 0)(inline-open . 0)) - indent-tabs-mode:nil - fill-column:99 - End: -*/ -// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 : diff --git a/src/extension/internal/pdfinput/pdf-input.cpp b/src/extension/internal/pdfinput/pdf-input.cpp index 3155ac098..63581bd8a 100644 --- a/src/extension/internal/pdfinput/pdf-input.cpp +++ b/src/extension/internal/pdfinput/pdf-input.cpp @@ -124,6 +124,9 @@ PdfImportDialog::PdfImportDialog(PDFDoc *doc, const gchar */*uri*/) _labelPrecision = Gtk::manage(new class Gtk::Label(_("Precision of approximating gradient meshes:"))); _labelPrecisionWarning = Gtk::manage(new class Gtk::Label(_("<b>Note</b>: setting the precision too high may result in a large SVG file and slow performance."))); +#ifdef HAVE_POPPLER_CAIRO + _importviaPopplerCheck = Gtk::manage(new class Gtk::CheckButton(_("import via Poppler"))); +#endif #if WITH_GTKMM_3_0 _fallbackPrecisionSlider_adj = Gtk::Adjustment::create(2, 1, 256, 1, 10, 10); _fallbackPrecisionSlider = Gtk::manage(new class Gtk::Scale(_fallbackPrecisionSlider_adj)); @@ -199,6 +202,12 @@ PdfImportDialog::PdfImportDialog(PDFDoc *doc, const gchar */*uri*/) _labelPrecisionWarning->set_line_wrap(true); _labelPrecisionWarning->set_use_markup(true); _labelPrecisionWarning->set_selectable(false); +#ifdef HAVE_POPPLER_CAIRO + _importviaPopplerCheck->set_can_focus(); + _importviaPopplerCheck->set_relief(Gtk::RELIEF_NORMAL); + _importviaPopplerCheck->set_mode(true); + _importviaPopplerCheck->set_active(false); +#endif _fallbackPrecisionSlider->set_size_request(180,-1); _fallbackPrecisionSlider->set_can_focus(); _fallbackPrecisionSlider->set_inverted(false); @@ -230,6 +239,9 @@ PdfImportDialog::PdfImportDialog(PDFDoc *doc, const gchar */*uri*/) _embedImagesCheck->set_relief(Gtk::RELIEF_NORMAL); _embedImagesCheck->set_mode(true); _embedImagesCheck->set_active(true); +#ifdef HAVE_POPPLER_CAIRO + vbox3->pack_start(*_importviaPopplerCheck, Gtk::PACK_SHRINK, 0); +#endif vbox3->pack_start(*_labelPrecision, Gtk::PACK_SHRINK, 0); vbox3->pack_start(*hbox6, Gtk::PACK_SHRINK, 0); vbox3->pack_start(*_labelPrecisionWarning, Gtk::PACK_SHRINK, 0); @@ -274,6 +286,9 @@ PdfImportDialog::PdfImportDialog(PDFDoc *doc, const gchar */*uri*/) _pageSettingsFrame->show(); _labelPrecision->show(); _labelPrecisionWarning->show(); +#ifdef HAVE_POPPLER_CAIRO + _importviaPopplerCheck->show(); +#endif _fallbackPrecisionSlider->show(); _labelPrecisionComment->show(); hbox6->show(); @@ -358,6 +373,14 @@ int PdfImportDialog::getSelectedPage() { return _current_page; } +int PdfImportDialog::getImportMethod() { +#ifdef HAVE_POPPLER_CAIRO + return (_importviaPopplerCheck->get_active()) ? 1 : 0; +#else + return 0; +#endif +} + /** * \brief Retrieves the current settings into a repr which SvgBuilder will use * for determining the behaviour desired by the user @@ -389,6 +412,13 @@ void PdfImportDialog::getImportSettings(Inkscape::XML::Node *prefs) { } else { prefs->setAttribute("embedImages", "0"); } +#ifdef HAVE_POPPLER_CAIRO + if (_importviaPopplerCheck->get_active()) { + prefs->setAttribute("importviapoppler", "1"); + } else { + prefs->setAttribute("importviapoppler", "0"); + } +#endif } /** @@ -595,6 +625,18 @@ PdfInput::wasCancelled () { return _cancelled; } +#ifdef HAVE_POPPLER_CAIRO +/// helper method +static cairo_status_t + _write_ustring_cb(void *closure, const unsigned char *data, unsigned int length) +{ + Glib::ustring* stream = static_cast<Glib::ustring*>(closure); + stream->append(reinterpret_cast<const char*>(data), length); + + return CAIRO_STATUS_SUCCESS; +} +#endif + /** * Parses the selected page of the given PDF document using PdfParser. */ @@ -672,79 +714,146 @@ PdfInput::open(::Inkscape::Extension::Input * /*mod*/, const gchar * uri) { page_num = 1; Catalog *catalog = pdf_doc->getCatalog(); Page *page = catalog->getPage(page_num); + + int is_importvia_poppler = 0; + if(dlg) + { +#ifdef HAVE_POPPLER_CAIRO + is_importvia_poppler = dlg->getImportMethod(); +#endif + } - SPDocument *doc = SPDocument::createNewDoc(NULL, TRUE, TRUE); - bool saved = DocumentUndo::getUndoSensitive(doc); - DocumentUndo::setUndoSensitive(doc, false); // No need to undo in this temporary document + SPDocument *doc = NULL; + bool saved = false; + if(is_importvia_poppler == 0) + { + // native importer + doc = SPDocument::createNewDoc(NULL, TRUE, TRUE); + saved = DocumentUndo::getUndoSensitive(doc); + DocumentUndo::setUndoSensitive(doc, false); // No need to undo in this temporary document + + // Create builder + gchar *docname = g_path_get_basename(uri); + gchar *dot = g_strrstr(docname, "."); + if (dot) { + *dot = 0; + } + SvgBuilder *builder = new SvgBuilder(doc, docname, pdf_doc->getXRef()); + + // Get preferences + Inkscape::XML::Node *prefs = builder->getPreferences(); + if (dlg) + dlg->getImportSettings(prefs); + + printf("pdf import via %s.", (is_importvia_poppler != 0) ? "poppler" : "native"); + + // Apply crop settings + PDFRectangle *clipToBox = NULL; + double crop_setting; + sp_repr_get_double(prefs, "cropTo", &crop_setting); + if ( crop_setting >= 0.0 ) { // Do page clipping + int crop_choice = (int)crop_setting; + switch (crop_choice) { + case 0: // Media box + clipToBox = page->getMediaBox(); + break; + case 1: // Crop box + clipToBox = page->getCropBox(); + break; + case 2: // Bleed box + clipToBox = page->getBleedBox(); + break; + case 3: // Trim box + clipToBox = page->getTrimBox(); + break; + case 4: // Art box + clipToBox = page->getArtBox(); + break; + default: + break; + } + } - // Create builder - gchar *docname = g_path_get_basename(uri); - gchar *dot = g_strrstr(docname, "."); - if (dot) { - *dot = 0; - } - SvgBuilder *builder = new SvgBuilder(doc, docname, pdf_doc->getXRef()); + // Create parser + PdfParser *pdf_parser = new PdfParser(pdf_doc->getXRef(), builder, page_num-1, page->getRotate(), + page->getResourceDict(), page->getCropBox(), clipToBox); - // Get preferences - Inkscape::XML::Node *prefs = builder->getPreferences(); - if (dlg) - dlg->getImportSettings(prefs); - - // Apply crop settings - PDFRectangle *clipToBox = NULL; - double crop_setting; - sp_repr_get_double(prefs, "cropTo", &crop_setting); - if ( crop_setting >= 0.0 ) { // Do page clipping - int crop_choice = (int)crop_setting; - switch (crop_choice) { - case 0: // Media box - clipToBox = page->getMediaBox(); - break; - case 1: // Crop box - clipToBox = page->getCropBox(); - break; - case 2: // Bleed box - clipToBox = page->getBleedBox(); - break; - case 3: // Trim box - clipToBox = page->getTrimBox(); - break; - case 4: // Art box - clipToBox = page->getArtBox(); - break; - default: - break; + // Set up approximation precision for parser + double color_delta; + sp_repr_get_double(prefs, "approximationPrecision", &color_delta); + if ( color_delta <= 0.0 ) { + color_delta = 1.0 / 2.0; + } else { + color_delta = 1.0 / color_delta; + } + for ( int i = 1 ; i <= pdfNumShadingTypes ; i++ ) { + pdf_parser->setApproximationPrecision(i, color_delta, 6); } - } - // Create parser - PdfParser *pdf_parser = new PdfParser(pdf_doc->getXRef(), builder, page_num-1, page->getRotate(), - page->getResourceDict(), page->getCropBox(), clipToBox); + // Parse the document structure + Object obj; + page->getContents(&obj); + if (!obj.isNull()) { + pdf_parser->parse(&obj); + } - // Set up approximation precision for parser - double color_delta; - sp_repr_get_double(prefs, "approximationPrecision", &color_delta); - if ( color_delta <= 0.0 ) { - color_delta = 1.0 / 2.0; - } else { - color_delta = 1.0 / color_delta; - } - for ( int i = 1 ; i <= pdfNumShadingTypes ; i++ ) { - pdf_parser->setApproximationPrecision(i, color_delta, 6); + // Cleanup + obj.free(); + delete pdf_parser; + delete builder; + g_free(docname); } + else + { +#ifdef HAVE_POPPLER_CAIRO + // the poppler import + gchar* filename_uri = g_filename_to_uri(uri, NULL, NULL); + GError *error = NULL; + /// @todo handle passwort + /// @todo check if win32 unicode needs special attention + PopplerDocument* document = poppler_document_new_from_file(filename_uri, NULL, &error); + + if(error != NULL) { + g_error_free (error); + } - // Parse the document structure - Object obj; - page->getContents(&obj); - if (!obj.isNull()) { - pdf_parser->parse(&obj); + if (document != NULL) + { + double width, height; + PopplerPage* page = poppler_document_get_page(document, page_num - 1); + poppler_page_get_size(page, &width, &height); + + Glib::ustring output; + cairo_surface_t* surface = cairo_svg_surface_create_for_stream(Inkscape::Extension::Internal::_write_ustring_cb, + &output, width, height); + cairo_t* cr = cairo_create(surface); + + poppler_page_render_for_printing(page, cr); + cairo_show_page(cr); + + cairo_destroy(cr); + cairo_surface_destroy(surface); + + doc = SPDocument::createNewDocFromMem(output.c_str(), output.length(), TRUE); + + // Cleanup + // delete output; + g_object_unref(G_OBJECT(page)); + g_object_unref(G_OBJECT(document)); + } + else + { + doc = SPDocument::createNewDoc(NULL, TRUE, TRUE); // fallback create empthy document + } + saved = DocumentUndo::getUndoSensitive(doc); + DocumentUndo::setUndoSensitive(doc, false); // No need to undo in this temporary document + + // Cleanup + g_free(filename_uri); +#endif } // Cleanup - obj.free(); - delete pdf_parser; - delete builder; - g_free(docname); delete pdf_doc; delete dlg; diff --git a/src/extension/internal/pdfinput/pdf-input.h b/src/extension/internal/pdfinput/pdf-input.h index f22a783ff..d57c3e993 100644 --- a/src/extension/internal/pdfinput/pdf-input.h +++ b/src/extension/internal/pdfinput/pdf-input.h @@ -75,6 +75,7 @@ public: bool showDialog(); int getSelectedPage(); + int getImportMethod(); void getImportSettings(Inkscape::XML::Node *prefs); private: @@ -103,6 +104,9 @@ private: class Inkscape::UI::Widget::Frame * _pageSettingsFrame; class Gtk::Label * _labelPrecision; class Gtk::Label * _labelPrecisionWarning; +#ifdef HAVE_POPPLER_CAIRO + class Gtk::CheckButton * _importviaPopplerCheck; // using poppler_cairo for importing +#endif #if WITH_GTKMM_3_0 class Gtk::Scale * _fallbackPrecisionSlider; Glib::RefPtr<Gtk::Adjustment> _fallbackPrecisionSlider_adj; diff --git a/src/id-clash.cpp b/src/id-clash.cpp index 66357b75b..4bd66e858 100644 --- a/src/id-clash.cpp +++ b/src/id-clash.cpp @@ -92,7 +92,7 @@ const char* clipboard_properties[] = { * (e.g., ID selectors in CSS stylesheets, and references in scripts). */ static void -find_references(SPObject *elem, refmap_type *refmap) +find_references(SPObject *elem, refmap_type &refmap) { if (elem->cloned) return; Inkscape::XML::Node *repr_elem = elem->getRepr(); @@ -110,7 +110,7 @@ find_references(SPObject *elem, refmap_type *refmap) gchar *uri = extract_uri(value); if (uri && uri[0] == '#') { IdReference idref = { REF_CLIPBOARD, elem, attr }; - (*refmap)[uri+1].push_back(idref); + refmap[uri+1].push_back(idref); } g_free(uri); } @@ -127,7 +127,7 @@ find_references(SPObject *elem, refmap_type *refmap) if (val && val[0] == '#') { std::string id(val+1); IdReference idref = { REF_HREF, elem, attr }; - (*refmap)[id].push_back(idref); + refmap[id].push_back(idref); } } @@ -142,7 +142,7 @@ find_references(SPObject *elem, refmap_type *refmap) if (obj) { const gchar *id = obj->getId(); IdReference idref = { REF_STYLE, elem, SPIPaint_properties[i] }; - (*refmap)[id].push_back(idref); + refmap[id].push_back(idref); } } } @@ -154,7 +154,7 @@ find_references(SPObject *elem, refmap_type *refmap) if (obj) { const gchar *id = obj->getId(); IdReference idref = { REF_STYLE, elem, "filter" }; - (*refmap)[id].push_back(idref); + refmap[id].push_back(idref); } } @@ -166,7 +166,7 @@ find_references(SPObject *elem, refmap_type *refmap) gchar *uri = extract_uri(value); if (uri && uri[0] == '#') { IdReference idref = { REF_STYLE, elem, markers[i] }; - (*refmap)[uri+1].push_back(idref); + refmap[uri+1].push_back(idref); } g_free(uri); } @@ -180,7 +180,7 @@ find_references(SPObject *elem, refmap_type *refmap) gchar *uri = extract_uri(value); if (uri && uri[0] == '#') { IdReference idref = { REF_URL, elem, attr }; - (*refmap)[uri+1].push_back(idref); + refmap[uri+1].push_back(idref); } g_free(uri); } @@ -199,7 +199,7 @@ find_references(SPObject *elem, refmap_type *refmap) */ static void change_clashing_ids(SPDocument *imported_doc, SPDocument *current_doc, - SPObject *elem, const refmap_type *refmap, + SPObject *elem, refmap_type const &refmap, id_changelist_type *id_changes) { const gchar *id = elem->getId(); @@ -216,8 +216,7 @@ change_clashing_ids(SPDocument *imported_doc, SPDocument *current_doc, if (cd_obj && SP_IS_GRADIENT(cd_obj)) { SPGradient *cd_gr = SP_GRADIENT(cd_obj); - if ( cd_gr->isEquivalent(SP_GRADIENT(elem)) && - cd_gr->isAligned(SP_GRADIENT(elem))) { + if ( cd_gr->isEquivalent(SP_GRADIENT(elem))) { fix_clashing_ids = false; } } @@ -234,9 +233,9 @@ change_clashing_ids(SPDocument *imported_doc, SPDocument *current_doc, } // Change to the new ID - elem->getRepr()->setAttribute("id", new_id.c_str()); + elem->getRepr()->setAttribute("id", new_id); // Make a note of this change, if we need to fix up refs to it - if (refmap->find(old_id) != refmap->end()) + if (refmap.find(old_id) != refmap.end()) id_changes->push_back(id_changeitem_type(elem, old_id)); } } @@ -253,36 +252,43 @@ change_clashing_ids(SPDocument *imported_doc, SPDocument *current_doc, * Fix up references to changed IDs. */ static void -fix_up_refs(const refmap_type *refmap, const id_changelist_type &id_changes) +fix_up_refs(refmap_type const &refmap, const id_changelist_type &id_changes) { id_changelist_type::const_iterator pp; const id_changelist_type::const_iterator pp_end = id_changes.end(); for (pp = id_changes.begin(); pp != pp_end; ++pp) { SPObject *obj = pp->first; - refmap_type::const_iterator pos = refmap->find(pp->second); + refmap_type::const_iterator pos = refmap.find(pp->second); std::list<IdReference>::const_iterator it; const std::list<IdReference>::const_iterator it_end = pos->second.end(); for (it = pos->second.begin(); it != it_end; ++it) { - if (it->type == REF_HREF) { - gchar *new_uri = g_strdup_printf("#%s", obj->getId()); - it->elem->getRepr()->setAttribute(it->attr, new_uri); - g_free(new_uri); - } else if (it->type == REF_STYLE) { - sp_style_set_property_url(it->elem, it->attr, obj, false); - } else if (it->type == REF_URL) { - gchar *url = g_strdup_printf("url(#%s)", obj->getId()); - it->elem->getRepr()->setAttribute(it->attr, url); - g_free(url); - } else if (it->type == REF_CLIPBOARD) { - SPCSSAttr *style = sp_repr_css_attr(it->elem->getRepr(), "style"); - gchar *url = g_strdup_printf("url(#%s)", obj->getId()); - sp_repr_css_set_property(style, it->attr, url); - g_free(url); - Glib::ustring style_string; - sp_repr_css_write_string(style, style_string); - it->elem->getRepr()->setAttribute("style", style_string.c_str()); - } else { - g_assert(0); // shouldn't happen + switch (it->type) { + case REF_HREF: { + gchar *new_uri = g_strdup_printf("#%s", obj->getId()); + it->elem->getRepr()->setAttribute(it->attr, new_uri); + g_free(new_uri); + break; + } + case REF_STYLE: { + sp_style_set_property_url(it->elem, it->attr, obj, false); + break; + } + case REF_URL: { + gchar *url = g_strdup_printf("url(#%s)", obj->getId()); + it->elem->getRepr()->setAttribute(it->attr, url); + g_free(url); + break; + } + case REF_CLIPBOARD: { + SPCSSAttr *style = sp_repr_css_attr(it->elem->getRepr(), "style"); + gchar *url = g_strdup_printf("url(#%s)", obj->getId()); + sp_repr_css_set_property(style, it->attr, url); + g_free(url); + Glib::ustring style_string; + sp_repr_css_write_string(style, style_string); + it->elem->getRepr()->setAttribute("style", style_string); + break; + } } } } @@ -297,7 +303,7 @@ fix_up_refs(const refmap_type *refmap, const id_changelist_type &id_changes) void prevent_id_clashes(SPDocument *imported_doc, SPDocument *current_doc) { - refmap_type *refmap = new refmap_type; + refmap_type refmap; id_changelist_type id_changes; SPObject *imported_root = imported_doc->getRoot(); @@ -305,8 +311,6 @@ prevent_id_clashes(SPDocument *imported_doc, SPDocument *current_doc) change_clashing_ids(imported_doc, current_doc, imported_root, refmap, &id_changes); fix_up_refs(refmap, id_changes); - - delete refmap; } /* @@ -315,24 +319,47 @@ prevent_id_clashes(SPDocument *imported_doc, SPDocument *current_doc) void change_def_references(SPObject *from_obj, SPObject *to_obj) { - refmap_type *refmap = new refmap_type; + refmap_type refmap; SPDocument *current_doc = from_obj->document; std::string old_id(from_obj->getId()); find_references(current_doc->getRoot(), refmap); - refmap_type::const_iterator pos = refmap->find(old_id); - if (pos != refmap->end()) { + refmap_type::const_iterator pos = refmap.find(old_id); + if (pos != refmap.end()) { std::list<IdReference>::const_iterator it; const std::list<IdReference>::const_iterator it_end = pos->second.end(); for (it = pos->second.begin(); it != it_end; ++it) { - if (it->type == REF_STYLE) { - sp_style_set_property_url(it->elem, it->attr, to_obj, false); - } + switch (it->type) { + case REF_HREF: { + gchar *new_uri = g_strdup_printf("#%s", to_obj->getId()); + it->elem->getRepr()->setAttribute(it->attr, new_uri); + g_free(new_uri); + break; + } + case REF_STYLE: { + sp_style_set_property_url(it->elem, it->attr, to_obj, false); + break; + } + case REF_URL: { + gchar *url = g_strdup_printf("url(#%s)", to_obj->getId()); + it->elem->getRepr()->setAttribute(it->attr, url); + g_free(url); + break; + } + case REF_CLIPBOARD: { + SPCSSAttr *style = sp_repr_css_attr(it->elem->getRepr(), "style"); + gchar *url = g_strdup_printf("url(#%s)", to_obj->getId()); + sp_repr_css_set_property(style, it->attr, url); + g_free(url); + Glib::ustring style_string; + sp_repr_css_write_string(style, style_string); + it->elem->getRepr()->setAttribute("style", style_string); + break; + } + } } } - - delete refmap; } /* @@ -355,8 +382,7 @@ void rename_id(SPObject *elem, Glib::ustring const &new_name) } SPDocument *current_doc = elem->document; - refmap_type *refmap = new refmap_type; - id_changelist_type id_changes; + refmap_type refmap; find_references(current_doc->getRoot(), refmap); std::string old_id(elem->getId()); @@ -374,14 +400,14 @@ void rename_id(SPObject *elem, Glib::ustring const &new_name) } // Change to the new ID - elem->getRepr()->setAttribute("id", new_name2.c_str()); + elem->getRepr()->setAttribute("id", new_name2); // Make a note of this change, if we need to fix up refs to it - if (refmap->find(old_id) != refmap->end()) { + id_changelist_type id_changes; + if (refmap.find(old_id) != refmap.end()) { id_changes.push_back(id_changeitem_type(elem, old_id)); } fix_up_refs(refmap, id_changes); - delete refmap; } /* diff --git a/src/ink-comboboxentry-action.cpp b/src/ink-comboboxentry-action.cpp index 06ccc3739..ebd238edc 100644 --- a/src/ink-comboboxentry-action.cpp +++ b/src/ink-comboboxentry-action.cpp @@ -38,7 +38,7 @@ static GtkWidget* create_tool_item( GtkAction* action ); static GtkWidget* create_menu_item( GtkAction* action ); // Internal -static gint get_active_row_from_text( Ink_ComboBoxEntry_Action* action, const gchar* target_text, gboolean exclude = false ); +static gint get_active_row_from_text( Ink_ComboBoxEntry_Action* action, const gchar* target_text, gboolean exclude = false, gboolean ignore_case = false ); static Glib::ustring check_comma_separated_text( Ink_ComboBoxEntry_Action* action ); // Callbacks @@ -732,7 +732,8 @@ void ink_comboboxentry_action_set_altx_name( Ink_ComboBoxEntry_Action* actio // use 3d colunm if available to exclude row from checking (useful to // skip rows added for font-families included in doc and not on // system) -gint get_active_row_from_text( Ink_ComboBoxEntry_Action* action, const gchar* target_text, gboolean exclude ) { +gint get_active_row_from_text( Ink_ComboBoxEntry_Action* action, const gchar* target_text, + gboolean exclude, gboolean ignore_case ) { // Check if text in list gint row = 0; @@ -752,10 +753,23 @@ gint get_active_row_from_text( Ink_ComboBoxEntry_Action* action, const gchar* ta gchar* text = 0; gtk_tree_model_get( action->model, &iter, 0, &text, -1 ); // Column 0 - // Check for match - if( strcmp( target_text, text ) == 0 ){ - found = true; - break; + if( !ignore_case ) { + // Case sensitive compare + if( strcmp( target_text, text ) == 0 ){ + found = true; + break; + } + } else { + // Case insensitive compare + gchar* target_text_casefolded = g_utf8_casefold( target_text, -1 ); + gchar* text_casefolded = g_utf8_casefold( text, -1 ); + gboolean equal = (strcmp( target_text_casefolded, text_casefolded ) == 0 ); + g_free( text_casefolded ); + g_free( target_text_casefolded ); + if( equal ) { + found = true; + break; + } } } @@ -794,7 +808,7 @@ static Glib::ustring check_comma_separated_text( Ink_ComboBoxEntry_Action* actio // Remove any surrounding white space. g_strstrip( tokens[i] ); - if( get_active_row_from_text( action, tokens[i], true ) == -1 ) { + if( get_active_row_from_text( action, tokens[i], true, true ) == -1 ) { missing += tokens[i]; missing += ", "; } diff --git a/src/libnrtype/FontFactory.cpp b/src/libnrtype/FontFactory.cpp index 4ae408397..6859a4a5c 100644 --- a/src/libnrtype/FontFactory.cpp +++ b/src/libnrtype/FontFactory.cpp @@ -54,226 +54,11 @@ bool font_descr_equal::operator()( PangoFontDescription *const&a, PangoFontDesc /////////////////// helper functions -/** - * A wrapper for strcasestr that also provides an implementation for Win32. - */ -static bool -ink_strstr(char const *haystack, char const *pneedle) -{ - // windows has no strcasestr implementation, so here is ours... - // stolen from nmap - /* FIXME: This is broken for e.g. ink_strstr("aab", "ab"). Report to nmap. - * - * Also, suggest use of g_ascii_todown instead of buffer stuff, and g_ascii_tolower instead - * of tolower. Given that haystack is a font name (i.e. fairly short), it should be ok to - * do g_ascii_strdown on both haystack and pneedle, and do normal strstr. - * - * Rather than fixing in inkscape, consider getting rid of this routine, instead using - * strdown and plain strstr at caller. We have control over the needle values, so we can - * modify the callers rather than calling strdown there. - */ - char buf[512]; - register char const *p; - char *needle, *q, *foundto; - if (!*pneedle) return true; - if (!haystack) return false; - - needle = buf; - p = pneedle; q = needle; - while ((*q++ = tolower(*p++))) - ; - p = haystack - 1; foundto = needle; - while (*++p) { - if (tolower(*p) == *foundto) { - if (!*++foundto) { - /* Yeah, we found it */ - return true; - } - } else foundto = needle; - } - return false; -} - -/** - * Regular fonts are 'Regular', 'Roman', 'Normal', or 'Plain' - */ -// FIXME: make this UTF8, add non-English style names -static bool -is_regular(char const *s) -{ - if (ink_strstr(s, "Regular")) return true; - if (ink_strstr(s, "Roman")) return true; - if (ink_strstr(s, "Normal")) return true; - if (ink_strstr(s, "Plain")) return true; - return false; -} - -/** - * Non-bold fonts are 'Medium' or 'Book' - */ -static bool -is_nonbold(char const *s) -{ - if (ink_strstr(s, "Medium")) return true; - if (ink_strstr(s, "Book")) return true; - return false; -} - -/** - * Italic fonts are 'Italic', 'Oblique', or 'Slanted' - */ -static bool -is_italic(char const *s) -{ - if (ink_strstr(s, "Italic")) return true; - if (ink_strstr(s, "Oblique")) return true; - if (ink_strstr(s, "Slanted")) return true; - return false; -} - -/** - * Bold fonts are 'Bold' - */ -static bool -is_bold(char const *s) -{ - if (ink_strstr(s, "Bold")) return true; - return false; -} - -/** - * Caps fonts are 'Caps' - */ -static bool -is_caps(char const *s) -{ - if (ink_strstr(s, "Caps")) return true; - return false; -} - -#if 0 /* FIXME: These are all unused. Please delete them or use them (presumably in -* style_name_compare). */ -/** - * Monospaced fonts are 'Mono' - */ -static bool -is_mono(char const *s) -{ - if (ink_strstr(s, "Mono")) return true; - return false; -} - -/** - * Rounded fonts are 'Round' - */ -static bool -is_round(char const *s) -{ - if (ink_strstr(s, "Round")) return true; - return false; -} - -/** - * Outline fonts are 'Outline' - */ -static bool -is_outline(char const *s) -{ - if (ink_strstr(s, "Outline")) return true; - return false; -} - -/** - * Swash fonts are 'Swash' - */ -static bool -is_swash(char const *s) -{ - if (ink_strstr(s, "Swash")) return true; - return false; -} -#endif - -/** - * Determines if two style names match. This allows us to match - * based on the type of style rather than simply doing string matching, - * because for instance 'Plain' and 'Normal' mean the same thing. - * - * Q: Shouldn't this include the other tests such as is_outline, etc.? - * Q: Is there a problem with strcasecmp on Win32? Should it use stricmp? - */ -int -style_name_compare(char const *aa, char const *bb) -{ - char const *a = (char const *) aa; - char const *b = (char const *) bb; - - if (is_regular(a) && !is_regular(b)) return -1; - if (is_regular(b) && !is_regular(a)) return 1; - - if (is_bold(a) && !is_bold(b)) return 1; - if (is_bold(b) && !is_bold(a)) return -1; - - if (is_italic(a) && !is_italic(b)) return 1; - if (is_italic(b) && !is_italic(a)) return -1; - - if (is_nonbold(a) && !is_nonbold(b)) return 1; - if (is_nonbold(b) && !is_nonbold(a)) return -1; - - if (is_caps(a) && !is_caps(b)) return 1; - if (is_caps(b) && !is_caps(a)) return -1; - - return strcasecmp(a, b); -} - -/* - defined but not used: - -static int -style_record_compare(void const *aa, void const *bb) -{ - NRStyleRecord const *a = (NRStyleRecord const *) aa; - NRStyleRecord const *b = (NRStyleRecord const *) bb; - - return (style_name_compare(a->name, b->name)); -} - -static void font_factory_name_list_destructor(NRNameList *list) -{ - for (unsigned int i = 0; i < list->length; i++) - g_free(list->names[i]); - if ( list->names ) g_free(list->names); -} - -static void font_factory_style_list_destructor(NRStyleList *list) -{ - for (unsigned int i = 0; i < list->length; i++) { - g_free((void *) (list->records)[i].name); - g_free((void *) (list->records)[i].descr); - } - if ( list->records ) g_free(list->records); -} -*/ - -/** - * On Win32 performs a stricmp(a,b), otherwise does a strcasecmp(a,b) - */ -int -family_name_compare(char const *a, char const *b) -{ -#ifndef WIN32 - return strcasecmp((*((char const **) a)), (*((char const **) b))); -#else - return stricmp((*((char const **) a)), (*((char const **) b))); -#endif -} - static void noop(...) {} //#define PANGO_DEBUG g_print #define PANGO_DEBUG noop - ///////////////////// FontFactory #ifndef USE_PANGO_WIN32 // the substitute function to tell fontconfig to enforce outline fonts @@ -708,9 +493,24 @@ Glib::ustring font_factory::FontSpecificationBestMatch(const Glib::ustring & fon ///// -static bool StyleNameCompareInternal(Glib::ustring style1, Glib::ustring style2) +// Calculate a Style "value" based on CSS values for ordering styles. +static int StyleNameValue( const Glib::ustring &style ) +{ + + PangoFontDescription *pfd = pango_font_description_from_string ( style.c_str() ); + int value = + pango_font_description_get_weight ( pfd ) * 1000000 + + pango_font_description_get_style ( pfd ) * 10000 + + pango_font_description_get_stretch( pfd ) * 100 + + pango_font_description_get_variant( pfd ); + pango_font_description_free ( pfd ); + return value; +} + +// Determines order in which styles are presented (sorted by CSS style values) +static bool StyleNameCompareInternal(const StyleNames &style1, const StyleNames &style2) { - return (style_name_compare(style1.c_str(), style2.c_str()) < 0); + return( StyleNameValue( style1.CssName ) < StyleNameValue( style2.CssName ) ); } void font_factory::GetUIFamiliesAndStyles(FamilyToStylesMap *map) @@ -736,7 +536,8 @@ void font_factory::GetUIFamiliesAndStyles(FamilyToStylesMap *map) // If the face has a name, describe it, and then use the // description to get the UI family and face strings - if (pango_font_face_get_face_name(faces[currentFace]) == NULL) { + const gchar* displayName = pango_font_face_get_face_name(faces[currentFace]); + if (displayName == NULL) { continue; } @@ -766,26 +567,26 @@ void font_factory::GetUIFamiliesAndStyles(FamilyToStylesMap *map) // Insert new family if (iter == map->end()) { - map->insert(std::make_pair(familyUIName, std::list<Glib::ustring>())); + map->insert(std::make_pair(familyUIName, std::list<StyleNames>())); } // Insert into the style list and save the info in the reference maps // only if the style does not yet exist bool exists = false; - std::list<Glib::ustring> &styleList = (*map)[familyUIName]; + std::list<StyleNames> &styleList = (*map)[familyUIName]; - for (std::list<Glib::ustring>::iterator it=styleList.begin(); + for (std::list<StyleNames>::iterator it=styleList.begin(); it != styleList.end(); ++it) { - if (*it == styleUIName) { + if ( (*it).CssName == styleUIName) { exists = true; break; } } if (!exists) { - styleList.push_back(styleUIName); + styleList.push_back( StyleNames(styleUIName,displayName) ); // Add the string info needed in the reference maps fontStringMap.insert( diff --git a/src/libnrtype/FontFactory.h b/src/libnrtype/FontFactory.h index 7b606d200..513ee4bf7 100644 --- a/src/libnrtype/FontFactory.h +++ b/src/libnrtype/FontFactory.h @@ -51,15 +51,26 @@ struct font_descr_equal : public std::binary_function<PangoFontDescription*, Pan bool operator()(PangoFontDescription *const &a, PangoFontDescription *const &b) const; }; -// Comparison functions for style names -int style_name_compare(char const *aa, char const *bb); -int family_name_compare(char const *a, char const *b); - // Wraps calls to pango_font_description_get_family with some name substitution const char *sp_font_description_get_family(PangoFontDescription const *fontDescr); -// Map type for gathering UI family and style strings -typedef std::map<Glib::ustring, std::list<Glib::ustring> > FamilyToStylesMap; +// Class for style strings: both CSS and as suggested by font. +class StyleNames { + +public: + StyleNames() {}; + StyleNames( Glib::ustring name ) : + CssName( name ), DisplayName( name ) {}; + StyleNames( Glib::ustring cssname, Glib::ustring displayname ) : + CssName( cssname ), DisplayName( displayname ) {}; + +public: + Glib::ustring CssName; // Style as Pango/CSS would write it. + Glib::ustring DisplayName; // Style as Font designer named it. +}; + +// Map type for gathering UI family and style names +typedef std::map<Glib::ustring, std::list<StyleNames> > FamilyToStylesMap; class font_factory { public: diff --git a/src/libnrtype/font-lister.cpp b/src/libnrtype/font-lister.cpp index 333c4ef5b..43c3045b1 100644 --- a/src/libnrtype/font-lister.cpp +++ b/src/libnrtype/font-lister.cpp @@ -25,6 +25,13 @@ //#define DEBUG_FONT +// CSS dictates that font family names are case insensitive. +// This should really implement full Unicode case unfolding. +bool familyNamesAreEqual( const Glib::ustring &a, const Glib::ustring &b ) { + + return( a.casefold().compare( b.casefold() ) == 0 ); +} + namespace Inkscape { FontLister::FontLister () @@ -57,11 +64,13 @@ namespace Inkscape // Now go through the styles GList *styles = NULL; - std::list<Glib::ustring> &styleStrings = familyStyleMap[familyName]; - for (std::list<Glib::ustring>::iterator it=styleStrings.begin(); + std::list<StyleNames> &styleStrings = familyStyleMap[familyName]; + for (std::list<StyleNames>::iterator it=styleStrings.begin(); it != styleStrings.end(); ++it) { - styles = g_list_append(styles, g_strdup((*it).c_str())); + // Our own copy + StyleNames *copy = new StyleNames( *it ); + styles = g_list_append(styles, copy); } (*treeModelIter)[FontList.styles] = styles; @@ -74,11 +83,11 @@ namespace Inkscape current_fontspec = "sans-serif"; // Empty style -> Normal current_fontspec_system = "Sans"; - /* Create default styles for use when font-family is unknown on system. */ - default_styles = g_list_append( NULL, g_strdup("Normal") ); - default_styles = g_list_append( default_styles, g_strdup("Italic") ); - default_styles = g_list_append( default_styles, g_strdup("Bold") ); - default_styles = g_list_append( default_styles, g_strdup("Bold Italic") ); + /* Create default styles for use when font-family is unknown on system. */ + default_styles = g_list_append( NULL, new StyleNames( "Normal" ) ); + default_styles = g_list_append( default_styles, new StyleNames( "Italic" ) ); + default_styles = g_list_append( default_styles, new StyleNames( "Bold" ) ); + default_styles = g_list_append( default_styles, new StyleNames( "Bold Italic" ) ); font_list_store->thaw_notify(); @@ -89,11 +98,31 @@ namespace Inkscape style_list_store->clear(); for (GList *l=default_styles; l; l = l->next) { Gtk::TreeModel::iterator treeModelIter = style_list_store->append(); - (*treeModelIter)[FontStyleList.styles] = (char*)l->data; + (*treeModelIter)[FontStyleList.cssStyle] = ((StyleNames*)l->data)->CssName; + (*treeModelIter)[FontStyleList.displayStyle] = ((StyleNames*)l->data)->DisplayName; } style_list_store->thaw_notify(); } + FontLister::~FontLister() { + + // Delete default_styles + for (GList *l=default_styles; l; l = l->next) { + delete ((StyleNames*)l->data); + } + + // Delete other styles + Gtk::TreeModel::iterator iter = font_list_store->get_iter( "0" ); + while( iter != font_list_store->children().end() ) { + Gtk::TreeModel::Row row = *iter; + GList *styles = row[FontList.styles]; + for (GList *l=styles; l; l = l->next) { + delete ((StyleNames*)l->data); + } + ++iter; + } + } + // Example of how to use "foreach_iter" // bool // FontLister::print_document_font( const Gtk::TreeModel::iterator &iter ) { @@ -106,7 +135,6 @@ namespace Inkscape // } // font_list_store->foreach_iter( sigc::mem_fun(*this, &FontLister::print_document_font )); - /* Used to insert a font that was not in the document and not on the system into the font list. */ void FontLister::insert_font_family( Glib::ustring new_family ) { @@ -120,7 +148,7 @@ namespace Inkscape Gtk::TreeModel::iterator iter2 = font_list_store->get_iter( "0" ); while( iter2 != font_list_store->children().end() ) { Gtk::TreeModel::Row row = *iter2; - if( row[FontList.onSystem] && tokens[0].compare( row[FontList.family] ) == 0 ) { + if( row[FontList.onSystem] && familyNamesAreEqual( tokens[0], row[FontList.family] ) ) { styles = row[FontList.styles]; break; } @@ -197,7 +225,7 @@ namespace Inkscape Gtk::TreeModel::iterator iter2 = font_list_store->get_iter( "0" ); while( iter2 != font_list_store->children().end() ) { Gtk::TreeModel::Row row = *iter2; - if( row[FontList.onSystem] && tokens[0].compare( row[FontList.family] ) == 0 ) { + if( row[FontList.onSystem] && familyNamesAreEqual( tokens[0], row[FontList.family] ) ) { styles = row[FontList.styles]; break; } @@ -228,7 +256,7 @@ namespace Inkscape path.push_back( row ); Gtk::TreeModel::iterator iter = font_list_store->get_iter( path ); if( iter ) { - if( current_family.compare( (*iter)[FontList.family] ) == 0 ) { + if( familyNamesAreEqual( current_family, (*iter)[FontList.family] ) ) { current_family_row = row; break; } @@ -384,6 +412,7 @@ namespace Inkscape std::pair<Glib::ustring, Glib::ustring> ui = ui_from_fontspec( current_fontspec ); set_font_family( ui.first ); + set_font_style( ui.second ); #ifdef DEBUG_FONT std::cout << " family_row: :" << current_family_row << ":" << std::endl; @@ -424,7 +453,7 @@ std::pair<Glib::ustring, Glib::ustring> FontLister::new_font_family (Glib::ustri #endif // No need to do anything if new family is same as old family. - if ( new_family.compare( current_family ) == 0 ) { + if ( familyNamesAreEqual( new_family, current_family ) ) { #ifdef DEBUG_FONT std::cout << "FontLister::new_font_family: exit: no change in family." << std::endl; std::cout << "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n" << std::endl; @@ -443,7 +472,7 @@ std::pair<Glib::ustring, Glib::ustring> FontLister::new_font_family (Glib::ustri Gtk::TreeModel::Row row = *iter; - if( new_family.compare( row[FontList.family] ) == 0 ) { + if( familyNamesAreEqual( new_family, row[FontList.family] ) ) { styles = row[FontList.styles]; break; } @@ -463,7 +492,8 @@ std::pair<Glib::ustring, Glib::ustring> FontLister::new_font_family (Glib::ustri for (GList *l=styles; l; l = l->next) { Gtk::TreeModel::iterator treeModelIter = style_list_store->append(); - (*treeModelIter)[FontStyleList.styles] = (char*)l->data; + (*treeModelIter)[FontStyleList.cssStyle] = ((StyleNames*)l->data)->CssName; + (*treeModelIter)[FontStyleList.displayStyle] = ((StyleNames*)l->data)->DisplayName; } style_list_store->thaw_notify(); @@ -571,8 +601,15 @@ std::pair<Glib::ustring, Glib::ustring> FontLister::new_font_family (Glib::ustri Glib::ustring family = ui.first; - sp_repr_css_set_property (css, "-inkscape-font-specification", fontspec.c_str() ); - sp_repr_css_set_property (css, "font-family", family.c_str() ); //Canonized w/ spaces + + // Font spec is single quoted... for the moment + Glib::ustring fontspec_quoted( fontspec ); + css_quote( fontspec_quoted ); + sp_repr_css_set_property (css, "-inkscape-font-specification", fontspec_quoted.c_str() ); + + // Font families needs to be properly quoted in CSS (used unquoted in font-lister) + css_font_family_quote( family ); + sp_repr_css_set_property (css, "font-family", family.c_str() ); PangoFontDescription *desc = pango_font_description_from_string( fontspec.c_str() ); PangoWeight weight = pango_font_description_get_weight( desc ); @@ -688,18 +725,19 @@ std::pair<Glib::ustring, Glib::ustring> FontLister::new_font_family (Glib::ustri fontspec = style->font_family.value; fontspec += ","; + // Use weight names as defined by Pango switch (style->font_weight.computed) { case SP_CSS_FONT_WEIGHT_100: - fontspec += " 100"; + fontspec += " Thin"; break; case SP_CSS_FONT_WEIGHT_200: - fontspec += " 200"; + fontspec += " Ultra-Light"; break; case SP_CSS_FONT_WEIGHT_300: - fontspec += " 300"; + fontspec += " Light"; break; case SP_CSS_FONT_WEIGHT_400: @@ -708,24 +746,24 @@ std::pair<Glib::ustring, Glib::ustring> FontLister::new_font_family (Glib::ustri break; case SP_CSS_FONT_WEIGHT_500: - fontspec += " 500"; + fontspec += " Medium"; break; case SP_CSS_FONT_WEIGHT_600: - fontspec += " 600"; + fontspec += " Semi-Bold"; break; case SP_CSS_FONT_WEIGHT_700: case SP_CSS_FONT_WEIGHT_BOLD: - fontspec += " bold"; + fontspec += " Bold"; break; case SP_CSS_FONT_WEIGHT_800: - fontspec += " 800"; + fontspec += " Ultra-Bold"; break; case SP_CSS_FONT_WEIGHT_900: - fontspec += " 900"; + fontspec += " Heavy"; break; case SP_CSS_FONT_WEIGHT_LIGHTER: @@ -821,7 +859,7 @@ std::pair<Glib::ustring, Glib::ustring> FontLister::new_font_family (Glib::ustri Gtk::TreeModel::Row row = *iter; - if( family.compare( row[FontList.family] ) == 0 ) { + if( familyNamesAreEqual( family, row[FontList.family] ) ) { return row; } @@ -847,7 +885,7 @@ std::pair<Glib::ustring, Glib::ustring> FontLister::new_font_family (Glib::ustri Gtk::TreeModel::Row row = *iter; - if( style.compare( row[FontStyleList.styles] ) == 0 ) { + if( familyNamesAreEqual( style, row[FontStyleList.cssStyle] ) ) { return row; } @@ -974,10 +1012,6 @@ std::pair<Glib::ustring, Glib::ustring> FontLister::new_font_family (Glib::ustri return best_style; } - FontLister::~FontLister () - { - }; - const Glib::RefPtr<Gtk::ListStore> FontLister::get_font_list () const { @@ -1035,7 +1069,7 @@ void font_lister_cell_data_func(GtkCellLayout */*cell_layout*/, valid = gtk_tree_model_iter_next( GTK_TREE_MODEL(model), &iter ) ) { gtk_tree_model_get(model, &iter, 0, &family, 2, &onSystem, -1); - if( onSystem && token.compare( family ) == 0 ) { + if( onSystem && familyNamesAreEqual( token, family ) ) { found = true; break; } diff --git a/src/libnrtype/font-lister.h b/src/libnrtype/font-lister.h index a460388d3..c89dab550 100644 --- a/src/libnrtype/font-lister.h +++ b/src/libnrtype/font-lister.h @@ -100,13 +100,18 @@ namespace Inkscape : public Gtk::TreeModelColumnRecord { public: - /** Column containing the styles + /** Column containing the styles as Font designer used. */ - Gtk::TreeModelColumn<Glib::ustring> styles; + Gtk::TreeModelColumn<Glib::ustring> displayStyle; + + /** Column containing the styles in CSS/Pango format. + */ + Gtk::TreeModelColumn<Glib::ustring> cssStyle; FontStyleListClass () { - add (styles); + add (cssStyle); + add (displayStyle); } }; @@ -276,7 +281,7 @@ namespace Inkscape private: FontLister (); - + NRNameList families; Glib::RefPtr<Gtk::ListStore> font_list_store; diff --git a/src/selection-chemistry.cpp b/src/selection-chemistry.cpp index 868a9d743..a350dd7a7 100644 --- a/src/selection-chemistry.cpp +++ b/src/selection-chemistry.cpp @@ -3950,6 +3950,10 @@ void sp_selection_unset_mask(SPDesktop *desktop, bool apply_clip_path) { for ( SPObject *child = obj->firstChild() ; child; child = child->getNext() ) { // Collect all clipped paths and masks within a single group Inkscape::XML::Node *copy = SP_OBJECT(child)->getRepr()->duplicate(xml_doc); + if(copy->attribute("inkscape:original-d")) + { + copy->setAttribute("d", copy->attribute("inkscape:original-d")); + } items_to_move = g_slist_prepend(items_to_move, copy); } diff --git a/src/sp-ellipse.cpp b/src/sp-ellipse.cpp index cda59e057..428e0e3dd 100644 --- a/src/sp-ellipse.cpp +++ b/src/sp-ellipse.cpp @@ -467,6 +467,8 @@ void SPGenericEllipse::set_shape() bool success = this->performPathEffect(c_lpe); if (success) { + sp_lpe_item_apply_to_mask(this); + sp_lpe_item_apply_to_clippath(this); this->setCurveInsync(c_lpe, TRUE); } diff --git a/src/sp-gradient.cpp b/src/sp-gradient.cpp index 115cb754a..1479acd69 100644 --- a/src/sp-gradient.cpp +++ b/src/sp-gradient.cpp @@ -117,12 +117,17 @@ gboolean SPGradient::isEquivalent(SPGradient *that) if (this->getStopCount() != that->getStopCount()) { break; } if (this->hasStops() != that->hasStops()) { break; } if (!this->getVector() || !that->getVector()) { break; } - if ( (SP_IS_LINEARGRADIENT(this) && SP_IS_LINEARGRADIENT(that)) || - (SP_IS_RADIALGRADIENT(this) && SP_IS_RADIALGRADIENT(that)) || - (SP_IS_MESHGRADIENT(this) && SP_IS_MESHGRADIENT(that))) { - /* OK! */ + if (this->isSwatch() != that->isSwatch()) { break; } + if ( this->isSwatch() ){ + // drop down to check stops. } - else { break; } + else if ( + (SP_IS_LINEARGRADIENT(this) && SP_IS_LINEARGRADIENT(that)) || + (SP_IS_RADIALGRADIENT(this) && SP_IS_RADIALGRADIENT(that)) || + (SP_IS_MESHGRADIENT(this) && SP_IS_MESHGRADIENT(that))) { + if(!this->isAligned(that))break; + } + else { break; } // this should never happen, some unhandled type of gradient SPStop *as = this->getVector()->getFirstStop(); SPStop *bs = that->getVector()->getFirstStop(); @@ -156,6 +161,18 @@ gboolean SPGradient::isAligned(SPGradient *that) { bool status = FALSE; + /* Some gradients have coordinates/other values specified, some don't. + yes/yes check the coordinates/other values + no/no aligned (because both have all default values) + yes/no not aligned + no/yes not aligned + It is NOT safe to just compare the computed values because if that field has + not been set the computed value could be full of garbage. + + In theory the yes/no and no/yes cases could be aligned if the specified value + matches the default value. + */ + while(1){ // not really a loop, used to avoid deep nesting or multiple exit points from function if(this->gradientTransform_set != that->gradientTransform_set) { break; } if(this->gradientTransform_set && @@ -164,31 +181,45 @@ gboolean SPGradient::isAligned(SPGradient *that) SPLinearGradient *sg=SP_LINEARGRADIENT(this); SPLinearGradient *tg=SP_LINEARGRADIENT(that); - if( !sg->x1._set || !tg->x1._set || // assume that if these are set so will be all the others - (sg->x1.computed != tg->x1.computed) || - (sg->y1.computed != tg->y1.computed) || - (sg->x2.computed != tg->x2.computed) || - (sg->y2.computed != tg->y2.computed) - ) { break; } + if( sg->x1._set != tg->x1._set) { break; } + if( sg->y1._set != tg->y1._set) { break; } + if( sg->x2._set != tg->x2._set) { break; } + if( sg->y2._set != tg->y2._set) { break; } + if( sg->x1._set && sg->y1._set && sg->x2._set && sg->y2._set) { + if( (sg->x1.computed != tg->x1.computed) || + (sg->y1.computed != tg->y1.computed) || + (sg->x2.computed != tg->x2.computed) || + (sg->y2.computed != tg->y2.computed) ) { break; } + } else if( sg->x1._set || sg->y1._set || sg->x2._set || sg->y2._set) { break; } // some mix of set and not set + // none set? assume aligned and fall through } else if (SP_IS_RADIALGRADIENT(this) && SP_IS_LINEARGRADIENT(that)) { SPRadialGradient *sg=SP_RADIALGRADIENT(this); SPRadialGradient *tg=SP_RADIALGRADIENT(that); - if( !sg->cx._set || !tg->cx._set || // assume that if these are set so will be all the others - (sg->cx.computed != tg->cx.computed) || - (sg->cy.computed != tg->cy.computed) || - (sg->r.computed != tg->r.computed ) || - (sg->fx.computed != tg->fx.computed) || - (sg->fy.computed != tg->fy.computed) - ) { break; } + + if( sg->cx._set != tg->cx._set) { break; } + if( sg->cy._set != tg->cy._set) { break; } + if( sg->r._set != tg->r._set) { break; } + if( sg->fx._set != tg->fx._set) { break; } + if( sg->fy._set != tg->fy._set) { break; } + if( sg->cx._set && sg->cy._set && sg->fx._set && sg->fy._set && sg->r._set) { + if( (sg->cx.computed != tg->cx.computed) || + (sg->cy.computed != tg->cy.computed) || + (sg->r.computed != tg->r.computed ) || + (sg->fx.computed != tg->fx.computed) || + (sg->fy.computed != tg->fy.computed) ) { break; } + } else if( sg->cx._set || sg->cy._set || sg->fx._set || sg->fy._set || sg->r._set ) { break; } // some mix of set and not set + // none set? assume aligned and fall through } else if (SP_IS_MESHGRADIENT(this) && SP_IS_MESHGRADIENT(that)) { SPMeshGradient *sg=SP_MESHGRADIENT(this); SPMeshGradient *tg=SP_MESHGRADIENT(that); - if( !sg->x._set || !tg->x._set || - !sg->y._set || !tg->y._set || - (sg->x.computed != tg->x.computed) || - (sg->y.computed != tg->y.computed) - ) { break; } + if( sg->x._set != !tg->x._set) { break; } + if( sg->y._set != !tg->y._set) { break; } + if( sg->x._set && sg->y._set) { + if( (sg->x.computed != tg->x.computed) || + (sg->y.computed != tg->y.computed) ) { break; } + } else if( sg->x._set || sg->y._set) { break; } // some mix of set and not set + // none set? assume aligned and fall through } else { break; } diff --git a/src/sp-item-group.cpp b/src/sp-item-group.cpp index 2cfe97db8..b3db0c1d7 100644 --- a/src/sp-item-group.cpp +++ b/src/sp-item-group.cpp @@ -778,17 +778,31 @@ void SPGroup::update_patheffect(bool write) { } } + +void +sp_gslist_update_by_clip_or_mask(GSList *item_list,SPItem * item) +{ + if(item->mask_ref->getObject()) { + SPObject * clipormask = item->mask_ref->getObject()->firstChild(); + item_list = g_slist_append(item_list,clipormask); + } + if(item->clip_ref->getObject()) { + SPObject * clipormask = item->clip_ref->getObject()->firstChild(); + item_list = g_slist_append(item_list,clipormask); + } +} + static void sp_group_perform_patheffect(SPGroup *group, SPGroup *topgroup, bool write) { - GSList const *item_list = sp_item_group_item_list(SP_GROUP(group)); - - for ( GSList const *iter = item_list; iter; iter = iter->next ) { + GSList *item_list = sp_item_group_item_list(group); + sp_gslist_update_by_clip_or_mask(item_list,group); + for ( GSList *iter = item_list; iter; iter = iter->next ) { SPObject *subitem = static_cast<SPObject *>(iter->data); - if (SP_IS_GROUP(subitem)) { sp_group_perform_patheffect(SP_GROUP(subitem), topgroup, write); } else if (SP_IS_SHAPE(subitem)) { + sp_gslist_update_by_clip_or_mask(item_list,SP_ITEM(subitem)); SPCurve * c = NULL; if (SP_IS_PATH(subitem)) { @@ -799,9 +813,17 @@ sp_group_perform_patheffect(SPGroup *group, SPGroup *topgroup, bool write) // only run LPEs when the shape has a curve defined if (c) { - c->transform(i2anc_affine(subitem, topgroup)); + if(SP_IS_MASK(subitem->parent) || SP_IS_CLIPPATH(subitem->parent)) { + c->transform(i2anc_affine(group, topgroup)); + } else { + c->transform(i2anc_affine(subitem, topgroup)); + } SP_LPE_ITEM(topgroup)->performPathEffect(c); - c->transform(i2anc_affine(subitem, topgroup).inverse()); + if(SP_IS_MASK(subitem->parent) || SP_IS_CLIPPATH(subitem->parent)) { + c->transform(i2anc_affine(group, topgroup).inverse()); + } else { + c->transform(i2anc_affine(subitem, topgroup).inverse()); + } SP_SHAPE(subitem)->setCurve(c, TRUE); if (write) { @@ -809,7 +831,7 @@ sp_group_perform_patheffect(SPGroup *group, SPGroup *topgroup, bool write) gchar *str = sp_svg_write_path(c->get_pathvector()); repr->setAttribute("d", str); #ifdef GROUP_VERBOSE -g_message("sp_group_perform_patheffect writes 'd' attribute"); + g_message("sp_group_perform_patheffect writes 'd' attribute"); #endif g_free(str); } diff --git a/src/sp-item-group.h b/src/sp-item-group.h index 2004a72b8..adec35571 100644 --- a/src/sp-item-group.h +++ b/src/sp-item-group.h @@ -88,7 +88,7 @@ public: void sp_item_group_ungroup (SPGroup *group, GSList **children, bool do_done = true); - +void sp_gslist_update_by_clip_or_mask(GSList *item_list, SPItem * item); GSList *sp_item_group_item_list (SPGroup *group); SPObject *sp_item_group_get_child_by_name (SPGroup *group, SPObject *ref, const gchar *name); diff --git a/src/sp-lpe-item.cpp b/src/sp-lpe-item.cpp index b5dd74fc6..bfecdcf98 100644 --- a/src/sp-lpe-item.cpp +++ b/src/sp-lpe-item.cpp @@ -38,6 +38,11 @@ #include "desktop.h" #include "shape-editor.h" #include "sp-ellipse.h" +#include "display/curve.h" +#include "svg/svg.h" +#include <2geom/pathvector.h> +#include "sp-clippath.h" +#include "sp-mask.h" #include "tools-switch.h" #include "ui/tools/node-tool.h" #include "ui/tools/tool-base.h" @@ -51,6 +56,8 @@ static void lpeobject_ref_modified(SPObject *href, guint flags, SPLPEItem *lpeit 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_apply_to_clip_or_mask_group(SPGroup * group, SPItem * item); + typedef std::list<std::string> HRefList; static std::string patheffectlist_write_svg(PathEffectList const & list); static std::string hreflist_write_svg(HRefList const & list); @@ -332,6 +339,16 @@ lpeobject_ref_modified(SPObject */*href*/, guint /*flags*/, SPLPEItem *lpeitem) static void sp_lpe_item_create_original_path_recursive(SPLPEItem *lpeitem) { + SPMask * mask = lpeitem->mask_ref->getObject(); + if(mask) + { + sp_lpe_item_create_original_path_recursive(SP_LPE_ITEM(mask->firstChild())); + } + SPClipPath * clipPath = lpeitem->clip_ref->getObject(); + if(clipPath) + { + sp_lpe_item_create_original_path_recursive(SP_LPE_ITEM(clipPath->firstChild())); + } if (SP_IS_GROUP(lpeitem)) { GSList const *item_list = sp_item_group_item_list(SP_GROUP(lpeitem)); for ( GSList const *iter = item_list; iter; iter = iter->next ) { @@ -352,6 +369,17 @@ sp_lpe_item_create_original_path_recursive(SPLPEItem *lpeitem) static void 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())); + } + SPClipPath * clipPath = lpeitem->clip_ref->getObject(); + if(clipPath) + { + sp_lpe_item_cleanup_original_path_recursive(SP_LPE_ITEM(clipPath->firstChild())); + } + if (SP_IS_GROUP(lpeitem)) { GSList const *item_list = sp_item_group_item_list(SP_GROUP(lpeitem)); for ( GSList const *iter = item_list; iter; iter = iter->next ) { @@ -597,6 +625,124 @@ bool SPLPEItem::hasPathEffectRecursive() const } } +void +sp_lpe_item_apply_to_clippath(SPItem * item) +{ + SPClipPath *clipPath = item->clip_ref->getObject(); + if(clipPath) { + SPObject * clip_data = clipPath->firstChild(); + SPCurve * clip_curve = NULL; + + if (SP_IS_PATH(clip_data)) { + clip_curve = SP_PATH(clip_data)->get_original_curve(); + } else if(SP_IS_SHAPE(clip_data)) { + clip_curve = SP_SHAPE(clip_data)->getCurve(); + } else if(SP_IS_GROUP(clip_data)) { + sp_lpe_item_apply_to_clip_or_mask_group(SP_GROUP(clip_data), item); + return; + } + if(clip_curve) { + bool success = SP_LPE_ITEM(item)->performPathEffect(clip_curve); + Inkscape::XML::Node *reprClip = clip_data->getRepr(); + if (success) { + gchar *str = sp_svg_write_path(clip_curve->get_pathvector()); + reprClip->setAttribute("d", str); + g_free(str); + } else { + // LPE was unsuccesfull. Read the old 'd'-attribute. + if (gchar const * value = reprClip->attribute("d")) { + Geom::PathVector pv = sp_svg_read_pathv(value); + SPCurve *oldcurve = new SPCurve(pv); + if (oldcurve) { + SP_SHAPE(clip_data)->setCurve(oldcurve, TRUE); + oldcurve->unref(); + } + } + } + clip_curve->unref(); + } + } +} + +void +sp_lpe_item_apply_to_mask(SPItem * item) +{ + SPMask *mask = item->mask_ref->getObject(); + if(mask) { + SPObject * mask_data = mask->firstChild(); + SPCurve * mask_curve = NULL; + mask_data = mask->firstChild(); + if (SP_IS_PATH(mask_data)) { + mask_curve = SP_PATH(mask_data)->get_original_curve(); + } else if(SP_IS_SHAPE(mask_data)) { + mask_curve = SP_SHAPE(mask_data)->getCurve(); + } else if(SP_IS_GROUP(mask_data)) { + sp_lpe_item_apply_to_clip_or_mask_group(SP_GROUP(mask_data), item); + return; + } + if(mask_curve) { + bool success = SP_LPE_ITEM(item)->performPathEffect(mask_curve); + Inkscape::XML::Node *reprmask = mask_data->getRepr(); + if (success) { + gchar *str = sp_svg_write_path(mask_curve->get_pathvector()); + reprmask->setAttribute("d", str); + g_free(str); + } else { + // LPE was unsuccesfull. Read the old 'd'-attribute. + if (gchar const * value = reprmask->attribute("d")) { + Geom::PathVector pv = sp_svg_read_pathv(value); + SPCurve *oldcurve = new SPCurve(pv); + if (oldcurve) { + SP_SHAPE(mask_data)->setCurve(oldcurve, TRUE); + oldcurve->unref(); + } + } + } + mask_curve->unref(); + } + } +} + +static void +sp_lpe_item_apply_to_clip_or_mask_group(SPGroup *group, SPItem *item) +{ + GSList *item_list = sp_item_group_item_list(group); + for ( GSList *iter = item_list; iter; iter = iter->next ) { + SPObject *subitem = static_cast<SPObject *>(iter->data); + if (SP_IS_GROUP(subitem)) { + sp_lpe_item_apply_to_clip_or_mask_group(SP_GROUP(subitem), item); + } else if (SP_IS_SHAPE(subitem)) { + SPCurve * c = NULL; + + if (SP_IS_PATH(subitem)) { + c = SP_PATH(subitem)->get_original_curve(); + } else { + c = SP_SHAPE(subitem)->getCurve(); + } + if (c) { + bool success = SP_LPE_ITEM(item)->performPathEffect(c); + Inkscape::XML::Node *repr = subitem->getRepr(); + if (success) { + gchar *str = sp_svg_write_path(c->get_pathvector()); + repr->setAttribute("d", str); + g_free(str); + } else { + // LPE was unsuccesfull. Read the old 'd'-attribute. + if (gchar const * value = repr->attribute("d")) { + Geom::PathVector pv = sp_svg_read_pathv(value); + SPCurve *oldcurve = new SPCurve(pv); + if (oldcurve) { + SP_SHAPE(subitem)->setCurve(oldcurve, TRUE); + oldcurve->unref(); + } + } + } + c->unref(); + } + } + } +} + Inkscape::LivePathEffect::Effect* SPLPEItem::getPathEffectOfType(int type) { diff --git a/src/sp-lpe-item.h b/src/sp-lpe-item.h index cd72ac55b..5a38fdd0b 100644 --- a/src/sp-lpe-item.h +++ b/src/sp-lpe-item.h @@ -97,6 +97,8 @@ public: void editNextParamOncanvas(SPDesktop *dt); }; +void sp_lpe_item_apply_to_mask(SPItem * item); +void sp_lpe_item_apply_to_clippath(SPItem * item); void sp_lpe_item_update_patheffect (SPLPEItem *lpeitem, bool wholetree, bool write); // careful, class already has method with *very* similar name! #endif /* !SP_LPE_ITEM_H_SEEN */ diff --git a/src/sp-path.cpp b/src/sp-path.cpp index cbb61b0f6..4a68b82c7 100644 --- a/src/sp-path.cpp +++ b/src/sp-path.cpp @@ -310,6 +310,8 @@ g_message("sp_path_update_patheffect"); bool success = this->performPathEffect(curve); if (success && write) { + sp_lpe_item_apply_to_mask(this); + sp_lpe_item_apply_to_clippath(this); // could also do this->getRepr()->updateRepr(); but only the d attribute needs updating. #ifdef PATH_VERBOSE g_message("sp_path_update_patheffect writes 'd' attribute"); diff --git a/src/sp-spiral.cpp b/src/sp-spiral.cpp index 9ef73d56d..8d4a37bf0 100644 --- a/src/sp-spiral.cpp +++ b/src/sp-spiral.cpp @@ -385,6 +385,8 @@ void SPSpiral::set_shape() { bool success = this->performPathEffect(c_lpe); if (success) { + sp_lpe_item_apply_to_mask(this); + sp_lpe_item_apply_to_clippath(this); this->setCurveInsync( c_lpe, TRUE); } diff --git a/src/sp-star.cpp b/src/sp-star.cpp index eac33ed7b..170a863b5 100644 --- a/src/sp-star.cpp +++ b/src/sp-star.cpp @@ -465,6 +465,8 @@ void SPStar::set_shape() { bool success = this->performPathEffect(c_lpe); if (success) { + sp_lpe_item_apply_to_mask(this); + sp_lpe_item_apply_to_clippath(this); this->setCurveInsync( c_lpe, TRUE); } diff --git a/src/style-internal.cpp b/src/style-internal.cpp index 8b4f3c1cd..c686a1807 100644 --- a/src/style-internal.cpp +++ b/src/style-internal.cpp @@ -656,20 +656,21 @@ SPIString::read( gchar const *str ) { set = true; inherit = false; - // libcroco puts quotes around some strings... remove - Glib::ustring str_unquoted(str); - css_unquote( str_unquoted ); - - // Unquote individual family names, Pango always uses unquoted names. + Glib::ustring str_temp(str); if( name.compare( "font-family" ) == 0 ) { - css_font_family_unquote( str_unquoted ); + // Family names may be quoted in CSS, internally we use unquoted names. + css_font_family_unquote( str_temp ); + } else if( name.compare( "-inkscape-font-specification" ) == 0 ) { + css_unquote( str_temp ); } - value = g_strdup(str_unquoted.c_str()); + value = g_strdup(str_temp.c_str()); } } +// This routine is actually rarely used. Writing is done usually +// in sp_repr_css_write_string... const Glib::ustring SPIString::write( guint const flags, SPIBase const *const base) const { @@ -684,13 +685,13 @@ SPIString::write( guint const flags, SPIBase const *const base) const { } else { if( this->value ) { if( name.compare( "font-family" ) == 0 ) { - // This is for compatibilty with the C version of code. - // This is incorrect as it puts single quotes around the - // entire string rather around the individule font names. - // This should be handled by the routines that extract - // out the font family names and reassembles them into a - // font fallback list. FIXME - return (name + ":" + css2_escape_quote(this->value) + ";"); + Glib::ustring font_family( this->value ); + css_font_family_quote( font_family ); + return (name + ":" + font_family + ";"); + } else if( name.compare( "-inkscape-font-specification" ) == 0 ) { + Glib::ustring font_spec( this->value ); + css_quote( font_spec ); + return (name + ":" + font_spec + ";"); } else { return (name + ":" + this->value + ";"); } diff --git a/src/style.cpp b/src/style.cpp index 8e4c89839..c6a98e7f4 100644 --- a/src/style.cpp +++ b/src/style.cpp @@ -1826,12 +1826,67 @@ sp_css_attr_scale(SPCSSAttr *css, double ex) } +/** + * Quote and/or escape string for writing to CSS, changing strings in place. + * See: http://www.w3.org/TR/CSS21/syndata.html#value-def-identifier + */ +void +css_quote(Glib::ustring &val) +{ + Glib::ustring out; + bool quote = false; + + // Can't wait for C++11! + for( Glib::ustring::iterator it = val.begin(); it != val.end(); ++it) { + if(g_ascii_isalnum(*it) || *it=='-' || *it=='_' || *it > 0xA0) { + out += *it; + } else if (*it == '\'') { + // Single quotes require escaping and quotes. + out += '\\'; + out += *it; + quote = true; + } else { + // Quote everything else including spaces. + // (CSS Fonts Level 3 recommends quoting with spaces.) + out += *it; + quote = true; + } + if( it == val.begin() && !g_ascii_isalpha(*it) ) { + // A non-ASCII/non-alpha initial value on any indentifier needs quotes. + // (Actually it's a bit more complicated but as it never hurts to quote...) + quote = true; + } + } + if( quote ) { + out.insert( out.begin(), '\'' ); + out += '\''; + } + val = out; +} + + +/** + * Quote font names in font-family lists, changing string in place. + * We use unquoted names internally but some need to be quoted in CSS. + */ +void +css_font_family_quote(Glib::ustring &val) +{ + std::vector<Glib::ustring> tokens = Glib::Regex::split_simple("\\s*,\\s*", val ); + + val.erase(); + for( unsigned i=0; i < tokens.size(); ++i ) { + css_quote( tokens[i] ); + val += tokens[i] + ", "; + } + if( val.size() > 1 ) + val.erase( val.size() - 2 ); // Remove trailing ", " +} + + // Called in style-internal.cpp, xml/repr-css.cpp /** * Remove paired single and double quotes from a string, changing string in place. - * Note: in CSS (in style= and in stylesheets), unquoting and unescaping is done - * by libcroco, our CSS parser, though it adds a new pair of "" quotes for the strings - * it parsed for us. */ void css_unquote(Glib::ustring &val) @@ -1849,7 +1904,7 @@ css_unquote(Glib::ustring &val) /** * Remove paired single and double quotes from font names in font-family lists, * changing string in place. - * Pango expects unquoted font family names. We use unquoted names in interface. + * We use unquoted family names internally but CSS sometimes uses quoted names. */ void css_font_family_unquote(Glib::ustring &val) @@ -1865,57 +1920,6 @@ css_font_family_unquote(Glib::ustring &val) val.erase( val.size() - 2 ); // Remove trailing ", " } -// Called in style.cpp, xml/repr-css.cpp -/** - * Quote and/or escape string for writing to CSS (style=). Returned value must be g_free'd. - */ -Glib::ustring css2_escape_quote(gchar const *val) { - - Glib::ustring t; - bool quote = false; - bool last_was_space = false; - - for (gchar const *i = val; *i; i++) { - bool is_space = ( *i == ' ' ); - if (g_ascii_isalnum(*i) || *i=='-' || *i=='_') { - // ASCII alphanumeric, - and _ don't require quotes - t.push_back(*i); - } else if ( is_space && !last_was_space ) { - // non-consecutive spaces don't require quotes - t.push_back(*i); - } else if (*i=='\'') { - // single quotes require escaping and quotes - t.push_back('\\'); - t.push_back(*i); - quote = true; - } else { - // everything else requires quotes - t.push_back(*i); - quote = true; - } - if (i == val && !g_ascii_isalpha(*i)) { - // a non-ASCII/non-alpha initial character requires quotes - quote = true; - } - last_was_space = is_space; - } - - if (last_was_space) { - // a trailing space requires quotes - quote = true; - } - - if (quote) { - // we use single quotes so the result can be stored in an XML - // attribute without incurring un-aesthetic additional quoting - // (our XML emitter always uses double quotes) - t.insert(t.begin(), '\''); - t.push_back('\''); - } - - return t; -} - /* Local Variables: mode:c++ diff --git a/src/style.h b/src/style.h index 506b90b44..931dcc90e 100644 --- a/src/style.h +++ b/src/style.h @@ -292,7 +292,9 @@ void sp_style_unset_property_attrs(SPObject *o); void sp_style_set_property_url (SPObject *item, gchar const *property, SPObject *linked, bool recursive); +void css_quote( Glib::ustring &val ); // Add quotes around CSS values void css_unquote( Glib::ustring &val ); // Remove quotes from CSS values (style-internal.cpp, xml/repr-css.cpp) +void css_font_family_quote( Glib::ustring &val ); // style-internal.cpp, text-toolbar.cpp void css_font_family_unquote( Glib::ustring &val ); // style-internal.cpp, text-toolbar.cpp Glib::ustring css2_escape_quote(gchar const *val); diff --git a/src/ui/dialog/aboutbox.cpp b/src/ui/dialog/aboutbox.cpp index 121773b6d..a66855b2a 100644 --- a/src/ui/dialog/aboutbox.cpp +++ b/src/ui/dialog/aboutbox.cpp @@ -442,7 +442,7 @@ void AboutBox::initStrings() { */ gchar const *allTranslators = "3ARRANO.com <3arrano@3arrano.com>, 2005.\n" -"Adib Taraben <theadib@googlemail.com>, 2004.\n" +"Adib Taraben <theadib@gmail.com>, 2004.\n" "Alan Monfort <alan.monfort@free.fr>, 2009-2010.\n" "Alastair McKinstry <mckinstry@computer.org>, 2000.\n" "Aleksandar Urošević <urke@users.sourceforge.net>, 2004-2006.\n" diff --git a/src/ui/dialog/symbols.cpp b/src/ui/dialog/symbols.cpp index 0b048ed82..27e40f552 100644 --- a/src/ui/dialog/symbols.cpp +++ b/src/ui/dialog/symbols.cpp @@ -219,25 +219,27 @@ SymbolsDialog::SymbolsDialog( gchar const* prefsPath ) : Gtk::Label* spacer = Gtk::manage(new Gtk::Label("")); tools->pack_start(* Gtk::manage(spacer)); - in_sizes = 2; // Default 32px + // Pack size (controls display area) + pack_size = 2; // Default 32px button = Gtk::manage(new Gtk::Button()); button->add(*Gtk::manage(Glib::wrap( - sp_icon_new (Inkscape::ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_ICON("symbol-bigger")))) ); - button->set_tooltip_text(_("Make Icons bigger by zooming in.")); + sp_icon_new (Inkscape::ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_ICON("pack-more")))) ); + button->set_tooltip_text(_("Display more icons in row.")); button->set_relief( Gtk::RELIEF_NONE ); button->set_focus_on_click( false ); - button->signal_clicked().connect(sigc::mem_fun(*this, &SymbolsDialog::zoomin)); + button->signal_clicked().connect(sigc::mem_fun(*this, &SymbolsDialog::packmore)); tools->pack_start(* button, Gtk::PACK_SHRINK); button = Gtk::manage(new Gtk::Button()); button->add(*Gtk::manage(Glib::wrap( - sp_icon_new (Inkscape::ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_ICON("symbol-smaller")))) ); - button->set_tooltip_text(_("Make Icons smaller by zooming out.")); + sp_icon_new (Inkscape::ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_ICON("pack-less")))) ); + button->set_tooltip_text(_("Display fewer icons in row.")); button->set_relief( Gtk::RELIEF_NONE ); button->set_focus_on_click( false ); - button->signal_clicked().connect(sigc::mem_fun(*this, &SymbolsDialog::zoomout)); + button->signal_clicked().connect(sigc::mem_fun(*this, &SymbolsDialog::packless)); tools->pack_start(* button, Gtk::PACK_SHRINK); + // Toggle scale to fit on/off fitSymbol = Gtk::manage(new Gtk::ToggleButton()); fitSymbol->add(*Gtk::manage(Glib::wrap( sp_icon_new (Inkscape::ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_ICON("symbol-fit")))) ); @@ -248,6 +250,28 @@ SymbolsDialog::SymbolsDialog( gchar const* prefsPath ) : fitSymbol->signal_clicked().connect(sigc::mem_fun(*this, &SymbolsDialog::rebuild)); tools->pack_start(* fitSymbol, Gtk::PACK_SHRINK); + // Render size (scales symbols within display area) + scale_factor = 0; // Default 1:1 * pack_size/pack_size default + zoomOut = Gtk::manage(new Gtk::Button()); + zoomOut->add(*Gtk::manage(Glib::wrap( + sp_icon_new (Inkscape::ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_ICON("symbol-smaller")))) ); + zoomOut->set_tooltip_text(_("Make symbols smaller by zooming out.")); + zoomOut->set_relief( Gtk::RELIEF_NONE ); + zoomOut->set_focus_on_click( false ); + zoomOut->set_sensitive( false ); + zoomOut->signal_clicked().connect(sigc::mem_fun(*this, &SymbolsDialog::zoomout)); + tools->pack_start(* zoomOut, Gtk::PACK_SHRINK); + + zoomIn = Gtk::manage(new Gtk::Button()); + zoomIn->add(*Gtk::manage(Glib::wrap( + sp_icon_new (Inkscape::ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_ICON("symbol-bigger")))) ); + zoomIn->set_tooltip_text(_("Make symbols bigger by zooming in.")); + zoomIn->set_relief( Gtk::RELIEF_NONE ); + zoomIn->set_focus_on_click( false ); + zoomIn->set_sensitive( false ); + zoomIn->signal_clicked().connect(sigc::mem_fun(*this, &SymbolsDialog::zoomin)); + tools->pack_start(* zoomIn, Gtk::PACK_SHRINK); + ++row; /**********************************************************/ @@ -298,22 +322,44 @@ SymbolsDialog& SymbolsDialog::getInstance() return *new SymbolsDialog(); } +void SymbolsDialog::packless() { + if(pack_size < 4) { + pack_size++; + rebuild(); + } +} + +void SymbolsDialog::packmore() { + if(pack_size > 0) { + pack_size--; + rebuild(); + } +} + void SymbolsDialog::zoomin() { - if(in_sizes < 4) { - in_sizes++; + if(scale_factor < 4) { + scale_factor++; rebuild(); } } void SymbolsDialog::zoomout() { - if(in_sizes > 0) { - in_sizes--; + if(scale_factor > -8) { + scale_factor--; rebuild(); } } void SymbolsDialog::rebuild() { + if( fitSymbol->get_active() ) { + zoomIn->set_sensitive( false ); + zoomOut->set_sensitive( false ); + } else { + zoomIn->set_sensitive( true); + zoomOut->set_sensitive( true ); + } + store->clear(); Glib::ustring symbolSetString = symbolSet->get_active_text(); @@ -615,6 +661,7 @@ GSList* SymbolsDialog::symbols_in_doc( SPDocument* symbolDocument ) { GSList *l = NULL; l = symbols_in_doc_recursive (symbolDocument->getRoot(), l ); + l = g_slist_reverse( l ); return l; } @@ -758,7 +805,7 @@ SymbolsDialog::draw_symbol(SPObject *symbol) previewDocument->ensureUpToDate(); SPItem *item = SP_ITEM(object_temp); - unsigned psize = SYMBOL_ICON_SIZES[in_sizes]; + unsigned psize = SYMBOL_ICON_SIZES[pack_size]; Glib::RefPtr<Gdk::Pixbuf> pixbuf(NULL); // We could use cache here, but it doesn't really work with the structure @@ -780,6 +827,8 @@ SymbolsDialog::draw_symbol(SPObject *symbol) if( fitSymbol->get_active() ) scale = psize / std::max(width, height); + else + scale = pow( 2.0, scale_factor/2.0 ) * psize / 32.0; pixbuf = Glib::wrap(render_pixbuf(renderDrawing, scale, *dbox, psize)); } diff --git a/src/ui/dialog/symbols.h b/src/ui/dialog/symbols.h index 8021fb0c1..5dc1e3cad 100644 --- a/src/ui/dialog/symbols.h +++ b/src/ui/dialog/symbols.h @@ -65,6 +65,8 @@ private: static SymbolColumns *getColumns(); + void packless(); + void packmore(); void zoomin(); void zoomout(); void rebuild(); @@ -95,13 +97,18 @@ private: std::map<Glib::ustring, SPDocument*> symbolSets; // Index into sizes which is selected - int in_sizes; + int pack_size; + + // Scale factor + int scale_factor; Glib::RefPtr<Gtk::ListStore> store; Gtk::ComboBoxText* symbolSet; Gtk::IconView* iconView; Gtk::Button* addSymbol; Gtk::Button* removeSymbol; + Gtk::Button* zoomIn; + Gtk::Button* zoomOut; Gtk::ToggleButton* fitSymbol; void setTargetDesktop(SPDesktop *desktop); diff --git a/src/ui/tools/pen-tool.cpp b/src/ui/tools/pen-tool.cpp index 09c0a2a4f..b089065e8 100644 --- a/src/ui/tools/pen-tool.cpp +++ b/src/ui/tools/pen-tool.cpp @@ -481,6 +481,7 @@ bool PenTool::_handleButtonPress(GdkEventButton const &bevent) { ret = true; } else if (bevent.button == 3 && this->npoints != 0) { // right click - finish path + this->ea = NULL; // unset end anchor if set (otherwise crashes) this->_finish(false); ret = true; } @@ -1018,6 +1019,7 @@ bool PenTool::_handleKeyPress(GdkEvent *event) { case GDK_KEY_Return: case GDK_KEY_KP_Enter: if (this->npoints != 0) { + this->ea = NULL; // unset end anchor if set (otherwise crashes) this->_finish(false); ret = true; } diff --git a/src/widgets/font-selector.cpp b/src/widgets/font-selector.cpp index 0e862638c..ccaf93e55 100644 --- a/src/widgets/font-selector.cpp +++ b/src/widgets/font-selector.cpp @@ -179,6 +179,7 @@ static void sp_font_selector_init(SPFontSelector *fsel) Inkscape::FontLister* fontlister = Inkscape::FontLister::get_instance(); Glib::RefPtr<Gtk::ListStore> store = fontlister->get_font_list(); gtk_tree_view_set_model (GTK_TREE_VIEW(fsel->family_treeview), GTK_TREE_MODEL (Glib::unwrap (store))); + //gtk_tree_view_set_tooltip_column(GTK_TREE_VIEW(fsel->family_treeview),2); gtk_container_add(GTK_CONTAINER(sw), fsel->family_treeview); gtk_widget_show_all (sw); @@ -210,12 +211,22 @@ static void sp_font_selector_init(SPFontSelector *fsel) gtk_box_pack_start(GTK_BOX (vb), sw, TRUE, TRUE, 0); fsel->style_treeview = gtk_tree_view_new (); - column = gtk_tree_view_column_new (); + + // CSS Style name cell = gtk_cell_renderer_text_new (); - gtk_tree_view_column_pack_start (column, cell, FALSE); - gtk_tree_view_column_set_attributes (column, cell, "text", 0, NULL); + column = gtk_tree_view_column_new_with_attributes ("CSS", cell, "text", 0, NULL ); + //gtk_tree_view_column_pack_start (column, cell, FALSE); + gtk_tree_view_column_set_resizable (column, TRUE); + gtk_tree_view_append_column (GTK_TREE_VIEW(fsel->style_treeview), column); + + // Display Style name + cell = gtk_cell_renderer_text_new (); + column = gtk_tree_view_column_new_with_attributes (_("Face"), cell, "text", 1, NULL ); + //gtk_tree_view_column_pack_start (column, cell, FALSE); gtk_tree_view_append_column (GTK_TREE_VIEW(fsel->style_treeview), column); - gtk_tree_view_set_headers_visible (GTK_TREE_VIEW(fsel->style_treeview), FALSE); + + //gtk_tree_view_set_tooltip_column(GTK_TREE_VIEW(fsel->style_treeview), 1); + gtk_tree_view_set_headers_visible (GTK_TREE_VIEW(fsel->style_treeview), TRUE); gtk_container_add(GTK_CONTAINER(sw), fsel->style_treeview); gtk_widget_show_all (sw); @@ -306,13 +317,15 @@ static void sp_font_selector_family_select_row(GtkTreeSelection *selection, // Create our own store of styles for selected font-family and find index of best style match int path_index = 0; int index = 0; - GtkListStore *store = gtk_list_store_new (1, G_TYPE_STRING); // Where is this deleted? + GtkListStore *store = gtk_list_store_new (2, G_TYPE_STRING, G_TYPE_STRING); // Where is this deleted? for ( ; list ; list = list->next ) { gtk_list_store_append (store, &iter); - gtk_list_store_set (store, &iter, 0, (char*)list->data, -1); - - if( best.compare( (char*)list->data ) == 0 ) { + gtk_list_store_set (store, &iter, + 0, ((StyleNames*)list->data)->CssName.c_str(), + 1, ((StyleNames*)list->data)->DisplayName.c_str(), + -1); + if( best.compare( ((StyleNames*)list->data)->CssName ) == 0 ) { path_index = index; } ++index; @@ -320,6 +333,7 @@ static void sp_font_selector_family_select_row(GtkTreeSelection *selection, // Attach store to tree view. Can trigger style changed signal (but not FONT_SET): gtk_tree_view_set_model (GTK_TREE_VIEW (fsel->style_treeview), GTK_TREE_MODEL (store)); + //gtk_tree_view_set_tooltip_column(GTK_TREE_VIEW(fsel->style_treeview),1); // Get path to best style GtkTreePath *path = gtk_tree_path_new (); diff --git a/src/widgets/toolbox.cpp b/src/widgets/toolbox.cpp index 3d6f73ef1..939546f78 100644 --- a/src/widgets/toolbox.cpp +++ b/src/widgets/toolbox.cpp @@ -314,8 +314,8 @@ static gchar const * ui_descr = " <toolitem action='SprayModeAction' />" " <separator />" " <toolitem action='SprayWidthAction' />" - " <toolitem action='SprayPressureAction' />" " <toolitem action='SprayPopulationAction' />" + " <toolitem action='SprayPressureAction' />" " <separator />" " <toolitem action='SprayRotationAction' />" " <toolitem action='SprayScaleAction' />" diff --git a/src/xml/repr-css.cpp b/src/xml/repr-css.cpp index e462f70da..c043904a7 100644 --- a/src/xml/repr-css.cpp +++ b/src/xml/repr-css.cpp @@ -283,14 +283,7 @@ void sp_repr_css_write_string(SPCSSAttr *css, Glib::ustring &str) str.append(g_quark_to_string(iter->key)); str.push_back(':'); - if (!strcmp(g_quark_to_string(iter->key), "font-family") - || !strcmp(g_quark_to_string(iter->key), "-inkscape-font-specification")) { - // we only quote font-family/font-specification, as SPStyle does - Glib::ustring val_quoted = css2_escape_quote (iter->value); - str.append(val_quoted); - } else { - str.append(iter->value); // unquoted - } + str.append(iter->value); // Any necessary quoting to be done by calling routine. if (rest(iter)) { str.push_back(';'); @@ -346,13 +339,23 @@ void sp_repr_css_merge(SPCSSAttr *dst, SPCSSAttr *src) /** * Merges style properties as parsed by libcroco into an existing SPCSSAttr. + * libcroco converts all single quotes to double quotes, which needs to be + * undone as we always use single quotes inside our 'style' strings since + * double quotes are used outside: e.g.: + * style="font-family:'DejaVu Sans'" */ static void sp_repr_css_merge_from_decl(SPCSSAttr *css, CRDeclaration const *const decl) { guchar *const str_value_unsigned = cr_term_to_string(decl->value); - Glib::ustring value_unquoted( reinterpret_cast<gchar *>(str_value_unsigned ) ); - css_unquote( value_unquoted ); // libcroco returns strings quoted in "", remove + Glib::ustring value( reinterpret_cast<gchar *>(str_value_unsigned ) ); + g_free(str_value_unsigned); + + Glib::ustring::size_type pos = 0; + while( (pos=value.find("\"",pos)) != Glib::ustring::npos) { + value.replace(pos,1,"'"); + ++pos; + } Glib::ustring units; @@ -363,11 +366,11 @@ static void sp_repr_css_merge_from_decl(SPCSSAttr *css, CRDeclaration const *con * * HACK for now is to strip off em and ex units and add them back at the end */ - int le = value_unquoted.length(); + int le = value.length(); if (le > 2) { - units = value_unquoted.substr(le-2, 2); + units = value.substr(le-2, 2); if ((units == "em") || (units == "ex")) { - value_unquoted = value_unquoted.substr(0, le-2); + value = value.substr(0, le-2); } else { units.clear(); @@ -378,7 +381,7 @@ static void sp_repr_css_merge_from_decl(SPCSSAttr *css, CRDeclaration const *con // CSSOStringStream is used here to write valid CSS (as in sp_style_write_string). This has // the additional benefit of respecting the numerical precission set in the SVG Output // preferences. We assume any numerical part comes first (if not, the whole string is copied). - std::stringstream ss( value_unquoted ); + std::stringstream ss( value ); double number = 0; std::string characters; std::string temp; @@ -400,7 +403,6 @@ static void sp_repr_css_merge_from_decl(SPCSSAttr *css, CRDeclaration const *con //g_message("sp_repr_css_merge_from_decl looks like em or ex units %s --> %s", str_value, os.str().c_str()); } ((Node *) css)->setAttribute(decl->property->stryng->str, os.str().c_str(), false); - g_free(str_value_unsigned); } /** |
