summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorsu_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
commitccacefacda584c206625b7759001d3d8c531cfed (patch)
tree8c00cc50f5bb400b62639c06c234d11fa982502b /src
parentupdate to trunk (r13407) (diff)
parentAllow symbol zooming independent of icon screen size. (diff)
downloadinkscape-ccacefacda584c206625b7759001d3d8c531cfed.tar.gz
inkscape-ccacefacda584c206625b7759001d3d8c531cfed.zip
update to trunk (r13425)
(bzr r13398.1.3)
Diffstat (limited to 'src')
-rw-r--r--src/box3d-side.cpp2
-rw-r--r--src/desktop-style.cpp8
-rw-r--r--src/document.cpp111
-rw-r--r--src/extension/CMakeLists.txt2
-rw-r--r--src/extension/dependency.cpp20
-rw-r--r--src/extension/extension.cpp3
-rw-r--r--src/extension/init.cpp8
-rw-r--r--src/extension/internal/Makefile_insert2
-rw-r--r--src/extension/internal/cairo-ps-out.cpp2
-rw-r--r--src/extension/internal/cairo-ps-out.h2
-rw-r--r--src/extension/internal/pdf-input-cairo.cpp680
-rw-r--r--src/extension/internal/pdf-input-cairo.h157
-rw-r--r--src/extension/internal/pdfinput/pdf-input.cpp233
-rw-r--r--src/extension/internal/pdfinput/pdf-input.h4
-rw-r--r--src/id-clash.cpp126
-rw-r--r--src/ink-comboboxentry-action.cpp28
-rw-r--r--src/libnrtype/FontFactory.cpp247
-rw-r--r--src/libnrtype/FontFactory.h23
-rw-r--r--src/libnrtype/font-lister.cpp100
-rw-r--r--src/libnrtype/font-lister.h13
-rw-r--r--src/selection-chemistry.cpp4
-rw-r--r--src/sp-ellipse.cpp2
-rw-r--r--src/sp-gradient.cpp77
-rw-r--r--src/sp-item-group.cpp36
-rw-r--r--src/sp-item-group.h2
-rw-r--r--src/sp-lpe-item.cpp146
-rw-r--r--src/sp-lpe-item.h2
-rw-r--r--src/sp-path.cpp2
-rw-r--r--src/sp-spiral.cpp2
-rw-r--r--src/sp-star.cpp2
-rw-r--r--src/style-internal.cpp29
-rw-r--r--src/style.cpp114
-rw-r--r--src/style.h2
-rw-r--r--src/ui/dialog/aboutbox.cpp2
-rw-r--r--src/ui/dialog/symbols.cpp73
-rw-r--r--src/ui/dialog/symbols.h9
-rw-r--r--src/ui/tools/pen-tool.cpp2
-rw-r--r--src/widgets/font-selector.cpp30
-rw-r--r--src/widgets/toolbox.cpp2
-rw-r--r--src/xml/repr-css.cpp32
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);
}
/**