summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorLiam P. White <inkscapebronyat-signgmaildotcom>2014-04-29 01:00:39 +0000
committerLiam P. White <inkscapebronyat-signgmaildotcom>2014-04-29 01:00:39 +0000
commiteca72e61451c8deae7f2f5fbaa9885aec946c790 (patch)
tree76d436abbbe469e0bc3b4a254e0ab6e5b4525e3b /src
parentUpdate to trunk (diff)
parentwhen removing LPE, with 'flattening' option, don't recalculate/rewrite ellips... (diff)
downloadinkscape-eca72e61451c8deae7f2f5fbaa9885aec946c790.tar.gz
inkscape-eca72e61451c8deae7f2f5fbaa9885aec946c790.zip
Update to trunk and fix issues
(bzr r13090.1.67)
Diffstat (limited to 'src')
-rw-r--r--src/2geom/CMakeLists.txt2
-rw-r--r--src/2geom/ellipse.cpp7
-rw-r--r--src/CMakeLists.txt2
-rw-r--r--src/Makefile_insert3
-rw-r--r--src/color.h1
-rw-r--r--src/desktop-style.cpp58
-rw-r--r--src/desktop-style.h8
-rw-r--r--src/desktop.h6
-rw-r--r--src/display/drawing-group.h2
-rw-r--r--src/display/drawing-item.h2
-rw-r--r--src/display/drawing-shape.h2
-rw-r--r--src/display/drawing-text.h2
-rw-r--r--src/display/nr-filter-primitive.h2
-rw-r--r--src/display/nr-style.cpp3
-rw-r--r--src/display/nr-style.h2
-rw-r--r--src/extension/CMakeLists.txt1
-rw-r--r--src/extension/extension.cpp12
-rw-r--r--src/extension/implementation/implementation.h2
-rw-r--r--src/extension/internal/emf-inout.cpp393
-rw-r--r--src/extension/internal/emf-inout.h78
-rw-r--r--src/extension/internal/emf-print.cpp4
-rw-r--r--src/extension/internal/metafile-inout.cpp63
-rw-r--r--src/extension/internal/metafile-inout.h1
-rw-r--r--src/extension/internal/wmf-inout.cpp403
-rw-r--r--src/extension/internal/wmf-inout.h71
-rw-r--r--src/extension/internal/wmf-print.cpp4
-rw-r--r--src/graphlayout.cpp4
-rw-r--r--src/id-clash.cpp8
-rw-r--r--src/libcroco/cr-sel-eng.c6
-rw-r--r--src/libdepixelize/CMakeLists.txt4
-rw-r--r--src/libnrtype/FontFactory.cpp10
-rw-r--r--src/libnrtype/Layout-TNG-Input.cpp5
-rw-r--r--src/libnrtype/Layout-TNG.h2
-rw-r--r--src/libnrtype/font-lister.cpp42
-rw-r--r--src/libnrtype/font-lister.h8
-rw-r--r--src/libnrtype/font-style-to-pos.h2
-rw-r--r--src/livarot/Path.h2
-rw-r--r--src/live_effects/Makefile_insert2
-rw-r--r--src/live_effects/lpe-jointype.cpp4
-rw-r--r--src/live_effects/lpe-powerstroke.cpp4
-rw-r--r--src/live_effects/lpe-taperstroke.cpp6
-rw-r--r--src/print.h2
-rw-r--r--src/selection-chemistry.cpp6
-rw-r--r--src/sp-lpe-item.cpp50
-rw-r--r--src/sp-object.h2
-rw-r--r--src/sp-shape.cpp6
-rw-r--r--src/style-enums.h265
-rw-r--r--src/style-internal.cpp2543
-rw-r--r--src/style-internal.h836
-rw-r--r--src/style-test.h330
-rw-r--r--src/style.cpp5177
-rw-r--r--src/style.h171
-rw-r--r--src/text-editing.h10
-rw-r--r--src/ui/dialog/font-substitution.cpp18
-rw-r--r--src/ui/dialog/livepatheffect-add.cpp14
-rw-r--r--src/ui/dialog/livepatheffect-add.h4
-rw-r--r--src/ui/widget/style-subject.h2
-rw-r--r--src/ui/widget/style-swatch.h2
-rw-r--r--src/util/CMakeLists.txt2
-rw-r--r--src/widgets/paint-selector.h2
-rw-r--r--src/widgets/stroke-style.cpp7
-rw-r--r--src/widgets/text-toolbar.cpp30
62 files changed, 5596 insertions, 5126 deletions
diff --git a/src/2geom/CMakeLists.txt b/src/2geom/CMakeLists.txt
index 3d516dc18..eeaecaa39 100644
--- a/src/2geom/CMakeLists.txt
+++ b/src/2geom/CMakeLists.txt
@@ -94,6 +94,7 @@ set(2geom_SRC
nearest-point.h
ord.h
path-intersection.h
+ path-sink.h
path.h
pathvector.h
piecewise.h
@@ -115,7 +116,6 @@ set(2geom_SRC
solver.h
svg-elliptical-arc.h
svg-path-parser.h
- svg-path.h
sweep.h
toposweep.h
transforms.h
diff --git a/src/2geom/ellipse.cpp b/src/2geom/ellipse.cpp
index bea99e5dd..2686844b2 100644
--- a/src/2geom/ellipse.cpp
+++ b/src/2geom/ellipse.cpp
@@ -36,6 +36,7 @@
#include <2geom/numeric/fitting-tool.h>
#include <2geom/numeric/fitting-model.h>
+using std::swap;
namespace Geom
{
@@ -102,7 +103,7 @@ void Ellipse::set(double A, double B, double C, double D, double E, double F)
// the solution is not unique so we choose always the ellipse
// with a rotation angle between 0 and PI/2
- if ( swap_axes ) std::swap(rx, ry);
+ if ( swap_axes ) swap(rx, ry);
if ( are_near(rot, M_PI/2)
|| are_near(rot, -M_PI/2)
|| are_near(rx, ry) )
@@ -233,7 +234,7 @@ Ellipse Ellipse::transformed(Affine const& m) const
Point new_center = center() * m;
Affine M = m.withoutTranslation();
Affine AM = A * M;
- if ( are_near(AM.det(), 0) )
+ if ( are_near(std::sqrt(fabs(AM.det())), 0) )
{
double angle;
if (AM[0] != 0)
@@ -262,7 +263,7 @@ Ellipse Ellipse::transformed(Affine const& m) const
Affine invm = M.inverse();
Q = invm * Q ;
- std::swap( invm[1], invm[2] );
+ swap( invm[1], invm[2] );
Q *= invm;
Ellipse e(Q[0], 2*Q[1], Q[3], 0, 0, -1);
e.m_centre = new_center;
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 8408d6270..d40aad802 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -259,6 +259,7 @@ set(inkscape_SRC
snapped-point.cpp
snapper.cpp
style.cpp
+ style-internal.cpp
svg-view-widget.cpp
svg-view.cpp
text-chemistry.cpp
@@ -433,6 +434,7 @@ set(inkscape_SRC
undo-stack-observer.h
unicoderange.h
uri-references.h
+ uri-test.h
uri.h
vanishing-point.h
verbs-test.h
diff --git a/src/Makefile_insert b/src/Makefile_insert
index 8872b045d..6d0d6b08c 100644
--- a/src/Makefile_insert
+++ b/src/Makefile_insert
@@ -210,7 +210,8 @@ ink_common_sources += \
streq.h \
strneq.h \
style.cpp style.h \
- style-enums.h style-internal.h \
+ style-enums.h \
+ style-internal.cpp style-internal.h \
svg-profile.h \
svg-view.cpp svg-view.h \
svg-view-widget.cpp svg-view-widget.h \
diff --git a/src/color.h b/src/color.h
index 746ecebbf..604dff0e3 100644
--- a/src/color.h
+++ b/src/color.h
@@ -46,6 +46,7 @@ struct SPColor {
SPColor& operator= (SPColor const& other);
bool operator == ( SPColor const& other ) const;
+ bool operator != ( SPColor const& other ) const { return !(*this == other); };
bool isClose( SPColor const& other, float epsilon ) const;
void set( float r, float g, float b );
diff --git a/src/desktop-style.cpp b/src/desktop-style.cpp
index bab9635a9..37f537cc5 100644
--- a/src/desktop-style.cpp
+++ b/src/desktop-style.cpp
@@ -722,10 +722,10 @@ objects_query_strokewidth (GSList *objects, SPStyle *style_res)
}
if ( style->stroke.isNone() && !(
- style->marker[SP_MARKER_LOC].set || // stroke width affects markers, so if there's no stroke but only markers then we should
- style->marker[SP_MARKER_LOC_START].set || // still calculate the stroke width
- style->marker[SP_MARKER_LOC_MID].set ||
- style->marker[SP_MARKER_LOC_END].set))
+ style->marker.set || // stroke width affects markers, so if there's no
+ style->marker_start.set || // stroke but only markers then we should
+ style->marker_mid.set || // still calculate the stroke width
+ style->marker_end.set))
{
continue;
}
@@ -1227,11 +1227,11 @@ objects_query_fontfamily (GSList *objects, SPStyle *style_res)
bool different = false;
int texts = 0;
- if (style_res->text->font_family.value) {
- g_free(style_res->text->font_family.value);
- style_res->text->font_family.value = NULL;
+ if (style_res->font_family.value) {
+ g_free(style_res->font_family.value);
+ style_res->font_family.value = NULL;
}
- style_res->text->font_family.set = FALSE;
+ style_res->font_family.set = FALSE;
for (GSList const *i = objects; i != NULL; i = i->next) {
SPObject *obj = SP_OBJECT (i->data);
@@ -1250,21 +1250,21 @@ objects_query_fontfamily (GSList *objects, SPStyle *style_res)
texts ++;
- if (style_res->text->font_family.value && style->text->font_family.value &&
- strcmp (style_res->text->font_family.value, style->text->font_family.value)) {
+ if (style_res->font_family.value && style->font_family.value &&
+ strcmp (style_res->font_family.value, style->font_family.value)) {
different = true; // different fonts
}
- if (style_res->text->font_family.value) {
- g_free(style_res->text->font_family.value);
- style_res->text->font_family.value = NULL;
+ if (style_res->font_family.value) {
+ g_free(style_res->font_family.value);
+ style_res->font_family.value = NULL;
}
- style_res->text->font_family.set = TRUE;
- style_res->text->font_family.value = g_strdup(style->text->font_family.value);
+ style_res->font_family.set = TRUE;
+ style_res->font_family.value = g_strdup(style->font_family.value);
}
- if (texts == 0 || !style_res->text->font_family.set) {
+ if (texts == 0 || !style_res->font_family.set) {
return QUERY_STYLE_NOTHING;
}
@@ -1285,11 +1285,11 @@ objects_query_fontspecification (GSList *objects, SPStyle *style_res)
bool different = false;
int texts = 0;
- if (style_res->text->font_specification.value) {
- g_free(style_res->text->font_specification.value);
- style_res->text->font_specification.value = NULL;
+ if (style_res->font_specification.value) {
+ g_free(style_res->font_specification.value);
+ style_res->font_specification.value = NULL;
}
- style_res->text->font_specification.set = FALSE;
+ style_res->font_specification.set = FALSE;
for (GSList const *i = objects; i != NULL; i = i->next) {
SPObject *obj = SP_OBJECT (i->data);
@@ -1308,21 +1308,21 @@ objects_query_fontspecification (GSList *objects, SPStyle *style_res)
texts ++;
- if (style_res->text->font_specification.value && style_res->text->font_specification.set &&
- style->text->font_specification.value && style->text->font_specification.set &&
- strcmp (style_res->text->font_specification.value, style->text->font_specification.value)) {
+ if (style_res->font_specification.value && style_res->font_specification.set &&
+ style->font_specification.value && style->font_specification.set &&
+ strcmp (style_res->font_specification.value, style->font_specification.value)) {
different = true; // different fonts
}
- if (style->text->font_specification.set) {
+ if (style->font_specification.set) {
- if (style_res->text->font_specification.value) {
- g_free(style_res->text->font_specification.value);
- style_res->text->font_specification.value = NULL;
+ if (style_res->font_specification.value) {
+ g_free(style_res->font_specification.value);
+ style_res->font_specification.value = NULL;
}
- style_res->text->font_specification.set = TRUE;
- style_res->text->font_specification.value = g_strdup(style->text->font_specification.value);
+ style_res->font_specification.set = TRUE;
+ style_res->font_specification.value = g_strdup(style->font_specification.value);
}
}
diff --git a/src/desktop-style.h b/src/desktop-style.h
index 47575de75..fc20e97b9 100644
--- a/src/desktop-style.h
+++ b/src/desktop-style.h
@@ -16,10 +16,10 @@
#include <glib.h>
class ColorRGBA;
-class SPCSSAttr;
-class SPDesktop;
-class SPObject;
-struct SPStyle;
+class SPCSSAttr;
+class SPDesktop;
+class SPObject;
+class SPStyle;
namespace Inkscape {
namespace XML {
class Node;
diff --git a/src/desktop.h b/src/desktop.h
index fec6249e9..be2bf891f 100644
--- a/src/desktop.h
+++ b/src/desktop.h
@@ -54,10 +54,10 @@ class ToolBase;
}
}
-class SPItem;
+class SPItem;
class SPNamedView;
-class SPObject;
-struct SPStyle;
+class SPObject;
+class SPStyle;
typedef struct _DocumentInterface DocumentInterface;//struct DocumentInterface;
namespace Gtk
diff --git a/src/display/drawing-group.h b/src/display/drawing-group.h
index 651e9d8af..ab1f9895d 100644
--- a/src/display/drawing-group.h
+++ b/src/display/drawing-group.h
@@ -14,7 +14,7 @@
#include "display/drawing-item.h"
-struct SPStyle;
+class SPStyle;
namespace Inkscape {
diff --git a/src/display/drawing-item.h b/src/display/drawing-item.h
index db803cf60..d89299eeb 100644
--- a/src/display/drawing-item.h
+++ b/src/display/drawing-item.h
@@ -20,7 +20,7 @@
#include <2geom/rect.h>
#include <2geom/affine.h>
-struct SPStyle;
+class SPStyle;
namespace Inkscape {
diff --git a/src/display/drawing-shape.h b/src/display/drawing-shape.h
index 405c789e0..f37de9ce7 100644
--- a/src/display/drawing-shape.h
+++ b/src/display/drawing-shape.h
@@ -15,7 +15,7 @@
#include "display/drawing-item.h"
#include "display/nr-style.h"
-struct SPStyle;
+class SPStyle;
class SPCurve;
namespace Inkscape {
diff --git a/src/display/drawing-text.h b/src/display/drawing-text.h
index b863ca2a4..41039d85d 100644
--- a/src/display/drawing-text.h
+++ b/src/display/drawing-text.h
@@ -15,7 +15,7 @@
#include "display/drawing-group.h"
#include "display/nr-style.h"
-struct SPStyle;
+class SPStyle;
class font_instance;
namespace Inkscape {
diff --git a/src/display/nr-filter-primitive.h b/src/display/nr-filter-primitive.h
index 94bd6abb0..214b2cfc5 100644
--- a/src/display/nr-filter-primitive.h
+++ b/src/display/nr-filter-primitive.h
@@ -16,7 +16,7 @@
#include "display/nr-filter-types.h"
#include "svg/svg-length.h"
-struct SPStyle;
+class SPStyle;
namespace Inkscape {
namespace Filters {
diff --git a/src/display/nr-style.cpp b/src/display/nr-style.cpp
index 125d0c6d6..3d2d36483 100644
--- a/src/display/nr-style.cpp
+++ b/src/display/nr-style.cpp
@@ -201,8 +201,7 @@ void NRStyle::set(SPStyle *style)
if( style->text_decoration_color.set ||
style->text_decoration_color.inherit ||
- style->text_decoration_color.currentcolor ||
- style->text_decoration_color.colorSet){
+ style->text_decoration_color.currentcolor ){
text_decoration_color.set(style->text_decoration_color.value.color);
text_decoration_useColor = true;
}
diff --git a/src/display/nr-style.h b/src/display/nr-style.h
index 717cda899..8b5a0ee3d 100644
--- a/src/display/nr-style.h
+++ b/src/display/nr-style.h
@@ -17,7 +17,7 @@
#include "color.h"
class SPPaintServer;
-struct SPStyle;
+class SPStyle;
namespace Inkscape {
class DrawingContext;
diff --git a/src/extension/CMakeLists.txt b/src/extension/CMakeLists.txt
index 9bc30a592..759c704f0 100644
--- a/src/extension/CMakeLists.txt
+++ b/src/extension/CMakeLists.txt
@@ -130,6 +130,7 @@ set(extension_SRC
internal/latex-pstricks-out.h
internal/latex-pstricks.h
internal/latex-text-renderer.h
+ internal/metafile-inout.h
internal/metafile-print.h
internal/odf.h
internal/pdf-input-cairo.h
diff --git a/src/extension/extension.cpp b/src/extension/extension.cpp
index d63ec7485..588efb521 100644
--- a/src/extension/extension.cpp
+++ b/src/extension/extension.cpp
@@ -262,6 +262,18 @@ Extension::check (void)
const char * inx_failure = _(" This is caused by an improper .inx file for this extension."
" An improper .inx file could have been caused by a faulty installation of Inkscape.");
+
+ // No need to include Windows only extensions
+ // See LP bug #1307554 for details - https://bugs.launchpad.net/inkscape/+bug/1307554
+#ifndef WIN32
+ const char* win_ext[] = {"com.vaxxine.print.win32"};
+ std::vector<std::string> v (win_ext, win_ext + sizeof(win_ext)/sizeof(win_ext[0]));
+ std::string ext_id(id);
+ if (std::find(v.begin(), v.end(), ext_id) != v.end()) {
+ printFailure(Glib::ustring(_("the extension is designed for Windows only.")) + inx_failure);
+ retval = false;
+ }
+#endif
if (id == NULL) {
printFailure(Glib::ustring(_("an ID was not defined for it.")) + inx_failure);
retval = false;
diff --git a/src/extension/implementation/implementation.h b/src/extension/implementation/implementation.h
index 9d679982a..fb323cd78 100644
--- a/src/extension/implementation/implementation.h
+++ b/src/extension/implementation/implementation.h
@@ -29,7 +29,7 @@ namespace Gtk {
}
class SPDocument;
-struct SPStyle;
+class SPStyle;
namespace Inkscape {
diff --git a/src/extension/internal/emf-inout.cpp b/src/extension/internal/emf-inout.cpp
index eae3bfb5a..6455e7555 100644
--- a/src/extension/internal/emf-inout.cpp
+++ b/src/extension/internal/emf-inout.cpp
@@ -33,9 +33,8 @@
#include <stdint.h>
#include <libuemf/symbol_convert.h>
-#include "sp-root.h"
+#include "sp-root.h" // even though it is included indirectly by wmf-inout.h
#include "sp-path.h"
-#include "style.h"
#include "print.h"
#include "extension/system.h"
#include "extension/print.h"
@@ -45,12 +44,8 @@
#include "display/drawing.h"
#include "display/drawing-item.h"
#include "clear-n_.h"
-#include "document.h"
-#include "util/units.h"
-#include "shape-editor.h"
-#include "sp-namedview.h"
-#include "document-undo.h"
-#include "inkscape.h"
+#include "util/units.h" // even though it is included indirectly by wmf-inout.h
+#include "inkscape.h" // even though it is included indirectly by wmf-inout.h
#include "emf-print.h"
#include "emf-inout.h"
@@ -273,54 +268,54 @@ uint32_t Emf::add_hatch(PEMF_CALLBACK_DATA d, uint32_t hatchType, U_COLORREF hat
if(d->hatches.count == d->hatches.size){ enlarge_hatches(d); }
d->hatches.strings[d->hatches.count++]=strdup(hpathname);
- *(d->defs) += "\n";
+ d->defs += "\n";
switch(hatchType){
case U_HS_HORIZONTAL:
- *(d->defs) += " <path id=\"";
- *(d->defs) += hpathname;
- *(d->defs) += "\" d=\"M 0 0 6 0\" style=\"fill:none;stroke:#";
- *(d->defs) += tmpcolor;
- *(d->defs) += "\" />\n";
+ d->defs += " <path id=\"";
+ d->defs += hpathname;
+ d->defs += "\" d=\"M 0 0 6 0\" style=\"fill:none;stroke:#";
+ d->defs += tmpcolor;
+ d->defs += "\" />\n";
break;
case U_HS_VERTICAL:
- *(d->defs) += " <path id=\"";
- *(d->defs) += hpathname;
- *(d->defs) += "\" d=\"M 0 0 0 6\" style=\"fill:none;stroke:#";
- *(d->defs) += tmpcolor;
- *(d->defs) += "\" />\n";
+ d->defs += " <path id=\"";
+ d->defs += hpathname;
+ d->defs += "\" d=\"M 0 0 0 6\" style=\"fill:none;stroke:#";
+ d->defs += tmpcolor;
+ d->defs += "\" />\n";
break;
case U_HS_FDIAGONAL:
- *(d->defs) += " <line id=\"sub";
- *(d->defs) += hpathname;
- *(d->defs) += "\" x1=\"-1\" y1=\"-1\" x2=\"7\" y2=\"7\" stroke=\"#";
- *(d->defs) += tmpcolor;
- *(d->defs) += "\"/>\n";
+ d->defs += " <line id=\"sub";
+ d->defs += hpathname;
+ d->defs += "\" x1=\"-1\" y1=\"-1\" x2=\"7\" y2=\"7\" stroke=\"#";
+ d->defs += tmpcolor;
+ d->defs += "\"/>\n";
break;
case U_HS_BDIAGONAL:
- *(d->defs) += " <line id=\"sub";
- *(d->defs) += hpathname;
- *(d->defs) += "\" x1=\"-1\" y1=\"7\" x2=\"7\" y2=\"-1\" stroke=\"#";
- *(d->defs) += tmpcolor;
- *(d->defs) += "\"/>\n";
+ d->defs += " <line id=\"sub";
+ d->defs += hpathname;
+ d->defs += "\" x1=\"-1\" y1=\"7\" x2=\"7\" y2=\"-1\" stroke=\"#";
+ d->defs += tmpcolor;
+ d->defs += "\"/>\n";
break;
case U_HS_CROSS:
- *(d->defs) += " <path id=\"";
- *(d->defs) += hpathname;
- *(d->defs) += "\" d=\"M 0 0 6 0 M 0 0 0 6\" style=\"fill:none;stroke:#";
- *(d->defs) += tmpcolor;
- *(d->defs) += "\" />\n";
+ d->defs += " <path id=\"";
+ d->defs += hpathname;
+ d->defs += "\" d=\"M 0 0 6 0 M 0 0 0 6\" style=\"fill:none;stroke:#";
+ d->defs += tmpcolor;
+ d->defs += "\" />\n";
break;
case U_HS_DIAGCROSS:
- *(d->defs) += " <line id=\"subfd";
- *(d->defs) += hpathname;
- *(d->defs) += "\" x1=\"-1\" y1=\"-1\" x2=\"7\" y2=\"7\" stroke=\"#";
- *(d->defs) += tmpcolor;
- *(d->defs) += "\"/>\n";
- *(d->defs) += " <line id=\"subbd";
- *(d->defs) += hpathname;
- *(d->defs) += "\" x1=\"-1\" y1=\"7\" x2=\"7\" y2=\"-1\" stroke=\"#";
- *(d->defs) += tmpcolor;
- *(d->defs) += "\"/>\n";
+ d->defs += " <line id=\"subfd";
+ d->defs += hpathname;
+ d->defs += "\" x1=\"-1\" y1=\"-1\" x2=\"7\" y2=\"7\" stroke=\"#";
+ d->defs += tmpcolor;
+ d->defs += "\"/>\n";
+ d->defs += " <line id=\"subbd";
+ d->defs += hpathname;
+ d->defs += "\" x1=\"-1\" y1=\"7\" x2=\"7\" y2=\"-1\" stroke=\"#";
+ d->defs += tmpcolor;
+ d->defs += "\"/>\n";
break;
case U_HS_SOLIDCLR:
case U_HS_DITHEREDCLR:
@@ -329,12 +324,12 @@ uint32_t Emf::add_hatch(PEMF_CALLBACK_DATA d, uint32_t hatchType, U_COLORREF hat
case U_HS_SOLIDBKCLR:
case U_HS_DITHEREDBKCLR:
default:
- *(d->defs) += " <path id=\"";
- *(d->defs) += hpathname;
- *(d->defs) += "\" d=\"M 0 0 6 0 6 6 0 6 z\" style=\"fill:#";
- *(d->defs) += tmpcolor;
- *(d->defs) += ";stroke:none";
- *(d->defs) += "\" />\n";
+ d->defs += " <path id=\"";
+ d->defs += hpathname;
+ d->defs += "\" d=\"M 0 0 6 0 6 6 0 6 z\" style=\"fill:#";
+ d->defs += tmpcolor;
+ d->defs += ";stroke:none";
+ d->defs += "\" />\n";
break;
}
}
@@ -396,12 +391,12 @@ uint32_t Emf::add_hatch(PEMF_CALLBACK_DATA d, uint32_t hatchType, U_COLORREF hat
if(!idx){ // add it if not already present
if(d->hatches.count == d->hatches.size){ enlarge_hatches(d); }
d->hatches.strings[d->hatches.count++]=strdup(hatchname);
- *(d->defs) += "\n";
- *(d->defs) += " <pattern id=\"";
- *(d->defs) += hatchname;
- *(d->defs) += "\" xlink:href=\"#EMFhbasepattern\">\n";
- *(d->defs) += refpath;
- *(d->defs) += " </pattern>\n";
+ d->defs += "\n";
+ d->defs += " <pattern id=\"";
+ d->defs += hatchname;
+ d->defs += "\" xlink:href=\"#EMFhbasepattern\">\n";
+ d->defs += refpath;
+ d->defs += " </pattern>\n";
idx = d->hatches.count;
}
}
@@ -414,12 +409,12 @@ uint32_t Emf::add_hatch(PEMF_CALLBACK_DATA d, uint32_t hatchType, U_COLORREF hat
if(d->hatches.count == d->hatches.size){ enlarge_hatches(d); }
d->hatches.strings[d->hatches.count++]=strdup(hbkname);
- *(d->defs) += "\n";
- *(d->defs) += " <rect id=\"";
- *(d->defs) += hbkname;
- *(d->defs) += "\" x=\"0\" y=\"0\" width=\"6\" height=\"6\" fill=\"#";
- *(d->defs) += bkcolor;
- *(d->defs) += "\" />\n";
+ d->defs += "\n";
+ d->defs += " <rect id=\"";
+ d->defs += hbkname;
+ d->defs += "\" x=\"0\" y=\"0\" width=\"6\" height=\"6\" fill=\"#";
+ d->defs += bkcolor;
+ d->defs += "\" />\n";
}
// this is the pattern, its name will show up in Inkscape's pattern selector
@@ -428,15 +423,15 @@ uint32_t Emf::add_hatch(PEMF_CALLBACK_DATA d, uint32_t hatchType, U_COLORREF hat
if(!idx){ // add it if not already present
if(d->hatches.count == d->hatches.size){ enlarge_hatches(d); }
d->hatches.strings[d->hatches.count++]=strdup(hatchname);
- *(d->defs) += "\n";
- *(d->defs) += " <pattern id=\"";
- *(d->defs) += hatchname;
- *(d->defs) += "\" xlink:href=\"#EMFhbasepattern\">\n";
- *(d->defs) += " <use xlink:href=\"#";
- *(d->defs) += hbkname;
- *(d->defs) += "\" />\n";
- *(d->defs) += refpath;
- *(d->defs) += " </pattern>\n";
+ d->defs += "\n";
+ d->defs += " <pattern id=\"";
+ d->defs += hatchname;
+ d->defs += "\" xlink:href=\"#EMFhbasepattern\">\n";
+ d->defs += " <use xlink:href=\"#";
+ d->defs += hbkname;
+ d->defs += "\" />\n";
+ d->defs += refpath;
+ d->defs += " </pattern>\n";
idx = d->hatches.count;
}
}
@@ -544,35 +539,35 @@ uint32_t Emf::add_image(PEMF_CALLBACK_DATA d, void *pEmr, uint32_t cbBits, uint
sprintf(imagename,"EMFimage%d",idx++);
sprintf(xywh," x=\"0\" y=\"0\" width=\"%d\" height=\"%d\" ",width,height); // reuse this buffer
- *(d->defs) += "\n";
- *(d->defs) += " <image id=\"";
- *(d->defs) += imagename;
- *(d->defs) += "\"\n ";
- *(d->defs) += xywh;
- *(d->defs) += "\n";
- if(dibparams == U_BI_JPEG){ *(d->defs) += " xlink:href=\"data:image/jpeg;base64,"; }
- else { *(d->defs) += " xlink:href=\"data:image/png;base64,"; }
- *(d->defs) += base64String;
- *(d->defs) += "\"\n";
- *(d->defs) += " preserveAspectRatio=\"none\"\n";
- *(d->defs) += " />\n";
-
-
- *(d->defs) += "\n";
- *(d->defs) += " <pattern id=\"";
- *(d->defs) += imagename;
- *(d->defs) += "_ref\"\n ";
- *(d->defs) += xywh;
- *(d->defs) += "\n patternUnits=\"userSpaceOnUse\"";
- *(d->defs) += " >\n";
- *(d->defs) += " <use id=\"";
- *(d->defs) += imagename;
- *(d->defs) += "_ign\" ";
- *(d->defs) += " xlink:href=\"#";
- *(d->defs) += imagename;
- *(d->defs) += "\" />\n";
- *(d->defs) += " ";
- *(d->defs) += " </pattern>\n";
+ d->defs += "\n";
+ d->defs += " <image id=\"";
+ d->defs += imagename;
+ d->defs += "\"\n ";
+ d->defs += xywh;
+ d->defs += "\n";
+ if(dibparams == U_BI_JPEG){ d->defs += " xlink:href=\"data:image/jpeg;base64,"; }
+ else { d->defs += " xlink:href=\"data:image/png;base64,"; }
+ d->defs += base64String;
+ d->defs += "\"\n";
+ d->defs += " preserveAspectRatio=\"none\"\n";
+ d->defs += " />\n";
+
+
+ d->defs += "\n";
+ d->defs += " <pattern id=\"";
+ d->defs += imagename;
+ d->defs += "_ref\"\n ";
+ d->defs += xywh;
+ d->defs += "\n patternUnits=\"userSpaceOnUse\"";
+ d->defs += " >\n";
+ d->defs += " <use id=\"";
+ d->defs += imagename;
+ d->defs += "_ign\" ";
+ d->defs += " xlink:href=\"#";
+ d->defs += imagename;
+ d->defs += "\" />\n";
+ d->defs += " ";
+ d->defs += " </pattern>\n";
}
g_free(base64String);//wait until this point to free because it might be a duplicate image
@@ -596,17 +591,17 @@ uint32_t Emf::add_image(PEMF_CALLBACK_DATA d, void *pEmr, uint32_t cbBits, uint
d->images.strings[d->images.count++]=strdup(base64String);
sprintf(imrotname,"EMFimage%d",idx++);
- *(d->defs) += "\n";
- *(d->defs) += " <pattern\n";
- *(d->defs) += " id=\"";
- *(d->defs) += imrotname;
- *(d->defs) += "_ref\"\n";
- *(d->defs) += " xlink:href=\"#";
- *(d->defs) += imagename;
- *(d->defs) += "_ref\"\n";
- *(d->defs) += " patternTransform=";
- *(d->defs) += current_matrix(d, 0.0, 0.0, 0); //j use offset 0,0
- *(d->defs) += " />\n";
+ d->defs += "\n";
+ d->defs += " <pattern\n";
+ d->defs += " id=\"";
+ d->defs += imrotname;
+ d->defs += "_ref\"\n";
+ d->defs += " xlink:href=\"#";
+ d->defs += imagename;
+ d->defs += "_ref\"\n";
+ d->defs += " patternTransform=";
+ d->defs += current_matrix(d, 0.0, 0.0, 0); //j use offset 0,0
+ d->defs += " />\n";
}
g_free(base64String);
}
@@ -716,7 +711,7 @@ uint32_t Emf::add_gradient(PEMF_CALLBACK_DATA d, uint32_t gradientType, U_TRIVER
stmp << tmpcolor2;
stmp << ";stop-opacity:1\" />\n";
stmp << " </linearGradient>\n";
- *(d->defs) += stmp.str().c_str();
+ d->defs += stmp.str().c_str();
}
return(idx-1);
@@ -811,8 +806,8 @@ Emf::output_style(PEMF_CALLBACK_DATA d, int iType)
// tmp_id << "\n\tid=\"" << (d->id++) << "\"";
-// *(d->outsvg) += tmp_id.str().c_str();
- *(d->outsvg) += "\n\tstyle=\"";
+// d->outsvg += tmp_id.str().c_str();
+ d->outsvg += "\n\tstyle=\"";
if (iType == U_EMR_STROKEPATH || !d->dc[d->level].fill_set) {
tmp_style << "fill:none;";
} else {
@@ -936,7 +931,7 @@ Emf::output_style(PEMF_CALLBACK_DATA d, int iType)
tmp_style << "\n\tclip-path=\"url(#clipEmfPath" << d->id << ")\" ";
clipset = false;
- *(d->outsvg) += tmp_style.str().c_str();
+ d->outsvg += tmp_style.str().c_str();
}
@@ -1104,14 +1099,11 @@ Emf::select_extpen(PEMF_CALLBACK_DATA d, int index)
if (!d->dc[d->level].style.stroke_dasharray.values.empty() && (d->level==0 || (d->level>0 && d->dc[d->level].style.stroke_dasharray.values!=d->dc[d->level-1].style.stroke_dasharray.values)))
d->dc[d->level].style.stroke_dasharray.values.clear();
for (unsigned int i=0; i<pEmr->elp.elpNumEntries; i++) {
- int cur_level = d->level;
- d->level = d->emf_obj[index].level;
// Doing it this way typically results in a pattern that is tiny, better to assume the array
// is the same scale as for dot/dash below, that is, no scaling should be applied
// double dash_length = pix_to_abs_size( d, pEmr->elp.elpStyleEntry[i] );
double dash_length = pEmr->elp.elpStyleEntry[i];
- d->level = cur_level;
- d->dc[d->level].style.stroke_dasharray.values[i] = dash_length;
+ d->dc[d->level].style.stroke_dasharray.values.push_back(dash_length);
}
d->dc[d->level].style.stroke_dasharray.set = 1;
} else {
@@ -1525,8 +1517,8 @@ void Emf::common_image_extraction(PEMF_CALLBACK_DATA d, void *pEmr,
tmp_image << " preserveAspectRatio=\"none\"\n";
tmp_image << "/> \n";
- *(d->outsvg) += tmp_image.str().c_str();
- *(d->path) = "";
+ d->outsvg += tmp_image.str().c_str();
+ d->path = "";
}
/**
@@ -1595,7 +1587,7 @@ int Emf::myEnhMetaFileProc(char *contents, unsigned int length, PEMF_CALLBACK_DA
TR_layout_2_svg(d->tri);
SVGOStringStream ts;
ts << d->tri->out;
- *(d->outsvg) += ts.str().c_str();
+ d->outsvg += ts.str().c_str();
d->tri = trinfo_clear(d->tri);
}
if(d->dc[d->level].dirty){ //Apply the delayed background changes, clear the flag
@@ -1652,7 +1644,7 @@ std::cout << "BEFORE DRAW"
)
){
// std::cout << "PATH DRAW at TOP" << std::endl;
- *(d->outsvg) += " <path "; // this is the ONLY place <path should be used!!! One exception, gradientfill.
+ d->outsvg += " <path "; // this is the ONLY place <path should be used!!! One exception, gradientfill.
if(d->drawtype){ // explicit draw type EMR record
output_style(d, d->drawtype);
}
@@ -1662,11 +1654,11 @@ std::cout << "BEFORE DRAW"
else {
output_style(d, U_EMR_STROKEPATH);
}
- *(d->outsvg) += "\n\t";
- *(d->outsvg) += "\n\td=\""; // this is the ONLY place d=" should be used!!!! One exception, gradientfill.
- *(d->outsvg) += *(d->path);
- *(d->outsvg) += " \" /> \n";
- *(d->path) = "";
+ d->outsvg += "\n\t";
+ d->outsvg += "\n\td=\""; // this is the ONLY place d=" should be used!!!! One exception, gradientfill.
+ d->outsvg += d->path;
+ d->outsvg += " \" /> \n";
+ d->path = "";
// reset the flags
d->mask = 0;
d->drawtype = 0;
@@ -1679,12 +1671,12 @@ std::cout << "BEFORE DRAW"
{
dbg_str << "<!-- U_EMR_HEADER -->\n";
- *(d->outdef) += "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n";
+ d->outdef += "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n";
if (d->pDesc) {
- *(d->outdef) += "<!-- ";
- *(d->outdef) += d->pDesc;
- *(d->outdef) += " -->\n";
+ d->outdef += "<!-- ";
+ d->outdef += d->pDesc;
+ d->outdef += " -->\n";
}
PU_EMRHEADER pEmr = (PU_EMRHEADER) lpEMFR;
@@ -1745,8 +1737,8 @@ std::cout << "BEFORE DRAW"
tmp_outdef <<
" width=\"" << d->MMX << "mm\"\n" <<
" height=\"" << d->MMY << "mm\">\n";
- *(d->outdef) += tmp_outdef.str().c_str();
- *(d->outdef) += "<defs>"; // temporary end of header
+ d->outdef += tmp_outdef.str().c_str();
+ d->outdef += "<defs>"; // temporary end of header
// d->defs holds any defines which are read in.
@@ -2015,7 +2007,7 @@ std::cout << "BEFORE DRAW"
dbg_str << "<!-- U_EMR_EOF -->\n";
tmp_outsvg << "</svg>\n";
- *(d->outsvg) = *(d->outdef) + *(d->defs) + *(d->outsvg);
+ d->outsvg = d->outdef + d->defs + d->outsvg;
OK=0;
break;
}
@@ -2167,8 +2159,8 @@ std::cout << "BEFORE DRAW"
tmp_rectangle << "\n transform=" << current_matrix(d, dx, dy, 1); // calculate appropriate offset
tmp_rectangle << "/>\n</clipPath>";
- *(d->outdef) += tmp_rectangle.str().c_str();
- *(d->path) = "";
+ d->outdef += tmp_rectangle.str().c_str();
+ d->path = "";
break;
}
case U_EMR_SCALEVIEWPORTEXTEX: dbg_str << "<!-- U_EMR_SCALEVIEWPORTEXTEX -->\n"; break;
@@ -2453,12 +2445,12 @@ std::cout << "BEFORE DRAW"
d->mask |= emr_mask;
- *(d->outsvg) += " <ellipse ";
+ d->outsvg += " <ellipse ";
output_style(d, lpEMFR->iType); //
- *(d->outsvg) += "\n\t";
- *(d->outsvg) += tmp_ellipse.str().c_str();
- *(d->outsvg) += "/> \n";
- *(d->path) = "";
+ d->outsvg += "\n\t";
+ d->outsvg += tmp_ellipse.str().c_str();
+ d->outsvg += "/> \n";
+ d->path = "";
break;
}
case U_EMR_RECTANGLE:
@@ -2679,7 +2671,7 @@ std::cout << "BEFORE DRAW"
// The next line should never be needed, should have been handled before main switch
// qualifier added because EMF's encountered where moveto preceded beginpath followed by lineto
if(d->mask & U_DRAW_VISIBLE){
- *(d->path) = "";
+ d->path = "";
}
d->mask |= emr_mask;
break;
@@ -2739,7 +2731,7 @@ std::cout << "BEFORE DRAW"
case U_EMR_ABORTPATH:
{
dbg_str << "<!-- U_EMR_ABORTPATH -->\n";
- *(d->path) = "";
+ d->path = "";
d->drawtype = 0;
break;
}
@@ -3048,7 +3040,7 @@ std::cout << "BEFORE DRAW"
TR_layout_analyze(d->tri);
TR_layout_2_svg(d->tri);
ts << d->tri->out;
- *(d->outsvg) += ts.str().c_str();
+ d->outsvg += ts.str().c_str();
d->tri = trinfo_clear(d->tri);
(void) trinfo_load_textrec(d->tri, &tsp, tsp.ori,TR_EMFBOT); // ignore return status, it must work
}
@@ -3292,7 +3284,7 @@ std::cout << "BEFORE DRAW"
tmp_rectangle << d->gradients.strings[fill_idx];
tmp_rectangle << ");\"\n/>\n";
}
- *(d->outsvg) += tmp_rectangle.str().c_str();
+ d->outsvg += tmp_rectangle.str().c_str();
}
else if(pEmr->ulMode == U_GRADIENT_FILL_TRIANGLE){
SVGOStringStream tmp_triangle;
@@ -3310,9 +3302,9 @@ std::cout << "BEFORE DRAW"
tmp_triangle << tmpcolor;
tmp_triangle << ";\"\n/>\n";
}
- *(d->outsvg) += tmp_triangle.str().c_str();
+ d->outsvg += tmp_triangle.str().c_str();
}
- *(d->path) = "";
+ d->path = "";
// if it is anything else the record is bogus, so ignore it
break;
}
@@ -3325,13 +3317,13 @@ std::cout << "BEFORE DRAW"
break;
} //end of switch
// When testing, uncomment the following to place a comment for each processed EMR record in the SVG
-// *(d->outsvg) += dbg_str.str().c_str();
- *(d->outsvg) += tmp_outsvg.str().c_str();
- *(d->path) += tmp_path.str().c_str();
+// d->outsvg += dbg_str.str().c_str();
+ d->outsvg += tmp_outsvg.str().c_str();
+ d->path += tmp_path.str().c_str();
} //end of while
// When testing, uncomment the following to show the final SVG derived from the EMF
-// std::cout << *(d->outsvg) << std::endl;
+// std::cout << d->outsvg << std::endl;
(void) emr_properties(U_EMR_INVALID); // force the release of the lookup table memory, returned value is irrelevant
return 1;
@@ -3349,61 +3341,20 @@ Emf::open( Inkscape::Extension::Input * /*mod*/, const gchar *uri )
{
EMF_CALLBACK_DATA d;
-// memset(&d, 0, sizeof(d));
- memset(&d, 0, sizeof(EMF_CALLBACK_DATA));
-
- for(int i = 0; i < EMF_MAX_DC+1; i++){ // be sure all values and pointers are empty to start with
- memset(&(d.dc[i]),0,sizeof(EMF_DEVICE_CONTEXT));
- }
-
- d.dc[0].worldTransform.eM11 = 1.0;
- d.dc[0].worldTransform.eM12 = 0.0;
- d.dc[0].worldTransform.eM21 = 0.0;
- d.dc[0].worldTransform.eM22 = 1.0;
- d.dc[0].worldTransform.eDx = 0.0;
- d.dc[0].worldTransform.eDy = 0.0;
- d.dc[0].font_name = strdup("Arial"); // Default font, EMF spec says device can pick whatever it wants
- d.dc[0].textColor = U_RGB(0, 0, 0); // default foreground color (black)
- d.dc[0].bkColor = U_RGB(255, 255, 255); // default background color (white)
- d.dc[0].bkMode = U_TRANSPARENT;
- d.dc[0].dirty = 0;
-
if (uri == NULL) {
return NULL;
}
- d.outsvg = new Glib::ustring("");
- d.path = new Glib::ustring("");
- d.outdef = new Glib::ustring("");
- d.defs = new Glib::ustring("");
- d.mask = 0;
- d.drawtype = 0;
- d.arcdir = U_AD_COUNTERCLOCKWISE;
- d.dwRop2 = U_R2_COPYPEN;
- d.dwRop3 = 0;
- d.E2IdirY = 1.0;
- d.D2PscaleX = 1.0;
- d.D2PscaleY = 1.0;
- d.hatches.size = 0;
- d.hatches.count = 0;
- d.hatches.strings = NULL;
- d.images.size = 0;
- d.images.count = 0;
- d.images.strings = NULL;
- d.gradients.size = 0;
- d.gradients.count = 0;
- d.gradients.strings = NULL;
-
// set up the size default for patterns in defs. This might not be referenced if there are no patterns defined in the drawing.
- *(d.defs) += "\n";
- *(d.defs) += " <pattern id=\"EMFhbasepattern\" \n";
- *(d.defs) += " patternUnits=\"userSpaceOnUse\"\n";
- *(d.defs) += " width=\"6\" \n";
- *(d.defs) += " height=\"6\" \n";
- *(d.defs) += " x=\"0\" \n";
- *(d.defs) += " y=\"0\"> \n";
- *(d.defs) += " </pattern> \n";
+ d.defs += "\n";
+ d.defs += " <pattern id=\"EMFhbasepattern\" \n";
+ d.defs += " patternUnits=\"userSpaceOnUse\"\n";
+ d.defs += " width=\"6\" \n";
+ d.defs += " height=\"6\" \n";
+ d.defs += " x=\"0\" \n";
+ d.defs += " y=\"0\"> \n";
+ d.defs += " </pattern> \n";
size_t length;
@@ -3425,12 +3376,8 @@ Emf::open( Inkscape::Extension::Input * /*mod*/, const gchar *uri )
// std::cout << "SVG Output: " << std::endl << *(d.outsvg) << std::endl;
- SPDocument *doc = SPDocument::createNewDocFromMem(d.outsvg->c_str(), strlen(d.outsvg->c_str()), TRUE);
+ SPDocument *doc = SPDocument::createNewDocFromMem(d.outsvg.c_str(), strlen(d.outsvg.c_str()), TRUE);
- delete d.outsvg;
- delete d.path;
- delete d.outdef;
- delete d.defs;
free_emf_strings(d.hatches);
free_emf_strings(d.images);
free_emf_strings(d.gradients);
@@ -3450,39 +3397,7 @@ Emf::open( Inkscape::Extension::Input * /*mod*/, const gchar *uri )
d.tri = trinfo_release_except_FC(d.tri);
- // Set viewBox if it doesn't exist
- if (doc && !doc->getRoot()->viewBox_set) {
- bool saved = Inkscape::DocumentUndo::getUndoSensitive(doc);
- Inkscape::DocumentUndo::setUndoSensitive(doc, false);
-
- doc->ensureUpToDate();
-
- // Set document unit
- Inkscape::XML::Node *repr = sp_document_namedview(doc, 0)->getRepr();
- Inkscape::SVGOStringStream os;
- Inkscape::Util::Unit const* doc_unit = doc->getWidth().unit;
- os << doc_unit->abbr;
- repr->setAttribute("inkscape:document-units", os.str().c_str());
-
- // Set viewBox
- doc->setViewBox(Geom::Rect::from_xywh(0, 0, doc->getWidth().value(doc_unit), doc->getHeight().value(doc_unit)));
- doc->ensureUpToDate();
-
- // Scale and translate objects
- double scale = Inkscape::Util::Quantity::convert(1, "px", doc_unit);
- ShapeEditor::blockSetItem(true);
- double dh;
- if(SP_ACTIVE_DOCUMENT){ // for file menu open or import, or paste from clipboard
- dh = SP_ACTIVE_DOCUMENT->getHeight().value("px");
- }
- else { // for open via --file on command line
- dh = doc->getHeight().value("px");
- }
- doc->getRoot()->scaleChildItemsRec(Geom::Scale(scale), Geom::Point(0, dh));
- ShapeEditor::blockSetItem(false);
-
- Inkscape::DocumentUndo::setUndoSensitive(doc, saved);
- }
+ setViewBoxIfMissing(doc);
return doc;
}
diff --git a/src/extension/internal/emf-inout.h b/src/extension/internal/emf-inout.h
index a97cb0a54..f15db5518 100644
--- a/src/extension/internal/emf-inout.h
+++ b/src/extension/internal/emf-inout.h
@@ -27,20 +27,59 @@ namespace Internal {
#define DIRTY_FILL 0x02
#define DIRTY_STROKE 0x04
-typedef struct {
+typedef struct emf_object {
+ emf_object() :
+ type(0),
+ level(0),
+ lpEMFR(NULL)
+ {};
int type;
int level;
char *lpEMFR;
} EMF_OBJECT, *PEMF_OBJECT;
-typedef struct {
+typedef struct emf_strings {
+ emf_strings() :
+ size(0),
+ count(0),
+ strings(NULL)
+ {};
int size; // number of slots allocated in strings
int count; // number of slots used in strings
char **strings; // place to store strings
} EMF_STRINGS, *PEMF_STRINGS;
typedef struct emf_device_context {
- struct SPStyle style;
+ emf_device_context() :
+ // SPStyle: class with constructor
+ font_name(NULL),
+ stroke_set(false), stroke_mode(0), stroke_idx(0), stroke_recidx(0),
+ fill_set(false), fill_mode(0), fill_idx(0), fill_recidx(0),
+ dirty(0),
+ // sizeWnd, sizeView, winorg, vieworg,
+ ScaleInX(0), ScaleInY(0),
+ ScaleOutX(0), ScaleOutY(0),
+ bkMode(U_TRANSPARENT),
+ // bkColor, textColor
+ textAlign(0)
+ // worldTransform, cur
+ {
+ font_name = strdup("Arial"); // Default font, EMF spec says device can pick whatever it wants
+ sizeWnd = sizel_set( 0.0, 0.0 );
+ sizeView = sizel_set( 0.0, 0.0 );
+ winorg = point32_set( 0.0, 0.0 );
+ vieworg = point32_set( 0.0, 0.0 );
+ bkColor = U_RGB(255, 255, 255); // default foreground color (white)
+ textColor = U_RGB(0, 0, 0); // default foreground color (black)
+ worldTransform.eM11 = 1.0;
+ worldTransform.eM12 = 0.0;
+ worldTransform.eM21 = 0.0;
+ worldTransform.eM22 = 1.0;
+ worldTransform.eDx = 0.0;
+ worldTransform.eDy = 0.0;
+ cur = point32_set( 0, 0 );
+ };
+ SPStyle style;
char *font_name;
bool stroke_set;
int stroke_mode; // enumeration from drawmode, not used if fill_set is not True
@@ -67,11 +106,34 @@ typedef struct emf_device_context {
#define EMF_MAX_DC 128
-typedef struct {
- Glib::ustring *outsvg;
- Glib::ustring *path;
- Glib::ustring *outdef;
- Glib::ustring *defs;
+typedef struct emf_callback_data {
+
+ emf_callback_data() :
+ // dc: array, structure w/ constructor
+ level(0),
+ E2IdirY(1.0),
+ D2PscaleX(1.0), D2PscaleY(1.0),
+ MM100InX(0), MM100InY(0),
+ PixelsInX(0), PixelsInY(0),
+ PixelsOutX(0), PixelsOutY(0),
+ ulCornerInX(0), ulCornerInY(0),
+ ulCornerOutX(0), ulCornerOutY(0),
+ mask(0),
+ arcdir(U_AD_COUNTERCLOCKWISE),
+ dwRop2(U_R2_COPYPEN), dwRop3(0),
+ MMX(0),MMY(0),
+ id(0), drawtype(0),
+ pDesc(NULL),
+ // hatches, images, gradients, struct w/ constructor
+ tri(NULL),
+ n_obj(0)
+ // emf_obj;
+ {};
+
+ Glib::ustring outsvg;
+ Glib::ustring path;
+ Glib::ustring outdef;
+ Glib::ustring defs;
EMF_DEVICE_CONTEXT dc[EMF_MAX_DC+1]; // FIXME: This should be dynamic..
int level;
diff --git a/src/extension/internal/emf-print.cpp b/src/extension/internal/emf-print.cpp
index f4f7f08cb..8b80fec1c 100644
--- a/src/extension/internal/emf-print.cpp
+++ b/src/extension/internal/emf-print.cpp
@@ -1869,7 +1869,7 @@ unsigned int PrintEmf::text(Inkscape::Extension::Print * /*mod*/, char const *te
_lookup_ppt_fontfix("Convert To Wingdings", params);
break;
default: //also CVTNON
- _lookup_ppt_fontfix(style->text->font_family.value, params);
+ _lookup_ppt_fontfix(style->font_family.value, params);
break;
}
if (params.f2 != 0 || params.f3 != 0) {
@@ -1897,7 +1897,7 @@ unsigned int PrintEmf::text(Inkscape::Extension::Print * /*mod*/, char const *te
// of the special fonts.
uint16_t *wfacename;
if (!newfont) {
- wfacename = U_Utf8ToUtf16le(style->text->font_family.value, 0, NULL);
+ wfacename = U_Utf8ToUtf16le(style->font_family.value, 0, NULL);
} else {
wfacename = U_Utf8ToUtf16le(FontName(newfont), 0, NULL);
}
diff --git a/src/extension/internal/metafile-inout.cpp b/src/extension/internal/metafile-inout.cpp
index 1d419a6a0..53bb86d24 100644
--- a/src/extension/internal/metafile-inout.cpp
+++ b/src/extension/internal/metafile-inout.cpp
@@ -17,6 +17,7 @@
#include <glib.h>
#include <glibmm/miscutils.h>
+#include "sp-root.h"
#include "display/curve.h"
#include "extension/internal/metafile-inout.h" // picks up PNG
#include "extension/print.h"
@@ -27,6 +28,13 @@
#include "sp-pattern.h"
#include "sp-radial-gradient.h"
#include "style.h"
+#include "document.h"
+#include "util/units.h"
+#include "shape-editor.h"
+#include "sp-namedview.h"
+#include "document-undo.h"
+#include "inkscape.h"
+#include "preferences.h"
namespace Inkscape {
namespace Extension {
@@ -193,6 +201,61 @@ gchar *Metafile::bad_image_png(void){
return(gstring);
}
+/* If the viewBox is missing, set one
+*/
+void Metafile::setViewBoxIfMissing(SPDocument *doc) {
+
+ if (doc && !doc->getRoot()->viewBox_set) {
+ bool saved = Inkscape::DocumentUndo::getUndoSensitive(doc);
+ Inkscape::DocumentUndo::setUndoSensitive(doc, false);
+
+ doc->ensureUpToDate();
+
+ // Set document unit
+ Inkscape::XML::Node *repr = sp_document_namedview(doc, 0)->getRepr();
+ Inkscape::SVGOStringStream os;
+ Inkscape::Util::Unit const* doc_unit = doc->getWidth().unit;
+ os << doc_unit->abbr;
+ repr->setAttribute("inkscape:document-units", os.str().c_str());
+
+ // Set viewBox
+ doc->setViewBox(Geom::Rect::from_xywh(0, 0, doc->getWidth().value(doc_unit), doc->getHeight().value(doc_unit)));
+ doc->ensureUpToDate();
+
+ // Scale and translate objects
+ double scale = Inkscape::Util::Quantity::convert(1, "px", doc_unit);
+ ShapeEditor::blockSetItem(true);
+ double dh;
+ if(SP_ACTIVE_DOCUMENT){ // for file menu open or import, or paste from clipboard
+ dh = SP_ACTIVE_DOCUMENT->getHeight().value("px");
+ }
+ else { // for open via --file on command line
+ dh = doc->getHeight().value("px");
+ }
+
+ // These should not affect input, but they do, so set them to a neutral state
+ Inkscape::Preferences *prefs = Inkscape::Preferences::get();
+ bool transform_stroke = prefs->getBool("/options/transform/stroke", true);
+ bool transform_rectcorners = prefs->getBool("/options/transform/rectcorners", true);
+ bool transform_pattern = prefs->getBool("/options/transform/pattern", true);
+ bool transform_gradient = prefs->getBool("/options/transform/gradient", true);
+ prefs->setBool("/options/transform/stroke", true);
+ prefs->setBool("/options/transform/rectcorners", true);
+ prefs->setBool("/options/transform/pattern", true);
+ prefs->setBool("/options/transform/gradient", true);
+
+ doc->getRoot()->scaleChildItemsRec(Geom::Scale(scale), Geom::Point(0, dh));
+ ShapeEditor::blockSetItem(false);
+
+ // restore options
+ prefs->setBool("/options/transform/stroke", transform_stroke);
+ prefs->setBool("/options/transform/rectcorners", transform_rectcorners);
+ prefs->setBool("/options/transform/pattern", transform_pattern);
+ prefs->setBool("/options/transform/gradient", transform_gradient);
+
+ Inkscape::DocumentUndo::setUndoSensitive(doc, saved);
+ }
+}
} // namespace Internal
diff --git a/src/extension/internal/metafile-inout.h b/src/extension/internal/metafile-inout.h
index 968773a3a..2f7001cf2 100644
--- a/src/extension/internal/metafile-inout.h
+++ b/src/extension/internal/metafile-inout.h
@@ -71,6 +71,7 @@ protected:
static void my_png_write_data(png_structp png_ptr, png_bytep data, png_size_t length);
static void toPNG(PMEMPNG accum, int width, int height, const char *px);
static gchar *bad_image_png(void);
+ static void setViewBoxIfMissing(SPDocument *doc);
private:
diff --git a/src/extension/internal/wmf-inout.cpp b/src/extension/internal/wmf-inout.cpp
index ef95dbe45..5d7fc29d0 100644
--- a/src/extension/internal/wmf-inout.cpp
+++ b/src/extension/internal/wmf-inout.cpp
@@ -33,9 +33,8 @@
#include <stdint.h>
#include <libuemf/symbol_convert.h>
-#include "sp-root.h"
+#include "sp-root.h" // even though it is included indirectly by wmf-inout.h
#include "sp-path.h"
-#include "style.h"
#include "print.h"
#include "extension/system.h"
#include "extension/print.h"
@@ -44,13 +43,9 @@
#include "extension/output.h"
#include "display/drawing.h"
#include "display/drawing-item.h"
-#include "util/units.h"
#include "clear-n_.h"
-#include "document.h"
-#include "shape-editor.h"
-#include "sp-namedview.h"
-#include "document-undo.h"
-#include "inkscape.h"
+#include "util/units.h" // even though it is included indirectly by wmf-inout.h
+#include "inkscape.h" // even though it is included indirectly by wmf-inout.h
#include "wmf-inout.h"
@@ -251,54 +246,54 @@ uint32_t Wmf::add_hatch(PWMF_CALLBACK_DATA d, uint32_t hatchType, U_COLORREF hat
if(d->hatches.count == d->hatches.size){ enlarge_hatches(d); }
d->hatches.strings[d->hatches.count++]=strdup(hpathname);
- *(d->defs) += "\n";
+ d->defs += "\n";
switch(hatchType){
case U_HS_HORIZONTAL:
- *(d->defs) += " <path id=\"";
- *(d->defs) += hpathname;
- *(d->defs) += "\" d=\"M 0 0 6 0\" style=\"fill:none;stroke:#";
- *(d->defs) += tmpcolor;
- *(d->defs) += "\" />\n";
+ d->defs += " <path id=\"";
+ d->defs += hpathname;
+ d->defs += "\" d=\"M 0 0 6 0\" style=\"fill:none;stroke:#";
+ d->defs += tmpcolor;
+ d->defs += "\" />\n";
break;
case U_HS_VERTICAL:
- *(d->defs) += " <path id=\"";
- *(d->defs) += hpathname;
- *(d->defs) += "\" d=\"M 0 0 0 6\" style=\"fill:none;stroke:#";
- *(d->defs) += tmpcolor;
- *(d->defs) += "\" />\n";
+ d->defs += " <path id=\"";
+ d->defs += hpathname;
+ d->defs += "\" d=\"M 0 0 0 6\" style=\"fill:none;stroke:#";
+ d->defs += tmpcolor;
+ d->defs += "\" />\n";
break;
case U_HS_FDIAGONAL:
- *(d->defs) += " <line id=\"sub";
- *(d->defs) += hpathname;
- *(d->defs) += "\" x1=\"-1\" y1=\"-1\" x2=\"7\" y2=\"7\" stroke=\"#";
- *(d->defs) += tmpcolor;
- *(d->defs) += "\"/>\n";
+ d->defs += " <line id=\"sub";
+ d->defs += hpathname;
+ d->defs += "\" x1=\"-1\" y1=\"-1\" x2=\"7\" y2=\"7\" stroke=\"#";
+ d->defs += tmpcolor;
+ d->defs += "\"/>\n";
break;
case U_HS_BDIAGONAL:
- *(d->defs) += " <line id=\"sub";
- *(d->defs) += hpathname;
- *(d->defs) += "\" x1=\"-1\" y1=\"7\" x2=\"7\" y2=\"-1\" stroke=\"#";
- *(d->defs) += tmpcolor;
- *(d->defs) += "\"/>\n";
+ d->defs += " <line id=\"sub";
+ d->defs += hpathname;
+ d->defs += "\" x1=\"-1\" y1=\"7\" x2=\"7\" y2=\"-1\" stroke=\"#";
+ d->defs += tmpcolor;
+ d->defs += "\"/>\n";
break;
case U_HS_CROSS:
- *(d->defs) += " <path id=\"";
- *(d->defs) += hpathname;
- *(d->defs) += "\" d=\"M 0 0 6 0 M 0 0 0 6\" style=\"fill:none;stroke:#";
- *(d->defs) += tmpcolor;
- *(d->defs) += "\" />\n";
+ d->defs += " <path id=\"";
+ d->defs += hpathname;
+ d->defs += "\" d=\"M 0 0 6 0 M 0 0 0 6\" style=\"fill:none;stroke:#";
+ d->defs += tmpcolor;
+ d->defs += "\" />\n";
break;
case U_HS_DIAGCROSS:
- *(d->defs) += " <line id=\"subfd";
- *(d->defs) += hpathname;
- *(d->defs) += "\" x1=\"-1\" y1=\"-1\" x2=\"7\" y2=\"7\" stroke=\"#";
- *(d->defs) += tmpcolor;
- *(d->defs) += "\"/>\n";
- *(d->defs) += " <line id=\"subbd";
- *(d->defs) += hpathname;
- *(d->defs) += "\" x1=\"-1\" y1=\"7\" x2=\"7\" y2=\"-1\" stroke=\"#";
- *(d->defs) += tmpcolor;
- *(d->defs) += "\"/>\n";
+ d->defs += " <line id=\"subfd";
+ d->defs += hpathname;
+ d->defs += "\" x1=\"-1\" y1=\"-1\" x2=\"7\" y2=\"7\" stroke=\"#";
+ d->defs += tmpcolor;
+ d->defs += "\"/>\n";
+ d->defs += " <line id=\"subbd";
+ d->defs += hpathname;
+ d->defs += "\" x1=\"-1\" y1=\"7\" x2=\"7\" y2=\"-1\" stroke=\"#";
+ d->defs += tmpcolor;
+ d->defs += "\"/>\n";
break;
case U_HS_SOLIDCLR:
case U_HS_DITHEREDCLR:
@@ -307,12 +302,12 @@ uint32_t Wmf::add_hatch(PWMF_CALLBACK_DATA d, uint32_t hatchType, U_COLORREF hat
case U_HS_SOLIDBKCLR:
case U_HS_DITHEREDBKCLR:
default:
- *(d->defs) += " <path id=\"";
- *(d->defs) += hpathname;
- *(d->defs) += "\" d=\"M 0 0 6 0 6 6 0 6 z\" style=\"fill:#";
- *(d->defs) += tmpcolor;
- *(d->defs) += ";stroke:none";
- *(d->defs) += "\" />\n";
+ d->defs += " <path id=\"";
+ d->defs += hpathname;
+ d->defs += "\" d=\"M 0 0 6 0 6 6 0 6 z\" style=\"fill:#";
+ d->defs += tmpcolor;
+ d->defs += ";stroke:none";
+ d->defs += "\" />\n";
break;
}
}
@@ -374,12 +369,12 @@ uint32_t Wmf::add_hatch(PWMF_CALLBACK_DATA d, uint32_t hatchType, U_COLORREF hat
if(!idx){ // add it if not already present
if(d->hatches.count == d->hatches.size){ enlarge_hatches(d); }
d->hatches.strings[d->hatches.count++]=strdup(hatchname);
- *(d->defs) += "\n";
- *(d->defs) += " <pattern id=\"";
- *(d->defs) += hatchname;
- *(d->defs) += "\" xlink:href=\"#WMFhbasepattern\">\n";
- *(d->defs) += refpath;
- *(d->defs) += " </pattern>\n";
+ d->defs += "\n";
+ d->defs += " <pattern id=\"";
+ d->defs += hatchname;
+ d->defs += "\" xlink:href=\"#WMFhbasepattern\">\n";
+ d->defs += refpath;
+ d->defs += " </pattern>\n";
idx = d->hatches.count;
}
}
@@ -392,12 +387,12 @@ uint32_t Wmf::add_hatch(PWMF_CALLBACK_DATA d, uint32_t hatchType, U_COLORREF hat
if(d->hatches.count == d->hatches.size){ enlarge_hatches(d); }
d->hatches.strings[d->hatches.count++]=strdup(hbkname);
- *(d->defs) += "\n";
- *(d->defs) += " <rect id=\"";
- *(d->defs) += hbkname;
- *(d->defs) += "\" x=\"0\" y=\"0\" width=\"6\" height=\"6\" fill=\"#";
- *(d->defs) += bkcolor;
- *(d->defs) += "\" />\n";
+ d->defs += "\n";
+ d->defs += " <rect id=\"";
+ d->defs += hbkname;
+ d->defs += "\" x=\"0\" y=\"0\" width=\"6\" height=\"6\" fill=\"#";
+ d->defs += bkcolor;
+ d->defs += "\" />\n";
}
// this is the pattern, its name will show up in Inkscape's pattern selector
@@ -406,15 +401,15 @@ uint32_t Wmf::add_hatch(PWMF_CALLBACK_DATA d, uint32_t hatchType, U_COLORREF hat
if(!idx){ // add it if not already present
if(d->hatches.count == d->hatches.size){ enlarge_hatches(d); }
d->hatches.strings[d->hatches.count++]=strdup(hatchname);
- *(d->defs) += "\n";
- *(d->defs) += " <pattern id=\"";
- *(d->defs) += hatchname;
- *(d->defs) += "\" xlink:href=\"#WMFhbasepattern\">\n";
- *(d->defs) += " <use xlink:href=\"#";
- *(d->defs) += hbkname;
- *(d->defs) += "\" />\n";
- *(d->defs) += refpath;
- *(d->defs) += " </pattern>\n";
+ d->defs += "\n";
+ d->defs += " <pattern id=\"";
+ d->defs += hatchname;
+ d->defs += "\" xlink:href=\"#WMFhbasepattern\">\n";
+ d->defs += " <use xlink:href=\"#";
+ d->defs += hbkname;
+ d->defs += "\" />\n";
+ d->defs += refpath;
+ d->defs += " </pattern>\n";
idx = d->hatches.count;
}
}
@@ -503,35 +498,35 @@ uint32_t Wmf::add_dib_image(PWMF_CALLBACK_DATA d, const char *dib, uint32_t iUsa
sprintf(imagename,"WMFimage%d",idx++);
sprintf(xywh," x=\"0\" y=\"0\" width=\"%d\" height=\"%d\" ",width,height); // reuse this buffer
- *(d->defs) += "\n";
- *(d->defs) += " <image id=\"";
- *(d->defs) += imagename;
- *(d->defs) += "\"\n ";
- *(d->defs) += xywh;
- *(d->defs) += "\n";
- if(dibparams == U_BI_JPEG){ *(d->defs) += " xlink:href=\"data:image/jpeg;base64,"; }
- else { *(d->defs) += " xlink:href=\"data:image/png;base64,"; }
- *(d->defs) += base64String;
- *(d->defs) += "\"\n";
- *(d->defs) += " preserveAspectRatio=\"none\"\n";
- *(d->defs) += " />\n";
-
-
- *(d->defs) += "\n";
- *(d->defs) += " <pattern id=\"";
- *(d->defs) += imagename;
- *(d->defs) += "_ref\"\n ";
- *(d->defs) += xywh;
- *(d->defs) += "\n patternUnits=\"userSpaceOnUse\"";
- *(d->defs) += " >\n";
- *(d->defs) += " <use id=\"";
- *(d->defs) += imagename;
- *(d->defs) += "_ign\" ";
- *(d->defs) += " xlink:href=\"#";
- *(d->defs) += imagename;
- *(d->defs) += "\" />\n";
- *(d->defs) += " ";
- *(d->defs) += " </pattern>\n";
+ d->defs += "\n";
+ d->defs += " <image id=\"";
+ d->defs += imagename;
+ d->defs += "\"\n ";
+ d->defs += xywh;
+ d->defs += "\n";
+ if(dibparams == U_BI_JPEG){ d->defs += " xlink:href=\"data:image/jpeg;base64,"; }
+ else { d->defs += " xlink:href=\"data:image/png;base64,"; }
+ d->defs += base64String;
+ d->defs += "\"\n";
+ d->defs += " preserveAspectRatio=\"none\"\n";
+ d->defs += " />\n";
+
+
+ d->defs += "\n";
+ d->defs += " <pattern id=\"";
+ d->defs += imagename;
+ d->defs += "_ref\"\n ";
+ d->defs += xywh;
+ d->defs += "\n patternUnits=\"userSpaceOnUse\"";
+ d->defs += " >\n";
+ d->defs += " <use id=\"";
+ d->defs += imagename;
+ d->defs += "_ign\" ";
+ d->defs += " xlink:href=\"#";
+ d->defs += imagename;
+ d->defs += "\" />\n";
+ d->defs += " ";
+ d->defs += " </pattern>\n";
}
g_free(base64String); //wait until this point to free because it might be a duplicate image
return(idx-1);
@@ -599,33 +594,33 @@ uint32_t Wmf::add_bm16_image(PWMF_CALLBACK_DATA d, U_BITMAP16 Bm16, const char *
sprintf(imagename,"WMFimage%d",idx++);
sprintf(xywh," x=\"0\" y=\"0\" width=\"%d\" height=\"%d\" ",width,height); // reuse this buffer
- *(d->defs) += "\n";
- *(d->defs) += " <image id=\"";
- *(d->defs) += imagename;
- *(d->defs) += "\"\n ";
- *(d->defs) += xywh;
- *(d->defs) += "\n";
- *(d->defs) += " xlink:href=\"data:image/png;base64,";
- *(d->defs) += base64String;
- *(d->defs) += "\"\n";
- *(d->defs) += " preserveAspectRatio=\"none\"\n";
- *(d->defs) += " />\n";
-
-
- *(d->defs) += "\n";
- *(d->defs) += " <pattern id=\"";
- *(d->defs) += imagename;
- *(d->defs) += "_ref\"\n ";
- *(d->defs) += xywh;
- *(d->defs) += "\n patternUnits=\"userSpaceOnUse\"";
- *(d->defs) += " >\n";
- *(d->defs) += " <use id=\"";
- *(d->defs) += imagename;
- *(d->defs) += "_ign\" ";
- *(d->defs) += " xlink:href=\"#";
- *(d->defs) += imagename;
- *(d->defs) += "\" />\n";
- *(d->defs) += " </pattern>\n";
+ d->defs += "\n";
+ d->defs += " <image id=\"";
+ d->defs += imagename;
+ d->defs += "\"\n ";
+ d->defs += xywh;
+ d->defs += "\n";
+ d->defs += " xlink:href=\"data:image/png;base64,";
+ d->defs += base64String;
+ d->defs += "\"\n";
+ d->defs += " preserveAspectRatio=\"none\"\n";
+ d->defs += " />\n";
+
+
+ d->defs += "\n";
+ d->defs += " <pattern id=\"";
+ d->defs += imagename;
+ d->defs += "_ref\"\n ";
+ d->defs += xywh;
+ d->defs += "\n patternUnits=\"userSpaceOnUse\"";
+ d->defs += " >\n";
+ d->defs += " <use id=\"";
+ d->defs += imagename;
+ d->defs += "_ign\" ";
+ d->defs += " xlink:href=\"#";
+ d->defs += imagename;
+ d->defs += "\" />\n";
+ d->defs += " </pattern>\n";
}
g_free(base64String); //wait until this point to free because it might be a duplicate image
return(idx-1);
@@ -714,8 +709,8 @@ Wmf::output_style(PWMF_CALLBACK_DATA d)
// tmp_id << "\n\tid=\"" << (d->id++) << "\"";
-// *(d->outsvg) += tmp_id.str().c_str();
- *(d->outsvg) += "\n\tstyle=\"";
+// d->outsvg += tmp_id.str().c_str();
+ d->outsvg += "\n\tstyle=\"";
if (!d->dc[d->level].fill_set || ( d->mask & U_DRAW_NOFILL)) { // nofill are lines and arcs
tmp_style << "fill:none;";
} else {
@@ -842,7 +837,7 @@ Wmf::output_style(PWMF_CALLBACK_DATA d)
tmp_style << "\n\tclip-path=\"url(#clipWmfPath" << d->id << ")\" ";
clipset = false;
- *(d->outsvg) += tmp_style.str().c_str();
+ d->outsvg += tmp_style.str().c_str();
}
@@ -1326,8 +1321,8 @@ void Wmf::common_dib_to_image(PWMF_CALLBACK_DATA d, const char *dib,
tmp_image << " preserveAspectRatio=\"none\"\n";
tmp_image << "/> \n";
- *(d->outsvg) += tmp_image.str().c_str();
- *(d->path) = "";
+ d->outsvg += tmp_image.str().c_str();
+ d->path = "";
}
/**
@@ -1418,8 +1413,8 @@ void Wmf::common_bm16_to_image(PWMF_CALLBACK_DATA d, U_BITMAP16 Bm16, const char
tmp_image << " preserveAspectRatio=\"none\"\n";
tmp_image << "/> \n";
- *(d->outsvg) += tmp_image.str().c_str();
- *(d->path) = "";
+ d->outsvg += tmp_image.str().c_str();
+ d->path = "";
}
/**
@@ -1579,7 +1574,7 @@ int Wmf::myMetaFileProc(const char *contents, unsigned int length, PWMF_CALLBACK
d->dc[0].style.stroke_width.value = pix_to_abs_size( d, 1 ); // This could not be set until the size of the WMF was known
dbg_str << "<!-- U_WMR_HEADER -->\n";
- *(d->outdef) += "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n";
+ d->outdef += "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n";
SVGOStringStream tmp_outdef;
tmp_outdef << "<svg\n";
@@ -1592,8 +1587,8 @@ int Wmf::myMetaFileProc(const char *contents, unsigned int length, PWMF_CALLBACK
tmp_outdef <<
" width=\"" << Inkscape::Util::Quantity::convert(d->PixelsOutX, "px", "mm") << "mm\"\n" <<
" height=\"" << Inkscape::Util::Quantity::convert(d->PixelsOutY, "px", "mm") << "mm\">\n";
- *(d->outdef) += tmp_outdef.str().c_str();
- *(d->outdef) += "<defs>"; // temporary end of header
+ d->outdef += tmp_outdef.str().c_str();
+ d->outdef += "<defs>"; // temporary end of header
// d->defs holds any defines which are read in.
@@ -1636,7 +1631,7 @@ int Wmf::myMetaFileProc(const char *contents, unsigned int length, PWMF_CALLBACK
TR_layout_2_svg(d->tri);
SVGOStringStream ts;
ts << d->tri->out;
- *(d->outsvg) += ts.str().c_str();
+ d->outsvg += ts.str().c_str();
d->tri = trinfo_clear(d->tri);
}
if(d->dc[d->level].dirty){ //Apply the delayed background changes, clear the flag
@@ -1688,13 +1683,13 @@ std::cout << "BEFORE DRAW"
)
){
// std::cout << "PATH DRAW at TOP <<+++++++++++++++++++++++++++++++++++++" << std::endl;
- *(d->outsvg) += " <path "; // this is the ONLY place <path should be used!!!!
+ d->outsvg += " <path "; // this is the ONLY place <path should be used!!!!
output_style(d);
- *(d->outsvg) += "\n\t";
- *(d->outsvg) += "\n\td=\""; // this is the ONLY place d=" should be used!!!!
- *(d->outsvg) += *(d->path);
- *(d->outsvg) += " \" /> \n";
- *(d->path) = ""; //reset the path
+ d->outsvg += "\n\t";
+ d->outsvg += "\n\td=\""; // this is the ONLY place d=" should be used!!!!
+ d->outsvg += d->path;
+ d->outsvg += " \" /> \n";
+ d->path = ""; //reset the path
// reset the flags
d->mask = 0;
d->drawtype = 0;
@@ -1706,7 +1701,7 @@ std::cout << "BEFORE DRAW"
{
dbg_str << "<!-- U_WMR_EOF -->\n";
- *(d->outsvg) = *(d->outdef) + *(d->defs) + "\n</defs>\n\n" + *(d->outsvg) + "</svg>\n";
+ d->outsvg = d->outdef + d->defs + "\n</defs>\n\n" + d->outsvg + "</svg>\n";
OK=0;
break;
}
@@ -1944,8 +1939,8 @@ std::cout << "BEFORE DRAW"
tmp_rectangle << "\n height=\"" << dh << "\" />";
tmp_rectangle << "\n</clipPath>";
- *(d->outdef) += tmp_rectangle.str().c_str();
- *(d->path) = "";
+ d->outdef += tmp_rectangle.str().c_str();
+ d->path = "";
break;
}
case U_WMR_ARC:
@@ -1992,12 +1987,12 @@ std::cout << "BEFORE DRAW"
d->mask |= wmr_mask;
- *(d->outsvg) += " <ellipse ";
+ d->outsvg += " <ellipse ";
output_style(d);
- *(d->outsvg) += "\n\t";
- *(d->outsvg) += tmp_ellipse.str().c_str();
- *(d->outsvg) += "/> \n";
- *(d->path) = "";
+ d->outsvg += "\n\t";
+ d->outsvg += tmp_ellipse.str().c_str();
+ d->outsvg += "/> \n";
+ d->path = "";
break;
}
case U_WMR_FLOODFILL: dbg_str << "<!-- U_WMR_EXTFLOODFILL -->\n"; break;
@@ -2503,7 +2498,7 @@ std::cout << "BEFORE DRAW"
TR_layout_analyze(d->tri);
TR_layout_2_svg(d->tri);
ts << d->tri->out;
- *(d->outsvg) += ts.str().c_str();
+ d->outsvg += ts.str().c_str();
d->tri = trinfo_clear(d->tri);
(void) trinfo_load_textrec(d->tri, &tsp, tsp.ori,TR_EMFBOT); // ignore return status, it must work
}
@@ -2910,13 +2905,13 @@ std::cout << "BEFORE DRAW"
break;
} //end of switch
// When testing, uncomment the following to place a comment for each processed WMR record in the SVG
-// *(d->outsvg) += dbg_str.str().c_str();
- *(d->path) += tmp_path.str().c_str();
+// d->outsvg += dbg_str.str().c_str();
+ d->path += tmp_path.str().c_str();
if(!nSize){ OK=0; std::cout << "nSize == 0, oops!!!" << std::endl; } // There was some problem with this record, it is not safe to continue
} //end of while
// When testing, uncomment the following to show the final SVG derived from the WMF
-// std::cout << *(d->outsvg) << std::endl;
+// std::cout << d->outsvg << std::endl;
(void) U_wmr_properties(U_WMR_INVALID); // force the release of the lookup table memory, returned value is irrelevant
return 1;
@@ -2935,70 +2930,36 @@ Wmf::open( Inkscape::Extension::Input * /*mod*/, const gchar *uri )
WMF_CALLBACK_DATA d;
- memset(&d, 0, sizeof(WMF_CALLBACK_DATA));
-
- for(int i = 0; i < WMF_MAX_DC+1; i++){ // be sure all values and pointers are empty to start with
- memset(&(d.dc[i]),0,sizeof(WMF_DEVICE_CONTEXT));
- }
- // set default drawing objects, these are active if no object has been selected
- d.dc[0].active_pen = -1; // -1 when the default is used instead of a selected object
- d.dc[0].active_brush = -1;
- d.dc[0].active_font = -1;
- // Default font, WMF spec says device can pick whatever it wants. WMF files that do not specify a font are unlikely to look very good!
- d.dc[0].font_name = strdup("Arial");
+ // Default font, WMF spec says device can pick whatever it wants.
+ // WMF files that do not specify a font are unlikely to look very good!
d.dc[0].style.font_size.computed = 16.0;
d.dc[0].style.font_weight.value = SP_CSS_FONT_WEIGHT_400;
d.dc[0].style.font_style.value = SP_CSS_FONT_STYLE_NORMAL;
d.dc[0].style.text_decoration_line.underline = 0;
d.dc[0].style.text_decoration_line.line_through = 0;
d.dc[0].style.baseline_shift.value = 0;
- d.dc[0].textColor = U_RGB(0, 0, 0); // default foreground color (black)
- d.dc[0].bkColor = U_RGB(255, 255, 255); // default background color (white)
- d.dc[0].bkMode = U_TRANSPARENT;
- d.dc[0].dirty = 0;
+
// Default pen, WMF files that do not specify a pen are unlikely to look very good!
d.dc[0].style.stroke_dasharray.set = 0;
d.dc[0].style.stroke_linecap.computed = 2; // U_PS_ENDCAP_SQUARE;
d.dc[0].style.stroke_linejoin.computed = 0; // U_PS_JOIN_MITER;
- d.dc[0].stroke_set = true;
d.dc[0].style.stroke_width.value = 1.0; // will be reset to something reasonable once WMF draying size is known
d.dc[0].style.stroke.value.color.set( 0, 0, 0 );
- // Default brush = none, WMF files that do not specify a brush are unlikely to look very good!
- d.dc[0].fill_set = false;
if (uri == NULL) {
return NULL;
}
- d.outsvg = new Glib::ustring("");
- d.path = new Glib::ustring("");
- d.outdef = new Glib::ustring("");
- d.defs = new Glib::ustring("");
- d.mask = 0;
- d.drawtype = 0;
- d.arcdir = U_AD_COUNTERCLOCKWISE;
- d.dwRop2 = U_R2_COPYPEN;
- d.dwRop3 = 0;
- d.E2IdirY = 1.0;
- d.D2PscaleX = 1.0;
- d.D2PscaleY = 1.0;
- d.hatches.size = 0;
- d.hatches.count = 0;
- d.hatches.strings = NULL;
- d.images.size = 0;
- d.images.count = 0;
- d.images.strings = NULL;
-
// set up the size default for patterns in defs. This might not be referenced if there are no patterns defined in the drawing.
- *(d.defs) += "\n";
- *(d.defs) += " <pattern id=\"WMFhbasepattern\" \n";
- *(d.defs) += " patternUnits=\"userSpaceOnUse\"\n";
- *(d.defs) += " width=\"6\" \n";
- *(d.defs) += " height=\"6\" \n";
- *(d.defs) += " x=\"0\" \n";
- *(d.defs) += " y=\"0\"> \n";
- *(d.defs) += " </pattern> \n";
+ d.defs += "\n";
+ d.defs += " <pattern id=\"WMFhbasepattern\" \n";
+ d.defs += " patternUnits=\"userSpaceOnUse\"\n";
+ d.defs += " width=\"6\" \n";
+ d.defs += " height=\"6\" \n";
+ d.defs += " x=\"0\" \n";
+ d.defs += " y=\"0\"> \n";
+ d.defs += " </pattern> \n";
size_t length;
@@ -3016,12 +2977,8 @@ Wmf::open( Inkscape::Extension::Input * /*mod*/, const gchar *uri )
// std::cout << "SVG Output: " << std::endl << *(d.outsvg) << std::endl;
- SPDocument *doc = SPDocument::createNewDocFromMem(d.outsvg->c_str(), strlen(d.outsvg->c_str()), TRUE);
+ SPDocument *doc = SPDocument::createNewDocFromMem(d.outsvg.c_str(), strlen(d.outsvg.c_str()), TRUE);
- delete d.outsvg;
- delete d.path;
- delete d.outdef;
- delete d.defs;
free_wmf_strings(d.hatches);
free_wmf_strings(d.images);
@@ -3040,39 +2997,7 @@ Wmf::open( Inkscape::Extension::Input * /*mod*/, const gchar *uri )
d.tri = trinfo_release_except_FC(d.tri);
- // Set viewBox if it doesn't exist
- if (doc && !doc->getRoot()->viewBox_set) {
- bool saved = Inkscape::DocumentUndo::getUndoSensitive(doc);
- Inkscape::DocumentUndo::setUndoSensitive(doc, false);
-
- doc->ensureUpToDate();
-
- // Set document unit
- Inkscape::XML::Node *repr = sp_document_namedview(doc, 0)->getRepr();
- Inkscape::SVGOStringStream os;
- Inkscape::Util::Unit const* doc_unit = doc->getWidth().unit;
- os << doc_unit->abbr;
- repr->setAttribute("inkscape:document-units", os.str().c_str());
-
- // Set viewBox
- doc->setViewBox(Geom::Rect::from_xywh(0, 0, doc->getWidth().value(doc_unit), doc->getHeight().value(doc_unit)));
- doc->ensureUpToDate();
-
- // Scale and translate objects
- double scale = Inkscape::Util::Quantity::convert(1, "px", doc_unit);
- ShapeEditor::blockSetItem(true);
- double dh;
- if(SP_ACTIVE_DOCUMENT){ // for file menu open or import, or paste from clipboard
- dh = SP_ACTIVE_DOCUMENT->getHeight().value("px");
- }
- else { // for open via --file on command line
- dh = doc->getHeight().value("px");
- }
- doc->getRoot()->scaleChildItemsRec(Geom::Scale(scale), Geom::Point(0, dh));
- ShapeEditor::blockSetItem(false);
-
- Inkscape::DocumentUndo::setUndoSensitive(doc, saved);
- }
+ setViewBoxIfMissing(doc);
return doc;
}
diff --git a/src/extension/internal/wmf-inout.h b/src/extension/internal/wmf-inout.h
index 3d23ca749..6006479c7 100644
--- a/src/extension/internal/wmf-inout.h
+++ b/src/extension/internal/wmf-inout.h
@@ -26,20 +26,54 @@ namespace Internal {
#define DIRTY_FILL 0x02
#define DIRTY_STROKE 0x04 // not used currently
-typedef struct {
+typedef struct wmf_object {
+ wmf_object() :
+ type(0),
+ level(0),
+ record(NULL)
+ {};
int type;
int level;
char *record;
} WMF_OBJECT, *PWMF_OBJECT;
-typedef struct {
+typedef struct wmf_strings {
+ wmf_strings() :
+ size(0),
+ count(0),
+ strings(NULL)
+ {};
int size; // number of slots allocated in strings
int count; // number of slots used in strings
char **strings; // place to store strings
} WMF_STRINGS, *PWMF_STRINGS;
typedef struct wmf_device_context {
- struct SPStyle style;
+ wmf_device_context() :
+ // SPStyle: class with constructor
+ font_name(NULL),
+ stroke_set(false), stroke_mode(0), stroke_idx(0), stroke_recidx(0),
+ fill_set(false), fill_mode(0), fill_idx(0), fill_recidx(0),
+ dirty(0),
+ active_pen(-1), active_brush(-1), active_font(-1), // -1 when the default is used
+ // sizeWnd, sizeView, winorg, vieworg,
+ ScaleInX(0), ScaleInY(0),
+ ScaleOutX(0), ScaleOutY(0),
+ bkMode(U_TRANSPARENT),
+ // bkColor, textColor
+ textAlign(0)
+ // worldTransform, cur
+ {
+ font_name = strdup("Arial"); // Default font, WMF spec says device can pick whatever it wants
+ sizeWnd = point16_set( 0.0, 0.0 );
+ sizeView = point16_set( 0.0, 0.0 );
+ winorg = point16_set( 0.0, 0.0 );
+ vieworg = point16_set( 0.0, 0.0 );
+ bkColor = U_RGB(255, 255, 255); // default foreground color (white)
+ textColor = U_RGB(0, 0, 0); // default foreground color (black)
+ cur = point16_set( 0.0, 0.0 );
+ };
+ SPStyle style;
char *font_name;
bool stroke_set;
int stroke_mode; // enumeration from drawmode, not used if fill_set is not True
@@ -74,11 +108,32 @@ typedef struct wmf_device_context {
// this fixes it, so some confusion between this struct and the one in emf-inout???
//typedef struct wmf_callback_data {
// as does this
-typedef struct {
- Glib::ustring *outsvg;
- Glib::ustring *path;
- Glib::ustring *outdef;
- Glib::ustring *defs;
+typedef struct wmf_callback_data {
+
+ wmf_callback_data() :
+ // dc: array, structure w/ constructor
+ level(0),
+ E2IdirY(1.0),
+ D2PscaleX(1.0), D2PscaleY(1.0),
+ PixelsInX(0), PixelsInY(0),
+ PixelsOutX(0), PixelsOutY(0),
+ ulCornerInX(0), ulCornerInY(0),
+ ulCornerOutX(0), ulCornerOutY(0),
+ mask(0),
+ arcdir(U_AD_COUNTERCLOCKWISE),
+ dwRop2(U_R2_COPYPEN), dwRop3(0),
+ id(0), drawtype(0),
+ // hatches, images, gradients, struct w/ constructor
+ tri(NULL),
+ n_obj(0),
+ low_water(0)
+ //wmf_obj
+ {};
+
+ Glib::ustring outsvg;
+ Glib::ustring path;
+ Glib::ustring outdef;
+ Glib::ustring defs;
WMF_DEVICE_CONTEXT dc[WMF_MAX_DC+1]; // FIXME: This should be dynamic..
int level;
diff --git a/src/extension/internal/wmf-print.cpp b/src/extension/internal/wmf-print.cpp
index 5a552ad83..55ad5da5f 100644
--- a/src/extension/internal/wmf-print.cpp
+++ b/src/extension/internal/wmf-print.cpp
@@ -1387,7 +1387,7 @@ unsigned int PrintWmf::text(Inkscape::Extension::Print * /*mod*/, char const *te
_lookup_ppt_fontfix("Convert To Wingdings", params);
break;
default: //also CVTNON
- _lookup_ppt_fontfix(style->text->font_family.value, params);
+ _lookup_ppt_fontfix(style->font_family.value, params);
break;
}
if (params.f2 != 0 || params.f3 != 0) {
@@ -1416,7 +1416,7 @@ unsigned int PrintWmf::text(Inkscape::Extension::Print * /*mod*/, char const *te
// of the special fonts.
char *facename;
if (!newfont) {
- facename = U_Utf8ToLatin1(style->text->font_family.value, 0, NULL);
+ facename = U_Utf8ToLatin1(style->font_family.value, 0, NULL);
} else {
facename = U_Utf8ToLatin1(FontName(newfont), 0, NULL);
}
diff --git a/src/graphlayout.cpp b/src/graphlayout.cpp
index 7e10ccca1..18159cb41 100644
--- a/src/graphlayout.cpp
+++ b/src/graphlayout.cpp
@@ -195,8 +195,8 @@ void graphlayout(GSList const *const items) {
unsigned v=v_pair->second;
//cout << "Edge: (" << u <<","<<v<<")"<<endl;
es.push_back(make_pair(u,v));
- if(conn->style->marker[SP_MARKER_LOC_END].set) {
- if(directed && strcmp(conn->style->marker[SP_MARKER_LOC_END].value,"none")) {
+ if(conn->style->marker_end.set) {
+ if(directed && strcmp(conn->style->marker_end.value,"none")) {
scy.push_back(new SimpleConstraint(v, u,
(ideal_connector_length * directed_edge_height_modifier)));
}
diff --git a/src/id-clash.cpp b/src/id-clash.cpp
index f59b3b920..66357b75b 100644
--- a/src/id-clash.cpp
+++ b/src/id-clash.cpp
@@ -53,12 +53,12 @@ const char *href_like_attributes[] = {
#define NUM_HREF_LIKE_ATTRIBUTES (sizeof(href_like_attributes) / sizeof(*href_like_attributes))
const SPIPaint SPStyle::* SPIPaint_members[] = {
- &SPStyle::color,
+ //&SPStyle::color,
&SPStyle::fill,
&SPStyle::stroke,
};
const char* SPIPaint_properties[] = {
- "color",
+ //"color",
"fill",
"stroke",
};
@@ -76,7 +76,7 @@ const char* other_url_properties[] = {
#define NUM_OTHER_URL_PROPERTIES (sizeof(other_url_properties) / sizeof(*other_url_properties))
const char* clipboard_properties[] = {
- "color",
+ //"color",
"fill",
"filter",
"stroke",
@@ -161,7 +161,7 @@ find_references(SPObject *elem, refmap_type *refmap)
/* check for url(#...) references in markers */
const gchar *markers[4] = { "", "marker-start", "marker-mid", "marker-end" };
for (unsigned i = SP_MARKER_LOC_START; i < SP_MARKER_LOC_QTY; i++) {
- const gchar *value = style->marker[i].value;
+ const gchar *value = style->marker_ptrs[i]->value;
if (value) {
gchar *uri = extract_uri(value);
if (uri && uri[0] == '#') {
diff --git a/src/libcroco/cr-sel-eng.c b/src/libcroco/cr-sel-eng.c
index 0eba2b403..4f501ee05 100644
--- a/src/libcroco/cr-sel-eng.c
+++ b/src/libcroco/cr-sel-eng.c
@@ -136,8 +136,9 @@ lang_pseudo_class_handler (CRSelEng *const a_this,
node_iface = PRIVATE(a_this)->node_iface;
- if (strqcmp (a_sel->content.pseudo->name->stryng->str,
- "lang", 4)
+ /* "xml:lang" needed for SVG */
+ if ( (strqcmp (a_sel->content.pseudo->name->stryng->str, "lang", 4 ) &&
+ (strqcmp (a_sel->content.pseudo->name->stryng->str, "xml:lang", 8 ) ) )
|| !a_sel->content.pseudo->type == FUNCTION_PSEUDO) {
cr_utils_trace_info ("This handler is for :lang only");
return FALSE;
@@ -149,6 +150,7 @@ lang_pseudo_class_handler (CRSelEng *const a_this,
return FALSE;
for (; node; node = get_next_parent_element_node (node_iface, node)) {
char *val = node_iface->getProp (node, "lang");
+ if (!val) val = node_iface->getProp (node, "xml:lang");
if (val) {
if (!strcasecmp(val, a_sel->content.pseudo->extra->stryng->str)) {
result = TRUE;
diff --git a/src/libdepixelize/CMakeLists.txt b/src/libdepixelize/CMakeLists.txt
index 895e16e85..a69d37bc7 100644
--- a/src/libdepixelize/CMakeLists.txt
+++ b/src/libdepixelize/CMakeLists.txt
@@ -7,11 +7,11 @@ set(libdepixelize_SRC
kopftracer2011.h
splines.h
- priv/branchless.h
+ priv/branchless.h
priv/colorspace.h
priv/curvature.h
priv/homogeneoussplines.h
- priv/integral
+ priv/integral.h
priv/iterator.h
priv/optimization-kopf2011.h
priv/pixelgraph.h
diff --git a/src/libnrtype/FontFactory.cpp b/src/libnrtype/FontFactory.cpp
index 7c0b4ffba..4ae408397 100644
--- a/src/libnrtype/FontFactory.cpp
+++ b/src/libnrtype/FontFactory.cpp
@@ -825,17 +825,17 @@ font_instance* font_factory::FaceFromStyle(SPStyle const *style)
if (style) {
// First try to use the font specification if it is set
- if (style->text->font_specification.set
- && style->text->font_specification.value
- && *style->text->font_specification.value) {
+ if (style->font_specification.set
+ && style->font_specification.value
+ && *style->font_specification.value) {
- font = FaceFromFontSpecification(style->text->font_specification.value);
+ font = FaceFromFontSpecification(style->font_specification.value);
}
// If that failed, try using the CSS information in the style
if (!font) {
- font = Face(style->text->font_family.value, font_style_to_pos(*style));
+ font = Face(style->font_family.value, font_style_to_pos(*style));
// That was a hatchet job... so we need to check if this font exists!!
Glib::ustring fontSpec = font_factory::Default()->ConstructFontSpecification(font);
diff --git a/src/libnrtype/Layout-TNG-Input.cpp b/src/libnrtype/Layout-TNG-Input.cpp
index cb3e6f620..fa1e8c11b 100644
--- a/src/libnrtype/Layout-TNG-Input.cpp
+++ b/src/libnrtype/Layout-TNG-Input.cpp
@@ -286,16 +286,15 @@ font_instance *Layout::InputStreamTextSource::styleGetFontInstance() const
PangoFontDescription *Layout::InputStreamTextSource::styleGetFontDescription() const
{
- if (style->text == NULL) return NULL;
PangoFontDescription *descr = pango_font_description_new();
// Pango can't cope with spaces before or after the commas - let's remove them.
// this code is not exactly unicode-safe, but it's similar to what's done in
// pango, so it's not the limiting factor
Glib::ustring family;
- if (style->text->font_family.value == NULL) {
+ if (style->font_family.value == NULL) {
family = "sans-serif";
} else {
- gchar **families = g_strsplit(style->text->font_family.value, ",", -1);
+ gchar **families = g_strsplit(style->font_family.value, ",", -1);
if (families) {
for (gchar **f = families ; *f ; ++f) {
g_strstrip(*f);
diff --git a/src/libnrtype/Layout-TNG.h b/src/libnrtype/Layout-TNG.h
index c3ccbffb5..efb5ebc24 100644
--- a/src/libnrtype/Layout-TNG.h
+++ b/src/libnrtype/Layout-TNG.h
@@ -34,7 +34,7 @@ namespace Inkscape {
using Inkscape::Extension::Internal::CairoRenderContext;
#endif
-struct SPStyle;
+class SPStyle;
class Shape;
struct SPPrintContext;
class SVGLength;
diff --git a/src/libnrtype/font-lister.cpp b/src/libnrtype/font-lister.cpp
index 89d0cb037..98589d9d7 100644
--- a/src/libnrtype/font-lister.cpp
+++ b/src/libnrtype/font-lister.cpp
@@ -97,6 +97,34 @@ 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 ) {
+
+ GList *styles = default_styles;
+
+ /* In case this is a fallback list, check if first font-family on system. */
+ std::vector<Glib::ustring> tokens = Glib::Regex::split_simple(",", new_family );
+ if( !tokens.empty() && !tokens[0].empty() ) {
+
+ 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 ) {
+ styles = row[FontList.styles];
+ break;
+ }
+ ++iter2;
+ }
+ }
+
+ Gtk::TreeModel::iterator treeModelIter = font_list_store->prepend();
+ (*treeModelIter)[FontList.family] = reinterpret_cast<const char*>(g_strdup(new_family.c_str()));
+ (*treeModelIter)[FontList.styles] = styles;
+ (*treeModelIter)[FontList.onSystem] = false;
+ }
+
void
FontLister::update_font_list( SPDocument* document ) {
@@ -330,8 +358,8 @@ namespace Inkscape
sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONT_SPECIFICATION);
//std::cout << " Attempting selected style" << std::endl;
- if( result != QUERY_STYLE_NOTHING && query->text->font_specification.set ) {
- fontspec = query->text->font_specification.value;
+ if( result != QUERY_STYLE_NOTHING && query->font_specification.set ) {
+ fontspec = query->font_specification.value;
//std::cout << " fontspec from query :" << fontspec << ":" << std::endl;
}
@@ -665,15 +693,15 @@ std::pair<Glib::ustring, Glib::ustring> FontLister::new_font_family (Glib::ustri
if (style) {
// First try to use the font specification if it is set
- if (style->text->font_specification.set
- && style->text->font_specification.value
- && *style->text->font_specification.value) {
+ if (style->font_specification.set
+ && style->font_specification.value
+ && *style->font_specification.value) {
- fontspec = style->text->font_specification.value;
+ fontspec = style->font_specification.value;
} else {
- fontspec = style->text->font_family.value;
+ fontspec = style->font_family.value;
fontspec += ",";
switch (style->font_weight.computed) {
diff --git a/src/libnrtype/font-lister.h b/src/libnrtype/font-lister.h
index 5a8f578d9..a460388d3 100644
--- a/src/libnrtype/font-lister.h
+++ b/src/libnrtype/font-lister.h
@@ -26,7 +26,7 @@
class SPObject;
class SPDocument;
class SPCSSAttr;
-struct SPStyle;
+class SPStyle;
namespace Inkscape
{
@@ -127,6 +127,12 @@ namespace Inkscape
const Glib::RefPtr<Gtk::ListStore>
get_style_list () const;
+ /** Inserts a font family or font-fallback list (for use when not
+ * already in document or on system).
+ */
+ void
+ insert_font_family ( Glib::ustring new_family );
+
/** Updates font list to include fonts in document
*
*/
diff --git a/src/libnrtype/font-style-to-pos.h b/src/libnrtype/font-style-to-pos.h
index 56eb391c2..41ba6cf72 100644
--- a/src/libnrtype/font-style-to-pos.h
+++ b/src/libnrtype/font-style-to-pos.h
@@ -3,7 +3,7 @@
#include <libnrtype/nr-type-pos-def.h>
-struct SPStyle;
+class SPStyle;
NRTypePosDef font_style_to_pos(SPStyle const &style);
diff --git a/src/livarot/Path.h b/src/livarot/Path.h
index a109298a2..32ee71ffc 100644
--- a/src/livarot/Path.h
+++ b/src/livarot/Path.h
@@ -20,7 +20,7 @@ struct PathDescrCubicTo;
struct PathDescrBezierTo;
struct PathDescrIntermBezierTo;
-struct SPStyle;
+class SPStyle;
/*
* the Path class: a structure to hold path description and their polyline approximation (not kept in sync)
diff --git a/src/live_effects/Makefile_insert b/src/live_effects/Makefile_insert
index e2c35c3bd..fdbdec3b9 100644
--- a/src/live_effects/Makefile_insert
+++ b/src/live_effects/Makefile_insert
@@ -98,4 +98,4 @@ ink_common_sources += \
live_effects/lpe-jointype.cpp \
live_effects/lpe-jointype.h \
live_effects/lpe-taperstroke.cpp \
- live_effects/lpe-taperstroke.h
+ live_effects/lpe-taperstroke.h
diff --git a/src/live_effects/lpe-jointype.cpp b/src/live_effects/lpe-jointype.cpp
index f3ec02530..0c1813970 100644
--- a/src/live_effects/lpe-jointype.cpp
+++ b/src/live_effects/lpe-jointype.cpp
@@ -81,7 +81,7 @@ void LPEJoinType::doOnApply(SPLPEItem const* lpeitem)
double width = (lpeitem && lpeitem->style) ? lpeitem->style->stroke_width.computed : 1.;
SPCSSAttr *css = sp_repr_css_attr_new ();
- if (lpeitem->style->stroke.isSet()) {
+ if (true) {
if (lpeitem->style->stroke.isPaintserver()) {
SPPaintServer * server = lpeitem->style->getStrokePaintServer();
if (server) {
@@ -125,7 +125,7 @@ void LPEJoinType::doOnRemove(SPLPEItem const* lpeitem)
SPLPEItem *item = const_cast<SPLPEItem*>(lpeitem);
SPCSSAttr *css = sp_repr_css_attr_new ();
- if (lpeitem->style->fill.isSet()) {
+ if (true) {
if (lpeitem->style->fill.isPaintserver()) {
SPPaintServer * server = lpeitem->style->getFillPaintServer();
if (server) {
diff --git a/src/live_effects/lpe-powerstroke.cpp b/src/live_effects/lpe-powerstroke.cpp
index b63a2bf01..f7516677d 100644
--- a/src/live_effects/lpe-powerstroke.cpp
+++ b/src/live_effects/lpe-powerstroke.cpp
@@ -276,7 +276,7 @@ LPEPowerStroke::doOnApply(SPLPEItem const* lpeitem)
double width = (lpeitem && lpeitem->style) ? lpeitem->style->stroke_width.computed / 2 : 1.;
SPCSSAttr *css = sp_repr_css_attr_new ();
- if (lpeitem->style->stroke.isSet()) {
+ if (true) {
if (lpeitem->style->stroke.isPaintserver()) {
SPPaintServer * server = lpeitem->style->getStrokePaintServer();
if (server) {
@@ -329,7 +329,7 @@ void LPEPowerStroke::doOnRemove(SPLPEItem const* lpeitem)
if (SP_IS_SHAPE(lpeitem)) {
SPLPEItem *item = const_cast<SPLPEItem*>(lpeitem);
SPCSSAttr *css = sp_repr_css_attr_new ();
- if (lpeitem->style->fill.isSet()) {
+ if (true) {
if (lpeitem->style->fill.isPaintserver()) {
SPPaintServer * server = lpeitem->style->getFillPaintServer();
if (server) {
diff --git a/src/live_effects/lpe-taperstroke.cpp b/src/live_effects/lpe-taperstroke.cpp
index 8ddaa4087..5564a3b2c 100644
--- a/src/live_effects/lpe-taperstroke.cpp
+++ b/src/live_effects/lpe-taperstroke.cpp
@@ -107,7 +107,7 @@ void LPETaperStroke::doOnApply(SPLPEItem const* lpeitem)
double width = (lpeitem && lpeitem->style) ? lpeitem->style->stroke_width.computed : 1.;
SPCSSAttr *css = sp_repr_css_attr_new ();
- if (lpeitem->style->stroke.isSet()) {
+ if (true) {
if (lpeitem->style->stroke.isPaintserver()) {
SPPaintServer * server = lpeitem->style->getStrokePaintServer();
if (server) {
@@ -145,12 +145,10 @@ void LPETaperStroke::doOnRemove(SPLPEItem const* lpeitem)
{
if (SP_IS_SHAPE(lpeitem)) {
- //TODO: make it getobjbyrepr instead of const_cast because this can cause
- //undefined behavior
SPLPEItem *item = const_cast<SPLPEItem*>(lpeitem);
SPCSSAttr *css = sp_repr_css_attr_new ();
- if (lpeitem->style->fill.isSet()) {
+ if (true) {
if (lpeitem->style->fill.isPaintserver()) {
SPPaintServer * server = lpeitem->style->getFillPaintServer();
if (server) {
diff --git a/src/print.h b/src/print.h
index 80d0446fd..bbf95b833 100644
--- a/src/print.h
+++ b/src/print.h
@@ -18,7 +18,7 @@ class Window;
}
class SPDocument;
-struct SPStyle;
+class SPStyle;
namespace Inkscape {
namespace Extension {
diff --git a/src/selection-chemistry.cpp b/src/selection-chemistry.cpp
index 5a981c6a0..868a9d743 100644
--- a/src/selection-chemistry.cpp
+++ b/src/selection-chemistry.cpp
@@ -2076,9 +2076,9 @@ GSList *sp_get_same_stroke_style(SPItem *sel, GSList *src, SPSelectStrokeStyleTy
match = true;
int len = sizeof(sel_style->marker)/sizeof(SPIString);
for (int i = 0; i < len; i++) {
- match = (sel_style->marker[i].set == iter_style->marker[i].set);
- if (sel_style->marker[i].set && iter_style->marker[i].set &&
- (strcmp(sel_style->marker[i].value, iter_style->marker[i].value))) {
+ match = (sel_style->marker_ptrs[i]->set == iter_style->marker_ptrs[i]->set);
+ if (sel_style->marker_ptrs[i]->set && iter_style->marker_ptrs[i]->set &&
+ (strcmp(sel_style->marker_ptrs[i]->value, iter_style->marker_ptrs[i]->value))) {
match = false;
break;
}
diff --git a/src/sp-lpe-item.cpp b/src/sp-lpe-item.cpp
index ae5763e67..b5dd74fc6 100644
--- a/src/sp-lpe-item.cpp
+++ b/src/sp-lpe-item.cpp
@@ -16,7 +16,6 @@
# include "config.h"
#endif
-//the gtk devs are really not smart about backwards compatibility
#include "ui/tool/multi-path-manipulator.h"
#include <glibmm/i18n.h>
@@ -243,7 +242,7 @@ bool SPLPEItem::performPathEffect(SPCurve *curve) {
// Groups have their doBeforeEffect called elsewhere
if (!SP_IS_GROUP(this)) {
- lpe->doBeforeEffect_impl(this);
+ lpe->doBeforeEffect(this);
}
try {
@@ -257,9 +256,6 @@ bool SPLPEItem::performPathEffect(SPCurve *curve) {
}
return false;
}
- if (!SP_IS_GROUP(this)) {
- lpe->doAfterEffect(this);
- }
}
}
}
@@ -415,7 +411,7 @@ void SPLPEItem::addPathEffect(gchar *value, bool reset)
}
// perform this once when the effect is applied
- lpe->doOnApply_impl(this);
+ lpe->doOnApply(this);
// indicate that all necessary preparations are done and the effect can be performed
lpe->setReady();
@@ -428,11 +424,9 @@ void SPLPEItem::addPathEffect(gchar *value, bool reset)
sp_lpe_item_update_patheffect(this, true, true);
//fix bug 1219324
- Inkscape::UI::Tools::NodeTool *tool = 0;
if (SP_ACTIVE_DESKTOP ) {
Inkscape::UI::Tools::ToolBase *ec = SP_ACTIVE_DESKTOP->event_context;
if (INK_IS_NODE_TOOL(ec)) {
- tool = static_cast<Inkscape::UI::Tools::NodeTool*>(ec);
tools_switch(SP_ACTIVE_DESKTOP, TOOLS_LPETOOL); //mhh
tools_switch(SP_ACTIVE_DESKTOP, TOOLS_NODES);
}
@@ -448,45 +442,48 @@ void SPLPEItem::addPathEffect(LivePathEffectObject * new_lpeobj)
g_free(hrefstr);
}
+/**
+ * If keep_path == true, the item should not be updated, effectively 'flattening' the LPE.
+ */
void SPLPEItem::removeCurrentPathEffect(bool keep_paths)
{
Inkscape::LivePathEffect::LPEObjectReference* lperef = this->getCurrentLPEReference();
if (!lperef)
return;
-
- Inkscape::LivePathEffect::Effect * lpe = this->getCurrentLPE();
- lpe->doOnRemove(this);
-
+
PathEffectList new_list = *this->path_effect_list;
new_list.remove(lperef); //current lpe ref is always our 'own' pointer from the path_effect_list
std::string r = patheffectlist_write_svg(new_list);
-
if (!r.empty()) {
this->getRepr()->setAttribute("inkscape:path-effect", r.c_str());
} else {
this->getRepr()->setAttribute("inkscape:path-effect", NULL);
+ }
+
+ if (!keep_paths) {
// Make sure that ellipse is stored as <svg:circle> or <svg:ellipse> if possible.
if( SP_IS_GENERICELLIPSE(this)) {
SP_GENERICELLIPSE(this)->write( this->getRepr()->document(), this->getRepr(), SP_OBJECT_WRITE_EXT );
}
- }
- if (!keep_paths) {
sp_lpe_item_cleanup_original_path_recursive(this);
}
}
+/**
+ * If keep_path == true, the item should not be updated, effectively 'flattening' the LPE.
+ */
void SPLPEItem::removeAllPathEffects(bool keep_paths)
{
this->getRepr()->setAttribute("inkscape:path-effect", NULL);
- // Make sure that ellipse is stored as <svg:circle> or <svg:ellipse> if possible.
- if( SP_IS_GENERICELLIPSE(this)) {
- SP_GENERICELLIPSE(this)->write( this->getRepr()->document(), this->getRepr(), SP_OBJECT_WRITE_EXT );
- }
-
if (!keep_paths) {
+ // Make sure that ellipse is stored as <svg:circle> or <svg:ellipse> if possible.
+ if (SP_IS_GENERICELLIPSE(this)) {
+ SP_GENERICELLIPSE(this)->write(this->getRepr()->document(), this->getRepr(), SP_OBJECT_WRITE_EXT);
+ }
+
sp_lpe_item_cleanup_original_path_recursive(this);
}
}
@@ -554,7 +551,6 @@ bool SPLPEItem::hasBrokenPathEffect() const
bool SPLPEItem::hasPathEffect() const
{
- if (!path_effect_list) return false; //nullptr sucks
if (path_effect_list->empty()) {
return false;
}
@@ -689,26 +685,17 @@ static std::string hreflist_write_svg(HRefList const & list)
// Return a copy of the effect list
PathEffectList SPLPEItem::getEffectList()
{
- if (!path_effect_list) {
- g_critical("Broken path effect list in %s\n", __FILE__);
- return PathEffectList();
- }
return *path_effect_list;
}
// Return a copy of the effect list
PathEffectList const SPLPEItem::getEffectList() const
{
- if (!path_effect_list) {
- g_critical("Broken path effect list in %s\n", __FILE__);
- return PathEffectList();
- }
return *path_effect_list;
}
Inkscape::LivePathEffect::LPEObjectReference* SPLPEItem::getCurrentLPEReference()
{
- if (!this->hasPathEffect()) return NULL;
if (!this->current_path_effect && !this->path_effect_list->empty()) {
setCurrentPathEffect(this->path_effect_list->back());
}
@@ -718,9 +705,6 @@ Inkscape::LivePathEffect::LPEObjectReference* SPLPEItem::getCurrentLPEReference(
Inkscape::LivePathEffect::Effect* SPLPEItem::getCurrentLPE()
{
- if (path_effect_list == NULL) {
- return NULL;
- }
Inkscape::LivePathEffect::LPEObjectReference* lperef = getCurrentLPEReference();
if (lperef && lperef->lpeobject)
diff --git a/src/sp-object.h b/src/sp-object.h
index 08407a2ed..a308caeae 100644
--- a/src/sp-object.h
+++ b/src/sp-object.h
@@ -57,7 +57,7 @@ class SPObject;
#include "util/forward-pointer-iterator.h"
class SPCSSAttr;
-struct SPStyle;
+class SPStyle;
namespace Inkscape {
namespace XML {
diff --git a/src/sp-shape.cpp b/src/sp-shape.cpp
index b3a331cba..61d35e6ff 100644
--- a/src/sp-shape.cpp
+++ b/src/sp-shape.cpp
@@ -77,7 +77,7 @@ void SPShape::build(SPDocument *document, Inkscape::XML::Node *repr) {
SPLPEItem::build(document, repr);
for (int i = 0 ; i < SP_MARKER_LOC_QTY ; i++) {
- sp_shape_set_marker (this, i, this->style->marker[i].value);
+ sp_shape_set_marker (this, i, this->style->marker_ptrs[i]->value);
}
}
@@ -136,7 +136,7 @@ void SPShape::update(SPCtx* ctx, guint flags) {
* match the style.
*/
for (int i = 0 ; i < SP_MARKER_LOC_QTY ; i++) {
- sp_shape_set_marker (this, i, this->style->marker[i].value);
+ sp_shape_set_marker (this, i, this->style->marker_ptrs[i]->value);
}
if (flags & (SP_OBJECT_STYLE_MODIFIED_FLAG | SP_OBJECT_VIEWPORT_MODIFIED_FLAG)) {
@@ -723,7 +723,7 @@ Inkscape::DrawingItem* SPShape::show(Inkscape::Drawing &drawing, unsigned int /*
* match the style.
*/
for (int i = 0 ; i < SP_MARKER_LOC_QTY ; i++) {
- sp_shape_set_marker (this, i, this->style->marker[i].value);
+ sp_shape_set_marker (this, i, this->style->marker_ptrs[i]->value);
}
if (this->hasMarkers ()) {
diff --git a/src/style-enums.h b/src/style-enums.h
index c6f9a1ea1..356029a40 100644
--- a/src/style-enums.h
+++ b/src/style-enums.h
@@ -15,7 +15,9 @@
* Released under GNU GPL, read the file 'COPYING' for more information
*/
-/* SPTextStyle */
+/* SPFontStyle */
+
+#include "display/canvas-bpath.h"
enum SPCSSFontSize {
SP_CSS_FONT_SIZE_XX_SMALL,
@@ -215,6 +217,267 @@ enum SPTextRendering {
SP_CSS_TEXT_RENDERING_GEOMETRICPRECISION
};
+
+struct SPStyleEnum {
+ gchar const *key;
+ gint value;
+};
+
+static SPStyleEnum const enum_fill_rule[] = {
+ {"nonzero", SP_WIND_RULE_NONZERO},
+ {"evenodd", SP_WIND_RULE_EVENODD},
+ {NULL, -1}
+};
+
+static SPStyleEnum const enum_stroke_linecap[] = {
+ {"butt", SP_STROKE_LINECAP_BUTT},
+ {"round", SP_STROKE_LINECAP_ROUND},
+ {"square", SP_STROKE_LINECAP_SQUARE},
+ {NULL, -1}
+};
+
+static SPStyleEnum const enum_stroke_linejoin[] = {
+ {"miter", SP_STROKE_LINEJOIN_MITER},
+ {"round", SP_STROKE_LINEJOIN_ROUND},
+ {"bevel", SP_STROKE_LINEJOIN_BEVEL},
+ {NULL, -1}
+};
+
+static SPStyleEnum const enum_font_style[] = {
+ {"normal", SP_CSS_FONT_STYLE_NORMAL},
+ {"italic", SP_CSS_FONT_STYLE_ITALIC},
+ {"oblique", SP_CSS_FONT_STYLE_OBLIQUE},
+ {NULL, -1}
+};
+
+static SPStyleEnum const enum_font_size[] = {
+ {"xx-small", SP_CSS_FONT_SIZE_XX_SMALL},
+ {"x-small", SP_CSS_FONT_SIZE_X_SMALL},
+ {"small", SP_CSS_FONT_SIZE_SMALL},
+ {"medium", SP_CSS_FONT_SIZE_MEDIUM},
+ {"large", SP_CSS_FONT_SIZE_LARGE},
+ {"x-large", SP_CSS_FONT_SIZE_X_LARGE},
+ {"xx-large", SP_CSS_FONT_SIZE_XX_LARGE},
+ {"smaller", SP_CSS_FONT_SIZE_SMALLER},
+ {"larger", SP_CSS_FONT_SIZE_LARGER},
+ {NULL, -1}
+};
+
+static SPStyleEnum const enum_font_variant[] = {
+ {"normal", SP_CSS_FONT_VARIANT_NORMAL},
+ {"small-caps", SP_CSS_FONT_VARIANT_SMALL_CAPS},
+ {NULL, -1}
+};
+
+static SPStyleEnum const enum_font_weight[] = {
+ {"100", SP_CSS_FONT_WEIGHT_100},
+ {"200", SP_CSS_FONT_WEIGHT_200},
+ {"300", SP_CSS_FONT_WEIGHT_300},
+ {"400", SP_CSS_FONT_WEIGHT_400},
+ {"500", SP_CSS_FONT_WEIGHT_500},
+ {"600", SP_CSS_FONT_WEIGHT_600},
+ {"700", SP_CSS_FONT_WEIGHT_700},
+ {"800", SP_CSS_FONT_WEIGHT_800},
+ {"900", SP_CSS_FONT_WEIGHT_900},
+ {"normal", SP_CSS_FONT_WEIGHT_NORMAL},
+ {"bold", SP_CSS_FONT_WEIGHT_BOLD},
+ {"lighter", SP_CSS_FONT_WEIGHT_LIGHTER},
+ {"bolder", SP_CSS_FONT_WEIGHT_BOLDER},
+ {NULL, -1}
+};
+
+static SPStyleEnum const enum_font_stretch[] = {
+ {"ultra-condensed", SP_CSS_FONT_STRETCH_ULTRA_CONDENSED},
+ {"extra-condensed", SP_CSS_FONT_STRETCH_EXTRA_CONDENSED},
+ {"condensed", SP_CSS_FONT_STRETCH_CONDENSED},
+ {"semi-condensed", SP_CSS_FONT_STRETCH_SEMI_CONDENSED},
+ {"normal", SP_CSS_FONT_STRETCH_NORMAL},
+ {"semi-expanded", SP_CSS_FONT_STRETCH_SEMI_EXPANDED},
+ {"expanded", SP_CSS_FONT_STRETCH_EXPANDED},
+ {"extra-expanded", SP_CSS_FONT_STRETCH_EXTRA_EXPANDED},
+ {"ultra-expanded", SP_CSS_FONT_STRETCH_ULTRA_EXPANDED},
+ {"narrower", SP_CSS_FONT_STRETCH_NARROWER},
+ {"wider", SP_CSS_FONT_STRETCH_WIDER},
+ {NULL, -1}
+};
+
+static SPStyleEnum const enum_text_align[] = {
+ {"start", SP_CSS_TEXT_ALIGN_START},
+ {"end", SP_CSS_TEXT_ALIGN_END},
+ {"left", SP_CSS_TEXT_ALIGN_LEFT},
+ {"right", SP_CSS_TEXT_ALIGN_RIGHT},
+ {"center", SP_CSS_TEXT_ALIGN_CENTER},
+ {"justify", SP_CSS_TEXT_ALIGN_JUSTIFY},
+ {NULL, -1}
+};
+
+static SPStyleEnum const enum_text_transform[] = {
+ {"capitalize", SP_CSS_TEXT_TRANSFORM_CAPITALIZE},
+ {"uppercase", SP_CSS_TEXT_TRANSFORM_UPPERCASE},
+ {"lowercase", SP_CSS_TEXT_TRANSFORM_LOWERCASE},
+ {"none", SP_CSS_TEXT_TRANSFORM_NONE},
+ {NULL, -1}
+};
+
+static SPStyleEnum const enum_text_anchor[] = {
+ {"start", SP_CSS_TEXT_ANCHOR_START},
+ {"middle", SP_CSS_TEXT_ANCHOR_MIDDLE},
+ {"end", SP_CSS_TEXT_ANCHOR_END},
+ {NULL, -1}
+};
+
+static SPStyleEnum const enum_direction[] = {
+ {"ltr", SP_CSS_DIRECTION_LTR},
+ {"rtl", SP_CSS_DIRECTION_RTL},
+ {NULL, -1}
+};
+
+static SPStyleEnum const enum_block_progression[] = {
+ {"tb", SP_CSS_BLOCK_PROGRESSION_TB},
+ {"rl", SP_CSS_BLOCK_PROGRESSION_RL},
+ {"lr", SP_CSS_BLOCK_PROGRESSION_LR},
+ {NULL, -1}
+};
+
+static SPStyleEnum const enum_writing_mode[] = {
+ /* Note that using the same enumerator for lr as lr-tb means we write as lr-tb even if the
+ * input file said lr. We prefer writing lr-tb on the grounds that the spec says the initial
+ * value is lr-tb rather than lr.
+ *
+ * ECMA scripts may be surprised to find tb-rl in DOM if they set the attribute to rl, so
+ * sharing enumerators for different strings may be a bug (once we support ecma script).
+ */
+ {"lr-tb", SP_CSS_WRITING_MODE_LR_TB},
+ {"rl-tb", SP_CSS_WRITING_MODE_RL_TB},
+ {"tb-rl", SP_CSS_WRITING_MODE_TB_RL},
+ {"lr", SP_CSS_WRITING_MODE_LR_TB},
+ {"rl", SP_CSS_WRITING_MODE_RL_TB},
+ {"tb", SP_CSS_WRITING_MODE_TB_RL},
+ {NULL, -1}
+};
+
+static SPStyleEnum const enum_baseline_shift[] = {
+ {"baseline", SP_CSS_BASELINE_SHIFT_BASELINE},
+ {"sub", SP_CSS_BASELINE_SHIFT_SUB},
+ {"super", SP_CSS_BASELINE_SHIFT_SUPER},
+ {NULL, -1}
+};
+
+static SPStyleEnum const enum_visibility[] = {
+ {"hidden", SP_CSS_VISIBILITY_HIDDEN},
+ {"collapse", SP_CSS_VISIBILITY_COLLAPSE},
+ {"visible", SP_CSS_VISIBILITY_VISIBLE},
+ {NULL, -1}
+};
+
+static SPStyleEnum const enum_overflow[] = {
+ {"visible", SP_CSS_OVERFLOW_VISIBLE},
+ {"hidden", SP_CSS_OVERFLOW_HIDDEN},
+ {"scroll", SP_CSS_OVERFLOW_SCROLL},
+ {"auto", SP_CSS_OVERFLOW_AUTO},
+ {NULL, -1}
+};
+
+// CSS Compositing and Blending Level 1
+static SPStyleEnum const enum_isolation[] = {
+ {"auto", SP_CSS_ISOLATION_AUTO},
+ {"isolate", SP_CSS_ISOLATION_ISOLATE},
+ {NULL, -1}
+};
+
+static SPStyleEnum const enum_blend_mode[] = {
+ {"normal", SP_CSS_BLEND_NORMAL},
+ {"multiply", SP_CSS_BLEND_MULTIPLY},
+ {"screen", SP_CSS_BLEND_SCREEN},
+ {"darken", SP_CSS_BLEND_DARKEN},
+ {"lighten", SP_CSS_BLEND_LIGHTEN},
+ {"overlay", SP_CSS_BLEND_OVERLAY},
+ {"color-dodge", SP_CSS_BLEND_COLORDODGE},
+ {"color-burn", SP_CSS_BLEND_COLORBURN},
+ {"hard-light", SP_CSS_BLEND_HARDLIGHT},
+ {"soft-light", SP_CSS_BLEND_SOFTLIGHT},
+ {"difference", SP_CSS_BLEND_DIFFERENCE},
+ {"exclusion", SP_CSS_BLEND_EXCLUSION},
+ {"hue", SP_CSS_BLEND_HUE},
+ {"saturation", SP_CSS_BLEND_SATURATION},
+ {"color", SP_CSS_BLEND_COLOR},
+ {"luminosity", SP_CSS_BLEND_LUMINOSITY},
+ {NULL, -1}
+};
+
+static SPStyleEnum const enum_display[] = {
+ {"none", SP_CSS_DISPLAY_NONE},
+ {"inline", SP_CSS_DISPLAY_INLINE},
+ {"block", SP_CSS_DISPLAY_BLOCK},
+ {"list-item", SP_CSS_DISPLAY_LIST_ITEM},
+ {"run-in", SP_CSS_DISPLAY_RUN_IN},
+ {"compact", SP_CSS_DISPLAY_COMPACT},
+ {"marker", SP_CSS_DISPLAY_MARKER},
+ {"table", SP_CSS_DISPLAY_TABLE},
+ {"inline-table", SP_CSS_DISPLAY_INLINE_TABLE},
+ {"table-row-group", SP_CSS_DISPLAY_TABLE_ROW_GROUP},
+ {"table-header-group", SP_CSS_DISPLAY_TABLE_HEADER_GROUP},
+ {"table-footer-group", SP_CSS_DISPLAY_TABLE_FOOTER_GROUP},
+ {"table-row", SP_CSS_DISPLAY_TABLE_ROW},
+ {"table-column-group", SP_CSS_DISPLAY_TABLE_COLUMN_GROUP},
+ {"table-column", SP_CSS_DISPLAY_TABLE_COLUMN},
+ {"table-cell", SP_CSS_DISPLAY_TABLE_CELL},
+ {"table-caption", SP_CSS_DISPLAY_TABLE_CAPTION},
+ {NULL, -1}
+};
+
+static SPStyleEnum const enum_shape_rendering[] = {
+ {"auto", SP_CSS_SHAPE_RENDERING_AUTO},
+ {"optimizeSpeed", SP_CSS_SHAPE_RENDERING_OPTIMIZESPEED},
+ {"crispEdges", SP_CSS_SHAPE_RENDERING_CRISPEDGES},
+ {"geometricPrecision", SP_CSS_SHAPE_RENDERING_GEOMETRICPRECISION},
+ {NULL, -1}
+};
+
+static SPStyleEnum const enum_color_rendering[] = {
+ {"auto", SP_CSS_COLOR_RENDERING_AUTO},
+ {"optimizeSpeed", SP_CSS_COLOR_RENDERING_OPTIMIZESPEED},
+ {"optimizeQuality", SP_CSS_COLOR_RENDERING_OPTIMIZEQUALITY},
+ {NULL, -1}
+};
+
+static SPStyleEnum const enum_image_rendering[] = {
+ {"auto", SP_CSS_IMAGE_RENDERING_AUTO},
+ {"optimizeSpeed", SP_CSS_IMAGE_RENDERING_OPTIMIZESPEED},
+ {"optimizeQuality", SP_CSS_IMAGE_RENDERING_OPTIMIZEQUALITY},
+ {"-inkscape-crisp-edges", SP_CSS_IMAGE_RENDERING_CRISPEDGES},
+ {"-inkscape-pixelated", SP_CSS_IMAGE_RENDERING_PIXELATED},
+ {NULL, -1}
+};
+
+static SPStyleEnum const enum_text_rendering[] = {
+ {"auto", SP_CSS_TEXT_RENDERING_AUTO},
+ {"optimizeSpeed", SP_CSS_TEXT_RENDERING_OPTIMIZESPEED},
+ {"optimizeLegibility", SP_CSS_TEXT_RENDERING_OPTIMIZELEGIBILITY},
+ {"geometricPrecision", SP_CSS_TEXT_RENDERING_GEOMETRICPRECISION},
+ {NULL, -1}
+};
+
+static SPStyleEnum const enum_enable_background[] = {
+ {"accumulate", SP_CSS_BACKGROUND_ACCUMULATE},
+ {"new", SP_CSS_BACKGROUND_NEW},
+ {NULL, -1}
+};
+
+static SPStyleEnum const enum_clip_rule[] = {
+ {"nonzero", SP_WIND_RULE_NONZERO},
+ {"evenodd", SP_WIND_RULE_EVENODD},
+ {NULL, -1}
+};
+
+static SPStyleEnum const enum_color_interpolation[] = {
+ {"auto", SP_CSS_COLOR_INTERPOLATION_AUTO},
+ {"sRGB", SP_CSS_COLOR_INTERPOLATION_SRGB},
+ {"linearRGB", SP_CSS_COLOR_INTERPOLATION_LINEARRGB},
+ {NULL, -1}
+};
+
+
#endif // SEEN_SP_STYLE_ENUMS_H
diff --git a/src/style-internal.cpp b/src/style-internal.cpp
new file mode 100644
index 000000000..df08d0adf
--- /dev/null
+++ b/src/style-internal.cpp
@@ -0,0 +1,2543 @@
+/**
+ * @file
+ * SVG stylesheets implementation - Classes used by SPStyle class.
+ */
+
+/* Authors:
+ * C++ conversion:
+ * Tavmjong Bah <tavmjong@free.fr>
+ * Legacy C implementation:
+ * Lauris Kaplinski <lauris@kaplinski.com>
+ * Peter Moulder <pmoulder@mail.csse.monash.edu.au>
+ * bulia byak <buliabyak@users.sf.net>
+ * Abhishek Sharma
+ * Kris De Gussem <Kris.DeGussem@gmail.com>
+ *
+ * Copyright (C) 2001-2002 Lauris Kaplinski
+ * Copyright (C) 2001 Ximian, Inc.
+ * Copyright (C) 2005 Monash University
+ * Copyright (C) 2012 Kris De Gussem
+ * Copyright (C) 2014 Tavmjong Bah
+ *
+ * Released under GNU GPL, read the file 'COPYING' for more information
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include "style-internal.h"
+#include "style-enums.h"
+#include "style.h"
+
+#include "svg/svg.h"
+#include "svg/svg-color.h"
+#include "svg/svg-icc-color.h"
+
+#include "streq.h"
+#include "strneq.h"
+
+#include "extract-uri.h"
+#include "preferences.h"
+#include "svg/css-ostringstream.h"
+#include "util/units.h"
+
+#include <sigc++/functors/ptr_fun.h>
+#include <sigc++/adaptors/bind.h>
+
+// TODO REMOVE OR MAKE MEMBER FUNCTIONS
+void sp_style_fill_paint_server_ref_changed( SPObject *old_ref, SPObject *ref, SPStyle *style);
+void sp_style_stroke_paint_server_ref_changed(SPObject *old_ref, SPObject *ref, SPStyle *style);
+void sp_style_filter_ref_changed( SPObject *old_ref, SPObject *ref, SPStyle *style);
+void sp_style_set_ipaint_to_uri(SPStyle *style, SPIPaint *paint, const Inkscape::URI *uri, SPDocument *document);
+void sp_style_set_ipaint_to_uri_string (SPStyle *style, SPIPaint *paint, const gchar *uri);
+
+using Inkscape::CSSOStringStream;
+
+// SPIBase --------------------------------------------------------------
+
+
+// SPIFloat -------------------------------------------------------------
+
+void
+SPIFloat::read( gchar const *str ) {
+
+ if( !str ) return;
+
+ if ( !strcmp(str, "inherit") ) {
+ set = TRUE;
+ inherit = TRUE;
+ } else {
+ gfloat value_tmp;
+ if (sp_svg_number_read_f(str, &value_tmp)) {
+ set = TRUE;
+ inherit = FALSE;
+ value = value_tmp;
+ }
+ }
+}
+
+const Glib::ustring
+SPIFloat::write( guint const flags, SPIBase const *const base) const {
+
+ SPIFloat const *const my_base = dynamic_cast<const SPIFloat*>(base);
+ if ( (flags & SP_STYLE_FLAG_ALWAYS) ||
+ ((flags & SP_STYLE_FLAG_IFSET) && this->set) ||
+ ((flags & SP_STYLE_FLAG_IFDIFF) && this->set
+ && (!my_base->set || this != my_base )))
+ {
+ if (this->inherit) {
+ return (name + ":inherit;");
+ } else {
+ Inkscape::CSSOStringStream os;
+ os << name << ":" << this->value << ";";
+ return os.str();
+ }
+ }
+ return Glib::ustring("");
+}
+
+void
+SPIFloat::cascade( const SPIBase* const parent ) {
+ if( const SPIFloat* p = dynamic_cast<const SPIFloat*>(parent) ) {
+ if( (inherits && !set) || inherit ) value = p->value;
+ } else {
+ std::cerr << "SPIFloat::cascade(): Incorrect parent type" << std::endl;
+ }
+}
+
+void
+SPIFloat::merge( const SPIBase* const parent ) {
+ if( const SPIFloat* p = dynamic_cast<const SPIFloat*>(parent) ) {
+ if( inherits ) {
+ if( (!set || inherit) && p->set && !(p->inherit) ) {
+ set = p->set;
+ inherit = p->inherit;
+ value = p->value;
+ }
+ }
+ } else {
+ std::cerr << "SPIFloat::merge(): Incorrect parent type" << std::endl;
+ }
+}
+
+bool
+SPIFloat::operator==(const SPIBase& rhs) {
+ if( const SPIFloat* r = dynamic_cast<const SPIFloat*>(&rhs) ) {
+ return (value == r->value && SPIBase::operator==(rhs));
+ } else {
+ return false;
+ }
+}
+
+
+
+// SPIScale24 -----------------------------------------------------------
+
+void
+SPIScale24::read( gchar const *str ) {
+
+ if( !str ) return;
+
+ if ( !strcmp(str, "inherit") ) {
+ set = TRUE;
+ inherit = TRUE;
+ } else {
+ gfloat value_in;
+ if (sp_svg_number_read_f(str, &value_in)) {
+ set = TRUE;
+ inherit = FALSE;
+ value_in = CLAMP(value_in, 0.0, 1.0);
+ value = SP_SCALE24_FROM_FLOAT( value_in );
+ }
+ }
+}
+
+const Glib::ustring
+SPIScale24::write( guint const flags, SPIBase const *const base) const {
+
+ SPIScale24 const *const my_base = dynamic_cast<const SPIScale24*>(base);
+ if ( (flags & SP_STYLE_FLAG_ALWAYS) ||
+ ((flags & SP_STYLE_FLAG_IFSET) && this->set) ||
+ ((flags & SP_STYLE_FLAG_IFDIFF) && this->set
+ && (!my_base->set || this != my_base )))
+ {
+ if (this->inherit) {
+ return (name + ":inherit;");
+ } else {
+ Inkscape::CSSOStringStream os;
+ os << name << ":" << SP_SCALE24_TO_FLOAT(this->value) << ";";
+ return os.str();
+ }
+ }
+ return Glib::ustring("");
+}
+
+void
+SPIScale24::cascade( const SPIBase* const parent ) {
+ if( const SPIScale24* p = dynamic_cast<const SPIScale24*>(parent) ) {
+ if( (inherits && !set) || inherit ) value = p->value;
+ } else {
+ std::cerr << "SPIScale24::cascade(): Incorrect parent type" << std::endl;
+ }
+}
+
+void
+SPIScale24::merge( const SPIBase* const parent ) {
+ if( const SPIScale24* p = dynamic_cast<const SPIScale24*>(parent) ) {
+ if( inherits ) {
+ if( (!set || inherit) && p->set && !(p->inherit) ) {
+ set = p->set;
+ inherit = p->inherit;
+ value = p->value;
+ }
+ } else {
+ // Needed only for 'opacity' which does not inherit. See comment at bottom of file.
+ if( name.compare( "opacity" ) != 0 )
+ std::cerr << "SPIScale24::merge: unhandled property: " << name << std::endl;
+ if( !set || (!inherit && value == SP_SCALE24_MAX) ) {
+ value = p->value;
+ } else {
+ if( inherit ) value = p->value; // Insures child is up-to-date
+ value = SP_SCALE24_MUL( value, p->value );
+ inherit = (inherit && p->inherit && (p->value == 0 || p->value == SP_SCALE24_MAX) );
+ set = (inherit || value < SP_SCALE24_MAX);
+ }
+ }
+ } else {
+ std::cerr << "SPIScale24::merge(): Incorrect parent type" << std::endl;
+ }
+}
+
+bool
+SPIScale24::operator==(const SPIBase& rhs) {
+ if( const SPIScale24* r = dynamic_cast<const SPIScale24*>(&rhs) ) {
+ return (value == r->value && SPIBase::operator==(rhs));
+ } else {
+ return false;
+ }
+}
+
+
+
+// SPILength ------------------------------------------------------------
+
+void
+SPILength::read( gchar const *str ) {
+
+ if( !str ) return;
+
+ if (!strcmp(str, "inherit")) {
+ set = TRUE;
+ inherit = TRUE;
+ unit = SP_CSS_UNIT_NONE;
+ value = computed = 0.0;
+ } else {
+ gdouble value_tmp;
+ gchar *e;
+ /** \todo fixme: Move this to standard place (Lauris) */
+ value_tmp = g_ascii_strtod(str, &e);
+ if ( !IS_FINITE(value_tmp) ) { // fix for bug lp:935157
+ return;
+ }
+ if ((gchar const *) e != str) {
+
+ value = value_tmp;
+ if (!*e) {
+ /* Userspace */
+ unit = SP_CSS_UNIT_NONE;
+ computed = value;
+ } else if (!strcmp(e, "px")) {
+ /* Userspace */
+ unit = SP_CSS_UNIT_PX;
+ computed = value;
+ } else if (!strcmp(e, "pt")) {
+ /* Userspace / DEVICESCALE */
+ unit = SP_CSS_UNIT_PT;
+ computed = Inkscape::Util::Quantity::convert(value, "pt", "px");
+ } else if (!strcmp(e, "pc")) {
+ unit = SP_CSS_UNIT_PC;
+ computed = Inkscape::Util::Quantity::convert(value, "pc", "px");
+ } else if (!strcmp(e, "mm")) {
+ unit = SP_CSS_UNIT_MM;
+ computed = Inkscape::Util::Quantity::convert(value, "mm", "px");
+ } else if (!strcmp(e, "cm")) {
+ unit = SP_CSS_UNIT_CM;
+ computed = Inkscape::Util::Quantity::convert(value, "cm", "px");
+ } else if (!strcmp(e, "in")) {
+ unit = SP_CSS_UNIT_IN;
+ computed = Inkscape::Util::Quantity::convert(value, "in", "px");
+ } else if (!strcmp(e, "em")) {
+ /* EM square */
+ unit = SP_CSS_UNIT_EM;
+ if( style && &style->font_size ) {
+ computed = value * style->font_size.computed;
+ } else {
+ computed = value * style->font_size.font_size_default;
+ }
+ } else if (!strcmp(e, "ex")) {
+ /* ex square */
+ unit = SP_CSS_UNIT_EX;
+ if( style && &style->font_size ) {
+ computed = value * style->font_size.computed * 0.5; // FIXME
+ } else {
+ computed = value * style->font_size.font_size_default * 0.5;
+ }
+ } else if (!strcmp(e, "%")) {
+ /* Percentage */
+ unit = SP_CSS_UNIT_PERCENT;
+ value = value * 0.01;
+ } else {
+ /* Invalid */
+ return;
+ }
+ set = TRUE;
+ inherit = FALSE;
+ }
+ }
+}
+
+const Glib::ustring
+SPILength::write( guint const flags, SPIBase const *const base) const {
+
+ SPILength const *const my_base = dynamic_cast<const SPILength*>(base);
+ if ( (flags & SP_STYLE_FLAG_ALWAYS) ||
+ ((flags & SP_STYLE_FLAG_IFSET) && this->set) ||
+ ((flags & SP_STYLE_FLAG_IFDIFF) && this->set
+ && (!my_base->set || this != my_base )))
+ {
+ if (this->inherit) {
+ return (name + ":inherit;");
+ } else {
+ Inkscape::CSSOStringStream os;
+ switch (this->unit) {
+ case SP_CSS_UNIT_NONE:
+ os << name << ":" << this->computed << ";";
+ break;
+ case SP_CSS_UNIT_PX:
+ os << name << ":" << this->computed << "px;";
+ break;
+ case SP_CSS_UNIT_PT:
+ os << name << ":" << Inkscape::Util::Quantity::convert(this->computed, "px", "pt") << "pt;";
+ break;
+ case SP_CSS_UNIT_PC:
+ os << name << ":" << Inkscape::Util::Quantity::convert(this->computed, "px", "pc") << "pc;";
+ break;
+ case SP_CSS_UNIT_MM:
+ os << name << ":" << Inkscape::Util::Quantity::convert(this->computed, "px", "mm") << "mm;";
+ break;
+ case SP_CSS_UNIT_CM:
+ os << name << ":" << Inkscape::Util::Quantity::convert(this->computed, "px", "cm") << "cm;";
+ break;
+ case SP_CSS_UNIT_IN:
+ os << name << ":" << Inkscape::Util::Quantity::convert(this->computed, "px", "in") << "in;";
+ break;
+ case SP_CSS_UNIT_EM:
+ os << name << ":" << this->value << "em;";
+ break;
+ case SP_CSS_UNIT_EX:
+ os << name << ":" << this->value << "ex;";
+ break;
+ case SP_CSS_UNIT_PERCENT:
+ os << name << ":" << (this->value * 100.0) << "%;";
+ break;
+ default:
+ /* Invalid */
+ break;
+ }
+ return os.str();
+ }
+ }
+ return Glib::ustring("");
+}
+
+void
+SPILength::cascade( const SPIBase* const parent ) {
+ if( const SPILength* p = dynamic_cast<const SPILength*>(parent) ) {
+ if( (inherits && !set) || inherit ) {
+ value = p->value;
+ computed = p->computed;
+ } else {
+ // Recalculate based on new font-size, font-family inherited from parent
+ double const em = style->font_size.computed;
+ if (unit == SP_CSS_UNIT_EM) {
+ computed = value * em;
+ } else if (unit == SP_CSS_UNIT_EX) {
+ // FIXME: Get x height from libnrtype or pango.
+ computed = value * em * 0.5;
+ }
+ }
+ } else {
+ std::cerr << "SPILength::cascade(): Incorrect parent type" << std::endl;
+ }
+}
+
+void
+SPILength::merge( const SPIBase* const parent ) {
+ if( const SPILength* p = dynamic_cast<const SPILength*>(parent) ) {
+ if( inherits ) {
+ if( (!set || inherit) && p->set && !(p->inherit) ) {
+ set = p->set;
+ inherit = p->inherit;
+ unit = p->unit;
+ value = p->value;
+ computed = p->computed;
+
+ // Fix up so values are correct
+ switch (p->unit) {
+ case SP_CSS_UNIT_EM:
+ case SP_CSS_UNIT_EX:
+ g_assert( &style->font_size != NULL && &p->style->font_size != NULL );
+ value *= p->style->font_size.computed / style->font_size.computed;
+ /** \todo
+ * FIXME: Have separate ex ratio parameter.
+ * Get x height from libnrtype or pango.
+ */
+ if (!IS_FINITE(value)) {
+ value = computed;
+ unit = SP_CSS_UNIT_NONE;
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+ }
+ } else {
+ std::cerr << "SPIFloat::merge(): Incorrect parent type" << std::endl;
+ }
+}
+
+bool
+SPILength::operator==(const SPIBase& rhs) {
+ if( const SPILength* r = dynamic_cast<const SPILength*>(&rhs) ) {
+
+ if( unit != r->unit ) return false;
+
+ // If length depends on external parameter, lengths cannot be equal.
+ if (unit == SP_CSS_UNIT_EM) return false;
+ if (unit == SP_CSS_UNIT_EX) return false;
+ if (unit == SP_CSS_UNIT_PERCENT) return false;
+ if (r->unit == SP_CSS_UNIT_EM) return false;
+ if (r->unit == SP_CSS_UNIT_EX) return false;
+ if (r->unit == SP_CSS_UNIT_PERCENT) return false;
+
+ return (computed == r->computed );
+ } else {
+ return false;
+ }
+}
+
+
+
+// SPILengthOrNormal ----------------------------------------------------
+
+void
+SPILengthOrNormal::read( gchar const *str ) {
+
+ if( !str ) return;
+
+ if ( !strcmp(str, "normal") ) {
+ set = TRUE;
+ inherit = FALSE;
+ unit = SP_CSS_UNIT_NONE;
+ value = computed = 0.0;
+ normal = TRUE;
+ } else {
+ SPILength::read( str );
+ normal = false;
+ }
+};
+
+const Glib::ustring
+SPILengthOrNormal::write( guint const flags, SPIBase const *const base) const {
+
+ SPILength const *const my_base = dynamic_cast<const SPILength*>(base);
+ if ( (flags & SP_STYLE_FLAG_ALWAYS) ||
+ ((flags & SP_STYLE_FLAG_IFSET) && this->set) ||
+ ((flags & SP_STYLE_FLAG_IFDIFF) && this->set
+ && (!my_base->set || this != my_base )))
+ {
+ if (this->normal) {
+ return (name + ":normal;");
+ } else {
+ return SPILength::write(flags, base);
+ }
+ }
+ return Glib::ustring("");
+}
+
+void
+SPILengthOrNormal::merge( const SPIBase* const parent ) {
+ if( const SPILengthOrNormal* p = dynamic_cast<const SPILengthOrNormal*>(parent) ) {
+ if( inherits ) {
+ if( (!set || inherit) && p->set && !(p->inherit) ) {
+ normal = p->normal;
+ SPILength::merge( parent );
+ }
+ }
+ }
+}
+
+bool
+SPILengthOrNormal::operator==(const SPIBase& rhs) {
+ if( const SPILengthOrNormal* r = dynamic_cast<const SPILengthOrNormal*>(&rhs) ) {
+ if( normal && r->normal ) { return true; }
+ if( normal != r->normal ) { return false; }
+ return SPILength::operator==(rhs);
+ } else {
+ return false;
+ }
+}
+
+
+
+// SPIEnum --------------------------------------------------------------
+
+void
+SPIEnum::read( gchar const *str ) {
+
+ if( !str ) return;
+
+ if( !strcmp(str, "inherit") ) {
+ set = TRUE;
+ inherit = TRUE;
+ } else {
+ for (unsigned i = 0; enums[i].key; i++) {
+ if (!strcmp(str, enums[i].key)) {
+ set = TRUE;
+ inherit = FALSE;
+ value = enums[i].value;
+ /* Save copying for values not needing it */
+ computed = value;
+ break;
+ }
+ }
+ // The following is defined in CSS 2.1
+ if( name.compare("font-weight" ) == 0 ) {
+ if( value == SP_CSS_FONT_WEIGHT_NORMAL ) {
+ computed = SP_CSS_FONT_WEIGHT_400;
+ } else if (value == SP_CSS_FONT_WEIGHT_BOLD ) {
+ computed = SP_CSS_FONT_WEIGHT_700;
+ }
+ }
+ }
+}
+
+const Glib::ustring
+SPIEnum::write( guint const flags, SPIBase const *const base) const {
+
+ SPIEnum const *const my_base = dynamic_cast<const SPIEnum*>(base);
+ if ( (flags & SP_STYLE_FLAG_ALWAYS) ||
+ ((flags & SP_STYLE_FLAG_IFSET) && this->set) ||
+ ((flags & SP_STYLE_FLAG_IFDIFF) && this->set
+ && (!my_base->set || this != my_base )))
+ {
+ if (this->inherit) {
+ return (name + ":inherit;");
+ }
+ for (unsigned i = 0; enums[i].key; ++i) {
+ if (enums[i].value == static_cast< gint > (this->value) ) {
+ return (name + ":" + enums[i].key + ";");
+ }
+ }
+ }
+ return Glib::ustring("");
+}
+
+void
+SPIEnum::cascade( const SPIBase* const parent ) {
+ if( const SPIEnum* p = dynamic_cast<const SPIEnum*>(parent) ) {
+ if( inherits && (!set || inherit) ) {
+ computed = p->computed;
+ } else {
+ if( name.compare("font-stretch" ) == 0 ) {
+ unsigned const parent_val = p->computed;
+ if( value == SP_CSS_FONT_STRETCH_NARROWER ) {
+ computed = (parent_val == SP_CSS_FONT_STRETCH_ULTRA_CONDENSED ?
+ parent_val : parent_val - 1);
+ } else if (value == SP_CSS_FONT_STRETCH_WIDER ) {
+ computed = (parent_val == SP_CSS_FONT_STRETCH_ULTRA_EXPANDED ?
+ parent_val : parent_val + 1);
+ }
+ }
+ // strictly, 'bolder' and 'lighter' should go to the next weight
+ // expressible in the current font family, but that's difficult to
+ // find out, so jumping by 3 seems an appropriate approximation
+ if( name.compare("font-weight" ) == 0 ) {
+ unsigned const parent_val = p->computed;
+ if( value == SP_CSS_FONT_WEIGHT_LIGHTER ) {
+ computed = (parent_val <= SP_CSS_FONT_WEIGHT_100 + 3 ?
+ (unsigned)SP_CSS_FONT_WEIGHT_100 : parent_val - 3);
+ } else if (value == SP_CSS_FONT_WEIGHT_BOLDER ) {
+ computed = (parent_val >= SP_CSS_FONT_WEIGHT_900 - 3 ?
+ (unsigned)SP_CSS_FONT_WEIGHT_900 : parent_val + 3);
+ }
+ }
+ }
+ } else {
+ std::cerr << "SPIEnum::cascade(): Incorrect parent type" << std::endl;
+ }
+}
+
+// FIXME Handle font_stretch and font_weight (relative values) New derived class?
+void
+SPIEnum::merge( const SPIBase* const parent ) {
+ if( const SPIEnum* p = dynamic_cast<const SPIEnum*>(parent) ) {
+ if( inherits ) {
+ if( p->set && !p->inherit ) {
+ if( !set || inherit ) {
+ set = p->set;
+ inherit = p->inherit;
+ value = p->value;
+ computed = p->computed; // Different from value for font-weight and font-stretch
+ } else {
+ // The following is to special case 'font-stretch' and 'font-weight'
+ unsigned max_computed_val = 100;
+ unsigned smaller_val = 100;
+ if( name.compare("font-stretch" ) == 0 ) {
+ max_computed_val = SP_CSS_FONT_STRETCH_ULTRA_EXPANDED;
+ smaller_val = SP_CSS_FONT_STRETCH_NARROWER;
+ } else if( name.compare("font-weight" ) == 0 ) {
+ max_computed_val = SP_CSS_FONT_WEIGHT_900;
+ smaller_val = SP_CSS_FONT_WEIGHT_LIGHTER;
+ }
+ unsigned const min_computed_val = 0;
+ unsigned const larger_val = smaller_val + 1;
+ if( value < smaller_val ) {
+ // Child has absolute value, leave as is.
+ // Works for all enum properties
+ } else if( (value == smaller_val && p->value == larger_val ) ||
+ (value == larger_val && p->value == smaller_val) ) {
+ // Values cancel, unset
+ set = false;
+ } else if( value == p->value ) {
+ // Leave as is, what does applying "wider" twice do?
+ } else {
+ // Child is smaller or larger, adjust parent value accordingly
+ unsigned const parent_val = p->computed;
+ value = (value == smaller_val ?
+ ( parent_val == min_computed_val ? parent_val : parent_val - 1 ) :
+ ( parent_val == max_computed_val ? parent_val : parent_val + 1 ) );
+ g_assert(value <= max_computed_val);
+ inherit = false;
+ g_assert(set);
+ }
+ }
+ }
+ }
+ }
+}
+
+bool
+SPIEnum::operator==(const SPIBase& rhs) {
+ if( const SPIEnum* r = dynamic_cast<const SPIEnum*>(&rhs) ) {
+ return (computed == r->computed && SPIBase::operator==(rhs));
+ } else {
+ return false;
+ }
+}
+
+
+
+// SPIString ------------------------------------------------------------
+
+void
+SPIString::read( gchar const *str ) {
+
+ if( !str ) return;
+
+ g_free(value);
+
+ if (!strcmp(str, "inherit")) {
+ set = TRUE;
+ inherit = TRUE;
+ value = NULL;
+ } else {
+ set = TRUE;
+ inherit = FALSE;
+ value = g_strdup(str);
+ }
+}
+
+
+const Glib::ustring
+SPIString::write( guint const flags, SPIBase const *const base) const {
+
+ SPIString const *const my_base = dynamic_cast<const SPIString*>(base);
+ if ( (flags & SP_STYLE_FLAG_ALWAYS) ||
+ ((flags & SP_STYLE_FLAG_IFSET) && this->set) ||
+ ((flags & SP_STYLE_FLAG_IFDIFF) && this->set
+ && (!my_base->set || this != my_base )))
+ {
+ if (this->inherit) {
+ return (name + ":inherit;");
+ } 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) + ";");
+ } else {
+ return (name + ":" + this->value + ";");
+ }
+ }
+ }
+ }
+ return Glib::ustring("");
+}
+
+void
+SPIString::clear() {
+ SPIBase::clear();
+ g_free( value );
+ value = NULL;
+ if( value_default ) value = strdup( value_default );
+}
+
+void
+SPIString::cascade( const SPIBase* const parent ) {
+ if( const SPIString* p = dynamic_cast<const SPIString*>(parent) ) {
+ if( inherits && (!set || inherit) ) {
+ g_free(value);
+ value = g_strdup(p->value);
+ }
+ } else {
+ std::cerr << "SPIString::cascade(): Incorrect parent type" << std::endl;
+ }
+}
+
+void
+SPIString::merge( const SPIBase* const parent ) {
+ if( const SPIString* p = dynamic_cast<const SPIString*>(parent) ) {
+ if( inherits ) {
+ if( (!set || inherit) && p->set && !(p->inherit) ) {
+ set = p->set;
+ inherit = p->inherit;
+ g_free(value);
+ value = g_strdup(p->value);
+ }
+ }
+ }
+}
+
+bool
+SPIString::operator==(const SPIBase& rhs) {
+ if( const SPIString* r = dynamic_cast<const SPIString*>(&rhs) ) {
+ if( value == NULL && r->value == NULL ) return (SPIBase::operator==(rhs));
+ if( value == NULL || r->value == NULL ) return false;
+
+ return (strcmp(value, r->value) == 0 && SPIBase::operator==(rhs));
+ } else {
+ return false;
+ }
+}
+
+
+
+// SPIColor -------------------------------------------------------------
+
+// Used for 'color', 'text-decoration-color', 'flood-color', 'lighting-color', and 'stop-color'.
+// (The last three have yet to be implemented.)
+// CSS3: 'currentcolor' is allowed value and is equal to inherit for the 'color' property.
+// FIXME: We should preserve named colors, hsl colors, etc.
+void SPIColor::read( gchar const *str ) {
+
+ if( !str ) return;
+
+ set = false;
+ inherit = false;
+ currentcolor = false;
+ if ( !strcmp(str, "inherit") ) {
+ set = true;
+ inherit = true;
+ } else if ( !strcmp(str, "currentColor") ) {
+ set = true;
+ currentcolor = true;
+ if( name.compare( "color") == 0 ) {
+ inherit = true; // CSS3
+ } else {
+ value.color = style->color.value.color;
+ }
+ } else {
+ guint32 const rgb0 = sp_svg_read_color(str, 0xff);
+ if (rgb0 != 0xff) {
+ setColor(rgb0);
+ set = TRUE;
+ }
+ }
+}
+
+const Glib::ustring
+SPIColor::write( guint const flags, SPIBase const *const base) const {
+
+ SPIColor const *const my_base = dynamic_cast<const SPIColor*>(base);
+ if ( (flags & SP_STYLE_FLAG_ALWAYS) ||
+ ((flags & SP_STYLE_FLAG_IFSET) && this->set) ||
+ ((flags & SP_STYLE_FLAG_IFDIFF) && this->set
+ && (!my_base->set || this != my_base )))
+ {
+ CSSOStringStream css;
+
+ if (this->currentcolor) {
+ // currentcolor goes first to handle special case for 'color' property
+ css << "currentColor";
+ } else if (this->inherit) {
+ css << "inherit";
+ } else {
+ char color_buf[8];
+ sp_svg_write_color(color_buf, sizeof(color_buf), this->value.color.toRGBA32( 0 ));
+ css << color_buf;
+
+ if (this->value.color.icc) {
+ if ( !css.str().empty() ) {
+ css << " ";
+ }
+ css << "icc-color(" << this->value.color.icc->colorProfile;
+ for (std::vector<double>::const_iterator i(this->value.color.icc->colors.begin()),
+ iEnd(this->value.color.icc->colors.end());
+ i != iEnd; ++i) {
+ css << ", " << *i;
+ }
+ css << ')';
+ }
+ }
+
+ if ( !css.str().empty() ) {
+ return (name + ":" + css.str() + ";");
+ }
+ }
+
+ return Glib::ustring("");
+}
+
+void
+SPIColor::cascade( const SPIBase* const parent ) {
+ if( const SPIColor* p = dynamic_cast<const SPIColor*>(parent) ) {
+ if( (inherits && !set) || inherit) { // FIXME verify for 'color'
+ if( !(inherit && currentcolor) ) currentcolor = p->currentcolor;
+ value.color = p->value.color;
+ } else {
+ // Add CSS4 Color: Lighter, Darker
+ }
+ } else {
+ std::cerr << "SPIColor::cascade(): Incorrect parent type" << std::endl;
+ }
+
+}
+
+void
+SPIColor::merge( const SPIBase* const parent ) {
+ if( const SPIColor* p = dynamic_cast<const SPIColor*>(parent) ) {
+ if( inherits ) {
+ if( (!set || inherit) && p->set && !(p->inherit) ) {
+ set = p->set;
+ inherit = p->inherit;
+ currentcolor = p->currentcolor;
+ value.color = p->value.color;
+ }
+ }
+ }
+}
+
+bool
+SPIColor::operator==(const SPIBase& rhs) {
+ if( const SPIColor* r = dynamic_cast<const SPIColor*>(&rhs) ) {
+
+ if ( (this->currentcolor != r->currentcolor ) ||
+ (this->value.color != r->value.color ) ||
+ (this->value.color.icc != r->value.color.icc ) ||
+ (this->value.color.icc && r->value.color.icc &&
+ this->value.color.icc->colorProfile != r->value.color.icc->colorProfile &&
+ this->value.color.icc->colors != r->value.color.icc->colors ) ) {
+ return false;
+ }
+
+ return SPIBase::operator==(rhs);
+
+ } else {
+ return false;
+ }
+}
+
+
+
+// SPIPaint -------------------------------------------------------------
+
+// Paint is used for 'fill' and 'stroke'. SPIPaint perhaps should be derived from SPIColor.
+// 'style' is set in SPStyle::SPStyle or in the legacy SPIPaint::read( gchar, style, document )
+// It is needed for computed value when value is 'currentColor'. It is also needed to
+// find the object for creating an href (this is done through document but should be done
+// directly so document not needed.. FIXME).
+
+SPIPaint::~SPIPaint() {
+ if( value.href ) {
+ clear();
+ delete value.href;
+ value.href = NULL;
+ }
+}
+
+/**
+ * Set SPIPaint object from string.
+ *
+ * \pre paint == \&style.fill || paint == \&style.stroke.
+ */
+void
+SPIPaint::read( gchar const *str ) {
+
+ // std::cout << "SPIPaint::read: Entrance: " << " |" << (str?str:"null") << "|" << std::endl;
+ // if( style ) {
+ // std::cout << " document: " << (void*)style->document << std::endl;
+ // std::cout << " object: " << (style->object?"present":"null") << std::endl;
+ // if( style->object )
+ // std::cout << " : " << (style->object->getId()?style->object->getId():"no ID")
+ // << " document: " << (style->object->document?"yes":"no") << std::endl;
+ // }
+
+ if(!str ) return;
+
+ reset( false ); // Do not init
+
+ // Is this necessary?
+ while (g_ascii_isspace(*str)) {
+ ++str;
+ }
+
+ if (streq(str, "inherit")) {
+ set = TRUE;
+ inherit = TRUE;
+ } else {
+ // Read any URL first. The other values can be stand-alone or backup to the URL.
+
+ if ( strneq(str, "url", 3) ) {
+
+ // FIXME: THE FOLLOWING CODE SHOULD BE PUT IN A PRIVATE FUNCTION FOR REUSE
+ gchar *uri = extract_uri( str, &str );
+ if(uri == NULL || uri[0] == '\0') {
+ std::cerr << "SPIPaint::read: url is empty or invalid" << std::endl;
+ } else if (!style ) {
+ std::cerr << "SPIPaint::read: url with empty SPStyle pointer" << std::endl;
+ } else {
+ set = TRUE;
+ SPDocument *document = (style->object) ? style->object->document : NULL;
+
+ // Create href if not done already
+ if (!value.href && document) {
+ // std::cout << " Creating value.href" << std::endl;
+ value.href = new SPPaintServerReference(document);
+ value.href->changedSignal().connect(sigc::bind(sigc::ptr_fun((this == &style->fill)? sp_style_fill_paint_server_ref_changed : sp_style_stroke_paint_server_ref_changed), style));
+ }
+
+ // std::cout << "uri: " << (uri?uri:"null") << std::endl;
+ // TODO check what this does in light of move away from union
+ sp_style_set_ipaint_to_uri_string ( style, this, uri);
+ }
+ g_free( uri );
+ }
+
+ while ( g_ascii_isspace(*str) ) {
+ ++str;
+ }
+
+ if (streq(str, "currentColor")) {
+ set = TRUE;
+ currentcolor = TRUE;
+ value.color = style->color.value.color;
+ } else if (streq(str, "none")) {
+ set = TRUE;
+ noneSet = TRUE;
+ } else {
+ guint32 const rgb0 = sp_svg_read_color(str, &str, 0xff);
+ if (rgb0 != 0xff) {
+ setColor( rgb0 );
+ set = TRUE;
+
+ while (g_ascii_isspace(*str)) {
+ ++str;
+ }
+ if (strneq(str, "icc-color(", 10)) {
+ SVGICCColor* tmp = new SVGICCColor();
+ if ( ! sp_svg_read_icc_color( str, &str, tmp ) ) {
+ delete tmp;
+ tmp = 0;
+ }
+ value.color.icc = tmp;
+ }
+ }
+ }
+ }
+}
+
+// Stand-alone read (Legacy read()), used multiple places, e.g. sp-stop.cpp
+// This function should not be necessary. FIXME
+void
+SPIPaint::read( gchar const *str, SPStyle &style_in, SPDocument *document_in ) {
+ style = &style_in;
+ style->document = document_in;
+ read( str );
+}
+
+const Glib::ustring
+SPIPaint::write( guint const flags, SPIBase const *const base) const {
+
+ SPIPaint const *const my_base = dynamic_cast<const SPIPaint*>(base);
+ if ( (flags & SP_STYLE_FLAG_ALWAYS) ||
+ ((flags & SP_STYLE_FLAG_IFSET) && this->set) ||
+ ((flags & SP_STYLE_FLAG_IFDIFF) && this->set
+ && (!my_base->set || this != my_base )))
+ {
+ CSSOStringStream css;
+
+ if (this->inherit) {
+ css << "inherit";
+ } else {
+
+ // url must go first as other values can serve as fallbacks
+ if ( this->value.href && this->value.href->getURI() ) {
+ const gchar* uri = this->value.href->getURI()->toString();
+ css << "url(" << uri << ")";
+ g_free((void *)uri);
+ }
+
+ if ( this->noneSet ) {
+ if ( !css.str().empty() ) {
+ css << " ";
+ }
+ css << "none";
+ }
+
+ if ( this->currentcolor ) {
+ if ( !css.str().empty() ) {
+ css << " ";
+ }
+ css << "currentColor";
+ }
+
+ if ( this->colorSet && !this->currentcolor ) {
+ if ( !css.str().empty() ) {
+ css << " ";
+ }
+ char color_buf[8];
+ sp_svg_write_color(color_buf, sizeof(color_buf), this->value.color.toRGBA32( 0 ));
+ css << color_buf;
+ }
+
+ if (this->value.color.icc && !this->currentcolor) {
+ if ( !css.str().empty() ) {
+ css << " ";
+ }
+ css << "icc-color(" << this->value.color.icc->colorProfile;
+ for (std::vector<double>::const_iterator i(this->value.color.icc->colors.begin()),
+ iEnd(this->value.color.icc->colors.end());
+ i != iEnd; ++i) {
+ css << ", " << *i;
+ }
+ css << ')';
+ }
+ }
+
+ if ( !css.str().empty() ) {
+ return (name + ":" + css.str() + ";");
+ }
+ }
+
+ return Glib::ustring("");
+}
+
+void
+SPIPaint::clear() {
+ // std::cout << "SPIPaint::clear(): " << name << std::endl;
+ reset( true ); // Reset and Init
+}
+
+void
+SPIPaint::reset( bool init ) {
+
+ // std::cout << "SPIPaint::reset(): " << name << " " << init << std::endl;
+ SPIBase::clear();
+ currentcolor = false;
+ colorSet = false;
+ noneSet = false;
+ value.color.set( false );
+ if (value.href){
+ if (value.href->getObject()) {
+ value.href->detach();
+ }
+ }
+ if( init ) {
+ if( name.compare( "fill" ) == 0 ) {
+ // 'black' is default for 'fill'
+ setColor(0.0, 0.0, 0.0);
+ }
+ if( name.compare( "text-decoration-color" ) == 0 ) {
+ currentcolor = true;
+ }
+ }
+}
+
+void
+SPIPaint::cascade( const SPIBase* const parent ) {
+
+ // std::cout << "SPIPaint::cascade" << std::endl;
+ if( const SPIPaint* p = dynamic_cast<const SPIPaint*>(parent) ) {
+ if(!set || inherit) { // Always inherits
+
+ reset( false ); // Do not init
+
+ if( p->isPaintserver() ) {
+ if( p->value.href) {
+ // Why can we use p->document ?
+ sp_style_set_ipaint_to_uri( style, this, p->value.href->getURI(), p->value.href->getOwnerDocument());
+ } else {
+ std::cerr << "SPIPaint::cascade: Expected paint server not found." << std::endl;
+ }
+ } else if( p->isColor() ) {
+ setColor( p->value.color );
+ } else if( p->isNoneSet() ) {
+ noneSet = TRUE;
+ } else if( p->currentcolor ) {
+ currentcolor = TRUE;
+ value.color = style->color.value.color;
+ } else if( isNone() ) {
+ //
+ } else {
+ g_assert_not_reached();
+ }
+ } else {
+ if( currentcolor ) {
+ // Update in case color value changed.
+ value.color = style->color.value.color;
+ }
+ }
+
+ } else {
+ std::cerr << "SPIPaint::cascade(): Incorrect parent type" << std::endl;
+ }
+
+}
+
+void
+SPIPaint::merge( const SPIBase* const parent ) {
+ if( const SPIPaint* p = dynamic_cast<const SPIPaint*>(parent) ) {
+ // if( inherits ) { Paint always inherits
+ if( (!set || inherit) && p->set && !(p->inherit) ) {
+ this->cascade( parent ); // Must call before setting 'set'
+ set = p->set;
+ inherit = p->inherit;
+ }
+ }
+}
+
+bool
+SPIPaint::operator==(const SPIBase& rhs) {
+
+ if( const SPIPaint* r = dynamic_cast<const SPIPaint*>(&rhs) ) {
+
+ if ( (this->isColor() != r->isColor() ) ||
+ (this->isPaintserver() != r->isPaintserver() ) ||
+ (this->currentcolor != r->currentcolor ) ) {
+ return false;
+ }
+
+ if ( this->isPaintserver() ) {
+ if( this->value.href == NULL || r->value.href == NULL ||
+ this->value.href->getObject() != r->value.href->getObject() ) {
+ return false;
+ }
+ }
+
+ if ( this->isColor() ) {
+ if ( (this->value.color != r->value.color ) ||
+ (this->value.color.icc != r->value.color.icc ) ||
+ (this->value.color.icc && r->value.color.icc &&
+ this->value.color.icc->colorProfile != r->value.color.icc->colorProfile &&
+ this->value.color.icc->colors != r->value.color.icc->colors ) ) {
+ return false;
+ }
+ }
+
+ return SPIBase::operator==(rhs);
+
+ } else {
+ return false;
+ }
+}
+
+
+
+// SPIPaintOrder --------------------------------------------------------
+
+void
+SPIPaintOrder::read( gchar const *str ) {
+
+ if( !str ) return;
+
+ g_free(value);
+ set = FALSE;
+ inherit = FALSE;
+
+ if (!strcmp(str, "inherit")) {
+ set = TRUE;
+ inherit = TRUE;
+ } else {
+ set = TRUE;
+ value = g_strdup(str);
+
+ if (!strcmp(value, "normal")) {
+ layer[0] = SP_CSS_PAINT_ORDER_NORMAL;
+ layer_set[0] = true;
+ } else {
+ // This certainly can be done more efficiently
+ gchar** c = g_strsplit(value, " ", PAINT_ORDER_LAYERS + 1);
+ bool used[3] = {false, false, false};
+ unsigned int i = 0;
+ for( ; i < PAINT_ORDER_LAYERS; ++i ) {
+ if( c[i] ) {
+ layer_set[i] = false;
+ if( !strcmp( c[i], "fill")) {
+ layer[i] = SP_CSS_PAINT_ORDER_FILL;
+ layer_set[i] = true;
+ used[0] = true;
+ } else if( !strcmp( c[i], "stroke")) {
+ layer[i] = SP_CSS_PAINT_ORDER_STROKE;
+ layer_set[i] = true;
+ used[1] = true;
+ } else if( !strcmp( c[i], "markers")) {
+ layer[i] = SP_CSS_PAINT_ORDER_MARKER;
+ layer_set[i] = true;
+ used[2] = true;
+ } else {
+ std::cerr << "sp_style_read_ipaintorder: illegal value: " << c[i] << std::endl;
+ break;
+ }
+ } else {
+ break;
+ }
+ }
+ g_strfreev(c);
+
+ // Fill out rest of the layers using the default order
+ if( !used[0] && i < PAINT_ORDER_LAYERS ) {
+ layer[i] = SP_CSS_PAINT_ORDER_FILL;
+ layer_set[i] = false;
+ ++i;
+ }
+ if( !used[1] && i < PAINT_ORDER_LAYERS ) {
+ layer[i] = SP_CSS_PAINT_ORDER_STROKE;
+ layer_set[i] = false;
+ ++i;
+ }
+ if( !used[2] && i < PAINT_ORDER_LAYERS ) {
+ layer[i] = SP_CSS_PAINT_ORDER_MARKER;
+ layer_set[i] = false;
+ }
+ }
+ }
+}
+
+const Glib::ustring
+SPIPaintOrder::write( guint const flags, SPIBase const *const base) const {
+
+ SPIPaintOrder const *const my_base = dynamic_cast<const SPIPaintOrder*>(base);
+ if ( (flags & SP_STYLE_FLAG_ALWAYS) ||
+ ((flags & SP_STYLE_FLAG_IFSET) && this->set) ||
+ ((flags & SP_STYLE_FLAG_IFDIFF) && this->set
+ && (!my_base->set || this != my_base )))
+ {
+ CSSOStringStream css;
+
+ if (this->inherit) {
+ css << "inherit";
+ } else {
+ for( unsigned i = 0; i < PAINT_ORDER_LAYERS; ++i ) {
+ if( this->layer_set[i] == true ) {
+ switch (this->layer[i]) {
+ case SP_CSS_PAINT_ORDER_NORMAL:
+ css << "normal";
+ assert( i == 0 );
+ break;
+ case SP_CSS_PAINT_ORDER_FILL:
+ if (i!=0) css << " ";
+ css << "fill";
+ break;
+ case SP_CSS_PAINT_ORDER_STROKE:
+ if (i!=0) css << " ";
+ css << "stroke";
+ break;
+ case SP_CSS_PAINT_ORDER_MARKER:
+ if (i!=0) css << " ";
+ css << "markers";
+ break;
+ }
+ } else {
+ break;
+ }
+ }
+ }
+ return (name + ":" + css.str() + ";");
+ }
+ return Glib::ustring("");
+}
+
+void
+SPIPaintOrder::cascade( const SPIBase* const parent ) {
+ if( const SPIPaintOrder* p = dynamic_cast<const SPIPaintOrder*>(parent) ) {
+ if(!set || inherit) { // Always inherits
+ for( unsigned i = 0; i < PAINT_ORDER_LAYERS; ++i ) {
+ layer[i] = p->layer[i];
+ layer_set[i] = p->layer_set[i];
+ }
+ g_free( value );
+ value = g_strdup(p->value);
+ }
+ } else {
+ std::cerr << "SPIPaintOrder::cascade(): Incorrect parent type" << std::endl;
+ }
+}
+
+void
+SPIPaintOrder::merge( const SPIBase* const parent ) {
+ if( const SPIPaintOrder* p = dynamic_cast<const SPIPaintOrder*>(parent) ) {
+ // if( inherits ) { PaintOrder always inherits
+ if( (!set || inherit) && p->set && !(p->inherit) ) {
+ this->cascade( parent ); // Must call be setting 'set'
+ set = p->set;
+ inherit = p->inherit;
+ }
+ }
+}
+
+bool
+SPIPaintOrder::operator==(const SPIBase& rhs) {
+ if( const SPIPaintOrder* r = dynamic_cast<const SPIPaintOrder*>(&rhs) ) {
+ if( layer[0] == SP_CSS_PAINT_ORDER_NORMAL &&
+ r->layer[0] == SP_CSS_PAINT_ORDER_NORMAL ) return SPIBase::operator==(rhs);
+ for (unsigned i = 0; i < PAINT_ORDER_LAYERS; ++i ) {
+ if( layer[i] != r->layer[i] ) return false;
+ }
+ return SPIBase::operator==(rhs);
+ } else {
+ return false;
+ }
+}
+
+
+
+// SPIFilter ------------------------------------------------------------
+
+SPIFilter::~SPIFilter() {
+ if( href ) {
+ clear();
+ delete href;
+ href = NULL;
+ }
+}
+
+void
+SPIFilter::read( gchar const *str ) {
+
+ if( !str ) return;
+
+ clear();
+
+ if ( streq(str, "inherit") ) {
+ set = TRUE;
+ inherit = TRUE;
+ } else if(streq(str, "none")) {
+ set = TRUE;
+ } else if (strneq(str, "url", 3)) {
+ gchar *uri = extract_uri(str);
+ if(uri == NULL || uri[0] == '\0') {
+ std::cerr << "SPIFilter::read: url is empty or invalid" << std::endl;
+ return;
+ } else if (!style) {
+ std::cerr << "SPIFilter::read: url with empty SPStyle pointer" << std::endl;
+ return;
+ }
+ set = TRUE;
+
+ // Create href if not already done.
+ if (!href && style->object) {
+ href = new SPFilterReference(style->object);
+ href->changedSignal().connect(sigc::bind(sigc::ptr_fun(sp_style_filter_ref_changed), style));
+ }
+
+ try {
+ href->attach(Inkscape::URI(uri));
+ } catch (Inkscape::BadURIException &e) {
+ std::cerr << "SPIFilter::read() " << e.what() << std::endl;
+ href->detach();
+ }
+ g_free (uri);
+
+ } else {
+ std::cerr << "SPIFilter::read(): malformed value: " << str << std::endl;
+ }
+}
+
+const Glib::ustring
+SPIFilter::write( guint const flags, SPIBase const *const base) const {
+
+ // TODO: fix base
+ //SPILength const *const my_base = dynamic_cast<const SPILength*>(base);
+ if ( (flags & SP_STYLE_FLAG_ALWAYS) ||
+ ((flags & SP_STYLE_FLAG_IFSET) && this->set))
+ {
+ if (this->inherit) {
+ return (name + ":inherit;");
+ } else if(this->href && this->href->getURI()) {
+ gchar *uri = this->href->getURI()->toString();
+ Glib::ustring retval = name + ":url(" + uri + ");";
+ g_free(uri);
+ return retval;
+ }
+ }
+ return Glib::ustring("");
+}
+
+
+void
+SPIFilter::clear() {
+
+ SPIBase::clear();
+ if( href ) {
+ if( href->getObject() ) {
+ href->detach();
+ }
+ }
+}
+
+void
+SPIFilter::cascade( const SPIBase* const parent ) {
+ if( const SPIFilter* p = dynamic_cast<const SPIFilter*>(parent) ) {
+ if( inherit ) { // Only inherits if 'inherit' true/
+ // This is rather unlikely so ignore for now. FIXME
+ (void)p;
+ std::cerr << "SPIFilter::cascade: value 'inherit' not supported." << std::endl;
+ } else {
+ // Do nothing
+ }
+ } else {
+ std::cerr << "SPIFilter::cascade(): Incorrect parent type" << std::endl;
+ }
+}
+
+void
+SPIFilter::merge( const SPIBase* const parent ) {
+ if( const SPIFilter* p = dynamic_cast<const SPIFilter*>(parent) ) {
+ // The "correct" thing to due is to combine the filter primitives.
+ // The next best thing is to keep any filter on this object. If there
+ // is no filter on this object, then use any filter on the parent.
+ if( (!set || inherit) && p->href && p->href->getObject() ) { // is the getObject() needed?
+ set = p->set;
+ inherit = p->inherit;
+ if( href ) {
+ // If we alread have an href, use it (unlikely but heck...)
+ if( href->getObject() ) {
+ href->detach();
+ }
+ } else {
+ // If we don't have an href, create it
+ if( &style->document ) { // FIXME
+ href = new SPFilterReference(style->document);
+ //href->changedSignal().connect(sigc::bind(sigc::ptr_fun(sp_style_filter_ref_changed), style));
+ }
+ }
+ if( href ) {
+ // If we now have an href, try to attach parent filter
+ try {
+ href->attach(*p->href->getURI());
+ } catch (Inkscape::BadURIException &e) {
+ std::cerr << "SPIFilter::merge: " << e.what() << std::endl;
+ href->detach();
+ }
+ }
+ }
+ }
+}
+
+// FIXME
+bool
+SPIFilter::operator==(const SPIBase& rhs) {
+ if( const SPIFilter* r = dynamic_cast<const SPIFilter*>(&rhs) ) {
+ (void)r;
+ return true;
+ } else {
+ return false;
+ }
+}
+
+
+
+// SPIDashArray ---------------------------------------------------------
+
+void
+SPIDashArray::read( gchar const *str ) {
+
+ if( !str ) return;
+
+ set = true;
+
+ if( strcmp( str, "inherit") == 0 ) {
+ inherit = true;
+ return;
+ }
+
+ values.clear();
+
+ if( strcmp(str, "none") == 0) {
+ return;
+ }
+
+ gchar *e = NULL;
+ bool LineSolid = true;
+ while (e != str) {
+ /* TODO: Should allow <length> rather than just a unitless (px) number. */
+ double number = g_ascii_strtod(str, (char **) &e);
+ values.push_back( number );
+ if (number > 0.00000001)
+ LineSolid = false;
+ if (e != str) {
+ str = e;
+ }
+ while (str && *str && !isalnum(*str)) str += 1;
+ }
+
+ if (LineSolid) {
+ values.clear();
+ }
+ return;
+}
+
+const Glib::ustring
+SPIDashArray::write( guint const flags, SPIBase const *const base) const {
+
+ SPIDashArray const *const my_base = dynamic_cast<const SPIDashArray*>(base);
+ if ( (flags & SP_STYLE_FLAG_ALWAYS) ||
+ ((flags & SP_STYLE_FLAG_IFSET) && this->set) ||
+ ((flags & SP_STYLE_FLAG_IFDIFF) && this->set
+ && (!my_base->set || this != my_base )))
+ {
+ if (this->inherit) {
+ return (name + ":inherit;");
+ } else if (this->values.empty() ) {
+ return (name + ":none;");
+ } else {
+ Inkscape::CSSOStringStream os;
+ os << name << ":";
+ for (unsigned i = 0; i < this->values.size(); ++i) {
+ if (i) {
+ os << ", ";
+ }
+ os << this->values[i];
+ }
+ os << ";";
+ return os.str();
+ }
+ }
+ return Glib::ustring("");
+}
+
+
+void
+SPIDashArray::cascade( const SPIBase* const parent ) {
+ if( const SPIDashArray* p = dynamic_cast<const SPIDashArray*>(parent) ) {
+ if( !set || inherit ) values = p->values; // Always inherits
+ } else {
+ std::cerr << "SPIDashArray::cascade(): Incorrect parent type" << std::endl;
+ }
+}
+
+void
+SPIDashArray::merge( const SPIBase* const parent ) {
+ if( const SPIDashArray* p = dynamic_cast<const SPIDashArray*>(parent) ) {
+ if( inherits ) {
+ if( (!set || inherit) && p->set && !(p->inherit) ) {
+ set = p->set;
+ inherit = p->inherit;
+ values = p->values;
+ }
+ }
+ } else {
+ std::cerr << "SPIDashArray::merge(): Incorrect parent type" << std::endl;
+ }
+}
+
+bool
+SPIDashArray::operator==(const SPIBase& rhs) {
+ if( const SPIDashArray* r = dynamic_cast<const SPIDashArray*>(&rhs) ) {
+ return values == r->values && SPIBase::operator==(rhs);
+ } else {
+ return false;
+ }
+}
+
+
+
+// SPIFontSize ----------------------------------------------------------
+
+/** Indexed by SP_CSS_FONT_SIZE_blah. These seem a bit small */
+float const SPIFontSize::font_size_table[] = {6.0, 8.0, 10.0, 12.0, 14.0, 18.0, 24.0};
+float const SPIFontSize::font_size_default = 12.0;
+
+void
+SPIFontSize::read( gchar const *str ) {
+
+ if( !str ) return;
+
+ if (!strcmp(str, "inherit")) {
+ set = TRUE;
+ inherit = TRUE;
+ } else if ((*str == 'x') || (*str == 's') || (*str == 'm') || (*str == 'l')) {
+ // xx-small, x-small, etc.
+ for (unsigned i = 0; enum_font_size[i].key; i++) {
+ if (!strcmp(str, enum_font_size[i].key)) {
+ set = TRUE;
+ inherit = FALSE;
+ type = SP_FONT_SIZE_LITERAL;
+ literal = enum_font_size[i].value;
+ return;
+ }
+ }
+ /* Invalid */
+ return;
+ } else {
+ SPILength length("temp");
+ length.set = FALSE;
+ length.read( str );
+ if( length.set ) {
+ set = TRUE;
+ inherit = length.inherit;
+ unit = length.unit;
+ value = length.value;
+ computed = length.computed;
+ if( unit == SP_CSS_UNIT_PERCENT ) {
+ type = SP_FONT_SIZE_PERCENTAGE;
+ } else {
+ type = SP_FONT_SIZE_LENGTH;
+ }
+ }
+ return;
+ }
+}
+
+const Glib::ustring
+SPIFontSize::write( guint const flags, SPIBase const *const base) const {
+
+ SPIFontSize const *const my_base = dynamic_cast<const SPIFontSize*>(base);
+ if ( (flags & SP_STYLE_FLAG_ALWAYS) ||
+ ((flags & SP_STYLE_FLAG_IFSET) && this->set) ||
+ ((flags & SP_STYLE_FLAG_IFDIFF) && this->set
+ && (!my_base->set || this != my_base )))
+ {
+ CSSOStringStream css;
+
+ if (this->inherit) {
+ css << "inherit";
+ } else if (this->type == SP_FONT_SIZE_LITERAL) {
+ for (unsigned i = 0; enum_font_size[i].key; i++) {
+ if (enum_font_size[i].value == static_cast< gint > (this->literal) ) {
+ css << enum_font_size[i].key;
+ }
+ }
+ } else if (this->type == SP_FONT_SIZE_LENGTH) {
+ Inkscape::Preferences *prefs = Inkscape::Preferences::get();
+ int unit = prefs->getInt("/options/font/unitType", SP_CSS_UNIT_PT);
+ if (prefs->getBool("/options/font/textOutputPx", true)) {
+ unit = SP_CSS_UNIT_PX;
+ }
+ css << sp_style_css_size_px_to_units(this->computed, unit) << sp_style_get_css_unit_string(unit);
+ } else if (this->type == SP_FONT_SIZE_PERCENTAGE) {
+ css << (this->value * 100.0) << "%";
+ }
+ return (name + ":" + css.str() + ";");
+ }
+ return Glib::ustring("");
+}
+
+void
+SPIFontSize::cascade( const SPIBase* const parent ) {
+ if( const SPIFontSize* p = dynamic_cast<const SPIFontSize*>(parent) ) {
+ if( !set || inherit ) { // Always inherits
+ computed = p->computed;value = p->value;
+
+
+ // Calculate computed based on parent as needed
+ } else if( type == SP_FONT_SIZE_LITERAL ) {
+ if( literal < SP_CSS_FONT_SIZE_SMALLER ) {
+ computed = font_size_table[ literal ];
+ } else if( literal == SP_CSS_FONT_SIZE_SMALLER ) {
+ computed = p->computed / 1.2;
+ } else if( literal == SP_CSS_FONT_SIZE_LARGER ) {
+ computed = p->computed * 1.2;
+ } else {
+ std::cerr << "SPIFontSize::cascade: Illegal literal value" << std::endl;
+ }
+ } else if( type == SP_FONT_SIZE_PERCENTAGE ) {
+ // Percentage for font size is relative to parent computed (rather than viewport)
+ computed = p->computed * value;
+ } else if( type == SP_FONT_SIZE_LENGTH ) {
+ switch ( unit ) {
+ case SP_CSS_UNIT_EM:
+ /* Relative to parent font size */
+ computed = p->computed * value;
+ break;
+ case SP_CSS_UNIT_EX:
+ /* Relative to parent font size */
+ computed = p->computed * value * 0.5; /* Hack FIXME */
+ break;
+ default:
+ /* No change */
+ break;
+ }
+ }
+ } else {
+ std::cerr << "SPIFontSize::cascade(): Incorrect parent type" << std::endl;
+ }
+}
+
+double
+SPIFontSize::relative_fraction() const {
+
+ switch (type) {
+ case SP_FONT_SIZE_LITERAL: {
+ switch (literal) {
+ case SP_CSS_FONT_SIZE_SMALLER:
+ return 5.0 / 6.0;
+
+ case SP_CSS_FONT_SIZE_LARGER:
+ return 6.0 / 5.0;
+
+ default:
+ g_assert_not_reached();
+ }
+ }
+
+ case SP_FONT_SIZE_PERCENTAGE:
+ return value;
+
+ case SP_FONT_SIZE_LENGTH: {
+ switch (unit ) {
+ case SP_CSS_UNIT_EM:
+ return value;
+
+ case SP_CSS_UNIT_EX:
+ return value * 0.5;
+
+ default:
+ g_assert_not_reached();
+ }
+ }
+ }
+ g_assert_not_reached();
+}
+
+void
+SPIFontSize::merge( const SPIBase* const parent ) {
+ if( const SPIFontSize* p = dynamic_cast<const SPIFontSize*>(parent) ) {
+ if( p->set && !(p->inherit) ) {
+ // Parent has definined font-size
+ if( (!set || inherit) ) {
+ // Computed value same as parent
+ set = p->set;
+ inherit = p->inherit;
+ value = p->value;
+ computed = p->computed; // Just to be sure
+ } else if ( type == SP_FONT_SIZE_LENGTH &&
+ unit != SP_CSS_UNIT_EM &&
+ unit != SP_CSS_UNIT_EX ) {
+ // Absolute size, computed value already set
+ } else if ( type == SP_FONT_SIZE_LITERAL &&
+ literal < SP_CSS_FONT_SIZE_SMALLER ) {
+ // Absolute size, computed value already set
+ //g_assert( literal < G_N_ELEMENTS(font_size_table) );
+ g_assert( computed == font_size_table[literal] );
+ } else {
+ // Relative size
+ double const child_frac( relative_fraction() );
+ set = true;
+ inherit = false;
+ computed = p->computed * child_frac;
+
+ if ( ( p->type == SP_FONT_SIZE_LITERAL &&
+ p->literal < SP_CSS_FONT_SIZE_SMALLER ) ||
+ ( p->type == SP_FONT_SIZE_LENGTH &&
+ p->unit != SP_CSS_UNIT_EM &&
+ p->unit != SP_CSS_UNIT_EX ) ) {
+ // Parent absolut size
+ type = SP_FONT_SIZE_LENGTH;
+
+ } else {
+ // Parent relative size
+ double const parent_frac( p->relative_fraction() );
+ if( type == SP_FONT_SIZE_LENGTH ) {
+ // ex/em
+ value *= parent_frac;
+ } else {
+ value = parent_frac * child_frac;
+ type = SP_FONT_SIZE_PERCENTAGE;
+ }
+ }
+ } // Relative size
+ } // Parent set and not inherit
+ } else {
+ std::cerr << "SPIFontSize::merge(): Incorrect parent type" << std::endl;
+ }
+}
+
+// What about different SVG units?
+bool
+SPIFontSize::operator==(const SPIBase& rhs) {
+ if( const SPIFontSize* r = dynamic_cast<const SPIFontSize*>(&rhs) ) {
+ if( type != r->type ) { return false;}
+ if( type == SP_FONT_SIZE_LENGTH ) {
+ if( computed != r->computed ) { return false;}
+ } else if (type == SP_FONT_SIZE_LITERAL ) {
+ if( literal != r->literal ) { return false;}
+ } else {
+ if( value != r->value ) { return false;}
+ }
+ return SPIBase::operator==(rhs);
+ } else {
+ return false;
+ }
+}
+
+
+
+// SPIFont ----------------------------------------------------------
+
+void
+SPIFont::read( gchar const *str ) {
+
+ if( !str ) return;
+
+ if( !style ) {
+ std::cerr << "SPIFont::read(): style is void" << std::endl;
+ return;
+ }
+
+ if ( !strcmp(str, "inherit") ) {
+ set = TRUE;
+ inherit = TRUE;
+ } else {
+
+ // Break string into white space separated tokens
+ std::stringstream os( str );
+ Glib::ustring param;
+
+ while (os >> param) {
+
+ // CSS is case insensitive but we're comparing against lowercase strings
+ Glib::ustring lparam = param.lowercase();
+
+ if (lparam == "/" ) {
+ // line_height follows... note: font-size already read
+
+ os >> param;
+ lparam = param.lowercase();
+ style->line_height.readIfUnset( lparam.c_str() );
+
+ } else {
+ // Try to parse each property in turn
+
+ SPIEnum test_style("font-style", enum_font_style);
+ test_style.read( lparam.c_str() );
+ if( test_style.set ) {
+ style->font_style = test_style;
+ continue;
+ }
+
+ // font-variant (Note: only CSS2.1 value small-caps is valid in shortcut.)
+ SPIEnum test_variant("font-variant", enum_font_variant);
+ test_variant.read( lparam.c_str() );
+ if( test_variant.set ) {
+ style->font_variant = test_variant;
+ continue;
+ }
+
+ // font-weight
+ SPIEnum test_weight("font-weight", enum_font_weight);
+ test_weight.read( lparam.c_str() );
+ if( test_weight.set ) {
+ style->font_weight = test_weight;
+ continue;
+ }
+
+ // font-stretch (added in CSS 3 Fonts)
+ SPIEnum test_stretch("font-stretch", enum_font_stretch);
+ test_stretch.read( lparam.c_str() );
+ if( test_stretch.set ) {
+ style->font_stretch = test_stretch;
+ continue;
+ }
+
+ // font-size
+ SPIFontSize test_size;
+ test_size.read( lparam.c_str() );
+ if( test_size.set ) {
+ style->font_size = test_size;
+ continue;
+ }
+
+ // No valid property value found.
+ break;
+ }
+ } // params
+
+ // The rest must be font-family...
+ std::string str_s = str; // Why this extra step?
+ std::string family = str_s.substr( str_s.find( param ) );
+
+ style->font_family.readIfUnset( family.c_str() );
+
+ // Everything in shorthand is set per CSS rules, this works since
+ // properties are read backwards from end to start.
+ style->font_style.set = true;
+ style->font_variant.set = true;
+ style->font_weight.set = true;
+ style->font_stretch.set = true;
+ style->font_size.set = true;
+ style->line_height.set = true;
+ style->font_family.set = true;
+ // style->font_size_adjust.set = true;
+ // style->font_kerning.set = true;
+ // style->font_language_override.set = true;;
+ }
+}
+
+const Glib::ustring
+SPIFont::write( guint const flags, SPIBase const *const base) const {
+
+ // At the moment, do nothing. We could add a preference to write out
+ // 'font' shorthand rather than longhand properties.
+
+ // SPIFontSize const *const my_base = dynamic_cast<const SPIFontSize*>(base);
+ // if ( (flags & SP_STYLE_FLAG_ALWAYS) ||
+ // ((flags & SP_STYLE_FLAG_IFSET) && this->set) ||
+ // ((flags & SP_STYLE_FLAG_IFDIFF) && this->set
+ // && (!my_base->set || this != my_base )))
+ // {
+ // CSSOStringStream css;
+ // }
+ return Glib::ustring("");
+}
+
+// void
+// SPIFont::cascade( const SPIBase* const parent ) {
+// }
+
+// void
+// SPIFont::merge( const SPIBase* const parent ) {
+// }
+
+// Does nothing...
+bool
+SPIFont::operator==(const SPIBase& rhs) {
+ if( /* const SPIFont* r = */ dynamic_cast<const SPIFont*>(&rhs) ) {
+ return SPIBase::operator==(rhs);
+ } else {
+ return false;
+ }
+}
+
+
+
+// SPIBaselineShift -----------------------------------------------------
+
+void
+SPIBaselineShift::read( gchar const *str ) {
+
+ if( !str ) return;
+
+ if (!strcmp(str, "inherit")) {
+ set = TRUE;
+ inherit = TRUE;
+ } else if ((*str == 'b') || (*str == 's')) {
+ // baseline or sub or super
+ for (unsigned i = 0; enum_baseline_shift[i].key; i++) {
+ if (!strcmp(str, enum_baseline_shift[i].key)) {
+ set = TRUE;
+ inherit = FALSE;
+ type = SP_BASELINE_SHIFT_LITERAL;
+ literal = enum_baseline_shift[i].value;
+ return;
+ }
+ }
+ /* Invalid */
+ return;
+ } else {
+ SPILength length( "temp" );
+ length.read( str );
+ set = length.set;
+ inherit = length.inherit;
+ unit = length.unit;
+ value = length.value;
+ computed = length.computed;
+ if( unit == SP_CSS_UNIT_PERCENT ) {
+ type = SP_BASELINE_SHIFT_PERCENTAGE;
+ } else {
+ type = SP_BASELINE_SHIFT_LENGTH;
+ }
+ return;
+ }
+}
+
+const Glib::ustring
+SPIBaselineShift::write( guint const flags, SPIBase const *const base) const {
+
+ SPIBaselineShift const *const my_base = dynamic_cast<const SPIBaselineShift*>(base);
+ if ( (flags & SP_STYLE_FLAG_ALWAYS) ||
+ ((flags & SP_STYLE_FLAG_IFSET) && this->set) ||
+ ((flags & SP_STYLE_FLAG_IFDIFF) && this->set
+ && (!my_base->set || !this->isZero() )))
+ {
+ CSSOStringStream css;
+
+ if (this->inherit) {
+ css << "inherit";
+ } else if (this->type == SP_BASELINE_SHIFT_LITERAL) {
+ for (unsigned i = 0; enum_baseline_shift[i].key; i++) {
+ if (enum_baseline_shift[i].value == static_cast< gint > (this->literal) ) {
+ css << enum_baseline_shift[i].key;
+ }
+ }
+ } else if (this->type == SP_BASELINE_SHIFT_LENGTH) {
+ if( this->unit == SP_CSS_UNIT_EM || this->unit == SP_CSS_UNIT_EX ) {
+ css << this->value << (this->unit == SP_CSS_UNIT_EM ? "em" : "ex");
+ } else {
+ css << this->computed << "px"; // must specify px, see inkscape bug 1221626, mozilla bug 234789
+ }
+ } else if (this->type == SP_BASELINE_SHIFT_PERCENTAGE) {
+ css << (this->value * 100.0) << "%";
+ }
+ return (name + ":" + css.str() + ";");
+ }
+ return Glib::ustring("");
+}
+
+void
+SPIBaselineShift::cascade( const SPIBase* const parent ) {
+ if( const SPIBaselineShift* p = dynamic_cast<const SPIBaselineShift*>(parent) ) {
+ SPIFontSize *pfont_size = &(p->style->font_size);
+ g_assert( pfont_size != NULL );
+
+ if( !set || inherit ) {
+ computed = p->computed; // Shift relative to parent shift, corrected below
+ } else if (type == SP_BASELINE_SHIFT_LITERAL) {
+ if( literal == SP_CSS_BASELINE_SHIFT_BASELINE ) {
+ computed = 0; // No change
+ } else if (literal == SP_CSS_BASELINE_SHIFT_SUB ) {
+ // Should use subscript position from font relative to alphabetic baseline
+ // OpenOffice, Adobe: -0.33, Word -0.14, LaTex about -0.2.
+ computed = -0.2 * pfont_size->computed;
+ } else if (literal == SP_CSS_BASELINE_SHIFT_SUPER ) {
+ // Should use superscript position from font relative to alphabetic baseline
+ // OpenOffice, Adobe: 0.33, Word 0.35, LaTex about 0.45.
+ computed = 0.4 * pfont_size->computed;
+ } else {
+ /* Illegal value */
+ }
+ } else if (type == SP_BASELINE_SHIFT_PERCENTAGE) {
+ // Percentage for baseline shift is relative to computed "line-height"
+ // which is just font-size (see SVG1.1 'font').
+ computed = pfont_size->computed * value;
+ } else if (type == SP_BASELINE_SHIFT_LENGTH) {
+ switch (unit) {
+ case SP_CSS_UNIT_EM:
+ computed = value * pfont_size->computed;
+ break;
+ case SP_CSS_UNIT_EX:
+ computed = value * 0.5 * pfont_size->computed;
+ break;
+ default:
+ /* No change */
+ break;
+ }
+ }
+ // baseline-shifts are relative to parent baseline
+ computed += p->computed;
+
+ } else {
+ std::cerr << "SPIBaselineShift::cascade(): Incorrect parent type" << std::endl;
+ }
+}
+
+// This was not defined in the legacy C code, it needs some serious thinking (but is low priority).
+// FIX ME
+void
+SPIBaselineShift::merge( const SPIBase* const parent ) {
+ if( const SPIBaselineShift* p = dynamic_cast<const SPIBaselineShift*>(parent) ) {
+ if( (!set || inherit) && p->set && !(p->inherit) ) {
+ set = p->set;
+ inherit = p->inherit;
+ value = p->value;
+ }
+ } else {
+ std::cerr << "SPIBaselineShift::merge(): Incorrect parent type" << std::endl;
+ }
+}
+
+// This is not used but we have it for completeness, it has not been tested.
+bool
+SPIBaselineShift::operator==(const SPIBase& rhs) {
+ if( const SPIBaselineShift* r = dynamic_cast<const SPIBaselineShift*>(&rhs) ) {
+ if( type != r->type ) return false;
+ if( type == SP_BASELINE_SHIFT_LENGTH ) {
+ if( computed != r->computed ) return false;
+ } else if ( type == SP_BASELINE_SHIFT_LITERAL ) {
+ if( literal != r->literal ) return false;
+ } else {
+ if( value != r->value ) return false;
+ }
+ return SPIBase::operator==(rhs);
+ } else {
+ return false;
+ }
+}
+
+bool
+SPIBaselineShift::isZero() const {
+ if( type == SP_BASELINE_SHIFT_LITERAL ) {
+ if( literal == SP_CSS_BASELINE_SHIFT_BASELINE ) return true;
+ } else {
+ if( value == 0.0 ) return true;
+ }
+ return false;
+}
+
+
+
+// SPITextDecorationLine ------------------------------------------------
+
+void
+SPITextDecorationLine::read( gchar const *str ) {
+
+ if( !str ) return;
+
+ if (!strcmp(str, "inherit")) {
+ set = true;
+ inherit = true;
+ } else if (!strcmp(str, "none")) {
+ set = true;
+ inherit = false;
+ underline = false;
+ overline = false;
+ line_through = false;
+ blink = false;
+ } else {
+ bool found_one = false;
+ bool hit_one = false;
+
+ // CSS 2 keywords
+ bool found_underline = false;
+ bool found_overline = false;
+ bool found_line_through = false;
+ bool found_blink = false;
+
+ // This method ignores inlineid keys and extra delimiters, so " ,,, blink hello" will set
+ // blink and ignore hello
+ const gchar *hstr = str;
+ while (1) {
+ if (*str == ' ' || *str == ',' || *str == '\0'){
+ int slen = str - hstr;
+ // CSS 2 keywords
+ while(1){ // not really a loop, used to avoid a goto
+ hit_one = true; // most likely we will
+ if ((slen == 9) && strneq(hstr, "underline", slen)){ found_underline = true; break; }
+ if ((slen == 8) && strneq(hstr, "overline", slen)){ found_overline = true; break; }
+ if ((slen == 12) && strneq(hstr, "line-through", slen)){ found_line_through = true; break; }
+ if ((slen == 5) && strneq(hstr, "blink", slen)){ found_blink = true; break; }
+ if ((slen == 4) && strneq(hstr, "none", slen)){ break; }
+
+ hit_one = false; // whatever this thing is, we do not recognize it
+ break;
+ }
+ found_one |= hit_one;
+ if(*str == '\0')break;
+ hstr = str + 1;
+ }
+ str++;
+ }
+ if (found_one) {
+ set = true;
+ inherit = false;
+ underline = found_underline;
+ overline = found_overline;
+ line_through = found_line_through;
+ blink = found_blink;
+ }
+ else {
+ set = false;
+ inherit = false;
+ }
+ }
+}
+
+const Glib::ustring
+SPITextDecorationLine::write( guint const flags, SPIBase const *const base) const {
+ SPITextDecorationLine const *const my_base = dynamic_cast<const SPITextDecorationLine*>(base);
+ if ( (flags & SP_STYLE_FLAG_ALWAYS) ||
+ ((flags & SP_STYLE_FLAG_IFSET) && this->set) ||
+ ((flags & SP_STYLE_FLAG_IFDIFF) && this->set
+ && (!my_base->set || this != my_base )))
+ {
+ Inkscape::CSSOStringStream os;
+ os << name << ":";
+ if( inherit ) {
+ os << "inherit";
+ } else if (this->underline || this->overline || this->line_through || this->blink) {
+ if (this->underline) os << " underline";
+ if (this->overline) os << " overline";
+ if (this->line_through) os << " line-through";
+ if (this->blink) os << " blink"; // Deprecated
+ } else {
+ os << "none";
+ }
+ os << ";";
+ return ( os.str() );
+ }
+ return Glib::ustring("");
+}
+
+void
+SPITextDecorationLine::cascade( const SPIBase* const parent ) {
+ if( const SPITextDecorationLine* p = dynamic_cast<const SPITextDecorationLine*>(parent) ) {
+ if( inherits && (!set || inherit) ) {
+ underline = p->underline;
+ overline = p->overline;
+ line_through = p->line_through;
+ blink = p->blink;
+ }
+ } else {
+ std::cerr << "SPITextDecorationLine::cascade(): Incorrect parent type" << std::endl;
+ }
+}
+
+void
+SPITextDecorationLine::merge( const SPIBase* const parent ) {
+ if( const SPITextDecorationLine* p = dynamic_cast<const SPITextDecorationLine*>(parent) ) {
+ if( inherits ) { // Always inherits... but special rules?
+ if( (!set || inherit) && p->set && !(p->inherit) ) {
+ set = p->set;
+ inherit = p->inherit;
+ underline = p->underline;
+ overline = p->overline;
+ line_through = p->line_through;
+ blink = p->blink;
+ }
+ }
+ }
+}
+
+bool
+SPITextDecorationLine::operator==(const SPIBase& rhs) {
+ if( const SPITextDecorationLine* r = dynamic_cast<const SPITextDecorationLine*>(&rhs) ) {
+ return
+ (underline == r->underline ) &&
+ (overline == r->overline ) &&
+ (line_through == r->line_through ) &&
+ (blink == r->blink ) &&
+ SPIBase::operator==(rhs);
+ } else {
+ return false;
+ }
+}
+
+
+
+// SPITextDecorationStyle -----------------------------------------------
+
+void
+SPITextDecorationStyle::read( gchar const *str ) {
+
+ if( !str ) return;
+
+ set = false;
+ inherit = false;
+
+ solid = true; // Default
+ isdouble = false;
+ dotted = false;
+ dashed = false;
+ wavy = false;
+
+ if (!strcmp(str, "inherit")) {
+ set = true;
+ inherit = true;
+ solid = false;
+ } else {
+ // note, these are CSS 3 keywords
+ bool found_solid = false;
+ bool found_double = false;
+ bool found_dotted = false;
+ bool found_dashed = false;
+ bool found_wavy = false;
+ bool found_one = false;
+
+ // this method ignores inlineid keys and extra delimiters, so " ,,, style hello" will set style and ignore hello
+ // if more than one style is present, the first is used
+ const gchar *hstr = str;
+ while (1) {
+ if (*str == ' ' || *str == ',' || *str == '\0'){
+ int slen = str - hstr;
+ if ( (slen == 5) && strneq(hstr, "solid", slen)){ found_solid = true; found_one = true; break; }
+ else if ((slen == 6) && strneq(hstr, "double", slen)){ found_double = true; found_one = true; break; }
+ else if ((slen == 6) && strneq(hstr, "dotted", slen)){ found_dotted = true; found_one = true; break; }
+ else if ((slen == 6) && strneq(hstr, "dashed", slen)){ found_dashed = true; found_one = true; break; }
+ else if ((slen == 4) && strneq(hstr, "wavy", slen)){ found_wavy = true; found_one = true; break; }
+ if(*str == '\0')break; // nothing more to test
+ hstr = str + 1;
+ }
+ str++;
+ }
+ if(found_one){
+ set = true;
+ solid = found_solid;
+ isdouble = found_double;
+ dotted = found_dotted;
+ dashed = found_dashed;
+ wavy = found_wavy;
+ }
+ else {
+ set = false;
+ inherit = false;
+ }
+ }
+}
+
+const Glib::ustring
+SPITextDecorationStyle::write( guint const flags, SPIBase const *const base) const {
+ SPITextDecorationStyle const *const my_base = dynamic_cast<const SPITextDecorationStyle*>(base);
+ if ( (flags & SP_STYLE_FLAG_ALWAYS) ||
+ ((flags & SP_STYLE_FLAG_IFSET) && this->set) ||
+ ((flags & SP_STYLE_FLAG_IFDIFF) && this->set
+ && (!my_base->set || this != my_base )))
+ {
+ Inkscape::CSSOStringStream os;
+ os << name << ":";
+ if( inherit ) {
+ os << "inherit";
+ } else if (this->solid ) {
+ os << "solid";
+ } else if (this->isdouble ) {
+ os << "double";
+ } else if (this->dotted ) {
+ os << "dotted";
+ } else if (this->dashed ) {
+ os << "dashed";
+ } else if (this->wavy ) {
+ os << "wavy";
+ } else {
+ std::cerr << "SPITextDecorationStyle::write(): No valid value for property" << std::endl;
+ return Glib::ustring("");
+ }
+ os << ";";
+ return ( os.str() );
+ }
+ return Glib::ustring("");
+}
+
+void
+SPITextDecorationStyle::cascade( const SPIBase* const parent ) {
+ if( const SPITextDecorationStyle* p = dynamic_cast<const SPITextDecorationStyle*>(parent) ) {
+ if( inherits && (!set || inherit) ) {
+ solid = p->solid;
+ isdouble = p->isdouble;
+ dotted = p->dotted;
+ dashed = p->dashed;
+ wavy = p->wavy;
+ }
+ } else {
+ std::cerr << "SPITextDecorationStyle::cascade(): Incorrect parent type" << std::endl;
+ }
+}
+
+void
+SPITextDecorationStyle::merge( const SPIBase* const parent ) {
+ if( const SPITextDecorationStyle* p = dynamic_cast<const SPITextDecorationStyle*>(parent) ) {
+ if( inherits ) { // Always inherits... but special rules?
+ if( (!set || inherit) && p->set && !(p->inherit) ) {
+ set = p->set;
+ inherit = p->inherit;
+ solid = p->solid;
+ isdouble = p->isdouble;
+ dotted = p->dotted;
+ dashed = p->dashed;
+ wavy = p->wavy;
+ }
+ }
+ }
+}
+
+bool
+SPITextDecorationStyle::operator==(const SPIBase& rhs) {
+ if( const SPITextDecorationStyle* r = dynamic_cast<const SPITextDecorationStyle*>(&rhs) ) {
+ return
+ (solid == r->solid ) &&
+ (isdouble == r->isdouble ) &&
+ (dotted == r->dotted ) &&
+ (dashed == r->dashed ) &&
+ (wavy == r->wavy ) &&
+ SPIBase::operator==(rhs);
+ } else {
+ return false;
+ }
+}
+
+
+
+// TextDecorationColor is handled by SPIPaint (should be SPIColor), default value is "currentColor"
+// FIXME
+
+
+
+// SPITextDecoration ----------------------------------------------------
+
+void
+SPITextDecoration::read( gchar const *str ) {
+
+ if( !str ) return;
+
+ style->text_decoration_line.read( str );
+ style->text_decoration_style.read( str );
+ // the color routine must be fed one token at a time - if multiple colors are found the LAST
+ // one is used ???? then why break on set?
+ const gchar *hstr = str;
+
+ style->text_decoration_color.read( "currentColor" ); // Default value
+ style->text_decoration_color.set = false;
+ while (1) {
+ if (*str == ' ' || *str == ',' || *str == '\0'){
+ int slen = str - hstr;
+ gchar *frag = g_strndup(hstr,slen+1); // only send one piece at a time, since keywords may be intermixed
+
+ if( strcmp( frag, "none" ) != 0 ) { // 'none' not allowed
+ style->text_decoration_color.read( frag );
+ }
+
+ free(frag);
+ if( style->text_decoration_color.set ) break;
+ style->text_decoration_color.read( "currentColor" ); // Default value
+ if( *str == '\0' )break;
+ hstr = str + 1;
+ }
+ str++;
+ }
+}
+
+// Returns CSS2 'text-decoration' (using settings in SPTextDecorationLine)
+// This is required until all SVG renderers support CSS3 'text-decoration'
+const Glib::ustring
+SPITextDecoration::write( guint const flags, SPIBase const *const base) const {
+ SPITextDecoration const *const my_base = dynamic_cast<const SPITextDecoration*>(base);
+ if ( (flags & SP_STYLE_FLAG_ALWAYS) ||
+ ((flags & SP_STYLE_FLAG_IFSET) && style->text_decoration_line.set) ||
+ ((flags & SP_STYLE_FLAG_IFDIFF) && style->text_decoration_line.set
+ && (!my_base->style->text_decoration_line.set ||
+ style->text_decoration_line != my_base->style->text_decoration_line )))
+ {
+ Inkscape::CSSOStringStream os;
+ os << name << ":";
+ if( inherit ) {
+ os << "inherit";
+ } else if (style->text_decoration_line.underline ||
+ style->text_decoration_line.overline ||
+ style->text_decoration_line.line_through ||
+ style->text_decoration_line.blink) {
+ if (style->text_decoration_line.underline) os << " underline";
+ if (style->text_decoration_line.overline) os << " overline";
+ if (style->text_decoration_line.line_through) os << " line-through";
+ if (style->text_decoration_line.blink) os << " blink"; // Deprecated
+ } else {
+ os << "none";
+ }
+ os << ";";
+ return ( os.str() );
+ }
+ return Glib::ustring("");
+}
+
+// Done in SPITextDecorationLine
+// void
+// SPITextDecoration::cascade( const SPIBase* const parent ) {
+// }
+
+// void
+// SPITextDecoration::merge( const SPIBase* const parent ) {
+// }
+
+// Use CSS2 value
+bool
+SPITextDecoration::operator==(const SPIBase& rhs) {
+ if( const SPITextDecoration* r = dynamic_cast<const SPITextDecoration*>(&rhs) ) {
+ return (style->text_decoration_line == r->style->text_decoration_line &&
+ SPIBase::operator==(rhs));
+ } else {
+ return false;
+ }
+}
+
+
+
+/* ---------------------------- NOTES ----------------------------- */
+
+/*
+ * opacity's effect is cumulative; we set the new value to the combined effect. The
+ * default value for opacity is 1.0, not inherit. (Note that stroke-opacity and
+ * fill-opacity are quite different from opacity, and don't need any special handling.)
+ *
+ * Cases:
+ * - parent & child were each previously unset, in which case the effective
+ * opacity value is 1.0, and style should remain unset.
+ * - parent was previously unset (so computed opacity value of 1.0)
+ * and child was set to inherit. The merged child should
+ * get a value of 1.0, and shouldn't inherit (lest the new parent
+ * has a different opacity value). Given that opacity's default
+ * value is 1.0 (rather than inherit), we might as well have the
+ * merged child's opacity be unset.
+ * - parent was previously unset (so opacity 1.0), and child was set to a number.
+ * The merged child should retain its existing settings (though it doesn't matter
+ * if we make it unset if that number was 1.0).
+ * - parent was inherit and child was unset. Merged child should be set to inherit.
+ * - parent was inherit and child was inherit. (We can't in general reproduce this
+ * effect (short of introducing a new group), but setting opacity to inherit is rare.)
+ * If the inherited value was strictly between 0.0 and 1.0 (exclusive) then the merged
+ * child's value should be set to the product of the two, i.e. the square of the
+ * inherited value, and should not be marked as inherit. (This decision assumes that it
+ * is more important to retain the effective opacity than to retain the inheriting
+ * effect, and assumes that the inheriting effect either isn't important enough to create
+ * a group or isn't common enough to bother maintaining the code to create a group.) If
+ * the inherited value was 0.0 or 1.0, then marking the merged child as inherit comes
+ * closer to maintaining the effect.
+ * - parent was inherit and child was set to a numerical value. If the child's value
+ * was 1.0, then the merged child should have the same settings as the parent.
+ * If the child's value was 0, then the merged child should also be set to 0.
+ * If the child's value was anything else, then we do the same as for the inherit/inherit
+ * case above: have the merged child set to the product of the two opacities and not
+ * marked as inherit, for the same reasons as for that case.
+ * - parent was set to a value, and child was unset. The merged child should have
+ * parent's settings.
+ * - parent was set to a value, and child was inherit. The merged child should
+ * be set to the product, i.e. the square of the parent's value.
+ * - parent & child are each set to a value. The merged child should be set to the
+ * product.
+ */
+
+
+/*
+ Local Variables:
+ mode:c++
+ c-file-style:"stroustrup"
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
+ indent-tabs-mode:nil
+ fill-column:99
+ End:
+*/
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :
diff --git a/src/style-internal.h b/src/style-internal.h
index 7d45f96f8..d1a331acf 100644
--- a/src/style-internal.h
+++ b/src/style-internal.h
@@ -7,7 +7,9 @@
/* Authors:
* Lauris Kaplinski <lauris@kaplinski.com>
* Jon A. Cruz <jon@joncruz.org>
+ * Tavmjong Bah <tavmjong@free.fr>
*
+ * Copyright (C) 2014 Tavmjong Bah
* Copyright (C) 2010 Jon A. Cruz
* Copyright (C) 2001-2002 Lauris Kaplinski
* Copyright (C) 2001 Ximian, Inc.
@@ -15,21 +17,168 @@
* Released under GNU GPL, read the file 'COPYING' for more information
*/
+#include "style-enums.h"
+
#include "color.h"
+#include "svg/svg-icc-color.h"
#include "sp-marker-loc.h"
#include "sp-filter.h"
#include "sp-filter-reference.h"
#include "sp-paint-server-reference.h"
#include "uri.h"
+#include "xml/repr.h"
#include <vector>
-/// Float type internal to SPStyle.
-struct SPIFloat {
- unsigned set : 1;
- unsigned inherit : 1;
- unsigned data : 30;
+struct SPStyleEnum;
+
+static const unsigned SP_STYLE_FLAG_ALWAYS (1 << 2);
+static const unsigned SP_STYLE_FLAG_IFSET (1 << 0);
+static const unsigned SP_STYLE_FLAG_IFDIFF (1 << 1);
+
+
+/* General comments:
+ *
+ * This code is derived from the original C style code in style.cpp.
+ *
+ * Overview:
+ * Style can be obtained (in order of precidence) [CHECK]
+ * 1. "style" property in an element (style="fill:red").
+ * 2. Style sheet, internal or external (<style> rect {fill:red;}</style>).
+ * 3. Attributes in an element (fill="red").
+ * 4. Parent's style.
+ * A later property overrides an earlier property. This is implemented by
+ * reading in the properties backwards. If a property is already set, it
+ * prevents an earlier property from being read.
+ *
+ * In order for cascading to work, each element in the tree must be read in from top to bottom
+ * (parent before child). At each step, if a style property is not explicitly set, the property
+ * value is taken from the parent. Some properties have "computed" values that depend on:
+ * the parent's value (e.g. "font-size:larger"),
+ * another property value ("stroke-width":1em"), or
+ * an external value ("stroke-width:5%").
+ *
+ * To summarize:
+ *
+ * An explicitly set value (including 'inherit') has a 'true' "set" flag.
+ * The "value" is either explicitly set or inherited.
+ * The "computed" value (if present) is calculated from "value" and some other input.
+ *
+ * Functions:
+ * write(): Write a property and its value to a string.
+ * Flags:
+ * ALWAYS: Always write out property.
+ * IFSET: Write a property if 'set' flag is true, otherwise return empty string.
+ * IFDIFF: Write a property if computed values are different, otherwise return empty string,
+ * This is only used for text!!
+ *
+ * read(): Set a property value from a string.
+ * clear(): Set a property to its default value and set the 'set' flag to false.
+ * cascade(): Cascade the parent's property values to the child if the child's property
+ * is unset (and it allows inheriting) or the value is 'inherit'.
+ * Calculate computed values that depend on parent.
+ * This requires that the parent already be updated.
+ * merge(): Merge the property values of a child and a parent that is being deleted,
+ * attempting to preserve the style of the child.
+ * operator=: Assignment operator required due to use of templates (in original C code).
+ * operator==: True if computed values are equal. TO DO: DEFINE EXACTLY WHAT THIS MEANS
+ * operator!=: Inverse of operator==.
+ *
+ *
+ * Outside dependencies:
+ *
+ * The C structures that these classes are evolved from were designed to be embedded in to the
+ * style structure (i.e they are "internal" and thus have an "I" in the SPI prefix). However,
+ * they should be reasonably stand-alone and can provide some functionality outside of the style
+ * stucture (i.e. reading and writing style strings). Some properties do need access to other
+ * properties from the same object (e.g. SPILength sometimes needs to know font size) to
+ * calculate 'computed' values. Inheritence, of course, requires access to the parent object's
+ * style class.
+ *
+ * The only real outside dependancy is SPObject... which is needed in the cases of SPIPaint and
+ * SPIFilter for setting up the "href". (Currently, SPDocument is needed but this dependency
+ * should be removed as an "href" only needs the SPDocument for attaching an external document to
+ * the XML tree [see uri-references.cpp]. If SPDocument is really needed, it can be obtained from
+ * SPObject.)
+ *
+ */
+
+/// Virtual base class for all SPStyle interal classes
+class SPIBase {
+
+ public:
+ SPIBase( Glib::ustring const &name, bool inherits = true )
+ : name(name), inherits(inherits), set(false), inherit(false), style_att(false), style(NULL) {};
+ virtual ~SPIBase() {};
+ virtual void read( gchar const *str ) = 0;
+ virtual void readIfUnset( gchar const *str ) { if( !set ) read( str ); }
+ virtual void readAttribute( Inkscape::XML::Node *repr ) { readIfUnset( repr->attribute( name.c_str() ) ); }
+ virtual const Glib::ustring write( guint const flags = SP_STYLE_FLAG_IFSET,
+ SPIBase const *const base = NULL ) const = 0;
+ virtual void clear() { set = false, inherit = false; };
+ virtual void cascade( const SPIBase* const parent ) {};
+ virtual void merge( const SPIBase* const parent ) {}; // To do: Set to 0
+
+ virtual void setStylePointer( SPStyle *style_in ) { style = style_in; };
+
+ // Explicit assignment operator required due to templates.
+ SPIBase& operator=(const SPIBase& rhs) {
+ name = rhs.name;
+ inherits = rhs.inherits;
+ set = rhs.set;
+ inherit = rhs.inherit;
+ style_att = rhs.style_att;
+ return *this;
+ }
+
+ // Check apples being compared to apples
+ virtual bool operator==(const SPIBase& rhs) { return (name == rhs.name); };
+ virtual bool operator!=(const SPIBase& rhs) { return !(*this == rhs); };
+
+ // To do: make private
+ public:
+ Glib::ustring name; // Make const
+ unsigned inherits : 1; // Property inherits by default from parent.
+ unsigned set : 1; // Property has been explicitly set (vs. inherited).
+ unsigned inherit : 1; // Property value set to 'inherit'.
+ unsigned style_att : 2; // Source (attribute, style attribute, style-sheet). NOT USED YET FIX ME
+
+ // To do: make private after g_asserts removed
+ public:
+ SPStyle* style; // Used by SPIPaint, SPIFilter... to find values of other properties
+};
+
+/// Float type internal to SPStyle. (Only 'stroke-miterlimit')
+class SPIFloat : public SPIBase {
+
+ public:
+ SPIFloat() : SPIBase( "anonymous_float" ), value(0.0) {};
+ SPIFloat( Glib::ustring name, float value_default = 0.0 )
+ : SPIBase( name ), value(value_default), value_default(value_default) {};
+ virtual ~SPIFloat() {};
+ virtual void read( gchar const *str );
+ virtual const Glib::ustring write( guint const flags = SP_STYLE_FLAG_IFSET,
+ SPIBase const *const base = NULL ) const;
+ virtual void clear() { SPIBase::clear(); value = value_default; };
+ virtual void cascade( const SPIBase* const parent );
+ virtual void merge( const SPIBase* const parent );
+
+ SPIFloat& operator=(const SPIFloat& rhs) {
+ SPIBase::operator=(rhs);
+ value = rhs.value;
+ value_default = value_default;
+ return *this;
+ }
+
+ virtual bool operator==(const SPIBase& rhs);
+ virtual bool operator!=(const SPIBase& rhs) { return !(*this == rhs); };
+
+ // To do: make private
+ public:
float value;
+
+ private:
+ float value_default;
};
/*
@@ -60,44 +209,42 @@ static const unsigned SP_SCALE24_MAX = 0xff0000;
/** Returns a scale24 for the product of two scale24 values. */
#define SP_SCALE24_MUL(_v1, _v2) unsigned((double)(_v1) * (_v2) / SP_SCALE24_MAX + .5)
+
/// 24 bit data type internal to SPStyle.
-struct SPIScale24 {
- unsigned set : 1;
- unsigned inherit : 1;
+// Used only for opacity, fill-opacity, stroke-opacity.
+// Opacity does not inherit but stroke-opacity and fill-opacity do.
+class SPIScale24 : public SPIBase {
+
+ public:
+ SPIScale24() : SPIBase( "anonymous_scale24" ), value(0) {};
+ SPIScale24( Glib::ustring name, unsigned value = 0, bool inherits = true )
+ : SPIBase( name, inherits ), value(value), value_default(value) {};
+ virtual ~SPIScale24() {};
+ virtual void read( gchar const *str );
+ virtual const Glib::ustring write( guint const flags = SP_STYLE_FLAG_IFSET,
+ SPIBase const *const base = NULL ) const;
+ virtual void clear() { SPIBase::clear(); value = value_default; };
+ virtual void cascade( const SPIBase* const parent );
+ virtual void merge( const SPIBase* const parent );
+
+ SPIScale24& operator=(const SPIScale24& rhs) {
+ SPIBase::operator=(rhs);
+ value = rhs.value;
+ return *this;
+ }
+
+ virtual bool operator==(const SPIBase& rhs);
+ virtual bool operator!=(const SPIBase& rhs) { return !(*this == rhs); };
+
+
+ // To do: make private
+ public:
unsigned value : 24;
-};
-
-/// Int type internal to SPStyle.
-struct SPIInt {
- unsigned set : 1;
- unsigned inherit : 1;
- unsigned data : 30;
- int value;
-};
-/// Short type internal to SPStyle.
-struct SPIShort {
- unsigned set : 1;
- unsigned inherit : 1;
- unsigned data : 14;
- int value : 16;
-};
-
-/// Enum type internal to SPStyle.
-struct SPIEnum {
- unsigned set : 1;
- unsigned inherit : 1;
- unsigned value : 8;
- unsigned computed : 8;
+ private:
+ unsigned value_default : 24;
};
-/// String type internal to SPStyle.
-struct SPIString {
- unsigned set : 1;
- unsigned inherit : 1;
- unsigned data : 30;
- gchar *value;
-};
enum SPCSSUnit {
SP_CSS_UNIT_NONE,
@@ -112,33 +259,235 @@ enum SPCSSUnit {
SP_CSS_UNIT_PERCENT
};
+
/// Length type internal to SPStyle.
-struct SPILength {
- unsigned set : 1;
- unsigned inherit : 1;
+// Needs access to 'font-size' and 'font-family' for computed values.
+// Used for 'stroke-width' 'stroke-dash-offset' ('none' not handled), text-indent
+class SPILength : public SPIBase {
+
+ public:
+ SPILength() : SPIBase( "anonymous_length" ), unit(SP_CSS_UNIT_NONE), value(0), computed(0) {};
+ SPILength( Glib::ustring name, unsigned value = 0 )
+ : SPIBase( name ), unit(SP_CSS_UNIT_NONE), value(value), computed(value), value_default(value) {};
+ virtual ~SPILength() {};
+ virtual void read( gchar const *str );
+ virtual const Glib::ustring write( guint const flags = SP_STYLE_FLAG_IFSET,
+ SPIBase const *const base = NULL ) const;
+ virtual void clear() { SPIBase::clear(); unit = SP_CSS_UNIT_NONE, value = value_default; computed = value_default; };
+ virtual void cascade( const SPIBase* const parent );
+ virtual void merge( const SPIBase* const parent );
+
+ SPILength& operator=(const SPILength& rhs) {
+ SPIBase::operator=(rhs);
+ unit = rhs.unit;
+ value = rhs.value;
+ computed = rhs.computed;
+ value_default = rhs.value_default;
+ return *this;
+ };
+
+ virtual bool operator==(const SPIBase& rhs);
+ virtual bool operator!=(const SPIBase& rhs) { return !(*this == rhs); };
+
+ // To do: make private
+ public:
unsigned unit : 4;
float value;
float computed;
+
+ private:
+ float value_default;
};
-#define SP_STYLE_FILL_SERVER(s) ((const_cast<SPStyle *> (s))->getFillPaintServer())
-#define SP_STYLE_STROKE_SERVER(s) ((const_cast<SPStyle *> (s))->getStrokePaintServer())
-/// Paint type internal to SPStyle.
-struct SPIPaint {
- unsigned int set : 1; //c++ bitfields are used here as opposed to bools to reduce memory consumption, see http://tinyurl.com/cswh6mq
- unsigned int inherit : 1;
- unsigned int currentcolor : 1;
- unsigned int colorSet : 1;
- unsigned int noneSet : 1;
+/// Extended length type internal to SPStyle.
+// Used for: line-height, letter-spacing, word-spacing
+class SPILengthOrNormal : public SPILength {
+
+ public:
+ SPILengthOrNormal() : SPILength( "anonymous_length" ), normal(true) {};
+ SPILengthOrNormal( Glib::ustring name, unsigned value = 0 )
+ : SPILength( name, value ), normal(true) {};
+ virtual ~SPILengthOrNormal() {};
+ virtual void read( gchar const *str );
+ virtual const Glib::ustring write( guint const flags = SP_STYLE_FLAG_IFSET,
+ SPIBase const *const base = NULL ) const;
+ virtual void clear() { SPILength::clear(); normal = true; };
+ // virtual void cascade( const SPIBase* const parent ); // Use SPILength::cascade
+ virtual void merge( const SPIBase* const parent );
+
+ SPILengthOrNormal& operator=(const SPILengthOrNormal& rhs) {
+ SPILength::operator=(rhs);
+ normal = rhs.normal;
+ return *this;
+ }
+
+ virtual bool operator==(const SPIBase& rhs);
+ virtual bool operator!=(const SPIBase& rhs) { return !(*this == rhs); };
+
+ // To do: make private
+ public:
+ bool normal : 1;
+};
+
+
+/// Enum type internal to SPStyle.
+// Used for many properties. 'font-stretch' and 'font-weight' must be special cased.
+class SPIEnum : public SPIBase {
+
+ public:
+ SPIEnum() :
+ SPIBase( "anonymous_enum" ), enums( NULL ), value(0), computed(0) {};
+ SPIEnum( Glib::ustring name, SPStyleEnum const *enums, unsigned value = 0, bool inherits = true ) :
+ SPIBase( name, inherits ), enums( enums ), value(value), computed(value),
+ value_default(value), computed_default(value) {};
+ // Following is needed for font-weight
+ SPIEnum( Glib::ustring name, SPStyleEnum const *enums, SPCSSFontWeight value, SPCSSFontWeight computed ) :
+ SPIBase( name ), enums( enums ), value(value), computed(computed),
+ value_default(value), computed_default(computed) {};
+ virtual ~SPIEnum() {};
+ virtual void read( gchar const *str );
+ virtual const Glib::ustring write( guint const flags = SP_STYLE_FLAG_IFSET,
+ SPIBase const *const base = NULL ) const;
+ virtual void clear() { SPIBase::clear(); value = value_default, computed = computed_default; };
+ virtual void cascade( const SPIBase* const parent );
+ virtual void merge( const SPIBase* const parent );
+
+ SPIEnum& operator=(const SPIEnum& rhs) {
+ SPIBase::operator=(rhs);
+ value = rhs.value;
+ computed = rhs.computed;
+ value_default = rhs.value_default;
+ computed_default = rhs.computed_default;
+ return *this;
+ }
+
+ virtual bool operator==(const SPIBase& rhs);
+ virtual bool operator!=(const SPIBase& rhs) { return !(*this == rhs); };
+
+ // To do: make private
+ public:
+ SPStyleEnum const *enums;
+
+ unsigned value : 8;
+ unsigned computed: 8;
+
+ private:
+ unsigned value_default : 8;
+ unsigned computed_default: 8; // for font-weight
+};
+
+
+/// String type internal to SPStyle.
+// Used for 'marker', ..., 'font', 'font-family', 'inkscape-font-specification'
+class SPIString : public SPIBase {
+
+ public:
+ SPIString() :
+ SPIBase( "anonymous_string" ), value(NULL) {};
+ SPIString( Glib::ustring name, gchar* value_default_in = NULL ) :
+ SPIBase( name ) , value(NULL) , value_default(NULL) {
+ value_default = value_default_in?g_strdup(value_default_in):NULL;
+ };
+ virtual ~SPIString() { g_free(value); };
+ virtual void read( gchar const *str );
+ virtual const Glib::ustring write( guint const flags = SP_STYLE_FLAG_IFSET,
+ SPIBase const *const base = NULL ) const;
+ virtual void clear();
+ virtual void cascade( const SPIBase* const parent );
+ virtual void merge( const SPIBase* const parent );
+
+ SPIString& operator=(const SPIString& rhs) {
+ SPIBase::operator=(rhs);
+ value = rhs.value?g_strdup(rhs.value):NULL;
+ return *this;
+ }
+
+ virtual bool operator==(const SPIBase& rhs);
+ virtual bool operator!=(const SPIBase& rhs) { return !(*this == rhs); };
+
+ // To do: make private, convert value to Glib::ustring
+ public:
+ gchar *value;
+ gchar *value_default;
+};
+
+/// Color type interal to SPStyle, FIXME Add string value to store SVG named color.
+class SPIColor : public SPIBase {
+
+ public:
+ SPIColor() : SPIBase( "anonymous_color" ), currentcolor(false) { value.color.set(0); }
+ SPIColor( Glib::ustring name ) : SPIBase( name ), currentcolor(false) { value.color.set(0); }
+ virtual ~SPIColor() {}
+ virtual void read( gchar const *str );
+ virtual const Glib::ustring write( guint const flags = SP_STYLE_FLAG_IFSET,
+ SPIBase const *const base = NULL ) const;
+ virtual void clear() { SPIBase::clear(); value.color.set(0); }
+ virtual void cascade( const SPIBase* const parent );
+ virtual void merge( const SPIBase* const parent );
+
+ SPIColor& operator=(const SPIColor& rhs) {
+ SPIBase::operator=(rhs);
+ value.color = rhs.value.color;
+ return *this;
+ }
+
+ virtual bool operator==(const SPIBase& rhs);
+ virtual bool operator!=(const SPIBase& rhs) { return !(*this == rhs); }
+
+ void setColor( float r, float g, float b ) { value.color.set( r, g, b ); }
+ void setColor( guint32 val ) { value.color.set( val ); }
+ void setColor( SPColor const& color ) { value.color = color; }
+
+ public:
+ bool currentcolor : 1;
+ // FIXME: remove structure and derive SPIPaint from this class.
struct {
- SPPaintServerReference *href;
SPColor color;
} value;
+};
+
- SPIPaint();
- bool isSet() const { return true; /* set || colorSet*/}
+#define SP_STYLE_FILL_SERVER(s) ((const_cast<SPStyle *> (s))->getFillPaintServer())
+#define SP_STYLE_STROKE_SERVER(s) ((const_cast<SPStyle *> (s))->getStrokePaintServer())
+
+/// Paint type internal to SPStyle.
+class SPIPaint : public SPIBase {
+
+ public:
+ SPIPaint() : SPIBase( "anonymous_paint" ), currentcolor(false), colorSet(false), noneSet(false) {
+ value.href = NULL;
+ clear();
+ };
+ SPIPaint( Glib::ustring name )
+ : SPIBase( name ), currentcolor(false), colorSet(false), noneSet(false) {
+ value.href = NULL;
+ clear(); // Sets defaults
+ };
+ virtual ~SPIPaint(); // Clear and delete href.
+ virtual void read( gchar const *str );
+ virtual void read( gchar const *str, SPStyle &style, SPDocument *document = 0);
+ virtual const Glib::ustring write( guint const flags = SP_STYLE_FLAG_IFSET,
+ SPIBase const *const base = NULL ) const;
+ virtual void clear();
+ virtual void reset( bool init ); // Used internally when reading or cascading
+ virtual void cascade( const SPIBase* const parent );
+ virtual void merge( const SPIBase* const parent );
+
+ SPIPaint& operator=(const SPIPaint& rhs) {
+ SPIBase::operator=(rhs);
+ currentcolor = rhs.currentcolor;
+ colorSet = rhs.colorSet;
+ noneSet = rhs.noneSet;
+ value.color = rhs.value.color;
+ value.href = rhs.value.href;
+ return *this;
+ }
+
+ virtual bool operator==(const SPIBase& rhs);
+ virtual bool operator!=(const SPIBase& rhs) { return !(*this == rhs); };
+
bool isSameType( SPIPaint const & other ) const {return (isPaintserver() == other.isPaintserver()) && (colorSet == other.colorSet) && (currentcolor == other.currentcolor);}
bool isNoneSet() const {return noneSet;}
@@ -147,22 +496,24 @@ struct SPIPaint {
bool isColor() const {return colorSet && !isPaintserver();}
bool isPaintserver() const {return (value.href) ? value.href->getObject():0;}
- void clear();
-
void setColor( float r, float g, float b ) {value.color.set( r, g, b ); colorSet = true;}
void setColor( guint32 val ) {value.color.set( val ); colorSet = true;}
void setColor( SPColor const& color ) {value.color = color; colorSet = true;}
- void read( gchar const *str, SPStyle &tyle, SPDocument *document = 0);
-};
-class SPIDashArray {
- public:
- unsigned set : 1;
- unsigned inherit : 1;
- std::vector<double> values;
+
+ // To do: make private
+ public:
+ bool currentcolor : 1;
+ bool colorSet : 1;
+ bool noneSet : 1;
+ struct {
+ SPPaintServerReference *href;
+ SPColor color;
+ } value;
};
+
// SVG 2
enum SPPaintOrderLayer {
SP_CSS_PAINT_ORDER_NORMAL,
@@ -171,54 +522,225 @@ enum SPPaintOrderLayer {
SP_CSS_PAINT_ORDER_MARKER
};
+// Normal maybe should be moved out as is done in other classes.
+// This could be replaced by a generic enum class where multiple keywords are allowed and
+// where order matters (in contrast to 'text-decoration-line' where order does not matter).
+
+// Each layer represents a layer of paint which can be a fill, a stroke, or markers.
const size_t PAINT_ORDER_LAYERS = 3;
-struct SPIPaintOrder {
- unsigned set : 1;
- unsigned inherit : 1;
+
+/// Paint order type internal to SPStyle
+class SPIPaintOrder : public SPIBase {
+
+ public:
+ SPIPaintOrder() : SPIBase( "paint-order" ), value(NULL) { this->clear(); };
+ virtual ~SPIPaintOrder() { g_free( value ); };
+ virtual void read( gchar const *str );
+ virtual const Glib::ustring write( guint const flags = SP_STYLE_FLAG_IFSET,
+ SPIBase const *const base = NULL ) const;
+ virtual void clear() {
+ SPIBase::clear();
+ for( unsigned i = 0; i < PAINT_ORDER_LAYERS; ++i ) {
+ layer[i] = SP_CSS_PAINT_ORDER_NORMAL;
+ layer_set[i] = false;
+ }
+ g_free(value);
+ value = NULL;
+ }
+ virtual void cascade( const SPIBase* const parent );
+ virtual void merge( const SPIBase* const parent );
+
+ SPIPaintOrder& operator=(const SPIPaintOrder& rhs) {
+ SPIBase::operator=(rhs);
+ for( unsigned i = 0; i < PAINT_ORDER_LAYERS; ++i ) {
+ layer[i] = rhs.layer[i];
+ layer_set[i] = rhs.layer_set[i];
+ }
+ value = g_strdup(rhs.value);
+ return *this;
+ }
+
+ virtual bool operator==(const SPIBase& rhs);
+ virtual bool operator!=(const SPIBase& rhs) { return !(*this == rhs); };
+
+
+ // To do: make private
+ public:
SPPaintOrderLayer layer[PAINT_ORDER_LAYERS];
bool layer_set[PAINT_ORDER_LAYERS];
gchar *value; // Raw string
};
+
/// Filter type internal to SPStyle
-struct SPIFilter {
- unsigned set : 1;
- unsigned inherit : 1;
+class SPIDashArray : public SPIBase {
+
+ public:
+ SPIDashArray() : SPIBase( "stroke-dasharray" ) {}; // Only one instance of SPIDashArray
+ virtual ~SPIDashArray() {};
+ virtual void read( gchar const *str );
+ virtual const Glib::ustring write( guint const flags = SP_STYLE_FLAG_IFSET,
+ SPIBase const *const base = NULL ) const;
+ virtual void clear() { SPIBase::clear(); values.clear(); };
+ virtual void cascade( const SPIBase* const parent );
+ virtual void merge( const SPIBase* const parent );
+
+ SPIDashArray& operator=(const SPIDashArray& rhs) {
+ SPIBase::operator=(rhs);
+ values = rhs.values;
+ return *this;
+ }
+
+ virtual bool operator==(const SPIBase& rhs);
+ virtual bool operator!=(const SPIBase& rhs) { return !(*this == rhs); };
+
+
+ // To do: make private, change double to SVGLength
+ public:
+ std::vector<double> values;
+};
+
+/// Filter type internal to SPStyle
+class SPIFilter : public SPIBase {
+
+ public:
+ SPIFilter() : SPIBase( "filter", false ), href(NULL) {};
+ virtual ~SPIFilter();
+ virtual void read( gchar const *str );
+ virtual const Glib::ustring write( guint const flags = SP_STYLE_FLAG_IFSET,
+ SPIBase const *const base = NULL ) const;
+ virtual void clear();
+ virtual void cascade( const SPIBase* const parent );
+ virtual void merge( const SPIBase* const parent );
+
+ SPIFilter& operator=(const SPIFilter& rhs) {
+ SPIBase::operator=(rhs);
+ href = rhs.href;
+ return *this;
+ }
+
+ virtual bool operator==(const SPIBase& rhs);
+ virtual bool operator!=(const SPIBase& rhs) { return !(*this == rhs); };
+
+ // To do: make private
+ public:
SPFilterReference *href;
};
+
+
enum {
SP_FONT_SIZE_LITERAL,
SP_FONT_SIZE_LENGTH,
SP_FONT_SIZE_PERCENTAGE
};
-enum {
- SP_BASELINE_SHIFT_LITERAL,
- SP_BASELINE_SHIFT_LENGTH,
- SP_BASELINE_SHIFT_PERCENTAGE
-};
-
-
-#define SP_STYLE_FLAG_IFSET (1 << 0)
-#define SP_STYLE_FLAG_IFDIFF (1 << 1)
-#define SP_STYLE_FLAG_ALWAYS (1 << 2)
-
/// Fontsize type internal to SPStyle (also used by libnrtype/Layout-TNG-Input.cpp).
-struct SPIFontSize {
- unsigned set : 1;
- unsigned inherit : 1;
+class SPIFontSize : public SPIBase {
+
+ public:
+ SPIFontSize() : SPIBase( "font-size" ) { this->clear(); };
+ virtual ~SPIFontSize() {};
+ virtual void read( gchar const *str );
+ virtual const Glib::ustring write( guint const flags = SP_STYLE_FLAG_IFSET,
+ SPIBase const *const base = NULL ) const;
+ virtual void clear() { SPIBase::clear(); type = SP_FONT_SIZE_LITERAL, unit = SP_CSS_UNIT_NONE,
+ literal = SP_CSS_FONT_SIZE_MEDIUM, value = 12.0, computed = 12.0; }
+ virtual void cascade( const SPIBase* const parent );
+ virtual void merge( const SPIBase* const parent );
+
+ SPIFontSize& operator=(const SPIFontSize& rhs) {
+ SPIBase::operator=(rhs);
+ type = rhs.type;
+ unit = rhs.unit;
+ literal = rhs.literal;
+ value = rhs.value;
+ computed = rhs.computed;
+ return *this;
+ }
+
+ virtual bool operator==(const SPIBase& rhs);
+ virtual bool operator!=(const SPIBase& rhs) { return !(*this == rhs); };
+
+ public:
+ static float const font_size_default;
+
+ // To do: make private
+ public:
unsigned type : 2;
unsigned unit : 4;
- unsigned literal: 4;
+ unsigned literal : 4;
float value;
float computed;
+
+ private:
+ double relative_fraction() const;
+ static float const font_size_table[];
};
-/// Baseline shift type internal to SPStyle.
-struct SPIBaselineShift {
- unsigned set : 1;
- unsigned inherit : 1;
+
+/// Font type internal to SPStyle ('font' shorthand)
+class SPIFont : public SPIBase {
+
+ public:
+ SPIFont() : SPIBase( "font" ) {};
+ virtual ~SPIFont() {};
+ virtual void read( gchar const *str );
+ virtual const Glib::ustring write( guint const flags = SP_STYLE_FLAG_IFSET,
+ SPIBase const *const base = NULL ) const;
+ virtual void clear() {
+ SPIBase::clear();
+ };
+ virtual void cascade( const SPIBase* const parent ) {}; // Done in dependent properties
+ virtual void merge( const SPIBase* const parent ) {};
+
+ SPIFont& operator=(const SPIFont& rhs) {
+ SPIBase::operator=(rhs);
+ return *this;
+ }
+
+ virtual bool operator==(const SPIBase& rhs);
+ virtual bool operator!=(const SPIBase& rhs) { return !(*this == rhs); };
+};
+
+
+enum {
+ SP_BASELINE_SHIFT_LITERAL,
+ SP_BASELINE_SHIFT_LENGTH,
+ SP_BASELINE_SHIFT_PERCENTAGE
+};
+
+/// Baseline shift type internal to SPStyle. (This is actually just like SPIFontSize)
+class SPIBaselineShift : public SPIBase {
+
+ public:
+ SPIBaselineShift() : SPIBase( "baseline-shift", false ) { this->clear(); };
+ virtual ~SPIBaselineShift() {};
+ virtual void read( gchar const *str );
+ virtual const Glib::ustring write( guint const flags = SP_STYLE_FLAG_IFSET,
+ SPIBase const *const base = NULL ) const;
+ virtual void clear() { SPIBase::clear(); type=SP_BASELINE_SHIFT_LITERAL, unit=SP_CSS_UNIT_NONE,
+ literal = SP_CSS_BASELINE_SHIFT_BASELINE, value = 0.0, computed = 0.0; }
+ virtual void cascade( const SPIBase* const parent );
+ virtual void merge( const SPIBase* const parent );
+
+ SPIBaselineShift& operator=(const SPIBaselineShift& rhs) {
+ SPIBase::operator=(rhs);
+ type = rhs.type;
+ unit = rhs.unit;
+ literal = rhs.literal;
+ value = rhs.value;
+ computed = rhs.computed;
+ return *this;
+ }
+
+ // This is not used but we have it for completeness, it has not been tested.
+ virtual bool operator==(const SPIBase& rhs);
+ virtual bool operator!=(const SPIBase& rhs) { return !(*this == rhs); };
+ bool isZero() const;
+
+ // To do: make private
+ public:
unsigned type : 2;
unsigned unit : 4;
unsigned literal: 2;
@@ -227,38 +749,112 @@ struct SPIBaselineShift {
};
// CSS 2. Changes in CSS 3, where description is for TextDecorationLine, NOT TextDecoration
-/// Text decoration type internal to SPStyle.
-struct SPITextDecorationLine {
- unsigned set : 1;
- unsigned inherit : 1;
- unsigned underline : 1;
- unsigned overline : 1;
- unsigned line_through : 1;
- unsigned blink : 1; // "Conforming user agents are not required to support this value." yay!
+// See http://www.w3.org/TR/css-text-decor-3/
+
+// CSS3 2.2
+/// Text decoration line type internal to SPStyle. THIS SHOULD BE A GENERIC CLASS
+class SPITextDecorationLine : public SPIBase {
+
+ public:
+ SPITextDecorationLine() : SPIBase( "text-decoration-line" ) { this->clear(); };
+ virtual ~SPITextDecorationLine() {};
+ virtual void read( gchar const *str );
+ virtual const Glib::ustring write( guint const flags = SP_STYLE_FLAG_IFSET,
+ SPIBase const *const base = NULL ) const;
+ virtual void clear() { SPIBase::clear(); underline = false, overline = false, line_through = false, blink = false; }
+ virtual void cascade( const SPIBase* const parent );
+ virtual void merge( const SPIBase* const parent );
+
+ SPITextDecorationLine& operator=(const SPITextDecorationLine& rhs) {
+ SPIBase::operator=(rhs);
+ underline = rhs.underline;
+ overline = rhs.overline;
+ line_through = rhs.line_through;
+ blink = rhs.blink;
+ return *this;
+ }
+
+ virtual bool operator==(const SPIBase& rhs);
+ virtual bool operator!=(const SPIBase& rhs) { return !(*this == rhs); };
+
+ // To do: make private
+ public:
+ bool underline : 1;
+ bool overline : 1;
+ bool line_through : 1;
+ bool blink : 1; // "Conforming user agents are not required to support this value." yay!
};
// CSS3 2.2
-/// Text decoration style type internal to SPStyle.
-struct SPITextDecorationStyle {
- unsigned set : 1;
- unsigned inherit : 1;
- unsigned solid : 1;
- unsigned isdouble : 1; // cannot use "double" as it is a reserved keyword
- unsigned dotted : 1;
- unsigned dashed : 1;
- unsigned wavy : 1;
+/// Text decoration style type internal to SPStyle. THIS SHOULD JUST BE SPIEnum!
+class SPITextDecorationStyle : public SPIBase {
+
+ public:
+ SPITextDecorationStyle() : SPIBase( "text-decoration-style" ) { this->clear(); };
+ virtual ~SPITextDecorationStyle() {};
+ virtual void read( gchar const *str );
+ virtual const Glib::ustring write( guint const flags = SP_STYLE_FLAG_IFSET,
+ SPIBase const *const base = NULL ) const;
+ virtual void clear() { SPIBase::clear(); solid = true, isdouble = false, dotted = false, dashed = false, wavy = false; }
+ virtual void cascade( const SPIBase* const parent );
+ virtual void merge( const SPIBase* const parent );
+
+ SPITextDecorationStyle& operator=(const SPITextDecorationStyle& rhs) {
+ SPIBase::operator=(rhs);
+ solid = rhs.solid;
+ isdouble = rhs.isdouble;
+ dotted = rhs.dotted;
+ dashed = rhs.dashed;
+ wavy = rhs.wavy;
+ return *this;
+ }
+
+ virtual bool operator==(const SPIBase& rhs);
+ virtual bool operator!=(const SPIBase& rhs) { return !(*this == rhs); };
+
+ // To do: make private
+ public:
+ bool solid : 1;
+ bool isdouble : 1; // cannot use "double" as it is a reserved keyword
+ bool dotted : 1;
+ bool dashed : 1;
+ bool wavy : 1;
};
-/// Extended length type internal to SPStyle.
-struct SPILengthOrNormal {
- unsigned set : 1;
- unsigned inherit : 1;
- unsigned normal : 1;
- unsigned unit : 4;
- float value;
- float computed;
+
+
+// This class reads in both CSS2 and CSS3 'text-decoration' property. It passes the line, style,
+// and color parts to the appropriate CSS3 long-hand classes for reading and storing values. When
+// writing out data, we write all four properties, with 'text-decoration' being written out with
+// the CSS2 format. This allows CSS1/CSS2 renderers to at least render lines, even if they are not
+// the right style. (See http://www.w3.org/TR/css-text-decor-3/#text-decoration-property )
+
+/// Text decoration type internal to SPStyle.
+class SPITextDecoration: public SPIBase {
+
+ public:
+ SPITextDecoration() : SPIBase( "text-decoration" ) {};
+ virtual ~SPITextDecoration() {};
+ virtual void read( gchar const *str );
+ virtual const Glib::ustring write( guint const flags = SP_STYLE_FLAG_IFSET,
+ SPIBase const *const base = NULL ) const;
+ virtual void clear() {
+ SPIBase::clear();
+ };
+ virtual void cascade( const SPIBase* const parent ) {}; // Done in SPITextDecorationLine
+ virtual void merge( const SPIBase* const parent ) {}; // Done in SPITextDecorationLine
+
+ SPITextDecoration& operator=(const SPITextDecoration& rhs) {
+ SPIBase::operator=(rhs);
+ return *this;
+ }
+
+ // Use CSS2 value
+ virtual bool operator==(const SPIBase& rhs);
+ virtual bool operator!=(const SPIBase& rhs) { return !(*this == rhs); };
};
+
// These are used to implement text_decoration. The values are not saved to or read from SVG file
struct SPITextDecorationData {
float phase_length; // length along text line,used for phase for dot/dash/wavy
@@ -274,22 +870,6 @@ struct SPITextDecorationData {
float line_through_position;
};
-struct SPTextStyle;
-
-/// An SPTextStyle has a refcount, a font family, and a font name.
-struct SPTextStyle {
- int refcount;
-
- /* CSS font properties */
- SPIString font_family;
-
- /* Full font name, as font_factory::ConstructFontSpecification would give */
- SPIString font_specification;
-
- /** \todo fixme: The 'font' property is ugly, and not working (lauris) */
- SPIString font;
-};
-
#endif // SEEN_SP_STYLE_INTERNAL_H
diff --git a/src/style-test.h b/src/style-test.h
index c88c1c30a..2fe270336 100644
--- a/src/style-test.h
+++ b/src/style-test.h
@@ -48,6 +48,7 @@ public:
// ---------------------------------------------------------------
// ---------------------------------------------------------------
+ // Reading and writing style string
void testOne()
{
struct TestCase {
@@ -95,15 +96,33 @@ public:
TestCase("overflow:visible"), // SPIEnum
TestCase("overflow:auto"), // SPIEnum
- // Not directly read
+ TestCase("color:#ff0000"),
+ TestCase("color:blue", "color:#0000ff"),
+ // TestCase("color:currentColor"), SVG 1.1 does not allow color value 'currentColor'
+
+ // Font shorthand
TestCase("font:bold 12px Arial",
- "font-size:12px;font-style:normal;font-variant:normal;font-weight:bold;font-family:Arial"),
- // line-height not read in
- //TestCase("font:bold 12px/24px 'Times New Roman'",
- // "font-size:12px;font-style:normal;font-variant:normal;font-weight:bold;line-height:24px;font-family:Times New Roman"),
+ "font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:12px;line-height:normal;font-family:Arial"),
+ TestCase("font:bold 12px/24px 'Times New Roman'",
+ "font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:12px;line-height:24px;font-family:\'\"Times New Roman\"\'"),
+ // From CSS 3 Fonts (examples):
+ TestCase("font: 12pt/14pt sans-serif",
+ "font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:15px;line-height:14pt;font-family:sans-serif"),
+ TestCase("font: 80% sans-serif",
+ "font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:80.00000119%;line-height:normal;font-family:sans-serif"),
+ TestCase("font: x-large/110% 'new century schoolbook', serif",
+ "font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:x-large;line-height:110.00000238%;font-family:\'\"new century schoolbook\", serif\'"),
+ TestCase("font: bold italic large Palatino, serif",
+ "font-style:italic;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:large;line-height:normal;font-family:\'Palatino, serif\'"),
+ TestCase("font: normal small-caps 120%/120% fantasy",
+ "font-style:normal;font-variant:small-caps;font-weight:normal;font-stretch:normal;font-size:120.00000477%;line-height:120.00000477%;font-family:fantasy"),
+ TestCase("font: condensed oblique 12pt 'Helvetica Neue', serif;",
+ "font-style:oblique;font-variant:normal;font-weight:normal;font-stretch:condensed;font-size:15px;line-height:normal;font-family:\'\"Helvetica Neue\", serif\'"),
+
TestCase("font-family:sans-serif"), // SPIString, text_private
TestCase("font-family:Arial"),
TestCase("font-variant:normal;font-stretch:normal;-inkscape-font-specification:Nimbus Roman No9 L Bold Italic"),
+
// Needs to be fixed (quotes should be around each font-family):
TestCase("font-family:Georgia, 'Minion Web'","font-family:'Georgia, \"Minion Web\"'"),
TestCase("font-size:12", "font-size:12px"), // SPIFontSize
@@ -121,9 +140,31 @@ public:
// Should be moved down
TestCase("text-indent:12em"), // SPILength?
TestCase("text-align:center"), // SPIEnum
- TestCase("text-decoration: underline"), // SPITextDecoration
- TestCase("text-decoration: underline wavy #0000ff"), // SPITextDecoration CSS3
- TestCase("text-decoration: overline double #ff0000"),
+
+ // SPITextDecoration
+ // The default value for 'text-decoration-color' is 'currentColor', but
+ // we cannot set the default to that value yet. (We need to switch
+ // SPIPaint to SPIColor and then add the ability to set default.)
+ TestCase("text-decoration: underline",
+ "text-decoration: underline;text-decoration-line: underline;text-decoration-color:currentColor"),
+ TestCase("text-decoration: overline underline",
+ "text-decoration: underline overline;text-decoration-line: underline overline;text-decoration-color:currentColor"),
+
+ TestCase("text-decoration: underline wavy #0000ff",
+ "text-decoration: underline;text-decoration-line: underline;text-decoration-style:wavy;text-decoration-color:#0000ff"),
+ TestCase("text-decoration: double overline underline #ff0000",
+ "text-decoration: underline overline;text-decoration-line: underline overline;text-decoration-style:double;text-decoration-color:#ff0000"),
+
+ // SPITextDecorationLine
+ TestCase("text-decoration-line: underline",
+ "text-decoration: underline;text-decoration-line: underline"),
+
+ // SPITextDecorationStyle
+ TestCase("text-decoration-style:solid"),
+ TestCase("text-decoration-style:dotted"),
+
+ // SPITextDecorationColor
+ TestCase("text-decoration-color:#ff00ff"),
// Should be moved up
TestCase("line-height:24px"), // SPILengthOrNormal
@@ -166,11 +207,13 @@ public:
TestCase("paint-order:stroke"), // SPIPaintOrder
TestCase("paint-order:normal"),
TestCase("paint-order: markers stroke fill", "paint-order:markers stroke fill"),
+
#endif
TestCase(0)
};
for ( gint i = 0; cases[i].src; i++ ) {
+ // std::cout << "Test one: " << i << std::endl;
SPStyle *style = sp_style_new(_doc);
TS_ASSERT(style);
if ( style ) {
@@ -188,10 +231,10 @@ public:
gchar *str0_set = sp_style_write_string( style, SP_STYLE_FLAG_IFSET );
//printf("<<%s>>\n", str0_set);
if ( cases[i].dst ) {
- //std::cout << " " << std::string(str0_set) << " " << std::string(cases[i].dst) << std::endl;
+ // std::cout << " " << std::string(str0_set) << " " << std::string(cases[i].dst) << std::endl;
TS_ASSERT_EQUALS( std::string(str0_set), std::string(cases[i].dst) );
} else {
- //std::cout << " " << std::string(str0_set) << " " << std::string(cases[i].src) << std::endl;
+ // std::cout << " " << std::string(str0_set) << " " << std::string(cases[i].src) << std::endl;
TS_ASSERT_EQUALS( std::string(str0_set), std::string(cases[i].src) );
}
@@ -201,6 +244,273 @@ public:
}
}
+ // Testing operator==
+ void testTwo()
+ {
+ struct TestCase {
+ TestCase(gchar const* src, gchar const* dst, bool match) :
+ src(src), dst(dst), match(match) {}
+ gchar const* src;
+ gchar const* dst;
+ bool match;
+ };
+
+ TestCase cases[] = {
+
+ // SPIFloat
+ TestCase("stroke-miterlimit:4", "stroke-miterlimit:4", true ),
+ TestCase("stroke-miterlimit:4", "stroke-miterlimit:2", false),
+ TestCase("stroke-miterlimit:4", "", true ), // Default
+
+ // SPIScale24
+ TestCase("opacity:0.3", "opacity:0.3", true ),
+ TestCase("opacity:0.3", "opacity:0.6", false),
+ TestCase("opacity:1.0", "", true ), // Default
+
+ // SPILength
+ TestCase("text-indent:3", "text-indent:3", true ),
+ TestCase("text-indent:6", "text-indent:3", false),
+ TestCase("text-indent:6px", "text-indent:3", false),
+ TestCase("text-indent:1px", "text-indent:12pc", false),
+ TestCase("text-indent:2ex", "text-indent:2ex", false),
+
+ // SPILengthOrNormal
+ TestCase("letter-spacing:normal", "letter-spacing:normal", true ),
+ TestCase("letter-spacing:2", "letter-spacing:normal", false),
+ TestCase("letter-spacing:normal", "letter-spacing:2", false),
+ TestCase("letter-spacing:5px", "letter-spacing:5px", true ),
+ TestCase("letter-spacing:10px", "letter-spacing:5px", false),
+ TestCase("letter-spacing:10em", "letter-spacing:10em", false),
+
+ // SPIEnum
+ TestCase("text-anchor:start", "text-anchor:start", true ),
+ TestCase("text-anchor:start", "text-anchor:middle", false),
+ TestCase("text-anchor:start", "", true ), // Default
+ TestCase("text-anchor:start", "text-anchor:junk", true ), // Bad value
+
+ TestCase("font-weight:normal", "font-weight:400", true ),
+ TestCase("font-weight:bold", "font-weight:700", true ),
+
+
+ // SPIString and SPIFontString
+ TestCase("font-family:Arial", "font-family:Arial", true ),
+ TestCase("font-family:A B", "font-family:A B", true ),
+ TestCase("font-family:A B", "font-family:A C", false),
+ // Default is not set by class... value is NULL which cannot be compared
+ // TestCase("font-family:sans-serif", "", true ), // Default
+
+ // SPIColor
+ TestCase("color:blue", "color:blue", true ),
+ TestCase("color:blue", "color:red", false),
+ TestCase("color:red", "color:#ff0000", true ),
+
+ // SPIPaint
+ TestCase("fill:blue", "fill:blue", true ),
+ TestCase("fill:blue", "fill:red", false),
+ TestCase("fill:currentColor", "fill:currentColor", true ),
+ TestCase("fill:url(#xxx)", "fill:url(#xxx)", true ),
+ // Needs URL defined as in test 1
+ //TestCase("fill:url(#xxx)", "fill:url(#yyy)", false),
+
+ // SPIPaintOrder
+ TestCase("paint-order:markers", "paint-order:markers", true ),
+ TestCase("paint-order:markers", "paint-order:stroke", false),
+ //TestCase("paint-order:fill stroke markers", "", true ), // Default
+ TestCase("paint-order:normal", "paint-order:normal", true ),
+ //TestCase("paint-order:fill stroke markers", "paint-order:normal", true ),
+
+ // SPIDashArray
+ TestCase("stroke-dasharray:0 1 2 3","stroke-dasharray:0 1 2 3",true ),
+ TestCase("stroke-dasharray:0 1", "stroke-dasharray:0 2", false),
+
+ // SPIFilter
+
+ // SPIFontSize
+ TestCase("font-size:12px", "font-size:12px", true ),
+ TestCase("font-size:12px", "font-size:24px", false),
+ TestCase("font-size:12ex", "font-size:24ex", false),
+ TestCase("font-size:medium", "font-size:medium", true ),
+ TestCase("font-size:medium", "font-size:large", false),
+
+ // SPIBaselineShift
+ TestCase("baseline-shift:baseline", "baseline-shift:baseline", true ),
+ TestCase("baseline-shift:sub", "baseline-shift:sub", true ),
+ TestCase("baseline-shift:sub", "baseline-shift:super", false),
+ TestCase("baseline-shift:baseline", "baseline-shift:sub", false),
+ TestCase("baseline-shift:10px", "baseline-shift:10px", true ),
+ TestCase("baseline-shift:10px", "baseline-shift:12px", false),
+
+
+ // SPITextDecorationLine
+ TestCase("text-decoration-line:underline", "text-decoration-line:underline", true ),
+ TestCase("text-decoration-line:underline", "text-decoration-line:overline", false),
+ TestCase("text-decoration-line:underline overline", "text-decoration-line:underline overline", true ),
+ TestCase("text-decoration-line:none", "", true ), // Default
+
+
+ // SPITextDecorationStyle
+ TestCase("text-decoration-style:solid", "text-decoration-style:solid", true ),
+ TestCase("text-decoration-style:dotted", "text-decoration-style:solid", false),
+ TestCase("text-decoration-style:solid", "", true ), // Default
+
+ // SPITextDecoration
+ TestCase("text-decoration:underline", "text-decoration:underline", true ),
+ TestCase("text-decoration:underline", "text-decoration:overline", false),
+ TestCase("text-decoration:underline overline","text-decoration:underline overline",true ),
+ TestCase("text-decoration:overline underline","text-decoration:underline overline",true ),
+ TestCase("text-decoration:none", "text-decoration-color:currentColor", true ), // Default
+
+
+ // Terminate
+ TestCase(0,0,0)
+ };
+ for ( gint i = 0; cases[i].src; i++ ) {
+ // std::cout << "Test two: " << i << std::endl;
+ SPStyle *style_src = sp_style_new(_doc);
+ TS_ASSERT(style_src);
+ SPStyle *style_dst = sp_style_new(_doc);
+ TS_ASSERT(style_dst);
+
+ if ( style_src && style_dst ) {
+ sp_style_merge_from_style_string( style_src, cases[i].src );
+ sp_style_merge_from_style_string( style_dst, cases[i].dst );
+ // std::cout << "Test:" << std::endl;
+ // std::cout << " C: |" << cases[i].src << "| |" << cases[i].dst << "|" << std::endl;
+ // std::cout << " S: |" << style_src->write( SP_STYLE_FLAG_IFSET, NULL ) << "| |"
+ // << style_dst->write( SP_STYLE_FLAG_IFSET, NULL ) << "|" <<std::endl;
+ TS_ASSERT( (*style_src == *style_dst) == cases[i].match );
+ sp_style_unref(style_src);
+ sp_style_unref(style_dst);
+ // std::cout << "End Test\n" << std::endl;
+ }
+ }
+ }
+
+ // Test of cascade
+ void testThree()
+ {
+ struct TestCase {
+ TestCase(gchar const* parent, gchar const* child, gchar const* result) :
+ parent(parent), child(child), result(result) {}
+ gchar const* parent;
+ gchar const* child;
+ gchar const* result;
+ };
+
+ TestCase cases[] = {
+
+ // SPIFloat
+ TestCase("stroke-miterlimit:6", "stroke-miterlimit:2", "stroke-miterlimit:2" ),
+ TestCase("stroke-miterlimit:6", "", "stroke-miterlimit:6" ),
+ TestCase("", "stroke-miterlimit:2", "stroke-miterlimit:2" ),
+
+ // SPIScale24
+ TestCase("opacity:0.3", "opacity:0.3", "opacity:0.3" ),
+ TestCase("opacity:0.3", "opacity:0.6", "opacity:0.6" ),
+ // 'opacity' does not inherit
+ TestCase("opacity:0.3", "", "opacity:1.0" ),
+ TestCase("", "opacity:0.3", "opacity:0.3" ),
+ TestCase("opacity:0.5", "opacity:inherit", "opacity:0.5" ),
+ TestCase("", "", "opacity:1.0" ),
+
+ // SPILength
+ TestCase("text-indent:3", "text-indent:3", "text-indent:3" ),
+ TestCase("text-indent:6", "text-indent:3", "text-indent:3" ),
+ TestCase("text-indent:6px", "text-indent:3", "text-indent:3" ),
+ TestCase("text-indent:1px", "text-indent:12pc", "text-indent:12pc" ),
+ // ex, em cannot be equal
+ //TestCase("text-indent:2ex", "text-indent:2ex", "text-indent:2ex" ),
+ TestCase("text-indent:3", "", "text-indent:3" ),
+ TestCase("text-indent:3", "text-indent:inherit", "text-indent:3" ),
+
+ // SPILengthOrNormal
+ TestCase("letter-spacing:normal", "letter-spacing:normal", "letter-spacing:normal" ),
+ TestCase("letter-spacing:2", "letter-spacing:normal", "letter-spacing:normal" ),
+ TestCase("letter-spacing:normal", "letter-spacing:2", "letter-spacing:2" ),
+ TestCase("letter-spacing:5px", "letter-spacing:5px", "letter-spacing:5px" ),
+ TestCase("letter-spacing:10px", "letter-spacing:5px", "letter-spacing:5px" ),
+ // ex, em cannot be equal
+ // TestCase("letter-spacing:10em", "letter-spacing:10em", "letter-spacing:10em" ),
+
+ // SPIEnum
+ TestCase("text-anchor:start", "text-anchor:start", "text-anchor:start" ),
+ TestCase("text-anchor:start", "text-anchor:middle", "text-anchor:middle" ),
+ TestCase("text-anchor:start", "", "text-anchor:start" ),
+ TestCase("text-anchor:start", "text-anchor:junk", "text-anchor:start" ),
+ TestCase("text-anchor:end", "text-anchor:inherit", "text-anchor:end" ),
+
+ TestCase("font-weight:400", "font-weight:400", "font-weight:400" ),
+ TestCase("font-weight:400", "font-weight:700", "font-weight:700" ),
+ TestCase("font-weight:400", "font-weight:bolder", "font-weight:700" ),
+ TestCase("font-weight:700", "font-weight:bolder", "font-weight:900" ),
+ TestCase("font-weight:400", "font-weight:lighter", "font-weight:100" ),
+ TestCase("font-weight:200", "font-weight:lighter", "font-weight:100" ),
+
+ TestCase("font-stretch:condensed","font-stretch:expanded", "font-stretch:expanded" ),
+ TestCase("font-stretch:condensed","font-stretch:wider", "font-stretch:semi-condensed" ),
+
+ // SPIString and SPIFontString
+
+ // SPIPaint
+
+ // SPIPaintOrder
+
+ // SPIDashArray
+
+ // SPIFilter
+
+ // SPIFontSize
+
+ // SPIBaselineShift
+
+
+ // SPITextDecorationLine
+ TestCase("text-decoration-line:overline", "text-decoration-line:underline",
+ "text-decoration-line:underline" ),
+
+ // SPITextDecorationStyle
+
+ // SPITextDecoration
+
+ // Terminate
+ TestCase(0,0,0)
+ };
+ for ( gint i = 0; cases[i].parent; i++ ) {
+ // std::cout << "Test three: " << i << std::endl;
+ SPStyle *style_parent = sp_style_new(_doc);
+ TS_ASSERT(style_parent);
+ SPStyle *style_child = sp_style_new(_doc);
+ TS_ASSERT(style_child);
+ SPStyle *style_result = sp_style_new(_doc);
+ TS_ASSERT(style_result);
+
+ if ( style_parent && style_child && style_result ) {
+ sp_style_merge_from_style_string( style_parent, cases[i].parent );
+ sp_style_merge_from_style_string( style_child, cases[i].child );
+ sp_style_merge_from_style_string( style_result, cases[i].result );
+ // std::cout << "Test:" << std::endl;
+ // std::cout << " Input: ";
+ // std::cout << " Parent: " << cases[i].parent
+ // << " Child: " << cases[i].child
+ // << " Result: " << cases[i].result << std::endl;
+ // std::cout << " Write: ";
+ // std::cout << " Parent: " << style_parent->write( SP_STYLE_FLAG_IFSET )
+ // << " Child: " << style_child->write( SP_STYLE_FLAG_IFSET )
+ // << " Result: " << style_result->write( SP_STYLE_FLAG_IFSET ) << std::endl;
+
+ //sp_style_merge_from_parent( style_child, style_parent );
+ style_child->cascade( style_parent );
+
+ TS_ASSERT(*style_child == *style_result );
+
+ sp_style_unref(style_child);
+ sp_style_unref(style_parent);
+ sp_style_unref(style_result);
+ // std::cout << "End Test: *************\n" << std::endl;
+ }
+ }
+ }
+
};
diff --git a/src/style.cpp b/src/style.cpp
index bc869b127..11b1dc440 100644
--- a/src/style.cpp
+++ b/src/style.cpp
@@ -14,6 +14,7 @@
* Copyright (C) 2001 Ximian, Inc.
* Copyright (C) 2005 Monash University
* Copyright (C) 2012 Kris De Gussem
+ * Copyright (C) 2014 Tavmjong Bah
*
* Released under GNU GPL, read the file 'COPYING' for more information
*/
@@ -24,6 +25,7 @@
#include <cstring>
#include <string>
+#include <algorithm>
#include "libcroco/cr-sel-eng.h"
#include "xml/croco-node-iface.h"
@@ -65,925 +67,541 @@ using std::vector;
struct SPStyleEnum;
+int SPStyle::_count = 0;
+
/*#########################
## FORWARD DECLARATIONS
#########################*/
-static void sp_style_clear(SPStyle *style);
-
-static void sp_style_merge_property(SPStyle *style, gint id, gchar const *val);
-
-static void sp_style_merge_ipaint(SPStyle *style, SPIPaint *paint, SPIPaint const *parent);
-static void sp_style_merge_ifilter(SPStyle *style, SPIFilter const *parent);
-static void sp_style_read_dash(SPStyle *style, gchar const *str);
-
-static SPTextStyle *sp_text_style_new(void);
-static void sp_text_style_clear(SPTextStyle *ts);
-static SPTextStyle *sp_text_style_unref(SPTextStyle *st);
-static SPTextStyle *sp_text_style_duplicate_unset(SPTextStyle *st);
-static guint sp_text_style_write(gchar *p, guint len, SPTextStyle const *st, guint flags = SP_STYLE_FLAG_IFSET);
-static void sp_style_privatize_text(SPStyle *style);
-
-static void sp_style_read_ifloat(SPIFloat *val, gchar const *str);
-static void sp_style_read_iscale24(SPIScale24 *val, gchar const *str);
-static void sp_style_read_ienum(SPIEnum *val, gchar const *str, SPStyleEnum const *dict, bool can_explicitly_inherit);
-static void sp_style_read_istring(SPIString *val, gchar const *str);
-static void sp_style_read_ilength(SPILength *val, gchar const *str);
-static void sp_style_read_ilengthornormal(SPILengthOrNormal *val, gchar const *str);
-
-static void sp_style_read_ipaintorder(SPIPaintOrder *val, gchar const *str);
-
-static void sp_style_read_itextdecoration(SPITextDecorationLine *line, SPITextDecorationStyle *style, SPIPaint *color, gchar const *str);
-static void sp_style_read_itextdecorationLine(SPITextDecorationLine *line, gchar const *str);
-static void sp_style_read_itextdecorationStyle(SPITextDecorationStyle *style, gchar const *str);
-static void sp_style_read_itextdecorationColor(SPIPaint *color, gchar const *str);
-
-static void sp_style_read_icolor(SPIPaint *paint, gchar const *str, SPStyle *style, SPDocument *document);
-static void sp_style_read_ifontsize(SPIFontSize *val, gchar const *str);
-static void sp_style_read_ibaselineshift(SPIBaselineShift *val, gchar const *str);
-static void sp_style_read_ifilter(gchar const *str, SPStyle *style, SPDocument *document);
-
-static void sp_style_read_penum(SPIEnum *val, Inkscape::XML::Node *repr, gchar const *key, SPStyleEnum const *dict, bool can_explicitly_inherit);
-static void sp_style_read_plength(SPILength *val, Inkscape::XML::Node *repr, gchar const *key);
-static void sp_style_read_pfontsize(SPIFontSize *val, Inkscape::XML::Node *repr, gchar const *key);
-static void sp_style_read_pbaselineshift(SPIBaselineShift *val, Inkscape::XML::Node *repr, gchar const *key);
-static void sp_style_read_pfloat(SPIFloat *val, Inkscape::XML::Node *repr, gchar const *key);
-
-static gint sp_style_write_ifloat(gchar *p, gint len, gchar const *key, SPIFloat const *val, SPIFloat const *base, guint flags);
-static gint sp_style_write_iscale24(gchar *p, gint len, gchar const *key, SPIScale24 const *val, SPIScale24 const *base, guint flags);
-static gint sp_style_write_ienum(gchar *p, gint len, gchar const *key, SPStyleEnum const *dict, SPIEnum const *val, SPIEnum const *base, guint flags);
-static gint sp_style_write_istring(gchar *p, gint len, gchar const *key, SPIString const *val, SPIString const *base, guint flags);
-static gint sp_style_write_ilength(gchar *p, gint len, gchar const *key, SPILength const *val, SPILength const *base, guint flags);
-static gint sp_style_write_ipaint(gchar *b, gint len, gchar const *key, SPIPaint const *paint, SPIPaint const *base, guint flags);
-static gint sp_style_write_ipaintorder(gchar *p, gint len, gchar const *key, SPIPaintOrder const *paint_order, SPIPaintOrder const *base, guint flags);
-static gint sp_style_write_idasharray(gchar *p, gint const len, gchar const *const key, SPIDashArray const *const val, SPIDashArray const *const base, guint const flags);
-
-static gint sp_style_write_ifontsize(gchar *p, gint len, gchar const *key, SPIFontSize const *val, SPIFontSize const *base, guint flags);
-static gint sp_style_write_ibaselineshift(gchar *p, gint len, gchar const *key, SPIBaselineShift const *val, SPIBaselineShift const *base, guint flags);
-static gint sp_style_write_ilengthornormal(gchar *p, gint const len, gchar const *const key, SPILengthOrNormal const *const val, SPILengthOrNormal const *const base, guint const flags);
-static gint sp_style_write_itextdecoration(gchar *p, gint const len, gchar const *const key,
- SPITextDecorationLine const *const line,
- SPITextDecorationStyle const *const style,
- SPIPaint const *const color,
- SPITextDecorationLine const *const baseLine,
- SPITextDecorationStyle const *const baseStyle,
- SPIPaint const *const baseColor,
- guint const flags);
-static gint sp_style_write_ifilter(gchar *b, gint len, gchar const *key, SPIFilter const *filter, SPIFilter const *base, guint flags);
-
-static void sp_style_filter_clear(SPStyle *style);
-
-#define SPS_READ_IENUM_IF_UNSET(v,s,d,i) if (!(v)->set) {sp_style_read_ienum((v), (s), (d), (i));}
-#define SPS_READ_PENUM_IF_UNSET(v,r,k,d,i) if (!(v)->set) {sp_style_read_penum((v), (r), (k), (d), (i));}
-
-#define SPS_READ_ILENGTH_IF_UNSET(v,s) if (!(v)->set) {sp_style_read_ilength((v), (s));}
-#define SPS_READ_PLENGTH_IF_UNSET(v,r,k) if (!(v)->set) {sp_style_read_plength((v), (r), (k));}
-
-#define SPS_READ_PFLOAT_IF_UNSET(v,r,k) if (!(v)->set) {sp_style_read_pfloat((v), (r), (k));}
-
-#define SPS_READ_IFONTSIZE_IF_UNSET(v,s) if (!(v)->set) {sp_style_read_ifontsize((v), (s));}
-#define SPS_READ_PFONTSIZE_IF_UNSET(v,r,k) if (!(v)->set) {sp_style_read_pfontsize((v), (r), (k));}
-
-#define SPS_READ_IBASELINE_SHIFT_IF_UNSET(v,s) if (!(v)->set) {sp_style_read_ibaselineshift((v), (s));}
-#define SPS_READ_PBASELINE_SHIFT_IF_UNSET(v,r,k) if (!(v)->set) {sp_style_read_pbaselineshift((v), (r), (k));}
-
-static void sp_style_merge_from_object_stylesheet(SPStyle *, SPObject const *);
-
-struct SPStyleEnum {
- gchar const *key;
- gint value;
-};
-
-static SPStyleEnum const enum_fill_rule[] = {
- {"nonzero", SP_WIND_RULE_NONZERO},
- {"evenodd", SP_WIND_RULE_EVENODD},
- {NULL, -1}
-};
-
-static SPStyleEnum const enum_stroke_linecap[] = {
- {"butt", SP_STROKE_LINECAP_BUTT},
- {"round", SP_STROKE_LINECAP_ROUND},
- {"square", SP_STROKE_LINECAP_SQUARE},
- {NULL, -1}
-};
-
-static SPStyleEnum const enum_stroke_linejoin[] = {
- {"miter", SP_STROKE_LINEJOIN_MITER},
- {"round", SP_STROKE_LINEJOIN_ROUND},
- {"bevel", SP_STROKE_LINEJOIN_BEVEL},
- {NULL, -1}
-};
-
-static SPStyleEnum const enum_font_style[] = {
- {"normal", SP_CSS_FONT_STYLE_NORMAL},
- {"italic", SP_CSS_FONT_STYLE_ITALIC},
- {"oblique", SP_CSS_FONT_STYLE_OBLIQUE},
- {NULL, -1}
-};
-
-static SPStyleEnum const enum_font_size[] = {
- {"xx-small", SP_CSS_FONT_SIZE_XX_SMALL},
- {"x-small", SP_CSS_FONT_SIZE_X_SMALL},
- {"small", SP_CSS_FONT_SIZE_SMALL},
- {"medium", SP_CSS_FONT_SIZE_MEDIUM},
- {"large", SP_CSS_FONT_SIZE_LARGE},
- {"x-large", SP_CSS_FONT_SIZE_X_LARGE},
- {"xx-large", SP_CSS_FONT_SIZE_XX_LARGE},
- {"smaller", SP_CSS_FONT_SIZE_SMALLER},
- {"larger", SP_CSS_FONT_SIZE_LARGER},
- {NULL, -1}
-};
-
-static SPStyleEnum const enum_font_variant[] = {
- {"normal", SP_CSS_FONT_VARIANT_NORMAL},
- {"small-caps", SP_CSS_FONT_VARIANT_SMALL_CAPS},
- {NULL, -1}
-};
-
-static SPStyleEnum const enum_font_weight[] = {
- {"100", SP_CSS_FONT_WEIGHT_100},
- {"200", SP_CSS_FONT_WEIGHT_200},
- {"300", SP_CSS_FONT_WEIGHT_300},
- {"400", SP_CSS_FONT_WEIGHT_400},
- {"500", SP_CSS_FONT_WEIGHT_500},
- {"600", SP_CSS_FONT_WEIGHT_600},
- {"700", SP_CSS_FONT_WEIGHT_700},
- {"800", SP_CSS_FONT_WEIGHT_800},
- {"900", SP_CSS_FONT_WEIGHT_900},
- {"normal", SP_CSS_FONT_WEIGHT_NORMAL},
- {"bold", SP_CSS_FONT_WEIGHT_BOLD},
- {"lighter", SP_CSS_FONT_WEIGHT_LIGHTER},
- {"bolder", SP_CSS_FONT_WEIGHT_BOLDER},
- {NULL, -1}
-};
-
-static SPStyleEnum const enum_font_stretch[] = {
- {"ultra-condensed", SP_CSS_FONT_STRETCH_ULTRA_CONDENSED},
- {"extra-condensed", SP_CSS_FONT_STRETCH_EXTRA_CONDENSED},
- {"condensed", SP_CSS_FONT_STRETCH_CONDENSED},
- {"semi-condensed", SP_CSS_FONT_STRETCH_SEMI_CONDENSED},
- {"normal", SP_CSS_FONT_STRETCH_NORMAL},
- {"semi-expanded", SP_CSS_FONT_STRETCH_SEMI_EXPANDED},
- {"expanded", SP_CSS_FONT_STRETCH_EXPANDED},
- {"extra-expanded", SP_CSS_FONT_STRETCH_EXTRA_EXPANDED},
- {"ultra-expanded", SP_CSS_FONT_STRETCH_ULTRA_EXPANDED},
- {"narrower", SP_CSS_FONT_STRETCH_NARROWER},
- {"wider", SP_CSS_FONT_STRETCH_WIDER},
- {NULL, -1}
-};
-
-static SPStyleEnum const enum_text_align[] = {
- {"start", SP_CSS_TEXT_ALIGN_START},
- {"end", SP_CSS_TEXT_ALIGN_END},
- {"left", SP_CSS_TEXT_ALIGN_LEFT},
- {"right", SP_CSS_TEXT_ALIGN_RIGHT},
- {"center", SP_CSS_TEXT_ALIGN_CENTER},
- {"justify", SP_CSS_TEXT_ALIGN_JUSTIFY},
- {NULL, -1}
-};
-
-static SPStyleEnum const enum_text_transform[] = {
- {"capitalize", SP_CSS_TEXT_TRANSFORM_CAPITALIZE},
- {"uppercase", SP_CSS_TEXT_TRANSFORM_UPPERCASE},
- {"lowercase", SP_CSS_TEXT_TRANSFORM_LOWERCASE},
- {"none", SP_CSS_TEXT_TRANSFORM_NONE},
- {NULL, -1}
-};
-
-static SPStyleEnum const enum_text_anchor[] = {
- {"start", SP_CSS_TEXT_ANCHOR_START},
- {"middle", SP_CSS_TEXT_ANCHOR_MIDDLE},
- {"end", SP_CSS_TEXT_ANCHOR_END},
- {NULL, -1}
-};
-
-static SPStyleEnum const enum_direction[] = {
- {"ltr", SP_CSS_DIRECTION_LTR},
- {"rtl", SP_CSS_DIRECTION_RTL},
- {NULL, -1}
-};
-
-static SPStyleEnum const enum_block_progression[] = {
- {"tb", SP_CSS_BLOCK_PROGRESSION_TB},
- {"rl", SP_CSS_BLOCK_PROGRESSION_RL},
- {"lr", SP_CSS_BLOCK_PROGRESSION_LR},
- {NULL, -1}
-};
-
-static SPStyleEnum const enum_writing_mode[] = {
- /* Note that using the same enumerator for lr as lr-tb means we write as lr-tb even if the
- * input file said lr. We prefer writing lr-tb on the grounds that the spec says the initial
- * value is lr-tb rather than lr.
- *
- * ECMA scripts may be surprised to find tb-rl in DOM if they set the attribute to rl, so
- * sharing enumerators for different strings may be a bug (once we support ecma script).
- */
- {"lr-tb", SP_CSS_WRITING_MODE_LR_TB},
- {"rl-tb", SP_CSS_WRITING_MODE_RL_TB},
- {"tb-rl", SP_CSS_WRITING_MODE_TB_RL},
- {"lr", SP_CSS_WRITING_MODE_LR_TB},
- {"rl", SP_CSS_WRITING_MODE_RL_TB},
- {"tb", SP_CSS_WRITING_MODE_TB_RL},
- {NULL, -1}
-};
-
-static SPStyleEnum const enum_baseline_shift[] = {
- {"baseline", SP_CSS_BASELINE_SHIFT_BASELINE},
- {"sub", SP_CSS_BASELINE_SHIFT_SUB},
- {"super", SP_CSS_BASELINE_SHIFT_SUPER},
- {NULL, -1}
-};
-
-static SPStyleEnum const enum_visibility[] = {
- {"hidden", SP_CSS_VISIBILITY_HIDDEN},
- {"collapse", SP_CSS_VISIBILITY_COLLAPSE},
- {"visible", SP_CSS_VISIBILITY_VISIBLE},
- {NULL, -1}
-};
-
-static SPStyleEnum const enum_overflow[] = {
- {"visible", SP_CSS_OVERFLOW_VISIBLE},
- {"hidden", SP_CSS_OVERFLOW_HIDDEN},
- {"scroll", SP_CSS_OVERFLOW_SCROLL},
- {"auto", SP_CSS_OVERFLOW_AUTO},
- {NULL, -1}
-};
-
-// CSS Compositing and Blending Level 1
-static SPStyleEnum const enum_isolation[] = {
- {"auto", SP_CSS_ISOLATION_AUTO},
- {"isolate", SP_CSS_ISOLATION_ISOLATE},
- {NULL, -1}
-};
-
-static SPStyleEnum const enum_blend_mode[] = {
- {"normal", SP_CSS_BLEND_NORMAL},
- {"multiply", SP_CSS_BLEND_MULTIPLY},
- {"screen", SP_CSS_BLEND_SCREEN},
- {"darken", SP_CSS_BLEND_DARKEN},
- {"lighten", SP_CSS_BLEND_LIGHTEN},
- {"overlay", SP_CSS_BLEND_OVERLAY},
- {"color-dodge", SP_CSS_BLEND_COLORDODGE},
- {"color-burn", SP_CSS_BLEND_COLORBURN},
- {"hard-light", SP_CSS_BLEND_HARDLIGHT},
- {"soft-light", SP_CSS_BLEND_SOFTLIGHT},
- {"difference", SP_CSS_BLEND_DIFFERENCE},
- {"exclusion", SP_CSS_BLEND_EXCLUSION},
- {"hue", SP_CSS_BLEND_HUE},
- {"saturation", SP_CSS_BLEND_SATURATION},
- {"color", SP_CSS_BLEND_COLOR},
- {"luminosity", SP_CSS_BLEND_LUMINOSITY},
- {NULL, -1}
-};
-
-static SPStyleEnum const enum_display[] = {
- {"none", SP_CSS_DISPLAY_NONE},
- {"inline", SP_CSS_DISPLAY_INLINE},
- {"block", SP_CSS_DISPLAY_BLOCK},
- {"list-item", SP_CSS_DISPLAY_LIST_ITEM},
- {"run-in", SP_CSS_DISPLAY_RUN_IN},
- {"compact", SP_CSS_DISPLAY_COMPACT},
- {"marker", SP_CSS_DISPLAY_MARKER},
- {"table", SP_CSS_DISPLAY_TABLE},
- {"inline-table", SP_CSS_DISPLAY_INLINE_TABLE},
- {"table-row-group", SP_CSS_DISPLAY_TABLE_ROW_GROUP},
- {"table-header-group", SP_CSS_DISPLAY_TABLE_HEADER_GROUP},
- {"table-footer-group", SP_CSS_DISPLAY_TABLE_FOOTER_GROUP},
- {"table-row", SP_CSS_DISPLAY_TABLE_ROW},
- {"table-column-group", SP_CSS_DISPLAY_TABLE_COLUMN_GROUP},
- {"table-column", SP_CSS_DISPLAY_TABLE_COLUMN},
- {"table-cell", SP_CSS_DISPLAY_TABLE_CELL},
- {"table-caption", SP_CSS_DISPLAY_TABLE_CAPTION},
- {NULL, -1}
-};
-
-static SPStyleEnum const enum_shape_rendering[] = {
- {"auto", SP_CSS_SHAPE_RENDERING_AUTO},
- {"optimizeSpeed", SP_CSS_SHAPE_RENDERING_OPTIMIZESPEED},
- {"crispEdges", SP_CSS_SHAPE_RENDERING_CRISPEDGES},
- {"geometricPrecision", SP_CSS_SHAPE_RENDERING_GEOMETRICPRECISION},
- {NULL, -1}
-};
-
-static SPStyleEnum const enum_color_rendering[] = {
- {"auto", SP_CSS_COLOR_RENDERING_AUTO},
- {"optimizeSpeed", SP_CSS_COLOR_RENDERING_OPTIMIZESPEED},
- {"optimizeQuality", SP_CSS_COLOR_RENDERING_OPTIMIZEQUALITY},
- {NULL, -1}
-};
-
-static SPStyleEnum const enum_image_rendering[] = {
- {"auto", SP_CSS_IMAGE_RENDERING_AUTO},
- {"optimizeSpeed", SP_CSS_IMAGE_RENDERING_OPTIMIZESPEED},
- {"optimizeQuality", SP_CSS_IMAGE_RENDERING_OPTIMIZEQUALITY},
- {"-inkscape-crisp-edges", SP_CSS_IMAGE_RENDERING_CRISPEDGES},
- {"-inkscape-pixelated", SP_CSS_IMAGE_RENDERING_PIXELATED},
- {NULL, -1}
-};
-
-static SPStyleEnum const enum_text_rendering[] = {
- {"auto", SP_CSS_TEXT_RENDERING_AUTO},
- {"optimizeSpeed", SP_CSS_TEXT_RENDERING_OPTIMIZESPEED},
- {"optimizeLegibility", SP_CSS_TEXT_RENDERING_OPTIMIZELEGIBILITY},
- {"geometricPrecision", SP_CSS_TEXT_RENDERING_GEOMETRICPRECISION},
- {NULL, -1}
-};
-
-static SPStyleEnum const enum_enable_background[] = {
- {"accumulate", SP_CSS_BACKGROUND_ACCUMULATE},
- {"new", SP_CSS_BACKGROUND_NEW},
- {NULL, -1}
-};
-
-static SPStyleEnum const enum_clip_rule[] = {
- {"nonzero", SP_WIND_RULE_NONZERO},
- {"evenodd", SP_WIND_RULE_EVENODD},
- {NULL, -1}
-};
-
-static SPStyleEnum const enum_color_interpolation[] = {
- {"auto", SP_CSS_COLOR_INTERPOLATION_AUTO},
- {"sRGB", SP_CSS_COLOR_INTERPOLATION_SRGB},
- {"linearRGB", SP_CSS_COLOR_INTERPOLATION_LINEARRGB},
- {NULL, -1}
-};
+void sp_style_filter_ref_changed(SPObject *old_ref, SPObject *ref, SPStyle *style);
+void sp_style_fill_paint_server_ref_changed(SPObject *old_ref, SPObject *ref, SPStyle *style);
+void sp_style_stroke_paint_server_ref_changed(SPObject *old_ref, SPObject *ref, SPStyle *style);
+
+static void sp_style_object_release(SPObject *object, SPStyle *style);
+static CRSelEng *sp_repr_sel_eng();
+
+
+//SPPropMap SPStyle::_propmap;
+
+// C++11 allows one constructor to call another... might be useful. The original C code
+// had separate calls to create SPStyle, one with only SPDocument and the other with only
+// SPObject as parameters.
+SPStyle::SPStyle(SPDocument *document_in, SPObject *object_in) :
+
+ // Unimplemented SVG 1.1: alignment-baseline, clip, clip-path, color-profile, cursor,
+ // dominant-baseline, flood-color, flood-opacity, font-size-adjust,
+ // glyph-orientation-horizontal, glyph-orientation-vertical, kerning, lighting-color,
+ // pointer-events, stop-color, stop-opacity, unicode-bidi
+
+ // For enums: property( name, enumeration, default value , inherits = true );
+ // For scale24: property( name, default value = 0, inherits = true );
+
+ // 'font', 'font-size', and 'font-family' must come first as other properties depend on them
+ // for calculated values (through 'em' and 'ex'). ('ex' is currently not read.)
+ // The following properties can depend on 'em' and 'ex':
+ // baseline-shift, kerning, letter-spacing, stroke-dash-offset, stroke-width, word-spacing,
+ // Non-SVG 1.1: text-indent, line-spacing
+
+ // Hidden in SPIFontStyle: (to be refactored)
+ // font-family
+ // font-specification
+
+ // Font related properties and 'font' shorthand
+ font_style( "font-style", enum_font_style, SP_CSS_FONT_STYLE_NORMAL ),
+ font_variant( "font-variant", enum_font_variant, SP_CSS_FONT_VARIANT_NORMAL ),
+ font_weight( "font-weight", enum_font_weight, SP_CSS_FONT_WEIGHT_NORMAL, SP_CSS_FONT_WEIGHT_400 ),
+ font_stretch( "font-stretch", enum_font_stretch, SP_CSS_FONT_STRETCH_NORMAL ),
+ font_size(),
+ line_height( "line-height", 1.0 ), // SPILengthOrNormal
+ font_family( "font-family", "sans-serif" ), // SPIString w/default
+ font(), // SPIFont
+ font_specification( "-inkscape-font-specification" ), // SPIString
+
+ // Text related properties
+ text_indent( "text-indent", 0.0 ), // SPILength
+ text_align( "text-align", enum_text_align, SP_CSS_TEXT_ALIGN_START ),
+ text_decoration(),
+ text_decoration_line(),
+ text_decoration_style(),
+ text_decoration_color( "text-decoration-color" ), // SPIColor
+
+ letter_spacing( "letter-spacing", 0.0 ), // SPILengthOrNormal
+ word_spacing( "word-spacing", 0.0 ), // SPILengthOrNormal
+ text_transform( "text-transform", enum_text_transform, SP_CSS_TEXT_TRANSFORM_NONE ),
+
+ direction( "direction", enum_direction, SP_CSS_DIRECTION_LTR ),
+ block_progression("block-progression", enum_block_progression, SP_CSS_BLOCK_PROGRESSION_TB),
+ writing_mode( "writing-mode", enum_writing_mode, SP_CSS_WRITING_MODE_LR_TB ),
+ baseline_shift(),
+ text_anchor( "text-anchor", enum_text_anchor, SP_CSS_TEXT_ANCHOR_START ),
+
+ // General visual properties
+ clip_rule( "clip-rule", enum_clip_rule, SP_WIND_RULE_NONZERO ),
+ display( "display", enum_display, SP_CSS_DISPLAY_INLINE, false ),
+ overflow( "overflow", enum_overflow, SP_CSS_OVERFLOW_VISIBLE, false ),
+ visibility( "visibility", enum_visibility, SP_CSS_VISIBILITY_VISIBLE ),
+ opacity( "opacity", SP_SCALE24_MAX, false ),
+
+ isolation( "isolation", enum_isolation, SP_CSS_ISOLATION_AUTO ),
+ blend_mode( "blend_mode", enum_blend_mode, SP_CSS_BLEND_NORMAL ),
+
+ paint_order(), // SPIPaintOrder
+
+ // Color properties
+ color( "color" ), // SPIColor
+ color_interpolation( "color-interpolation", enum_color_interpolation, SP_CSS_COLOR_INTERPOLATION_SRGB),
+ color_interpolation_filters("color-interpolation-filters", enum_color_interpolation, SP_CSS_COLOR_INTERPOLATION_LINEARRGB),
+
+ // Fill properties
+ fill( "fill" ), // SPIPaint
+ fill_opacity( "fill-opacity", SP_SCALE24_MAX ),
+ fill_rule( "fill-rule", enum_fill_rule, SP_WIND_RULE_NONZERO ),
+
+ // Stroke properites
+ stroke( "stroke" ), // SPIPaint
+ stroke_width( "stroke-width", 1.0 ), // SPILength
+ stroke_linecap( "stroke-linecap", enum_stroke_linecap, SP_STROKE_LINECAP_BUTT ),
+ stroke_linejoin( "stroke-linejoin", enum_stroke_linejoin, SP_STROKE_LINEJOIN_MITER ),
+ stroke_miterlimit("stroke-miterlimit", 4 ), // SPIFloat (only use of float!)
+ stroke_dasharray(), // SPIDashArray
+ stroke_dashoffset("stroke-dashoffset", 0.0 ), // SPILength for now
+
+ stroke_opacity( "stroke-opacity", SP_SCALE24_MAX ),
+
+ marker( "marker" ), // SPIString
+ marker_start( "marker-start" ), // SPIString
+ marker_mid( "marker-mid" ), // SPIString
+ marker_end( "marker-end" ), // SPIString
+
+ // Filter properties
+ filter(),
+ filter_blend_mode("filter-blend-mode", enum_blend_mode, SP_CSS_BLEND_NORMAL),
+ filter_gaussianBlur_deviation( "filter-gaussianBlur-deviation", 0.0 ), // SPILength
+ enable_background("enable-background", enum_enable_background, SP_CSS_BACKGROUND_ACCUMULATE, false),
+
+ // Rendering hint properties
+ color_rendering( "color-rendering", enum_color_rendering, SP_CSS_COLOR_RENDERING_AUTO),
+ image_rendering( "image-rendering", enum_image_rendering, SP_CSS_IMAGE_RENDERING_AUTO),
+ shape_rendering( "shape-rendering", enum_shape_rendering, SP_CSS_SHAPE_RENDERING_AUTO),
+ text_rendering( "text-rendering", enum_text_rendering, SP_CSS_TEXT_RENDERING_AUTO )
+
+{
+ // std::cout << "SPStyle::SPStyle( SPDocument ): Entrance: (" << _count << ")" << std::endl;
+ // std::cout << " Document: " << (document_in?"present":"null") << std::endl;
+ // std::cout << " Object: "
+ // << (object_in?(object_in->getId()?object_in->getId():"id null"):"object null") << std::endl;
+
+ // static bool first = true;
+ // if( first ) {
+ // std::cout << "Size of SPStyle: " << sizeof(SPStyle) << std::endl;
+ // std::cout << " SPIBase: " << sizeof(SPIBase) << std::endl;
+ // std::cout << " SPIFloat: " << sizeof(SPIFloat) << std::endl;
+ // std::cout << " SPIScale24: " << sizeof(SPIScale24) << std::endl;
+ // std::cout << " SPILength: " << sizeof(SPILength) << std::endl;
+ // std::cout << " SPILengthOrNormal: " << sizeof(SPILengthOrNormal) << std::endl;
+ // std::cout << " SPIColor: " << sizeof(SPIColor) << std::endl;
+ // std::cout << " SPIPaint: " << sizeof(SPIPaint) << std::endl;
+ // std::cout << " SPITextDecorationLine" << sizeof(SPITextDecorationLine) << std::endl;
+ // std::cout << " Glib::ustring:" << sizeof(Glib::ustring) << std::endl;
+ // std::cout << " SPColor: " << sizeof(SPColor) << std::endl;
+ // first = false;
+ // }
+
+ ++_count; // Poor man's memory leak detector
+
+ _refcount = 1;
+
+ cloned = false;
+
+ object = object_in;
+ if( object ) {
+ g_assert( SP_IS_OBJECT(object) );
+ document = object->document;
+ release_connection =
+ object->connectRelease(sigc::bind<1>(sigc::ptr_fun(&sp_style_object_release), this));
+
+ cloned = object->cloned;
-/**
- * Release callback.
- */
-static void
-sp_style_object_release(SPObject *object, SPStyle *style)
-{
- (void)object; // TODO
- style->object = NULL;
-}
+ } else {
+ document = document_in;
+ }
+
+ new (&release_connection) sigc::connection();
+ new (&filter_modified_connection) sigc::connection();
+ new (&fill_ps_modified_connection) sigc::connection();
+ new (&stroke_ps_modified_connection) sigc::connection();
+
+ // 'font' shorthand requires access to included properties.
+ font.setStylePointer( this );
+
+ // Properties that depend on 'font-size' for calculating lengths.
+ baseline_shift.setStylePointer( this );
+ text_indent.setStylePointer( this );
+ line_height.setStylePointer( this );
+ letter_spacing.setStylePointer( this );
+ word_spacing.setStylePointer( this );
+ stroke_width.setStylePointer( this );
+ stroke_dashoffset.setStylePointer( this );
+
+ // Properties that depend on 'color'
+ text_decoration_color.setStylePointer( this );
+ fill.setStylePointer( this );
+ stroke.setStylePointer( this );
+ // color.setStylePointer( this ); // Doen't need reference to self
+
+ // 'text_decoration' shorthand requires access to included properties.
+ text_decoration.setStylePointer( this );
+
+ // SPIPaint, SPIFilter needs access to 'this' (SPStyle)
+ // for setting up signals... 'fill', 'stroke' already done
+ filter.setStylePointer( this );
+
+ // Used to iterate over markers
+ marker_ptrs[SP_MARKER_LOC] = &marker;
+ marker_ptrs[SP_MARKER_LOC_START] = &marker_start;
+ marker_ptrs[SP_MARKER_LOC_MID] = &marker_mid;
+ marker_ptrs[SP_MARKER_LOC_END] = &marker_end;
+
+
+ // This might be too resource hungary... but for now it possible to loop over properties
+
+ // 'color' must be before 'fill', 'stroke', 'text-decoration-color', ...
+ _properties.push_back( &color );
+
+ // 'font-size'/'font' must be before properties that need to know em, ex size (SPILength,
+ // SPILenghtOrNormal)
+ _properties.push_back( &font_style );
+ _properties.push_back( &font_variant );
+ _properties.push_back( &font_weight );
+ _properties.push_back( &font_stretch );
+ _properties.push_back( &font_size );
+ _properties.push_back( &line_height );
+ _properties.push_back( &font_family );
+ _properties.push_back( &font );
+ _properties.push_back( &font_specification );
+
+ _properties.push_back( &text_indent );
+ _properties.push_back( &text_align );
+
+ _properties.push_back( &text_decoration );
+ _properties.push_back( &text_decoration_line );
+ _properties.push_back( &text_decoration_style );
+ _properties.push_back( &text_decoration_color );
+
+ _properties.push_back( &letter_spacing );
+ _properties.push_back( &word_spacing );
+ _properties.push_back( &text_transform );
+
+ _properties.push_back( &direction );
+ _properties.push_back( &block_progression );
+ _properties.push_back( &writing_mode );
+ _properties.push_back( &baseline_shift );
+ _properties.push_back( &text_anchor );
+
+ _properties.push_back( &clip_rule );
+ _properties.push_back( &display );
+ _properties.push_back( &overflow );
+ _properties.push_back( &visibility );
+ _properties.push_back( &opacity );
+
+ _properties.push_back( &isolation );
+ _properties.push_back( &blend_mode );
+
+ _properties.push_back( &color_interpolation );
+ _properties.push_back( &color_interpolation_filters );
+
+ _properties.push_back( &fill );
+ _properties.push_back( &fill_opacity );
+ _properties.push_back( &fill_rule );
+
+ _properties.push_back( &stroke );
+ _properties.push_back( &stroke_width );
+ _properties.push_back( &stroke_linecap );
+ _properties.push_back( &stroke_linejoin );
+ _properties.push_back( &stroke_miterlimit );
+ _properties.push_back( &stroke_dasharray );
+ _properties.push_back( &stroke_dashoffset );
+ _properties.push_back( &stroke_opacity );
+
+ _properties.push_back( &marker );
+ _properties.push_back( &marker_start );
+ _properties.push_back( &marker_mid );
+ _properties.push_back( &marker_end );
+
+ _properties.push_back( &paint_order );
+
+ _properties.push_back( &filter );
+ _properties.push_back( &filter_blend_mode );
+ _properties.push_back( &filter_gaussianBlur_deviation );
+
+ _properties.push_back( &color_rendering );
+ _properties.push_back( &image_rendering );
+ _properties.push_back( &shape_rendering );
+ _properties.push_back( &text_rendering );
+
+ _properties.push_back( &enable_background );
-/**
- * Emit style modified signal on style's object if the filter changed.
- */
-static void
-sp_style_filter_ref_modified(SPObject *obj, guint flags, SPStyle *style)
-{
- (void)flags; // TODO
- SPFilter *filter=static_cast<SPFilter *>(obj);
- if (style->getFilter() == filter)
- {
- if (style->object) {
- style->object->requestModified(SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_STYLE_MODIFIED_FLAG);
- }
- }
-}
+ // MAP -------------------------------------------
-/**
- * Gets called when the filter is (re)attached to the style
- */
-static void
-sp_style_filter_ref_changed(SPObject *old_ref, SPObject *ref, SPStyle *style)
-{
- if (old_ref) {
- style->filter_modified_connection.disconnect();
- }
- if ( SP_IS_FILTER(ref))
- {
- style->filter_modified_connection =
- ref->connectModified(sigc::bind(sigc::ptr_fun(&sp_style_filter_ref_modified), style));
- }
+ // if( _propmap.size() == 0 ) {
- sp_style_filter_ref_modified(ref, 0, style);
-}
+ // // 'color' must be before 'fill', 'stroke', 'text-decoration-color', ...
+ // _propmap.insert( std::make_pair( color.name, reinterpret_cast<SPIBasePtr>(&SPStyle::color ) ) );
-/**
- * Emit style modified signal on style's object if server is style's fill
- * or stroke paint server.
- */
-static void
-sp_style_paint_server_ref_modified(SPObject *obj, guint flags, SPStyle *style)
-{
- (void)flags; // TODO
- SPPaintServer *server = static_cast<SPPaintServer *>(obj);
+ // // 'font-size' must be before properties that need to know em, ex size (SPILength, SPILenghtOrNormal)
+ // _propmap.insert( std::make_pair( font_style.name, reinterpret_cast<SPIBasePtr>(&SPStyle::font_style ) ) );
+ // _propmap.insert( std::make_pair( font_variant.name, reinterpret_cast<SPIBasePtr>(&SPStyle::font_variant ) ) );
+ // _propmap.insert( std::make_pair( font_weight.name, reinterpret_cast<SPIBasePtr>(&SPStyle::font_weight ) ) );
+ // _propmap.insert( std::make_pair( font_stretch.name, reinterpret_cast<SPIBasePtr>(&SPStyle::font_stretch ) ) );
+ // _propmap.insert( std::make_pair( font_size.name, reinterpret_cast<SPIBasePtr>(&SPStyle::font_size ) ) );
+ // _propmap.insert( std::make_pair( line_height.name, reinterpret_cast<SPIBasePtr>(&SPStyle::line_height ) ) );
+ // _propmap.insert( std::make_pair( font_family.name, reinterpret_cast<SPIBasePtr>(&SPStyle::font_family ) ) );
+ // _propmap.insert( std::make_pair( font.name, reinterpret_cast<SPIBasePtr>(&SPStyle::font ) ) );
+ // _propmap.insert( std::make_pair( font_specification.name, reinterpret_cast<SPIBasePtr>(&SPStyle::font_specification ) ) );
- if ((style->fill.isPaintserver())
- && style->getFillPaintServer() == server)
- {
- if (style->object) {
- /** \todo
- * fixme: I do not know, whether it is optimal - we are
- * forcing reread of everything (Lauris)
- */
- /** \todo
- * fixme: We have to use object_modified flag, because parent
- * flag is only available downstreams.
- */
- style->object->requestModified(SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_STYLE_MODIFIED_FLAG);
- }
- } else if ((style->stroke.isPaintserver())
- && style->getStrokePaintServer() == server)
- {
- if (style->object) {
- /// \todo fixme:
- style->object->requestModified(SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_STYLE_MODIFIED_FLAG);
- }
- } else if (server) {
- g_assert_not_reached();
- }
-}
+ // _propmap.insert( std::make_pair( text_indent.name, reinterpret_cast<SPIBasePtr>(&SPStyle::text_indent ) ) );
+ // _propmap.insert( std::make_pair( text_align.name, reinterpret_cast<SPIBasePtr>(&SPStyle::text_align ) ) );
-/**
- * Gets called when the paintserver is (re)attached to the style
- */
-static void
-sp_style_fill_paint_server_ref_changed(SPObject *old_ref, SPObject *ref, SPStyle *style)
-{
- if (old_ref) {
- style->fill_ps_modified_connection.disconnect();
- }
- if (SP_IS_PAINT_SERVER(ref)) {
- style->fill_ps_modified_connection =
- ref->connectModified(sigc::bind(sigc::ptr_fun(&sp_style_paint_server_ref_modified), style));
- }
+ // _propmap.insert( std::make_pair( text_decoration.name, reinterpret_cast<SPIBasePtr>(&SPStyle::text_decoration ) ) );
+ // _propmap.insert( std::make_pair( text_decoration_line.name, reinterpret_cast<SPIBasePtr>(&SPStyle::text_decoration_line ) ) );
+ // _propmap.insert( std::make_pair( text_decoration_style.name, reinterpret_cast<SPIBasePtr>(&SPStyle::text_decoration_style ) ) );
+ // _propmap.insert( std::make_pair( text_decoration_color.name, reinterpret_cast<SPIBasePtr>(&SPStyle::text_decoration_color ) ) );
- sp_style_paint_server_ref_modified(ref, 0, style);
-}
+ // _propmap.insert( std::make_pair( letter_spacing.name, reinterpret_cast<SPIBasePtr>(&SPStyle::letter_spacing ) ) );
+ // _propmap.insert( std::make_pair( word_spacing.name, reinterpret_cast<SPIBasePtr>(&SPStyle::word_spacing ) ) );
+ // _propmap.insert( std::make_pair( text_transform.name, reinterpret_cast<SPIBasePtr>(&SPStyle::text_transform ) ) );
-/**
- * Gets called when the paintserver is (re)attached to the style
- */
-static void
-sp_style_stroke_paint_server_ref_changed(SPObject *old_ref, SPObject *ref, SPStyle *style)
-{
- if (old_ref) {
- style->stroke_ps_modified_connection.disconnect();
- }
- if (SP_IS_PAINT_SERVER(ref)) {
- style->stroke_ps_modified_connection =
- ref->connectModified(sigc::bind(sigc::ptr_fun(&sp_style_paint_server_ref_modified), style));
- }
+ // _propmap.insert( std::make_pair( direction.name, reinterpret_cast<SPIBasePtr>(&SPStyle::direction ) ) );
+ // _propmap.insert( std::make_pair( block_progression.name, reinterpret_cast<SPIBasePtr>(&SPStyle::block_progression ) ) );
+ // _propmap.insert( std::make_pair( writing_mode.name, reinterpret_cast<SPIBasePtr>(&SPStyle::writing_mode ) ) );
+ // _propmap.insert( std::make_pair( baseline_shift.name, reinterpret_cast<SPIBasePtr>(&SPStyle::baseline_shift ) ) );
+ // _propmap.insert( std::make_pair( text_anchor.name, reinterpret_cast<SPIBasePtr>(&SPStyle::text_anchor ) ) );
- sp_style_paint_server_ref_modified(ref, 0, style);
-}
+ // _propmap.insert( std::make_pair( clip_rule.name, reinterpret_cast<SPIBasePtr>(&SPStyle::clip_rule ) ) );
+ // _propmap.insert( std::make_pair( display.name, reinterpret_cast<SPIBasePtr>(&SPStyle::display ) ) );
+ // _propmap.insert( std::make_pair( overflow.name, reinterpret_cast<SPIBasePtr>(&SPStyle::overflow ) ) );
+ // _propmap.insert( std::make_pair( visibility.name, reinterpret_cast<SPIBasePtr>(&SPStyle::visibility ) ) );
+ // _propmap.insert( std::make_pair( opacity.name, reinterpret_cast<SPIBasePtr>(&SPStyle::opacity ) ) );
-/**
- * Returns a new SPStyle object with settings as per sp_style_clear().
- */
-SPStyle *
-sp_style_new(SPDocument *document)
-{
- SPStyle *const style = g_new0(SPStyle, 1);
+ // _propmap.insert( std::make_pair( isolation.name, reinterpret_cast<SPIBasePtr>(&SPStyle::isolation ) ) );
+ // _propmap.insert( std::make_pair( blend_mode.name, reinterpret_cast<SPIBasePtr>(&SPStyle::blend_mode ) ) );
- style->refcount = 1;
- style->object = NULL;
- style->document = document;
- style->text = sp_text_style_new();
- style->text_private = TRUE;
+ // _propmap.insert( std::make_pair( color_interpolation.name, reinterpret_cast<SPIBasePtr>(&SPStyle::color_interpolation ) ) );
+ // _propmap.insert( std::make_pair( color_interpolation_filters.name, reinterpret_cast<SPIBasePtr>(&SPStyle::color_interpolation_filters ) ) );
- sp_style_clear(style);
+ // _propmap.insert( std::make_pair( fill.name, reinterpret_cast<SPIBasePtr>(&SPStyle::fill ) ) );
+ // _propmap.insert( std::make_pair( fill_opacity.name, reinterpret_cast<SPIBasePtr>(&SPStyle::fill_opacity ) ) );
+ // _propmap.insert( std::make_pair( fill_rule.name, reinterpret_cast<SPIBasePtr>(&SPStyle::fill_rule ) ) );
- style->cloned = false;
+ // _propmap.insert( std::make_pair( stroke.name, reinterpret_cast<SPIBasePtr>(&SPStyle::stroke ) ) );
+ // _propmap.insert( std::make_pair( stroke_width.name, reinterpret_cast<SPIBasePtr>(&SPStyle::stroke_width ) ) );
+ // _propmap.insert( std::make_pair( stroke_linecap.name, reinterpret_cast<SPIBasePtr>(&SPStyle::stroke_linecap ) ) );
+ // _propmap.insert( std::make_pair( stroke_linejoin.name, reinterpret_cast<SPIBasePtr>(&SPStyle::stroke_linejoin ) ) );
+ // _propmap.insert( std::make_pair( stroke_miterlimit.name, reinterpret_cast<SPIBasePtr>(&SPStyle::stroke_miterlimit ) ) );
+ // _propmap.insert( std::make_pair( stroke_dasharray.name, reinterpret_cast<SPIBasePtr>(&SPStyle::stroke_dasharray ) ) );
+ // _propmap.insert( std::make_pair( stroke_dashoffset.name, reinterpret_cast<SPIBasePtr>(&SPStyle::stroke_dashoffset ) ) );
+ // _propmap.insert( std::make_pair( stroke_opacity.name, reinterpret_cast<SPIBasePtr>(&SPStyle::stroke_opacity ) ) );
- new (&style->release_connection) sigc::connection();
- new (&style->filter_modified_connection) sigc::connection();
- new (&style->fill_ps_modified_connection) sigc::connection();
- new (&style->stroke_ps_modified_connection) sigc::connection();
+ // _propmap.insert( std::make_pair( marker.name, reinterpret_cast<SPIBasePtr>(&SPStyle::marker ) ) );
+ // _propmap.insert( std::make_pair( marker_start.name, reinterpret_cast<SPIBasePtr>(&SPStyle::marker_start ) ) );
+ // _propmap.insert( std::make_pair( marker_mid.name, reinterpret_cast<SPIBasePtr>(&SPStyle::marker_mid ) ) );
+ // _propmap.insert( std::make_pair( marker_end.name, reinterpret_cast<SPIBasePtr>(&SPStyle::marker_end ) ) );
- return style;
+ // _propmap.insert( std::make_pair( paint_order.name, reinterpret_cast<SPIBasePtr>(&SPStyle::paint_order ) ) );
+
+ // _propmap.insert( std::make_pair( filter.name, reinterpret_cast<SPIBasePtr>(&SPStyle::filter ) ) );
+ // _propmap.insert( std::make_pair( filter_blend_mode.name, reinterpret_cast<SPIBasePtr>(&SPStyle::filter_blend_mode ) ) );
+ // _propmap.insert( std::make_pair( filter_gaussianBlur_deviation.name, reinterpret_cast<SPIBasePtr>(&SPStyle::filter_gaussianBlur_deviation ) ) );
+
+ // _propmap.insert( std::make_pair( color_rendering.name, reinterpret_cast<SPIBasePtr>(&SPStyle::color_rendering ) ) );
+ // _propmap.insert( std::make_pair( image_rendering.name, reinterpret_cast<SPIBasePtr>(&SPStyle::image_rendering ) ) );
+ // _propmap.insert( std::make_pair( shape_rendering.name, reinterpret_cast<SPIBasePtr>(&SPStyle::shape_rendering ) ) );
+ // _propmap.insert( std::make_pair( text_rendering.name, reinterpret_cast<SPIBasePtr>(&SPStyle::text_rendering ) ) );
+
+ // _propmap.insert( std::make_pair( enable_background.name, reinterpret_cast<SPIBasePtr>(&SPStyle::enable_background ) ) );
+
+ // }
}
+SPStyle::~SPStyle() {
-/**
- * Creates a new SPStyle object, and attaches it to the specified SPObject.
- */
-SPStyle *
-sp_style_new_from_object(SPObject *object)
-{
- g_return_val_if_fail(object != NULL, NULL);
- g_return_val_if_fail(SP_IS_OBJECT(object), NULL);
+ // std::cout << "SPStyle::~SPStyle" << std::endl;
+ --_count; // Poor man's memory leak detector.
- SPStyle *style = sp_style_new( object->document );
- style->object = object;
- style->release_connection = object->connectRelease(sigc::bind<1>(sigc::ptr_fun(&sp_style_object_release), style));
+ // Remove connections
+ release_connection.disconnect();
+ release_connection.~connection();
- if (object->cloned) {
- style->cloned = true;
+ // The following shoud be moved into SPIPaint and SPIFilter
+ if (fill.value.href) {
+ fill_ps_modified_connection.disconnect();
}
- return style;
-}
+ if (stroke.value.href) {
+ stroke_ps_modified_connection.disconnect();
+ }
+ if (filter.href) {
+ filter_modified_connection.disconnect();
+ }
-/**
- * Increase refcount of style.
- */
-SPStyle *
-sp_style_ref(SPStyle *style)
-{
- g_return_val_if_fail(style != NULL, NULL);
- g_return_val_if_fail(style->refcount > 0, NULL);
+ filter_modified_connection.~connection();
+ fill_ps_modified_connection.~connection();
+ stroke_ps_modified_connection.~connection();
- style->refcount += 1;
+ _properties.clear();
+ //_propmap.clear();
- return style;
+ // std::cout << "SPStyle::~SPstyle(): Exit\n" << std::endl;
}
+// Used in SPStyle::clear()
+void clear_property( SPIBase* p ) {
+ p->clear();
+}
-/**
- * Decrease refcount of style with possible destruction.
- */
-SPStyle *
-sp_style_unref(SPStyle *style)
-{
- g_return_val_if_fail(style != NULL, NULL);
- g_return_val_if_fail(style->refcount > 0, NULL);
-
- style->refcount -= 1;
-
- if (style->refcount < 1) {
- style->release_connection.disconnect();
- style->release_connection.~connection();
- if (style->text) sp_text_style_unref(style->text);
-
- if (style->fill.value.href) {
- style->fill_ps_modified_connection.disconnect();
- delete style->fill.value.href;
- style->fill.value.href = NULL;
- }
- if (style->stroke.value.href) {
- style->stroke_ps_modified_connection.disconnect();
- delete style->stroke.value.href;
- style->stroke.value.href = NULL;
- }
- if (style->filter.href) {
- style->filter_modified_connection.disconnect();
- delete style->filter.href;
- style->filter.href = NULL;
- }
-
- style->filter_modified_connection.~connection();
- style->fill_ps_modified_connection.~connection();
- style->stroke_ps_modified_connection.~connection();
-
- style->fill.clear();
- style->stroke.clear();
- sp_style_filter_clear(style);
-
- style->stroke_dasharray.values.clear();
-
- for (unsigned i = SP_MARKER_LOC; i < SP_MARKER_LOC_QTY; i++) {
- if (style->marker[i].value) {
- g_free(style->marker[i].value);
- style->marker[i].value = NULL;
- }
- }
- g_free(style);
- return NULL;
+// Matches void sp_style_clear();
+void
+SPStyle::clear() {
+
+ for_each( _properties.begin(), _properties.end(), clear_property );
+ // for(SPPropMap::iterator i = _propmap.begin(); i != _propmap.end(); ++i ) {
+ // (this->*(i->second)).clear();
+ // }
+
+ // Release connection to object, created in sp_style_new_from_object()
+ release_connection.disconnect();
+
+ // href->detach() called in fill->clear()...
+ fill_ps_modified_connection.disconnect();
+ if (fill.value.href) {
+ delete fill.value.href;
+ fill.value.href = NULL;
}
- return style;
+ stroke_ps_modified_connection.disconnect();
+ if (stroke.value.href) {
+ delete stroke.value.href;
+ stroke.value.href = NULL;
+ }
+ filter_modified_connection.disconnect();
+ if (filter.href) {
+ delete filter.href;
+ filter.href = NULL;
+ }
+
+ if (document) {
+ filter.href = new SPFilterReference(document);
+ filter.href->changedSignal().connect(sigc::bind(sigc::ptr_fun(sp_style_filter_ref_changed), this));
+
+ fill.value.href = new SPPaintServerReference(document);
+ fill.value.href->changedSignal().connect(sigc::bind(sigc::ptr_fun(sp_style_fill_paint_server_ref_changed), this));
+
+ stroke.value.href = new SPPaintServerReference(document);
+ stroke.value.href->changedSignal().connect(sigc::bind(sigc::ptr_fun(sp_style_stroke_paint_server_ref_changed), this));
+ }
+
+ cloned = false;
+
}
-/**
- * Reads the various style parameters for an object from repr.
- */
-static void
-sp_style_read(SPStyle *style, SPObject *object, Inkscape::XML::Node *repr)
-{
- g_assert(style != NULL);
+// Matches void sp_style_read(SPStyle *style, SPObject *object, Inkscape::XML::Node *repr)
+void
+SPStyle::read( SPObject *object, Inkscape::XML::Node *repr ) {
+
+ // std::cout << "SPstyle::read( SPObject, Inkscape::XML::Node ): Entrance: "
+ // << (object?(object->getId()?object->getId():"id null"):"object null") << " "
+ // << (repr?(repr->name()?repr->name():"no name"):"repr null")
+ // << std::endl;
g_assert(repr != NULL);
g_assert(!object || (object->getRepr() == repr));
- sp_style_clear(style);
+ // // Uncomment to verify that we don't need to call clear.
+ // std::cout << " Creating temp style for testing" << std::endl;
+ // SPStyle *temp = new SPStyle();
+ // if( !(*temp == *this ) ) std::cout << "SPStyle::read: Need to clear" << std::endl;
+ // delete temp;
+
+ clear(); // FIXME, If this isn't here, gradient editing stops working. Why?
if (object && object->cloned) {
- style->cloned = true;
+ cloned = true;
}
/* 1. Style attribute */
+ // std::cout << " MERGING STYLE ATTRIBUTE" << std::endl;
gchar const *val = repr->attribute("style");
- if (val != NULL && *val) {
- sp_style_merge_from_style_string(style, val);
+ if( val != NULL && *val ) {
+ _mergeString( val );
}
+ /* 2 Style sheet */
+ // std::cout << " MERGING OBJECT STYLESHEET" << std::endl;
if (object) {
- sp_style_merge_from_object_stylesheet(style, object);
+ _mergeObjectStylesheet( object );
} else {
- /** \todo No stylesheet information. Find out under what circumstances
- * this occurs, and handle accordingly. (If we really wanted to, we
- * could probably get stylesheets by going through repr->doc.)
- */
+ // std::cerr << "SPStyle::read: No object! Can not read style sheet" << std::endl;
}
- /* 2. Presentation attributes */
- /* Attributes are only read in if not already set in a style sheet or style attribute above. */
-
- /* CSS2 */
- SPS_READ_PENUM_IF_UNSET(&style->visibility, repr, "visibility", enum_visibility, true);
- SPS_READ_PENUM_IF_UNSET(&style->display, repr, "display", enum_display, true);
- SPS_READ_PENUM_IF_UNSET(&style->overflow, repr, "overflow", enum_overflow, true);
-
- /* CSS Compositing and Blending Level 1 */
- SPS_READ_PENUM_IF_UNSET(&style->isolation, repr, "isolation", enum_isolation, true);
- SPS_READ_PENUM_IF_UNSET(&style->blend_mode, repr, "mix_blend_mode", enum_blend_mode, true);
-
- /* Font */
- SPS_READ_PFONTSIZE_IF_UNSET(&style->font_size, repr, "font-size");
- SPS_READ_PENUM_IF_UNSET(&style->font_style, repr, "font-style", enum_font_style, true);
- SPS_READ_PENUM_IF_UNSET(&style->font_variant, repr, "font-variant", enum_font_variant, true);
- SPS_READ_PENUM_IF_UNSET(&style->font_weight, repr, "font-weight", enum_font_weight, true);
- SPS_READ_PENUM_IF_UNSET(&style->font_stretch, repr, "font-stretch", enum_font_stretch, true);
- /* Text (css2 chapter 16) */
- SPS_READ_PLENGTH_IF_UNSET(&style->text_indent, repr, "text-indent");
- SPS_READ_PENUM_IF_UNSET(&style->text_align, repr, "text-align", enum_text_align, true);
- if (!style->text_decoration_line.set) {
- // assume it uses either text-decoration or text-decoration-line, but not both
- if ((val = repr->attribute("text-decoration")) || (val = repr->attribute("text-decoration-line"))) {
- sp_style_read_itextdecoration(&style->text_decoration_line, &style->text_decoration_style, &style->text_decoration_color, val);
- }
- }
- if (!style->line_height.set) {
- val = repr->attribute("line-height");
- if (val) {
- sp_style_read_ilengthornormal(&style->line_height, val);
- }
- }
- if (!style->letter_spacing.set) {
- val = repr->attribute("letter-spacing");
- if (val) {
- sp_style_read_ilengthornormal(&style->letter_spacing, val);
- }
- }
- if (!style->word_spacing.set) {
- val = repr->attribute("word-spacing");
- if (val) {
- sp_style_read_ilengthornormal(&style->word_spacing, val);
- }
- }
- SPS_READ_PENUM_IF_UNSET(&style->text_transform, repr, "text-transform", enum_text_transform, true);
- SPS_READ_PENUM_IF_UNSET(&style->direction, repr, "direction", enum_direction, true);
- SPS_READ_PENUM_IF_UNSET(&style->block_progression, repr, "block_progression", enum_block_progression, true);
-
- /* SVG */
- SPS_READ_PENUM_IF_UNSET(&style->writing_mode, repr, "writing-mode",
- enum_writing_mode, true);
- SPS_READ_PENUM_IF_UNSET(&style->text_anchor, repr, "text-anchor",
- enum_text_anchor, true);
- SPS_READ_PBASELINE_SHIFT_IF_UNSET(&style->baseline_shift, repr, "baseline-shift");
-
- /* opacity */
- if (!style->opacity.set) {
- val = repr->attribute("opacity");
- if (val) {
- sp_style_read_iscale24(&style->opacity, val);
- }
- }
- /* color */
- if (!style->color.set) {
- val = repr->attribute("color");
- if (val) {
- sp_style_read_icolor(&style->color, val, style, ( object
- ? object->document
- : NULL ));
- }
- }
- /* color interpolation */
- SPS_READ_PENUM_IF_UNSET(&style->color_interpolation, repr, "color-interpolation", enum_color_interpolation, true);
- /* color interpolation filters*/
- SPS_READ_PENUM_IF_UNSET(&style->color_interpolation_filters, repr, "color-interpolation-filters", enum_color_interpolation, true);
- /* fill */
- if (!style->fill.set) {
- val = repr->attribute("fill");
- if (val) {
- style->fill.read( val, *style, (object) ? object->document : NULL );
- }
- }
- /* fill-opacity */
- if (!style->fill_opacity.set) {
- val = repr->attribute("fill-opacity");
- if (val) {
- sp_style_read_iscale24(&style->fill_opacity, val);
- }
- }
- /* fill-rule */
- SPS_READ_PENUM_IF_UNSET(&style->fill_rule, repr, "fill-rule", enum_fill_rule, true);
- /* stroke */
- if (!style->stroke.set) {
- val = repr->attribute("stroke");
- if (val) {
- style->stroke.read( val, *style, (object) ? object->document : NULL );
- }
- }
- SPS_READ_PLENGTH_IF_UNSET(&style->stroke_width, repr, "stroke-width");
- SPS_READ_PENUM_IF_UNSET(&style->stroke_linecap, repr, "stroke-linecap", enum_stroke_linecap, true);
- SPS_READ_PENUM_IF_UNSET(&style->stroke_linejoin, repr, "stroke-linejoin", enum_stroke_linejoin, true);
- SPS_READ_PFLOAT_IF_UNSET(&style->stroke_miterlimit, repr, "stroke-miterlimit");
-
- /* markers */
- if (!style->marker[SP_MARKER_LOC].set) {
- val = repr->attribute("marker");
- if (val) {
- sp_style_read_istring(&style->marker[SP_MARKER_LOC], val);
- }
- }
- if (!style->marker[SP_MARKER_LOC_START].set) {
- val = repr->attribute("marker-start");
- if (val) {
- sp_style_read_istring(&style->marker[SP_MARKER_LOC_START], val);
- }
- }
- if (!style->marker[SP_MARKER_LOC_MID].set) {
- val = repr->attribute("marker-mid");
- if (val) {
- sp_style_read_istring(&style->marker[SP_MARKER_LOC_MID], val);
- }
- }
- if (!style->marker[SP_MARKER_LOC_END].set) {
- val = repr->attribute("marker-end");
- if (val) {
- sp_style_read_istring(&style->marker[SP_MARKER_LOC_END], val);
- }
+ /* 3 Presentation attributes */
+ // std::cout << " MERGING PRESENTATION ATTRIBUTES" << std::endl;
+ for(std::vector<SPIBase*>::size_type i = 0; i != _properties.size(); ++i) {
+ _properties[i]->readAttribute( repr );
}
+ // for(SPPropMap::iterator i = _propmap.begin(); i != _propmap.end(); ++i ) {
+ // (this->*(i->second)).readAttribute( repr );
+ // }
- /* stroke-opacity */
- if (!style->stroke_opacity.set) {
- val = repr->attribute("stroke-opacity");
- if (val) {
- sp_style_read_iscale24(&style->stroke_opacity, val);
- }
- }
- if (!style->stroke_dasharray.set) {
- val = repr->attribute("stroke-dasharray");
- if (val) {
- sp_style_read_dash(style, val);
- }
- }
- SPS_READ_PLENGTH_IF_UNSET(&style->stroke_width, repr, "stroke-dashoffset");
-
- /* paint-order */
- if (!style->paint_order.set) {
- val = repr->attribute("paint-order");
- if (val) {
- sp_style_read_ipaintorder(&style->paint_order, val);
- } else {
- style->paint_order.layer[0] = SP_CSS_PAINT_ORDER_NORMAL;
- }
- }
-
- /* -inkscape-font-specification */
- if (!style->text_private || !style->text->font_specification.set) {
- val = repr->attribute("-inkscape-font-specification");
- if (val) {
- if (!style->text_private) sp_style_privatize_text(style);
- gchar *val_unquoted = attribute_unquote(val);
- sp_style_read_istring(&style->text->font_specification, val_unquoted);
- if (val_unquoted) g_free (val_unquoted);
- }
- }
-
- /* font-family */
- if (!style->text_private || !style->text->font_family.set) {
- val = repr->attribute("font-family");
- if (val) {
- if (!style->text_private) sp_style_privatize_text(style);
- gchar *val_unquoted = attribute_unquote(val);
- sp_style_read_istring(&style->text->font_family, val_unquoted);
- if (val_unquoted) g_free (val_unquoted);
- }
- }
-
- /* filter effects */
- if (!style->filter.set) {
- val = repr->attribute("filter");
- if (val) {
- sp_style_read_ifilter(val, style, (object) ? object->document : NULL);
- }
- }
- SPS_READ_PENUM_IF_UNSET(&style->enable_background, repr,
- "enable-background", enum_enable_background, true);
-
- /* clip-rule */
- SPS_READ_PENUM_IF_UNSET(&style->clip_rule, repr, "clip-rule", enum_clip_rule, true);
-
- /* color_rendering, image_rendering, shape_rendering, text_rendering */
- SPS_READ_PENUM_IF_UNSET(&style->color_rendering, repr, "color-rendering", enum_color_rendering, true);
- SPS_READ_PENUM_IF_UNSET(&style->image_rendering, repr, "image-rendering", enum_image_rendering, true);
- SPS_READ_PENUM_IF_UNSET(&style->shape_rendering, repr, "shape-rendering", enum_shape_rendering, true);
- SPS_READ_PENUM_IF_UNSET(&style->text_rendering, repr, "text-rendering", enum_text_rendering, true);
-
- /* 3. Merge from parent */
- if (object) {
- if (object->parent) {
- sp_style_merge_from_parent(style, object->parent->style);
+ /* 4 Cascade from parent */
+ // std::cout << " CASCADING FROM PARENT" << std::endl;
+ if( object ) {
+ if( object->parent ) {
+ cascade( object->parent->style );
}
} else {
- if (repr->parent()) {
- /// \todo fixme: This is not the prettiest thing (Lauris)
- SPStyle *parent = sp_style_new(NULL);
- sp_style_read(parent, NULL, repr->parent());
- sp_style_merge_from_parent(style, parent);
- sp_style_unref(parent);
+ // When does this happen?
+ // std::cout << "SPStyle::read(): reading via repr->parent()" << std::endl;
+ if( repr->parent() ) {
+ SPStyle *parent = new SPStyle();
+ parent->read( NULL, repr->parent() );
+ cascade( parent );
+ delete parent;
}
}
}
-
-/**
- * Read style properties from object's repr.
- *
- * 1. Reset existing object style
- * 2. Load current effective object style
- * 3. Load i attributes from immediate parent (which has to be up-to-date)
- */
+// Matches void sp_style_read_from_object(SPStyle *style, SPObject *object);
void
-sp_style_read_from_object(SPStyle *style, SPObject *object)
-{
- g_return_if_fail(style != NULL);
+SPStyle::readFromObject( SPObject *object ) {
+
+ // std::cout << "SPStyle::readFromObject: "<< (object->getId()?object->getId():"null")<< std::endl;
+
g_return_if_fail(object != NULL);
g_return_if_fail(SP_IS_OBJECT(object));
Inkscape::XML::Node *repr = object->getRepr();
g_return_if_fail(repr != NULL);
- sp_style_read(style, object, repr);
+ read( object, repr );
}
-
-/**
- * Read style properties from preferences.
- * @param style The style to write to
- * @param path Preferences directory from which the style should be read
- */
+// Matches sp_style_merge_property(SPStyle *style, gint id, gchar const *val)
void
-sp_style_read_from_prefs(SPStyle *style, Glib::ustring const &path)
-{
- g_return_if_fail(style != NULL);
- g_return_if_fail(path != "");
-
- Inkscape::Preferences *prefs = Inkscape::Preferences::get();
-
- // not optimal: we reconstruct the node based on the prefs, then pass it to
- // sp_style_read for actual processing.
- Inkscape::XML::SimpleDocument *tempdoc = new Inkscape::XML::SimpleDocument;
- Inkscape::XML::Node *tempnode = tempdoc->createElement("temp");
-
- std::vector<Inkscape::Preferences::Entry> attrs = prefs->getAllEntries(path);
- for (std::vector<Inkscape::Preferences::Entry>::iterator i = attrs.begin(); i != attrs.end(); ++i) {
- tempnode->setAttribute(i->getEntryName().data(), i->getString().data());
- }
-
- sp_style_read(style, NULL, tempnode);
-
- Inkscape::GC::release(tempnode);
- Inkscape::GC::release(tempdoc);
- delete tempdoc;
-}
-
+SPStyle::readIfUnset( gint id, gchar const *val ) {
-
-/**
- *
- */
-static void
-sp_style_privatize_text(SPStyle *style)
-{
- SPTextStyle *text = style->text;
- style->text = sp_text_style_duplicate_unset(style->text);
- sp_text_style_unref(text);
- style->text_private = TRUE;
-}
-
-
-/**
- * Merge property into style.
- *
- * Should be called in order of highest to lowest precedence.
- * E.g. for a single style string, call from the last declaration to the first,
- * as CSS says that later declarations override earlier ones.
- *
- * \pre val != NULL.
- */
-static void
-sp_style_merge_property(SPStyle *style, gint id, gchar const *val)
-{
+ // std::cout << "SPStyle::readIfUnset: Entrance: " << (val?val:"null") << std::endl;
+ // To Do: If it is not too slow, use std::map instead of std::vector inorder to remove switch()
+ // (looking up SP_PROP_xxxx already uses a hash).
g_return_if_fail(val != NULL);
switch (id) {
case SP_PROP_INKSCAPE_FONT_SPEC:
- if (!style->text_private) sp_style_privatize_text(style);
- if (!style->text->font_specification.set) {
- gchar *val_unquoted = attribute_unquote(val);
- sp_style_read_istring(&style->text->font_specification, val_unquoted);
- if (val_unquoted) g_free (val_unquoted);
- }
+ font_specification.readIfUnset( val );
break;
- /* CSS2 */
- /* Font */
case SP_PROP_FONT_FAMILY:
- if (!style->text_private) sp_style_privatize_text(style);
- if (!style->text->font_family.set) {
- gchar *val_unquoted = attribute_unquote(val);
- sp_style_read_istring(&style->text->font_family, val_unquoted);
- if (val_unquoted) g_free (val_unquoted);
- }
+ font_family.readIfUnset( val );
break;
case SP_PROP_FONT_SIZE:
- SPS_READ_IFONTSIZE_IF_UNSET(&style->font_size, val);
+ font_size.readIfUnset( val );
break;
case SP_PROP_FONT_SIZE_ADJUST:
if (strcmp(val, "none") != 0) {
@@ -991,220 +609,71 @@ sp_style_merge_property(SPStyle *style, gint id, gchar const *val)
}
break;
case SP_PROP_FONT_STYLE:
- SPS_READ_IENUM_IF_UNSET(&style->font_style, val, enum_font_style, true);
+ font_style.readIfUnset( val );
break;
case SP_PROP_FONT_VARIANT:
- SPS_READ_IENUM_IF_UNSET(&style->font_variant, val, enum_font_variant, true);
+ font_variant.readIfUnset( val );
break;
case SP_PROP_FONT_WEIGHT:
- SPS_READ_IENUM_IF_UNSET(&style->font_weight, val, enum_font_weight, true);
+ font_weight.readIfUnset( val );
break;
case SP_PROP_FONT_STRETCH:
- SPS_READ_IENUM_IF_UNSET(&style->font_stretch, val, enum_font_stretch, true);
+ font_stretch.readIfUnset( val );
break;
case SP_PROP_FONT:
- if (!style->text_private) sp_style_privatize_text(style);
- if (!style->text->font.set) {
- g_free(style->text->font.value);
- style->text->font.value = g_strdup(val);
- style->text->font.set = TRUE;
- style->text->font.inherit = (val && !strcmp(val, "inherit"));
-
- // Break string into white space separated tokens
- std::stringstream os( val );
- Glib::ustring param;
-
- while (os >> param) {
-
- // CSS is case insensitive but we're comparing against lowercase strings
- Glib::ustring lparam = param.lowercase();
-
- if (lparam == "/") {
-
- os >> param;
- // Eat the line-height for the moment as it is not an SVG property.
- // lparam = param.lowercase();
- // sp_style_read_ilengthornormal(&style->line_height, lparam);
-
- } else {
-
- // Skip if "normal" as that is the default (and we don't know which attribute it applies to).
- if (lparam == "normal") continue;
-
- // Check each property in turn
-
- // font-style
- SPIEnum test_style;
- test_style.set = FALSE;
-
- // Read once to see if param is valid style. If valid, .set will be TRUE.
- sp_style_read_ienum(&test_style, lparam.c_str(), enum_font_style, true);
-
- // If valid style parameter
- if (test_style.set) {
-
- // If not previously set
- if (!style->font_style.set) {
- style->font_style.set = TRUE;
- style->font_style.inherit = test_style.inherit;
- style->font_style.value = test_style.value;
- style->font_style.computed = test_style.computed;
- }
- continue; // Next parameter.
- }
-
- // font-variant (small-caps)
- SPIEnum test_variant;
- test_variant.set = FALSE;
- sp_style_read_ienum(&test_variant, lparam.c_str(), enum_font_variant, true);
-
- // If valid variant parameter
- if (test_variant.set) {
-
- // If not previously set
- if (!style->font_variant.set) {
- style->font_variant.set = TRUE;
- style->font_variant.inherit = test_variant.inherit;
- style->font_variant.value = test_variant.value;
- style->font_variant.computed = test_variant.computed;
- }
- continue; // Next parameter.
- }
-
- // font-weight
- SPIEnum test_weight;
- test_weight.set = FALSE;
- sp_style_read_ienum(&test_weight, lparam.c_str(), enum_font_weight, true);
-
- // If valid weight parameter
- if (test_weight.set) {
-
- // If not previously set
- if (!style->font_weight.set) {
- style->font_weight.set = TRUE;
- style->font_weight.inherit = test_weight.inherit;
- style->font_weight.value = test_weight.value;
- style->font_weight.computed = test_weight.computed;
- }
- continue; // Next parameter
- }
-
- // Font-size
- SPIFontSize test_size;
- test_size.set = FALSE;
-
- // Read once to see if param is valid size.
- sp_style_read_ifontsize( &test_size, lparam.c_str() );
-
- // If valid size parameter
- if (test_size.set) {
-
- // If not previously set
- if (!style->font_size.set) {
- style->font_size.set = TRUE;
- style->font_size.inherit = test_size.inherit;
- style->font_size.unit = test_size.unit;
- style->font_size.value = test_size.value;
- style->font_size.computed = test_size.computed;
- style->font_size.type = test_size.type;
- style->font_size.literal = test_size.literal;
- }
- continue;
- }
-
- // No valid property value found.
- break;
- }
- } // params
-
- // The rest must be font-family...
- std::string val_s = val;
- std::string family = val_s.substr( val_s.find( param ) );
-
- if (!style->text_private) sp_style_privatize_text(style);
- if (!style->text->font_family.set) {
- gchar *val_unquoted = attribute_unquote( family.c_str() );
- sp_style_read_istring(&style->text->font_family, val_unquoted);
- if (val_unquoted) g_free (val_unquoted);
- }
-
- // Set all properties to their default values per CSS 2.1 spec if not already set
- SPS_READ_IFONTSIZE_IF_UNSET(&style->font_size, "medium" );
- SPS_READ_IENUM_IF_UNSET(&style->font_style, "normal", enum_font_style, true);
- SPS_READ_IENUM_IF_UNSET(&style->font_variant, "normal", enum_font_variant, true);
- SPS_READ_IENUM_IF_UNSET(&style->font_weight, "normal", enum_font_weight, true);
- // Line height is not an SVG property but Inkscape uses it for multi-line text.
- // sp_style_read_ilengthornormal(&style->line_height, "normal");
-
- }
-
+ font.readIfUnset( val );
break;
/* Text */
case SP_PROP_TEXT_INDENT:
- SPS_READ_ILENGTH_IF_UNSET(&style->text_indent, val);
+ text_indent.readIfUnset( val );
break;
case SP_PROP_TEXT_ALIGN:
- SPS_READ_IENUM_IF_UNSET(&style->text_align, val, enum_text_align, true);
+ text_align.readIfUnset( val );
break;
case SP_PROP_TEXT_DECORATION:
- if (!style->text_decoration_line.set) {
- sp_style_read_itextdecoration(&style->text_decoration_line, &style->text_decoration_style, &style->text_decoration_color, val);
- }
+ text_decoration.readIfUnset( val );
break;
case SP_PROP_TEXT_DECORATION_LINE:
- if (!style->text_decoration_line.set) {
- sp_style_read_itextdecorationLine(&style->text_decoration_line, val);
- }
+ text_decoration_line.readIfUnset( val );
break;
case SP_PROP_TEXT_DECORATION_STYLE:
- if (!style->text_decoration_style.set) {
- sp_style_read_itextdecorationStyle(&style->text_decoration_style, val);
- }
+ text_decoration_style.readIfUnset( val );
break;
case SP_PROP_TEXT_DECORATION_COLOR:
- if (!style->text_decoration_color.set) {
- sp_style_read_itextdecorationColor(&style->text_decoration_color, val);
- }
+ text_decoration_color.readIfUnset( val );
break;
case SP_PROP_LINE_HEIGHT:
- if (!style->line_height.set) {
- sp_style_read_ilengthornormal(&style->line_height, val);
- }
+ line_height.readIfUnset( val );
break;
case SP_PROP_LETTER_SPACING:
- if (!style->letter_spacing.set) {
- sp_style_read_ilengthornormal(&style->letter_spacing, val);
- }
+ letter_spacing.readIfUnset( val );
break;
case SP_PROP_WORD_SPACING:
- if (!style->word_spacing.set) {
- sp_style_read_ilengthornormal(&style->word_spacing, val);
- }
+ word_spacing.readIfUnset( val );
break;
case SP_PROP_TEXT_TRANSFORM:
- SPS_READ_IENUM_IF_UNSET(&style->text_transform, val, enum_text_transform, true);
+ text_transform.readIfUnset( val );
break;
/* Text (css3) */
case SP_PROP_DIRECTION:
- SPS_READ_IENUM_IF_UNSET(&style->direction, val, enum_direction, true);
+ direction.readIfUnset( val );
break;
case SP_PROP_BLOCK_PROGRESSION:
- SPS_READ_IENUM_IF_UNSET(&style->block_progression, val, enum_block_progression, true);
+ block_progression.readIfUnset( val );
break;
case SP_PROP_WRITING_MODE:
- SPS_READ_IENUM_IF_UNSET(&style->writing_mode, val, enum_writing_mode, true);
+ writing_mode.readIfUnset( val );
break;
case SP_PROP_TEXT_ANCHOR:
- SPS_READ_IENUM_IF_UNSET(&style->text_anchor, val, enum_text_anchor, true);
+ text_anchor.readIfUnset( val );
break;
case SP_PROP_BASELINE_SHIFT:
- SPS_READ_IBASELINE_SHIFT_IF_UNSET(&style->baseline_shift, val);
+ baseline_shift.readIfUnset( val );
break;
- case SP_PROP_TEXT_RENDERING: {
- SPS_READ_IENUM_IF_UNSET(&style->text_rendering, val, enum_text_rendering, true);
+ case SP_PROP_TEXT_RENDERING:
+ text_rendering.readIfUnset( val );
break;
- }
case SP_PROP_ALIGNMENT_BASELINE:
g_warning("Unimplemented style property SP_PROP_ALIGNMENT_BASELINE: value: %s", val);
break;
@@ -1225,31 +694,25 @@ sp_style_merge_property(SPStyle *style, gint id, gchar const *val)
g_warning("Unimplemented style property SP_PROP_CLIP: value: %s", val);
break;
case SP_PROP_COLOR:
- if (!style->color.set) {
- sp_style_read_icolor(&style->color, val, style, (style->object) ? style->object->document : NULL);
- }
+ color.readIfUnset( val );
break;
case SP_PROP_CURSOR:
g_warning("Unimplemented style property SP_PROP_CURSOR: value: %s", val);
break;
case SP_PROP_DISPLAY:
- SPS_READ_IENUM_IF_UNSET(&style->display, val, enum_display, true);
+ display.readIfUnset( val );
break;
case SP_PROP_OVERFLOW:
- /** \todo
- * FIXME: not supported properly yet, we just read and write it,
- * but act as if it is always "display".
- */
- SPS_READ_IENUM_IF_UNSET(&style->overflow, val, enum_overflow, true);
+ overflow.readIfUnset( val );
break;
case SP_PROP_VISIBILITY:
- SPS_READ_IENUM_IF_UNSET(&style->visibility, val, enum_visibility, true);
+ visibility.readIfUnset( val );
break;
case SP_PROP_ISOLATION:
- SPS_READ_IENUM_IF_UNSET(&style->isolation, val, enum_isolation, true);
+ isolation.readIfUnset( val );
break;
case SP_PROP_BLEND_MODE:
- SPS_READ_IENUM_IF_UNSET(&style->blend_mode, val, enum_blend_mode, true);
+ blend_mode.readIfUnset( val );
break;
/* SVG */
@@ -1264,12 +727,10 @@ sp_style_merge_property(SPStyle *style, gint id, gchar const *val)
g_warning("attribute 'clip-path' given as CSS");
//XML Tree being directly used here.
- style->object->getRepr()->setAttribute("clip-path", val);
+ this->object->getRepr()->setAttribute("clip-path", val);
break;
case SP_PROP_CLIP_RULE:
- if (!style->clip_rule.set) {
- sp_style_read_ienum(&style->clip_rule, val, enum_clip_rule, true);
- }
+ clip_rule.readIfUnset( val );
break;
case SP_PROP_MASK:
/** \todo
@@ -1278,22 +739,17 @@ sp_style_merge_property(SPStyle *style, gint id, gchar const *val)
g_warning("attribute 'mask' given as CSS");
//XML Tree being directly used here.
- style->object->getRepr()->setAttribute("mask", val);
+ this->object->getRepr()->setAttribute("mask", val);
break;
case SP_PROP_OPACITY:
- if (!style->opacity.set) {
- sp_style_read_iscale24(&style->opacity, val);
- }
+ opacity.readIfUnset( val );
break;
case SP_PROP_ENABLE_BACKGROUND:
- SPS_READ_IENUM_IF_UNSET(&style->enable_background, val,
- enum_enable_background, true);
+ enable_background.readIfUnset( val );
break;
/* Filter */
case SP_PROP_FILTER:
- if (!style->filter.set && !style->filter.inherit) {
- sp_style_read_ifilter(val, style, (style->object) ? style->object->document : NULL);
- }
+ if( !filter.inherit ) filter.readIfUnset( val );
break;
case SP_PROP_FLOOD_COLOR:
g_warning("Unimplemented style property SP_PROP_FLOOD_COLOR: value: %s", val);
@@ -1318,139 +774,186 @@ sp_style_merge_property(SPStyle *style, gint id, gchar const *val)
/* Paint */
case SP_PROP_COLOR_INTERPOLATION:
// We read it but issue warning
- SPS_READ_IENUM_IF_UNSET(&style->color_interpolation, val, enum_color_interpolation, true);
- if( style->color_interpolation.value != SP_CSS_COLOR_INTERPOLATION_SRGB ) {
+ color_interpolation.readIfUnset( val );
+ if( color_interpolation.value != SP_CSS_COLOR_INTERPOLATION_SRGB ) {
g_warning("Inkscape currently only supports color-interpolation = sRGB");
}
break;
case SP_PROP_COLOR_INTERPOLATION_FILTERS:
- SPS_READ_IENUM_IF_UNSET(&style->color_interpolation_filters, val, enum_color_interpolation, true);
+ color_interpolation_filters.readIfUnset( val );
break;
case SP_PROP_COLOR_PROFILE:
g_warning("Unimplemented style property SP_PROP_COLOR_PROFILE: value: %s", val);
break;
- case SP_PROP_COLOR_RENDERING: {
- SPS_READ_IENUM_IF_UNSET(&style->color_rendering, val, enum_color_rendering, true);
+ case SP_PROP_COLOR_RENDERING:
+ color_rendering.readIfUnset( val );
break;
- }
case SP_PROP_FILL:
- if (!style->fill.set) {
- style->fill.read( val, *style, (style->object) ? style->object->document : NULL );
- }
+ fill.readIfUnset( val );
break;
case SP_PROP_FILL_OPACITY:
- if (!style->fill_opacity.set) {
- sp_style_read_iscale24(&style->fill_opacity, val);
- }
+ fill_opacity.readIfUnset( val );
break;
case SP_PROP_FILL_RULE:
- if (!style->fill_rule.set) {
- sp_style_read_ienum(&style->fill_rule, val, enum_fill_rule, true);
- }
+ fill_rule.readIfUnset( val );
break;
- case SP_PROP_IMAGE_RENDERING: {
- SPS_READ_IENUM_IF_UNSET(&style->image_rendering, val, enum_image_rendering, true);
+ case SP_PROP_IMAGE_RENDERING:
+ image_rendering.readIfUnset( val );
break;
- }
case SP_PROP_MARKER:
- /* TODO: Call sp_uri_reference_resolve(SPDocument *document, guchar const *uri) */
- /* style->marker[SP_MARKER_LOC] = g_quark_from_string(val); */
- if (!style->marker[SP_MARKER_LOC].set) {
- g_free(style->marker[SP_MARKER_LOC].value);
- style->marker[SP_MARKER_LOC].value = g_strdup(val);
- style->marker[SP_MARKER_LOC].set = TRUE;
- style->marker[SP_MARKER_LOC].inherit = (val && !strcmp(val, "inherit"));
- }
+ /* TODO: Call sp_uri_reference_resolve(SPDocument *document, guchar const *uri) */
+ marker.readIfUnset( val );
break;
-
case SP_PROP_MARKER_START:
/* TODO: Call sp_uri_reference_resolve(SPDocument *document, guchar const *uri) */
- if (!style->marker[SP_MARKER_LOC_START].set) {
- g_free(style->marker[SP_MARKER_LOC_START].value);
- style->marker[SP_MARKER_LOC_START].value = g_strdup(val);
- style->marker[SP_MARKER_LOC_START].set = TRUE;
- style->marker[SP_MARKER_LOC_START].inherit = (val && !strcmp(val, "inherit"));
- }
+ marker_start.readIfUnset( val );
break;
case SP_PROP_MARKER_MID:
/* TODO: Call sp_uri_reference_resolve(SPDocument *document, guchar const *uri) */
- if (!style->marker[SP_MARKER_LOC_MID].set) {
- g_free(style->marker[SP_MARKER_LOC_MID].value);
- style->marker[SP_MARKER_LOC_MID].value = g_strdup(val);
- style->marker[SP_MARKER_LOC_MID].set = TRUE;
- style->marker[SP_MARKER_LOC_MID].inherit = (val && !strcmp(val, "inherit"));
- }
+ marker_mid.readIfUnset( val );
break;
case SP_PROP_MARKER_END:
/* TODO: Call sp_uri_reference_resolve(SPDocument *document, guchar const *uri) */
- if (!style->marker[SP_MARKER_LOC_END].set) {
- g_free(style->marker[SP_MARKER_LOC_END].value);
- style->marker[SP_MARKER_LOC_END].value = g_strdup(val);
- style->marker[SP_MARKER_LOC_END].set = TRUE;
- style->marker[SP_MARKER_LOC_END].inherit = (val && !strcmp(val, "inherit"));
- }
+ marker_end.readIfUnset( val );
break;
-
- case SP_PROP_SHAPE_RENDERING: {
- SPS_READ_IENUM_IF_UNSET(&style->shape_rendering, val, enum_shape_rendering, true);
+ case SP_PROP_SHAPE_RENDERING:
+ shape_rendering.readIfUnset( val );
break;
- }
-
case SP_PROP_STROKE:
- if (!style->stroke.set) {
- style->stroke.read( val, *style, (style->object) ? style->object->document : NULL );
- }
+ stroke.readIfUnset( val );
break;
case SP_PROP_STROKE_WIDTH:
- SPS_READ_ILENGTH_IF_UNSET(&style->stroke_width, val);
+ stroke_width.readIfUnset( val );
break;
case SP_PROP_STROKE_DASHARRAY:
- if (!style->stroke_dasharray.set) {
- sp_style_read_dash(style, val);
- }
+ stroke_dasharray.readIfUnset( val );
break;
case SP_PROP_STROKE_DASHOFFSET:
- SPS_READ_ILENGTH_IF_UNSET(&style->stroke_dashoffset, val);
+ stroke_dashoffset.readIfUnset( val );
break;
case SP_PROP_STROKE_LINECAP:
- if (!style->stroke_linecap.set) {
- sp_style_read_ienum(&style->stroke_linecap, val, enum_stroke_linecap, true);
- }
+ stroke_linecap.readIfUnset( val );
break;
case SP_PROP_STROKE_LINEJOIN:
- if (!style->stroke_linejoin.set) {
- sp_style_read_ienum(&style->stroke_linejoin, val, enum_stroke_linejoin, true);
- }
+ stroke_linejoin.readIfUnset( val );
break;
case SP_PROP_STROKE_MITERLIMIT:
- if (!style->stroke_miterlimit.set) {
- sp_style_read_ifloat(&style->stroke_miterlimit, val);
- }
+ stroke_miterlimit.readIfUnset( val );
break;
case SP_PROP_STROKE_OPACITY:
- if (!style->stroke_opacity.set) {
- sp_style_read_iscale24(&style->stroke_opacity, val);
- }
+ stroke_opacity.readIfUnset( val );
break;
case SP_PROP_PAINT_ORDER:
- if (!style->paint_order.set) {
- sp_style_read_ipaintorder(&style->paint_order, val);
- }
+ paint_order.readIfUnset( val );
break;
-
default:
- g_warning("Invalid style property id: %d value: %s", id, val);
+ g_warning("SPIStyle::readIfUnset(): Invalid style property id: %d value: %s", id, val);
break;
}
}
-static void
-sp_style_merge_style_from_decl(SPStyle *const style, CRDeclaration const *const decl)
-{
- /** \todo Ensure that property is lcased, as per
- * http://www.w3.org/TR/REC-CSS2/syndata.html#q4.
- * Should probably be done in libcroco.
- */
+Glib::ustring
+SPStyle::write( guint const flags, SPStyle const *const base ) const {
+
+ // std::cout << "SPStyle::write" << std::endl;
+
+ Glib::ustring style_string;
+ for(std::vector<SPIBase*>::size_type i = 0; i != _properties.size(); ++i) {
+ if( base != NULL ) {
+ style_string += _properties[i]->write( flags, base->_properties[i] );
+ } else {
+ style_string += _properties[i]->write( flags, NULL );
+ }
+ }
+ // for(SPPropMap::iterator i = _propmap.begin(); i != _propmap.end(); ++i ) {
+ // if( base != NULL ) {
+ // style_string += (this->*(i->second)).write( flags, &(base->*(i->second)) );
+ // } else {
+ // style_string += (this->*(i->second)).write( flags, NULL );
+ // }
+ // }
+
+ // Remove trailing ';'
+ if( style_string.size() > 0 ) {
+ style_string.erase( style_string.size() - 1 );
+ }
+ return style_string;
+}
+
+// Corresponds to sp_style_merge_from_parent()
+void
+SPStyle::cascade( SPStyle const *const parent ) {
+ // std::cout << "SPStyle::cascade" << std::endl;
+ for(std::vector<SPIBase*>::size_type i = 0; i != _properties.size(); ++i) {
+ _properties[i]->cascade( parent->_properties[i] );
+ }
+ // for(SPPropMap::iterator i = _propmap.begin(); i != _propmap.end(); ++i ) {
+ // (this->*(i->second)).cascade( &(parent->*(i->second)) );
+ // }
+}
+
+// Corresponds to sp_style_merge_from_dying_parent()
+void
+SPStyle::merge( SPStyle const *const parent ) {
+ // std::cout << "SPStyle::merge" << std::endl;
+ for(std::vector<SPIBase*>::size_type i = 0; i != _properties.size(); ++i) {
+ _properties[i]->merge( parent->_properties[i] );
+ }
+ // for(SPPropMap::iterator i = _propmap.begin(); i != _propmap.end(); ++i ) {
+ // (this->*(i->second)).cascade( &(parent->*(i->second)) );
+ // }
+}
+
+// Mostly for unit testing
+bool
+SPStyle::operator==(const SPStyle& rhs) {
+
+ // Uncomment for testing
+ // for(std::vector<SPIBase*>::size_type i = 0; i != _properties.size(); ++i) {
+ // if( *_properties[i] != *rhs._properties[i])
+ // std::cout << _properties[i]->name << ": "
+ // << _properties[i]->write(SP_STYLE_FLAG_ALWAYS,NULL) << " "
+ // << rhs._properties[i]->write(SP_STYLE_FLAG_ALWAYS,NULL)
+ // << (*_properties[i] == *rhs._properties[i]) << std::endl;
+ // }
+
+ for(std::vector<SPIBase*>::size_type i = 0; i != _properties.size(); ++i) {
+ if( *_properties[i] != *rhs._properties[i]) return false;
+ }
+ return true;
+}
+
+void
+SPStyle::_mergeString( gchar const *const p ) {
+
+ // std::cout << "SPStyle::_mergeString: " << (p?p:"null") << std::endl;
+ CRDeclaration *const decl_list
+ = cr_declaration_parse_list_from_buf(reinterpret_cast<guchar const *>(p), CR_UTF_8);
+ if (decl_list) {
+ _mergeDeclList( decl_list );
+ cr_declaration_destroy(decl_list);
+ }
+}
+
+void
+SPStyle::_mergeDeclList( CRDeclaration const *const decl_list ) {
+
+ // std::cout << "SPStyle::_mergeDeclList" << std::endl;
+
+ // In reverse order, as later declarations to take precedence over earlier ones.
+ // (Properties are only set if not previously set. See:
+ // Ref: http://www.w3.org/TR/REC-CSS2/cascade.html#cascading-order point 4.)
+ if (decl_list->next) {
+ _mergeDeclList( decl_list->next );
+ }
+ _mergeDecl( decl_list );
+}
+
+void
+SPStyle::_mergeDecl( CRDeclaration const *const decl ) {
+
+ // std::cout << "SPStyle::_mergeDecl" << std::endl;
+
unsigned const prop_idx = sp_attribute_lookup(decl->property->stryng->str);
if (prop_idx != SP_ATTR_INVALID) {
/** \todo
@@ -1460,71 +963,30 @@ sp_style_merge_style_from_decl(SPStyle *const style, CRDeclaration const *const
*/
guchar *const str_value_unsigned = cr_term_to_string(decl->value);
gchar *const str_value = reinterpret_cast<gchar *>(str_value_unsigned);
- sp_style_merge_property(style, prop_idx, str_value);
+ readIfUnset( prop_idx, str_value );
g_free(str_value);
}
}
-static void
-sp_style_merge_from_props(SPStyle *const style, CRPropList *const props)
-{
-#if 0 /* forwards */
- for (CRPropList const *cur = props; cur; cur = cr_prop_list_get_next(cur)) {
- CRDeclaration *decl = NULL;
- cr_prop_list_get_decl(cur, &decl);
- sp_style_merge_style_from_decl(style, decl);
- }
-#else /* in reverse order, as we need later declarations to take precedence over earlier ones. */
+void
+SPStyle::_mergeProps( CRPropList *const props ) {
+
+ // std::cout << "SPStyle::_mergeProps" << std::endl;
+
+ // In reverse order, as later declarations to take precedence over earlier ones.
if (props) {
- sp_style_merge_from_props(style, cr_prop_list_get_next(props));
+ _mergeProps( cr_prop_list_get_next( props ) );
CRDeclaration *decl = NULL;
cr_prop_list_get_decl(props, &decl);
- sp_style_merge_style_from_decl(style, decl);
+ _mergeDecl( decl );
}
-#endif
-}
-
-/**
- * \pre decl_list != NULL
- */
-static void
-sp_style_merge_from_decl_list(SPStyle *const style, CRDeclaration const *const decl_list)
-{
- // read the decls from end to start, using head recursion, so that latter declarations override
- // (Ref: http://www.w3.org/TR/REC-CSS2/cascade.html#cascading-order point 4.)
- // because sp_style_merge_style_from_decl only sets properties that are unset
- if (decl_list->next) {
- sp_style_merge_from_decl_list(style, decl_list->next);
- }
- sp_style_merge_style_from_decl(style, decl_list);
}
-static CRSelEng *
-sp_repr_sel_eng()
-{
- CRSelEng *const ret = cr_sel_eng_new();
- cr_sel_eng_set_node_iface(ret, &Inkscape::XML::croco_node_iface);
-
- /** \todo
- * Check whether we need to register any pseudo-class handlers.
- * libcroco has its own default handlers for first-child and lang.
- *
- * We probably want handlers for link and arguably visited (though
- * inkscape can't visit links at the time of writing). hover etc.
- * more useful in inkview than the editor inkscape.
- *
- * http://www.w3.org/TR/SVG11/styling.html#StylingWithCSS says that
- * the following should be honoured, at least by inkview:
- * :hover, :active, :focus, :visited, :link.
- */
+void
+SPStyle::_mergeObjectStylesheet( SPObject const *const object ) {
- g_assert(ret);
- return ret;
-}
+ // std::cout << "SPStyle::_mergeObjectStylesheet: " << (object->getId()?object->getId():"null") << std::endl;
-static void
-sp_style_merge_from_object_stylesheet(SPStyle *const style, SPObject const *const object)
-{
static CRSelEng *sel_eng = NULL;
if (!sel_eng) {
sel_eng = sp_repr_sel_eng();
@@ -1540,586 +1002,319 @@ sp_style_merge_from_object_stylesheet(SPStyle *const style, SPObject const *cons
g_return_if_fail(status == CR_OK);
/// \todo Check what errors can occur, and handle them properly.
if (props) {
- sp_style_merge_from_props(style, props);
+ _mergeProps(props);
cr_prop_list_destroy(props);
}
}
+// Internal
/**
- * Parses a style="..." string and merges it with an existing SPStyle.
+ * Release callback.
*/
-void
-sp_style_merge_from_style_string(SPStyle *const style, gchar const *const p)
-{
- /*
- * Reference: http://www.w3.org/TR/SVG11/styling.html#StyleAttribute:
- * ``When CSS styling is used, CSS inline style is specified by including
- * semicolon-separated property declarations of the form "name : value"
- * within the style attribute''.
- *
- * That's fairly ambiguous. Is a `value' allowed to contain semicolons?
- * Why does it say "including", what else is allowed in the style
- * attribute value?
- */
-
- CRDeclaration *const decl_list
- = cr_declaration_parse_list_from_buf(reinterpret_cast<guchar const *>(p), CR_UTF_8);
- if (decl_list) {
- sp_style_merge_from_decl_list(style, decl_list);
- cr_declaration_destroy(decl_list);
- }
-}
-
-/** Indexed by SP_CSS_FONT_SIZE_blah. */
-static float const font_size_table[] = {6.0, 8.0, 10.0, 12.0, 14.0, 18.0, 24.0};
-
static void
-sp_style_merge_font_size_from_parent(SPIFontSize &child, SPIFontSize const &parent)
+sp_style_object_release(SPObject *object, SPStyle *style)
{
- /* 'font-size' */
- if (!child.set || child.inherit) {
- /* Inherit the computed value. Reference: http://www.w3.org/TR/SVG11/styling.html#Inheritance */
- child.computed = parent.computed;
- } else if (child.type == SP_FONT_SIZE_LITERAL) {
- /** \todo
- * fixme: SVG and CSS do not specify clearly, whether we should use
- * user or screen coordinates (Lauris)
- */
- if (child.literal < SP_CSS_FONT_SIZE_SMALLER) {
- child.computed = font_size_table[child.literal];
- } else if (child.literal == SP_CSS_FONT_SIZE_SMALLER) {
- child.computed = parent.computed / 1.2;
- } else if (child.literal == SP_CSS_FONT_SIZE_LARGER) {
- child.computed = parent.computed * 1.2;
- } else {
- /* Illegal value */
- }
- } else if (child.type == SP_FONT_SIZE_PERCENTAGE) {
- /* Unlike most other lengths, percentage for font size is relative to parent computed value
- * rather than viewport. */
- child.computed = parent.computed * child.value;
- } else if (child.type == SP_FONT_SIZE_LENGTH) {
- switch (child.unit) {
- case SP_CSS_UNIT_EM:
- /* Relative to parent font size */
- child.computed = parent.computed * child.value;
- break;
- case SP_CSS_UNIT_EX:
- /* Relative to parent font size */
- child.computed = parent.computed * child.value * 0.5; /* Hack */
- break;
- default:
- /* No change */
- break;
- }
- }
+ (void)object; // TODO
+ style->object = NULL;
}
-// Some shifts are defined relative to parent.
+// Internal
+/**
+ * Emit style modified signal on style's object if the filter changed.
+ */
static void
-sp_style_merge_baseline_shift_from_parent(SPIBaselineShift &child, SPIBaselineShift const &parent,
- SPIFontSize const &pfont_size)
+sp_style_filter_ref_modified(SPObject *obj, guint flags, SPStyle *style)
{
- /* 'baseline-shift' */
- if (!child.set || child.inherit) {
- /* Inherit the computed value. Reference: http://www.w3.org/TR/SVG11/styling.html#Inheritance */
- child.computed = parent.computed; // Does this make sense (applying a shift a second time)?
- } else if (child.type == SP_BASELINE_SHIFT_LITERAL) {
- if( child.literal == SP_CSS_BASELINE_SHIFT_BASELINE ) {
- child.computed = 0; // No change
- } else if (child.literal == SP_CSS_BASELINE_SHIFT_SUB ) {
- // Should use subscript position from font relative to alphabetic baseline
- // OpenOffice, Adobe: -0.33, Word -0.14, LaTex about -0.2.
- child.computed = -0.2 * pfont_size.computed;
- } else if (child.literal == SP_CSS_BASELINE_SHIFT_SUPER ) {
- // Should use superscript position from font relative to alphabetic baseline
- // OpenOffice, Adobe: 0.33, Word 0.35, LaTex about 0.45.
- child.computed = 0.4 * pfont_size.computed;
- } else {
- /* Illegal value */
- }
- } else if (child.type == SP_BASELINE_SHIFT_PERCENTAGE) {
- // Percentage for baseline shift is relative to computed "line-height"
- // which is just font-size (see SVG1.1 'font').
- child.computed = pfont_size.computed * child.value;
- } else if (child.type == SP_BASELINE_SHIFT_LENGTH) {
- switch (child.unit) {
- case SP_CSS_UNIT_EM:
- child.computed = child.value * pfont_size.computed;
- break;
- case SP_CSS_UNIT_EX:
- child.computed = child.value * 0.5 * pfont_size.computed;
- break;
- default:
- /* No change */
- break;
+ (void)flags; // TODO
+ SPFilter *filter=static_cast<SPFilter *>(obj);
+ if (style->getFilter() == filter)
+ {
+ if (style->object) {
+ style->object->requestModified(SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_STYLE_MODIFIED_FLAG);
}
}
- // baseline-shifts are relative to parent baseline
- child.computed += parent.computed;
}
+// Internal
/**
- * Sets computed values in \a style, which may involve inheriting from (or in some other way
- * calculating from) corresponding computed values of \a parent.
- *
- * References: http://www.w3.org/TR/SVG11/propidx.html shows what properties inherit by default.
- * http://www.w3.org/TR/SVG11/styling.html#Inheritance gives general rules as to what it means to
- * inherit a value. http://www.w3.org/TR/REC-CSS2/cascade.html#computed-value is more precise
- * about what the computed value is (not obvious for lengths).
- *
- * \pre \a parent's computed values are already up-to-date.
+ * Gets called when the filter is (re)attached to the style
*/
void
-sp_style_merge_from_parent(SPStyle *const style, SPStyle const *const parent)
+sp_style_filter_ref_changed(SPObject *old_ref, SPObject *ref, SPStyle *style)
{
- g_return_if_fail(style != NULL);
-
- /** \todo
- * fixme: Check for existing callers that might pass null parent.
- * This should probably be g_return_if_fail, or else we should make a
- * best attempt to set computed values correctly without having a parent
- * (i.e., by assuming parent has initial values).
- */
- if (!parent)
- return;
-
- /* CSS2 */
- /* Font */
- sp_style_merge_font_size_from_parent(style->font_size, parent->font_size);
-
- /* 'font-style' */
- if (!style->font_style.set || style->font_style.inherit) {
- style->font_style.computed = parent->font_style.computed;
- }
-
- /* 'font-variant' */
- if (!style->font_variant.set || style->font_variant.inherit) {
- style->font_variant.computed = parent->font_variant.computed;
- }
-
- /* 'font-weight' */
- if (!style->font_weight.set || style->font_weight.inherit) {
- style->font_weight.computed = parent->font_weight.computed;
- } else if (style->font_weight.value == SP_CSS_FONT_WEIGHT_NORMAL) {
- /** \todo
- * fixme: This is unconditional, i.e., happens even if parent not
- * present.
- */
- style->font_weight.computed = SP_CSS_FONT_WEIGHT_400;
- } else if (style->font_weight.value == SP_CSS_FONT_WEIGHT_BOLD) {
- style->font_weight.computed = SP_CSS_FONT_WEIGHT_700;
- } else if (style->font_weight.value == SP_CSS_FONT_WEIGHT_LIGHTER) {
- unsigned const parent_val = parent->font_weight.computed;
- g_assert(SP_CSS_FONT_WEIGHT_100 == 0);
- // strictly, 'bolder' and 'lighter' should go to the next weight
- // expressible in the current font family, but that's difficult to
- // find out, so jumping by 3 seems an appropriate approximation
- style->font_weight.computed = (parent_val <= SP_CSS_FONT_WEIGHT_100 + 3
- ? (unsigned)SP_CSS_FONT_WEIGHT_100
- : parent_val - 3);
- g_assert(style->font_weight.computed <= (unsigned) SP_CSS_FONT_WEIGHT_900);
- } else if (style->font_weight.value == SP_CSS_FONT_WEIGHT_BOLDER) {
- unsigned const parent_val = parent->font_weight.computed;
- g_assert(parent_val <= SP_CSS_FONT_WEIGHT_900);
- style->font_weight.computed = (parent_val >= SP_CSS_FONT_WEIGHT_900 - 3
- ? (unsigned)SP_CSS_FONT_WEIGHT_900
- : parent_val + 3);
- g_assert(style->font_weight.computed <= (unsigned) SP_CSS_FONT_WEIGHT_900);
- }
-
- /* 'font-stretch' */
- if (!style->font_stretch.set || style->font_stretch.inherit) {
- style->font_stretch.computed = parent->font_stretch.computed;
- } else if (style->font_stretch.value == SP_CSS_FONT_STRETCH_NARROWER) {
- unsigned const parent_val = parent->font_stretch.computed;
- style->font_stretch.computed = (parent_val == SP_CSS_FONT_STRETCH_ULTRA_CONDENSED
- ? parent_val
- : parent_val - 1);
- g_assert(style->font_stretch.computed <= (unsigned) SP_CSS_FONT_STRETCH_ULTRA_EXPANDED);
- } else if (style->font_stretch.value == SP_CSS_FONT_STRETCH_WIDER) {
- unsigned const parent_val = parent->font_stretch.computed;
- g_assert(parent_val <= SP_CSS_FONT_STRETCH_ULTRA_EXPANDED);
- style->font_stretch.computed = (parent_val == SP_CSS_FONT_STRETCH_ULTRA_EXPANDED
- ? parent_val
- : parent_val + 1);
- g_assert(style->font_stretch.computed <= (unsigned) SP_CSS_FONT_STRETCH_ULTRA_EXPANDED);
- }
-
- /* text (css2) */
- if (!style->text_indent.set || style->text_indent.inherit) {
- style->text_indent.computed = parent->text_indent.computed;
- }
-
- if (!style->text_align.set || style->text_align.inherit) {
- style->text_align.computed = parent->text_align.computed;
- }
-
- if (!style->text_decoration_line.set || style->text_decoration_line.inherit) {
- style->text_decoration_line.underline = parent->text_decoration_line.underline;
- style->text_decoration_line.overline = parent->text_decoration_line.overline;
- style->text_decoration_line.line_through = parent->text_decoration_line.line_through;
- style->text_decoration_line.blink = parent->text_decoration_line.blink;
- }
-
- if (!style->text_decoration_style.set || style->text_decoration_style.inherit) {
- style->text_decoration_style.solid = parent->text_decoration_style.solid;
- style->text_decoration_style.isdouble = parent->text_decoration_style.isdouble;
- style->text_decoration_style.dotted = parent->text_decoration_style.dotted;
- style->text_decoration_style.dashed = parent->text_decoration_style.dashed;
- style->text_decoration_style.wavy = parent->text_decoration_style.wavy;
+ if (old_ref) {
+ style->filter_modified_connection.disconnect();
}
-
- if (!style->text_decoration_color.set || style->text_decoration_color.inherit) {
- sp_style_merge_ipaint(style, &style->text_decoration_color, &parent->text_decoration_color);
+ if ( SP_IS_FILTER(ref))
+ {
+ style->filter_modified_connection =
+ ref->connectModified(sigc::bind(sigc::ptr_fun(&sp_style_filter_ref_modified), style));
}
- if (!style->line_height.set || style->line_height.inherit) {
- style->line_height.value = parent->line_height.value;
- style->line_height.computed = parent->line_height.computed;
- style->line_height.normal = parent->line_height.normal;
- }
+ sp_style_filter_ref_modified(ref, 0, style);
+}
- if (!style->letter_spacing.set || style->letter_spacing.inherit) {
- style->letter_spacing.value = parent->letter_spacing.value;
- style->letter_spacing.computed = parent->letter_spacing.computed;
- style->letter_spacing.normal = parent->letter_spacing.normal;
- }
+/**
+ * Emit style modified signal on style's object if server is style's fill
+ * or stroke paint server.
+ */
+static void
+sp_style_paint_server_ref_modified(SPObject *obj, guint flags, SPStyle *style)
+{
+ (void)flags; // TODO
+ SPPaintServer *server = static_cast<SPPaintServer *>(obj);
- if (!style->word_spacing.set || style->word_spacing.inherit) {
- style->word_spacing.value = parent->word_spacing.value;
- style->word_spacing.computed = parent->word_spacing.computed;
- style->word_spacing.normal = parent->word_spacing.normal;
+ if ((style->fill.isPaintserver())
+ && style->getFillPaintServer() == server)
+ {
+ if (style->object) {
+ /** \todo
+ * fixme: I do not know, whether it is optimal - we are
+ * forcing reread of everything (Lauris)
+ */
+ /** \todo
+ * fixme: We have to use object_modified flag, because parent
+ * flag is only available downstreams.
+ */
+ style->object->requestModified(SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_STYLE_MODIFIED_FLAG);
+ }
+ } else if ((style->stroke.isPaintserver())
+ && style->getStrokePaintServer() == server)
+ {
+ if (style->object) {
+ /// \todo fixme:
+ style->object->requestModified(SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_STYLE_MODIFIED_FLAG);
+ }
+ } else if (server) {
+ g_assert_not_reached();
}
+}
- if (!style->text_transform.set || style->text_transform.inherit) {
- style->text_transform.computed = parent->text_transform.computed;
+/**
+ * Gets called when the paintserver is (re)attached to the style
+ */
+void
+sp_style_fill_paint_server_ref_changed(SPObject *old_ref, SPObject *ref, SPStyle *style)
+{
+ if (old_ref) {
+ style->fill_ps_modified_connection.disconnect();
}
-
- if (!style->direction.set || style->direction.inherit) {
- style->direction.computed = parent->direction.computed;
+ if (SP_IS_PAINT_SERVER(ref)) {
+ style->fill_ps_modified_connection =
+ ref->connectModified(sigc::bind(sigc::ptr_fun(&sp_style_paint_server_ref_modified), style));
}
- if (!style->block_progression.set || style->block_progression.inherit) {
- style->block_progression.computed = parent->block_progression.computed;
- }
+ sp_style_paint_server_ref_modified(ref, 0, style);
+}
- if (!style->writing_mode.set || style->writing_mode.inherit) {
- style->writing_mode.computed = parent->writing_mode.computed;
+/**
+ * Gets called when the paintserver is (re)attached to the style
+ */
+void
+sp_style_stroke_paint_server_ref_changed(SPObject *old_ref, SPObject *ref, SPStyle *style)
+{
+ if (old_ref) {
+ style->stroke_ps_modified_connection.disconnect();
}
-
- if (!style->text_anchor.set || style->text_anchor.inherit) {
- style->text_anchor.computed = parent->text_anchor.computed;
+ if (SP_IS_PAINT_SERVER(ref)) {
+ style->stroke_ps_modified_connection =
+ ref->connectModified(sigc::bind(sigc::ptr_fun(&sp_style_paint_server_ref_modified), style));
}
- /* Baseline Shift... Some shifts are relative to parent. */
- sp_style_merge_baseline_shift_from_parent(style->baseline_shift, parent->baseline_shift,
- parent->font_size);
+ sp_style_paint_server_ref_modified(ref, 0, style);
+}
- if (style->opacity.inherit) {
- style->opacity.value = parent->opacity.value;
- }
+// Called in: desktop-style.cpp, gradient-chemistry.cpp, sp-object.cpp, sp-stop.cpp, style.cpp
+// text-editing.cpp, libnrtype/font-lister.cpp, widgets/dash-selector.cpp, widgets/fill-style.cpp,
+// widgets/stroke-style.cpp, widgets/text-toolbar.cpp, ui/dialog/glyphs.cpp, ui/dialog/swatches.cpp,
+// ui/dialog/swatches.cpp, ui/dialog/text-edit.cpp. ui/tools/freehand-base.cpp,
+// ui/widget/object-composite-settings.cpp, ui/widget/selected-style.cpp, ui/widget/style-swatch.cpp
+/**
+ * Returns a new SPStyle object with default settings.
+ */
+SPStyle *
+sp_style_new(SPDocument *document)
+{
+ SPStyle *const style = new SPStyle( document );
+ return style;
+}
- /* Color */
- if (!style->color.set || style->color.inherit) {
- sp_style_merge_ipaint(style, &style->color, &parent->color);
- }
- if (!style->color_interpolation.set || style->color_interpolation.inherit) {
- style->color_interpolation.computed = parent->color_interpolation.computed;
- }
- if (!style->color_interpolation_filters.set || style->color_interpolation_filters.inherit) {
- style->color_interpolation_filters.computed = parent->color_interpolation_filters.computed;
- }
+// Called in: sp-object.cpp
+/**
+ * Creates a new SPStyle object, and attaches it to the specified SPObject.
+ */
+SPStyle *
+sp_style_new_from_object(SPObject *object)
+{
+ g_return_val_if_fail(object != NULL, NULL);
+ g_return_val_if_fail(SP_IS_OBJECT(object), NULL);
+ SPStyle *const style = new SPStyle( NULL, object );
+ return style;
+}
- /* Fill */
- if (!style->fill.set || style->fill.inherit || style->fill.currentcolor) {
- sp_style_merge_ipaint(style, &style->fill, &parent->fill);
- }
+// Called in display/drawing-item.cpp, display/nr-filter-primitive.cpp, libnrtype/Layout-TNG-Input.cpp
+/**
+ * Increase refcount of style.
+ */
+SPStyle *
+sp_style_ref(SPStyle *style)
+{
+ g_return_val_if_fail(style != NULL, NULL);
- if (!style->fill_opacity.set || style->fill_opacity.inherit) {
- style->fill_opacity.value = parent->fill_opacity.value;
- }
+ style->ref(); // Increase ref count
- if (!style->fill_rule.set || style->fill_rule.inherit) {
- style->fill_rule.computed = parent->fill_rule.computed;
- }
+ return style;
+}
- /* Stroke */
- if (!style->stroke.set || style->stroke.inherit || style->stroke.currentcolor) {
- sp_style_merge_ipaint(style, &style->stroke, &parent->stroke);
+// Called in style.cpp, desktop-style.cpp, sp-object.cpp, sp-stop.cpp, text-editing.cpp
+// display/drawing-group.cpp, ...
+/**
+ * Decrease refcount of style with possible destruction.
+ */
+SPStyle *
+sp_style_unref(SPStyle *style)
+{
+ g_return_val_if_fail(style != NULL, NULL);
+ if (style->unref() < 1) {
+ delete style;
+ return NULL;
}
+ return style;
+}
- if (!style->stroke_width.set || style->stroke_width.inherit) {
- style->stroke_width.computed = parent->stroke_width.computed;
- } else {
- /* Update computed value for any change in font inherited from parent. */
- double const em = style->font_size.computed;
- if (style->stroke_width.unit == SP_CSS_UNIT_EM) {
- style->stroke_width.computed = style->stroke_width.value * em;
- } else if (style->stroke_width.unit == SP_CSS_UNIT_EX) {
- double const ex = em * 0.5; // fixme: Get x height from libnrtype or pango.
- style->stroke_width.computed = style->stroke_width.value * ex;
- }
- }
- if (!style->stroke_linecap.set || style->stroke_linecap.inherit) {
- style->stroke_linecap.computed = parent->stroke_linecap.computed;
- }
- if (!style->stroke_linejoin.set || style->stroke_linejoin.inherit) {
- style->stroke_linejoin.computed = parent->stroke_linejoin.computed;
- }
+// Called in: sp-clippath.cpp, sp-item.cpp (suspicious), sp-object.cpp, sp-style-elem.cpp
+/**
+ * Read style properties from object's repr.
+ *
+ * 1. Reset existing object style
+ * 2. Load current effective object style
+ * 3. Load i attributes from immediate parent (which has to be up-to-date)
+ */
+void
+sp_style_read_from_object(SPStyle *style, SPObject *object)
+{
+ // std::cout << "sp_style_read_from_object: " << (object->getId()?object->getId():"null") << std::endl;
+ g_return_if_fail(style != NULL);
+ g_return_if_fail(object != NULL);
+ g_return_if_fail(SP_IS_OBJECT(object));
- if (!style->stroke_miterlimit.set || style->stroke_miterlimit.inherit) {
- style->stroke_miterlimit.value = parent->stroke_miterlimit.value;
- }
+ Inkscape::XML::Node *repr = object->getRepr();
+ g_return_if_fail(repr != NULL);
- if (!style->stroke_dasharray.set || style->stroke_dasharray.inherit) {
- style->stroke_dasharray.values = parent->stroke_dasharray.values;
- }
+ style->read( object, repr );
+}
- if (!style->stroke_dashoffset.set || style->stroke_dashoffset.inherit) {
- style->stroke_dashoffset.value = parent->stroke_dashoffset.value;
- }
+// Called in: libnrtype/font-lister.cpp, widgets/dash-selector.cpp, widgets/text-toolbar.cpp,
+// ui/dialog/text-edit.cpp
+// Why is this called when draging a gradient handle?
+/**
+ * Read style properties from preferences.
+ * @param style The style to write to
+ * @param path Preferences directory from which the style should be read
+ */
+void
+sp_style_read_from_prefs(SPStyle *style, Glib::ustring const &path)
+{
+ g_return_if_fail(style != NULL);
+ g_return_if_fail(path != "");
- if (!style->stroke_opacity.set || style->stroke_opacity.inherit) {
- style->stroke_opacity.value = parent->stroke_opacity.value;
- }
+ Inkscape::Preferences *prefs = Inkscape::Preferences::get();
- if (!style->paint_order.set || style->paint_order.inherit) {
- g_free(style->paint_order.value);
- style->paint_order.value = g_strdup(parent->paint_order.value);
- for (unsigned i = 0; i < PAINT_ORDER_LAYERS; ++i) {
- style->paint_order.layer[i] = parent->paint_order.layer[i];
- style->paint_order.layer_set[i] = parent->paint_order.layer_set[i];
- }
- }
+ // not optimal: we reconstruct the node based on the prefs, then pass it to
+ // sp_style_read for actual processing.
+ Inkscape::XML::SimpleDocument *tempdoc = new Inkscape::XML::SimpleDocument;
+ Inkscape::XML::Node *tempnode = tempdoc->createElement("prefs");
- if (style->text && parent->text) {
- if (!style->text->font_family.set || style->text->font_family.inherit) {
- g_free(style->text->font_family.value);
- style->text->font_family.value = g_strdup(parent->text->font_family.value);
- }
+ std::vector<Inkscape::Preferences::Entry> attrs = prefs->getAllEntries(path);
+ for (std::vector<Inkscape::Preferences::Entry>::iterator i = attrs.begin(); i != attrs.end(); ++i) {
+ tempnode->setAttribute(i->getEntryName().data(), i->getString().data());
}
- if (style->text && parent->text) {
- if (!style->text->font_specification.set || style->text->font_specification.inherit) {
- g_free(style->text->font_specification.value);
- style->text->font_specification.value = g_strdup(parent->text->font_specification.value);
- }
- }
+ style->read( NULL, tempnode );
- /* Markers - Free the old value and make copy of the new */
- for (unsigned i = SP_MARKER_LOC; i < SP_MARKER_LOC_QTY; i++) {
- if (!style->marker[i].set || style->marker[i].inherit) {
- g_free(style->marker[i].value);
- style->marker[i].value = g_strdup(parent->marker[i].value);
- }
- }
+ Inkscape::GC::release(tempnode);
+ Inkscape::GC::release(tempdoc);
+ delete tempdoc;
+}
- /* Filter effects */
- if (style->filter.inherit) {
- sp_style_merge_ifilter(style, &parent->filter);
- }
- if(style->enable_background.inherit) {
- style->enable_background.value = parent->enable_background.value;
- }
+static CRSelEng *
+sp_repr_sel_eng()
+{
+ CRSelEng *const ret = cr_sel_eng_new();
+ cr_sel_eng_set_node_iface(ret, &Inkscape::XML::croco_node_iface);
- /* Clipping */
- if (!style->clip_rule.set || style->clip_rule.inherit) {
- style->clip_rule.computed = parent->clip_rule.computed;
- }
+ /** \todo
+ * Check whether we need to register any pseudo-class handlers.
+ * libcroco has its own default handlers for first-child and lang.
+ *
+ * We probably want handlers for link and arguably visited (though
+ * inkscape can't visit links at the time of writing). hover etc.
+ * more useful in inkview than the editor inkscape.
+ *
+ * http://www.w3.org/TR/SVG11/styling.html#StylingWithCSS says that
+ * the following should be honoured, at least by inkview:
+ * :hover, :active, :focus, :visited, :link.
+ */
- /* Rendering */
- if (!style->color_rendering.set || style->color_rendering.inherit) {
- style->color_rendering.computed = parent->color_rendering.computed;
- }
- if (!style->image_rendering.set || style->image_rendering.inherit) {
- style->image_rendering.computed = parent->image_rendering.computed;
- }
- if (!style->shape_rendering.set || style->shape_rendering.inherit) {
- style->shape_rendering.computed = parent->shape_rendering.computed;
- }
- if (!style->text_rendering.set || style->text_rendering.inherit) {
- style->text_rendering.computed = parent->text_rendering.computed;
- }
+ g_assert(ret);
+ return ret;
}
-template <typename T>
-static void
-sp_style_merge_prop_from_dying_parent(T &child, T const &parent)
-{
- if ( ( !(child.set) || child.inherit )
- && parent.set && !(parent.inherit) )
- {
- child = parent;
- }
-}
+// Called in text-editting.cpp, ui/tools/frehand-base.cpp, ui/widget/style-swatch.cpp
/**
- * Copy SPIString from parent to child.
+ * Parses a style="..." string and merges it with an existing SPStyle.
*/
-static void
-sp_style_merge_string_prop_from_dying_parent(SPIString &child, SPIString const &parent)
-{
- if ( ( !(child.set) || child.inherit )
- && parent.set && !(parent.inherit) )
- {
- g_free(child.value);
- child.value = g_strdup(parent.value);
- child.set = parent.set;
- child.inherit = parent.inherit;
- }
-}
-
-static void
-sp_style_merge_paint_prop_from_dying_parent(SPStyle *style,
- SPIPaint &child, SPIPaint const &parent)
+void
+sp_style_merge_from_style_string(SPStyle *const style, gchar const *const p)
{
- /** \todo
- * I haven't given this much attention. See comments below about
- * currentColor, colorProfile, and relative URIs.
+ // std::cout << "sp_style_merge_from_style_string: " << (p?p:"null") <<std::endl;
+ /*
+ * Reference: http://www.w3.org/TR/SVG11/styling.html#StyleAttribute:
+ * ``When CSS styling is used, CSS inline style is specified by including
+ * semicolon-separated property declarations of the form "name : value"
+ * within the style attribute''.
+ *
+ * That's fairly ambiguous. Is a `value' allowed to contain semicolons?
+ * Why does it say "including", what else is allowed in the style
+ * attribute value?
*/
- if (!child.set || child.inherit) {
- sp_style_merge_ipaint(style, &child, &parent);
- child.set = parent.set;
- child.inherit = parent.inherit;
- }
+ style->_mergeString( p );
}
-static void
-sp_style_merge_rel_enum_prop_from_dying_parent(SPIEnum &child, SPIEnum const &parent,
- unsigned const max_computed_val,
- unsigned const smaller_val)
-{
- /* We assume that min computed val is 0, contiguous up to max_computed_val,
- then zero or more other absolute values, then smaller_val then larger_val. */
- unsigned const min_computed_val = 0;
- unsigned const larger_val = smaller_val + 1;
- g_return_if_fail(min_computed_val < max_computed_val);
- g_return_if_fail(max_computed_val < smaller_val);
-
- if (parent.set && !parent.inherit) {
- if (!child.set || child.inherit) {
- child.value = parent.value;
- child.set = parent.set; // i.e. true
- child.inherit = parent.inherit; // i.e. false
- } else if (child.value < smaller_val) {
- /* Child has absolute value: leave as is. */
- } else if ( ( child.value == smaller_val
- && parent.value == larger_val )
- || ( parent.value == smaller_val
- && child.value == larger_val ) )
- {
- child.set = false;
- /*
- * Note that this can result in a change in computed value in the
- * rare case that the parent's setting was a no-op (i.e. if the
- * parent's parent's computed value was already ultra-condensed or
- * ultra-expanded). However, I'd guess that the change is for the
- * better: I'd guess that if the properties were specified
- * relatively, then the intent is to counteract parent's effect.
- * I.e. I believe this is the best code even in that case.
- */
- } else if (child.value == parent.value) {
- /* Leave as is. */
- /** \todo
- * It's unclear what to do if style and parent specify the same
- * relative directive (narrower or wider). We can either convert
- * to absolute specification or coalesce to a single relative
- * request (of half the strength of the original pair).
- *
- * Converting to a single level of relative specification is a
- * better choice if the newly-unlinked clone is itself cloned to
- * other contexts (inheriting different font stretchiness): it
- * would preserve the effect that it will be narrower than
- * the inherited context in each case. The disadvantage is that
- * it will ~certainly affect the computed value of the
- * newly-unlinked clone.
- */
- } else {
- unsigned const parent_val = parent.computed;
- child.value = ( child.value == smaller_val
- ? ( parent_val == min_computed_val
- ? parent_val
- : parent_val - 1 )
- : ( parent_val == max_computed_val
- ? parent_val
- : parent_val + 1 ) );
- g_assert(child.value <= max_computed_val);
- child.inherit = false;
- g_assert(child.set);
- }
- }
-}
-
-template <typename LengthT>
-static void
-sp_style_merge_length_prop_from_dying_parent(LengthT &child, LengthT const &parent,
- double const parent_child_em_ratio)
-{
- if ( ( !(child.set) || child.inherit )
- && parent.set && !(parent.inherit) )
- {
- child = parent;
- switch (parent.unit) {
- case SP_CSS_UNIT_EM:
- case SP_CSS_UNIT_EX:
- child.value *= parent_child_em_ratio;
- /** \todo
- * fixme: Have separate ex ratio parameter.
- * Get x height from libnrtype or pango.
- */
- if (!IS_FINITE(child.value)) {
- child.value = child.computed;
- child.unit = SP_CSS_UNIT_NONE;
- }
- break;
-
- default:
- break;
- }
- }
-}
+/** Indexed by SP_CSS_FONT_SIZE_blah. These seem a bit small */
+static float const font_size_table[] = {6.0, 8.0, 10.0, 12.0, 14.0, 18.0, 24.0};
-static double
-get_relative_font_size_frac(SPIFontSize const &font_size)
+// Called in sp-object.cpp, sp-tref.cpp, sp-use.cpp
+/**
+ * Sets computed values in \a style, which may involve inheriting from (or in some other way
+ * calculating from) corresponding computed values of \a parent.
+ *
+ * References: http://www.w3.org/TR/SVG11/propidx.html shows what properties inherit by default.
+ * http://www.w3.org/TR/SVG11/styling.html#Inheritance gives general rules as to what it means to
+ * inherit a value. http://www.w3.org/TR/REC-CSS2/cascade.html#computed-value is more precise
+ * about what the computed value is (not obvious for lengths).
+ *
+ * \pre \a parent's computed values are already up-to-date.
+ */
+void
+sp_style_merge_from_parent(SPStyle *const style, SPStyle const *const parent)
{
- switch (font_size.type) {
- case SP_FONT_SIZE_LITERAL: {
- switch (font_size.literal) {
- case SP_CSS_FONT_SIZE_SMALLER:
- return 5.0 / 6.0;
-
- case SP_CSS_FONT_SIZE_LARGER:
- return 6.0 / 5.0;
-
- default:
- g_assert_not_reached();
- }
- }
-
- case SP_FONT_SIZE_PERCENTAGE:
- return font_size.value;
-
- case SP_FONT_SIZE_LENGTH: {
- switch (font_size.unit ) {
- case SP_CSS_UNIT_EM:
- return font_size.value;
+ // std::cout << "sp_style_merge_from_parent" << std::endl;
+ g_return_if_fail(style != NULL);
- case SP_CSS_UNIT_EX:
- return font_size.value * 0.5;
+ if (!parent)
+ return;
- default:
- g_assert_not_reached();
- }
- }
- }
- g_assert_not_reached();
+ style->cascade( parent );
+ return;
}
+// Called in: sp-use.cpp, sp-tref.cpp, sp-item.cpp
/**
* Combine \a style and \a parent style specifications into a single style specification that
* preserves (as much as possible) the effect of the existing \a style being a child of \a parent.
@@ -2140,370 +1335,16 @@ get_relative_font_size_frac(SPIFontSize const &font_size)
void
sp_style_merge_from_dying_parent(SPStyle *const style, SPStyle const *const parent)
{
- /** \note
- * The general rule for each property is as follows:
- *
- * If style is set to an absolute value, then leave it as is.
- *
- * Otherwise (i.e. if style has a relative value):
- *
- * If parent is set to an absolute value, then set style to the computed value.
- *
- * Otherwise, calculate the combined relative value (e.g. multiplying the two percentages).
- */
-
- /* We do font-size first, to ensure that em size is up-to-date. */
- /** \todo
- * fixme: We'll need to have more font-related things up the top once
- * we're getting x-height from pango or libnrtype.
- */
-
- /* Some things that allow relative specifications. */
- {
- /* font-size. Note that we update the computed font-size of style,
- to assist in em calculations later in this function. */
-
- if (parent->font_size.set && !parent->font_size.inherit) {
- /* Parent has defined font-size */
-
- if (!style->font_size.set || style->font_size.inherit) {
- /* font_size inherits the computed value, so we can use the parent value
- * verbatim. */
- style->font_size = parent->font_size;
-
- } else if ( style->font_size.type == SP_FONT_SIZE_LENGTH &&
- style->font_size.unit != SP_CSS_UNIT_EM &&
- style->font_size.unit != SP_CSS_UNIT_EX ) {
-
- /* Child already has absolute size (stored in computed value), so do nothing. */
-
- } else if ( style->font_size.type == SP_FONT_SIZE_LITERAL
- && style->font_size.literal < SP_CSS_FONT_SIZE_SMALLER ) {
- /* Child already has absolute size, but we ensure that the computed value
- is up-to-date. */
- unsigned const ix = style->font_size.literal;
- g_assert(ix < G_N_ELEMENTS(font_size_table));
- style->font_size.computed = font_size_table[ix];
-
- } else {
- /* Child has relative size. */
- double const child_frac(get_relative_font_size_frac(style->font_size));
- style->font_size.set = true;
- style->font_size.inherit = false;
- style->font_size.computed = parent->font_size.computed * child_frac;
-
- if ( ( parent->font_size.type == SP_FONT_SIZE_LITERAL
- && parent->font_size.literal < SP_CSS_FONT_SIZE_SMALLER ) ||
- ( parent->font_size.type == SP_FONT_SIZE_LENGTH &&
- parent->font_size.unit != SP_CSS_UNIT_EM &&
- parent->font_size.unit != SP_CSS_UNIT_EX ) ) {
-
- /* Absolute value. */
- style->font_size.type = SP_FONT_SIZE_LENGTH;
- /* .value is unused for non ex/em SP_FONT_SIZE_LENGTH. */
-
- } else {
- /* Relative value. */
-
- double const parent_frac(get_relative_font_size_frac(parent->font_size));
- if( style->font_size.type == SP_FONT_SIZE_LENGTH ) {
- /* Value in terms of ex/em */
- style->font_size.value *= parent_frac;
- } else {
- style->font_size.value = parent_frac * child_frac;
- style->font_size.type = SP_FONT_SIZE_PERCENTAGE;
- }
- }
- }
- }
-
- /* 'font-stretch' */
- sp_style_merge_rel_enum_prop_from_dying_parent(style->font_stretch,
- parent->font_stretch,
- SP_CSS_FONT_STRETCH_ULTRA_EXPANDED,
- SP_CSS_FONT_STRETCH_NARROWER);
-
- /* font-weight */
- sp_style_merge_rel_enum_prop_from_dying_parent(style->font_weight,
- parent->font_weight,
- SP_CSS_FONT_WEIGHT_900,
- SP_CSS_FONT_WEIGHT_LIGHTER);
- }
-
-
- /* Enum values that don't have any relative settings (other than `inherit'). */
- {
- SPIEnum SPStyle::*const fields[] = {
- &SPStyle::blend_mode,
- &SPStyle::clip_rule,
- &SPStyle::color_interpolation,
- &SPStyle::color_interpolation_filters,
- &SPStyle::color_rendering,
- &SPStyle::direction,
- &SPStyle::fill_rule,
- &SPStyle::font_style,
- &SPStyle::font_variant,
- &SPStyle::image_rendering,
- &SPStyle::isolation,
- //nyi: SPStyle::pointer_events,
- &SPStyle::shape_rendering,
- &SPStyle::stroke_linecap,
- &SPStyle::stroke_linejoin,
- &SPStyle::text_anchor,
- &SPStyle::text_rendering,
- &SPStyle::visibility,
- &SPStyle::writing_mode
- };
-
- for (unsigned i = 0; i < G_N_ELEMENTS(fields); ++i) {
- SPIEnum SPStyle::*const fld = fields[i];
- sp_style_merge_prop_from_dying_parent<SPIEnum>(style->*fld, parent->*fld);
- }
- }
-
- /* A few other simple inheritance properties. */
- {
- sp_style_merge_prop_from_dying_parent<SPIScale24>(style->fill_opacity, parent->fill_opacity);
- sp_style_merge_prop_from_dying_parent<SPIScale24>(style->stroke_opacity, parent->stroke_opacity);
- sp_style_merge_prop_from_dying_parent<SPIFloat>(style->stroke_miterlimit, parent->stroke_miterlimit);
-
- /** \todo
- * We currently treat text-decoration as if it were a simple inherited
- * property (fixme). This code may need changing once we do the
- * special fill/stroke inheritance mentioned by the spec.
- */
- sp_style_merge_prop_from_dying_parent<SPITextDecorationLine>( style->text_decoration_line, parent->text_decoration_line);
- sp_style_merge_prop_from_dying_parent<SPITextDecorationStyle>(style->text_decoration_style, parent->text_decoration_style);
- sp_style_merge_paint_prop_from_dying_parent(style,style->text_decoration_color, parent->text_decoration_color);
-
- //nyi: font-size-adjust, // <number> | none | inherit
- //nyi: glyph-orientation-horizontal,
- //nyi: glyph-orientation-vertical,
- }
-
- /* Properties that involve length but are easy in other respects. */
- {
- /* The difficulty with lengths is that font-relative units need adjusting if the font
- * varies between parent & child.
- *
- * Lengths specified in the existing child can stay as they are: its computed font
- * specification should stay unchanged, so em & ex lengths should continue to mean the same
- * size.
- *
- * Lengths specified in the dying parent in em or ex need to be scaled according to the
- * ratio of em or ex size between parent & child.
- */
- double const parent_child_em_ratio = parent->font_size.computed / style->font_size.computed;
-
- SPILength SPStyle::*const lfields[] = {
- &SPStyle::stroke_width,
- &SPStyle::text_indent
- };
- for (unsigned i = 0; i < G_N_ELEMENTS(lfields); ++i) {
- SPILength SPStyle::*fld = lfields[i];
- sp_style_merge_length_prop_from_dying_parent<SPILength>(style->*fld,
- parent->*fld,
- parent_child_em_ratio);
- }
-
- SPILengthOrNormal SPStyle::*const nfields[] = {
- &SPStyle::letter_spacing,
- &SPStyle::line_height,
- &SPStyle::word_spacing
- };
- for (unsigned i = 0; i < G_N_ELEMENTS(nfields); ++i) {
- SPILengthOrNormal SPStyle::*fld = nfields[i];
- sp_style_merge_length_prop_from_dying_parent<SPILengthOrNormal>(style->*fld,
- parent->*fld,
- parent_child_em_ratio);
- }
-
- //nyi: &SPStyle::kerning: length or `auto'
-
- /* fixme: Move stroke-dash and stroke-dash-offset here once they
- can accept units. */
- }
-
- /* Properties that involve a URI but are easy in other respects. */
- {
- /** \todo
- * Could cause problems if original object was in another document
- * and it used a relative URL. (At the time of writing, we don't
- * allow hrefs to other documents, so this isn't a problem yet.)
- * Paint properties also allow URIs.
- */
- //nyi: cursor, // may involve change in effect, but we can't do much better
- //nyi: color-profile,
-
- // Markers (marker-start, marker-mid, marker-end).
- for (unsigned i = SP_MARKER_LOC; i < SP_MARKER_LOC_QTY; i++) {
- sp_style_merge_string_prop_from_dying_parent(style->marker[i], parent->marker[i]);
- }
- }
-
- /* CSS2 */
- /* Font */
-
- if (style->text && parent->text) {
- sp_style_merge_string_prop_from_dying_parent(style->text->font_specification,
- parent->text->font_specification);
-
- sp_style_merge_string_prop_from_dying_parent(style->text->font_family,
- parent->text->font_family);
- }
-
-
- /* Properties that don't inherit by default. Most of these need special handling. */
- {
- /*
- * opacity's effect is cumulative; we set the new value to the combined effect. The
- * default value for opacity is 1.0, not inherit. (Note that stroke-opacity and
- * fill-opacity are quite different from opacity, and don't need any special handling.)
- *
- * Cases:
- * - parent & child were each previously unset, in which case the effective
- * opacity value is 1.0, and style should remain unset.
- * - parent was previously unset (so computed opacity value of 1.0)
- * and child was set to inherit. The merged child should
- * get a value of 1.0, and shouldn't inherit (lest the new parent
- * has a different opacity value). Given that opacity's default
- * value is 1.0 (rather than inherit), we might as well have the
- * merged child's opacity be unset.
- * - parent was previously unset (so opacity 1.0), and child was set to a number.
- * The merged child should retain its existing settings (though it doesn't matter
- * if we make it unset if that number was 1.0).
- * - parent was inherit and child was unset. Merged child should be set to inherit.
- * - parent was inherit and child was inherit. (We can't in general reproduce this
- * effect (short of introducing a new group), but setting opacity to inherit is rare.)
- * If the inherited value was strictly between 0.0 and 1.0 (exclusive) then the merged
- * child's value should be set to the product of the two, i.e. the square of the
- * inherited value, and should not be marked as inherit. (This decision assumes that it
- * is more important to retain the effective opacity than to retain the inheriting
- * effect, and assumes that the inheriting effect either isn't important enough to create
- * a group or isn't common enough to bother maintaining the code to create a group.) If
- * the inherited value was 0.0 or 1.0, then marking the merged child as inherit comes
- * closer to maintaining the effect.
- * - parent was inherit and child was set to a numerical value. If the child's value
- * was 1.0, then the merged child should have the same settings as the parent.
- * If the child's value was 0, then the merged child should also be set to 0.
- * If the child's value was anything else, then we do the same as for the inherit/inherit
- * case above: have the merged child set to the product of the two opacities and not
- * marked as inherit, for the same reasons as for that case.
- * - parent was set to a value, and child was unset. The merged child should have
- * parent's settings.
- * - parent was set to a value, and child was inherit. The merged child should
- * be set to the product, i.e. the square of the parent's value.
- * - parent & child are each set to a value. The merged child should be set to the
- * product.
- */
- if ( !style->opacity.set
- || ( !style->opacity.inherit
- && style->opacity.value == SP_SCALE24_MAX ) )
- {
- style->opacity = parent->opacity;
- } else {
- /* Ensure that style's computed value is up-to-date. */
- if (style->opacity.inherit) {
- style->opacity.value = parent->opacity.value;
- }
-
- /* Multiplication of opacities occurs even if a child's opacity is set to inherit. */
- style->opacity.value = SP_SCALE24_MUL(style->opacity.value,
- parent->opacity.value);
-
- style->opacity.inherit = (parent->opacity.inherit
- && style->opacity.inherit
- && (parent->opacity.value == 0 ||
- parent->opacity.value == SP_SCALE24_MAX));
- style->opacity.set = ( style->opacity.inherit
- || style->opacity.value < SP_SCALE24_MAX );
- }
-
- /* display is in principle similar to opacity, but implementation is easier. */
- if ( parent->display.set && !parent->display.inherit
- && parent->display.value == SP_CSS_DISPLAY_NONE ) {
- style->display.value = SP_CSS_DISPLAY_NONE;
- style->display.set = true;
- style->display.inherit = false;
- } else if (style->display.inherit) {
- style->display.value = parent->display.value;
- style->display.set = parent->display.set;
- style->display.inherit = parent->display.inherit;
- } else {
- /* Leave as is. (display doesn't inherit by default.) */
- }
-
- /* enable-background - this is rather complicated, because
- * it is valid only when applied to container elements.
- * Let's check a simple case anyhow. */
- if (parent->enable_background.set
- && !parent->enable_background.inherit
- && style->enable_background.inherit)
- {
- style->enable_background.set = true;
- style->enable_background.inherit = false;
- style->enable_background.value = parent->enable_background.value;
- }
-
- if (!style->filter.set || style->filter.inherit)
- {
- sp_style_merge_ifilter(style, &parent->filter);
-
+ // std::cout << "sp_style_merge_from_dying_parent" << std::endl;
+ style->merge( parent );
}
- /** \todo
- * fixme: Check that we correctly handle all properties that don't
- * inherit by default (as shown in
- * http://www.w3.org/TR/SVG11/propidx.html for most SVG 1.1 properties).
- */
- }
-
- /* SPIPaint properties (including color). */
- {
- /** \todo
- * Think about the issues involved if specified as currentColor or
- * if specified relative to colorProfile, and if the currentColor or
- * colorProfile differs between parent \& child. See also comments
- * elsewhere in this function about URIs.
- */
- SPIPaint SPStyle::*const fields[] = {
- &SPStyle::color,
- &SPStyle::fill,
- &SPStyle::stroke
- };
- for (unsigned i = 0; i < G_N_ELEMENTS(fields); ++i) {
- SPIPaint SPStyle::*const fld = fields[i];
- sp_style_merge_paint_prop_from_dying_parent(style, style->*fld, parent->*fld);
- }
- }
-
- /* Things from SVG 1.2 or CSS3. */
- {
- /* Note: If we ever support setting string values for text-align then we'd need strdup
- * handling here. */
- sp_style_merge_prop_from_dying_parent<SPIEnum>(style->text_align, parent->text_align);
-
- sp_style_merge_prop_from_dying_parent<SPIEnum>(style->text_transform, parent->text_transform);
- sp_style_merge_prop_from_dying_parent<SPIEnum>(style->block_progression, parent->block_progression);
- }
-
- /* Note: this will need length handling once dasharray supports units. */
- if ( ( !style->stroke_dasharray.set || style->stroke_dasharray.inherit )
- && parent->stroke_dasharray.set && !parent->stroke_dasharray.inherit )
- {
- style->stroke_dasharray.values = parent->stroke_dasharray.values;
- style->stroke_dasharray.set = parent->stroke_dasharray.set;
- style->stroke_dasharray.inherit = parent->stroke_dasharray.inherit;
- }
- {
- sp_style_merge_prop_from_dying_parent<SPILength>(style->stroke_dashoffset, parent->stroke_dashoffset);
- }
-}
-
-
-static void
+// The following functions should be incorporated into SPIPaint. FIXME
+// Called in: style.cpp, style-internal.cpp
+void
sp_style_set_ipaint_to_uri(SPStyle *style, SPIPaint *paint, const Inkscape::URI *uri, SPDocument *document)
{
+ // std::cout << "sp_style_set_ipaint_to_uri: Entrance: " << uri << " " << (void*)document << std::endl;
// it may be that this style's SPIPaint has not yet created its URIReference;
// now that we have a document, we can create it here
if (!paint->value.href && document) {
@@ -2525,7 +1366,8 @@ sp_style_set_ipaint_to_uri(SPStyle *style, SPIPaint *paint, const Inkscape::URI
}
}
-static void
+// Called in: style.cpp, style-internal.cpp
+void
sp_style_set_ipaint_to_uri_string (SPStyle *style, SPIPaint *paint, const gchar *uri)
{
try {
@@ -2536,12 +1378,14 @@ sp_style_set_ipaint_to_uri_string (SPStyle *style, SPIPaint *paint, const gchar
}
}
+// Called in: desktop-style.cpp
void
sp_style_set_to_uri_string (SPStyle *style, bool isfill, const gchar *uri)
{
sp_style_set_ipaint_to_uri_string (style, isfill? &style->fill : &style->stroke, uri);
}
+// Called in: widgets/font-selector.cpp, widgets/text-toolbar.cpp, ui/dialog/text-edit.cpp
gchar const *
sp_style_get_css_unit_string(int unit)
{
@@ -2564,6 +1408,7 @@ sp_style_get_css_unit_string(int unit)
return "px";
}
+// Called in: style-internal.cpp, widgets/text-toolbar.cpp, ui/dialog/text-edit.cpp
/*
* Convert a size in pixels into another CSS unit size
*/
@@ -2592,6 +1437,7 @@ sp_style_css_size_px_to_units(double size, int unit)
return unit_size;
}
+// Called in: widgets/text-toolbar.cpp, ui/dialog/text-edit.cpp
/*
* Convert a size in a CSS unit size to pixels
*/
@@ -2604,82 +1450,8 @@ sp_style_css_size_units_to_px(double size, int unit)
//g_message("sp_style_css_size_units_to_px %f %d = %f px", size, unit, out);
return size * (size / sp_style_css_size_px_to_units(size, unit));;
}
-/**
- *
- */
-static void
-sp_style_merge_ipaint(SPStyle *style, SPIPaint *paint, SPIPaint const *parent)
-{
- if ((paint->set && paint->currentcolor) || parent->currentcolor) {
- bool isset = paint->set;
- paint->clear();
- paint->set = isset;
- paint->currentcolor = TRUE;
- paint->setColor(style->color.value.color);
- return;
- }
-
- paint->clear();
- if ( parent->isPaintserver() ) {
- if (parent->value.href) {
- sp_style_set_ipaint_to_uri(style, paint, parent->value.href->getURI(), parent->value.href->getOwnerDocument());
- } else {
- g_warning("Expected paint server not found.");
- }
- } else if ( parent->isColor() ) {
- paint->setColor( parent->value.color );
- } else if ( parent->isNoneSet() ) {
- paint->noneSet = TRUE;
- } else if ( parent->isNone() ) {
- //
- } else {
- g_assert_not_reached();
- }
-}
-
-
-/**
- * Merge filter style from parent.
- * Filter effects do not inherit by default
- */
-static void
-sp_style_merge_ifilter(SPStyle *style, SPIFilter const *parent)
-{
- // FIXME:
- // instead of just copying over, we need to _really merge_ the two filters by combining their
- // filter primitives
-
- sp_style_filter_clear(style);
- style->filter.set = parent->set;
- style->filter.inherit = parent->inherit;
-
- if (style->filter.href){
- if (style->filter.href->getObject()){
- style->filter.href->detach();
- }
- }
- else{
- // it may be that this style has not yet created its SPFilterReference
- if (style->object){
- if (style->object->document) {
- style->filter.href = new SPFilterReference(style->object->document);
- style->filter.href->changedSignal().connect(sigc::bind(sigc::ptr_fun(sp_style_filter_ref_changed), style));
- }
- }
- }
-
- if (style->filter.href && parent->href){
- if (parent->href->getObject()) {
- try {
- style->filter.href->attach(*parent->href->getURI());
- } catch (Inkscape::BadURIException &e) {
- g_warning("%s", e.what());
- style->filter.href->detach();
- }
- }
- }
-}
+// Called in style.cpp, text-editing.cpp
/**
* Dumps the style to a CSS string, with either SP_STYLE_FLAG_IFSET or
* SP_STYLE_FLAG_ALWAYS flags. Used with Always for copying an object's
@@ -2702,146 +1474,11 @@ sp_style_write_string(SPStyle const *const style, guint const flags)
(flags == SP_STYLE_FLAG_ALWAYS) ),
NULL);
- gchar c[BMAX];
- gchar *p = c;
- *p = '\0';
-
- p += sp_style_write_ifontsize(p, c + BMAX - p, "font-size", &style->font_size, NULL, flags);
- p += sp_style_write_ienum(p, c + BMAX - p, "font-style", enum_font_style, &style->font_style, NULL, flags);
- p += sp_style_write_ienum(p, c + BMAX - p, "font-variant", enum_font_variant, &style->font_variant, NULL, flags);
- p += sp_style_write_ienum(p, c + BMAX - p, "font-weight", enum_font_weight, &style->font_weight, NULL, flags);
- p += sp_style_write_ienum(p, c + BMAX - p, "font-stretch", enum_font_stretch, &style->font_stretch, NULL, flags);
-
- /* Text */
- p += sp_style_write_ilength(p, c + BMAX - p, "text-indent", &style->text_indent, NULL, flags);
- p += sp_style_write_ienum(p, c + BMAX - p, "text-align", enum_text_align, &style->text_align, NULL, flags);
- p += sp_style_write_itextdecoration(p, c + BMAX - p, "text-decoration",
- &style->text_decoration_line, &style->text_decoration_style, &style->text_decoration_color,
- NULL, NULL, NULL, flags);
- p += sp_style_write_ilengthornormal(p, c + BMAX - p, "line-height", &style->line_height, NULL, flags);
- p += sp_style_write_ilengthornormal(p, c + BMAX - p, "letter-spacing", &style->letter_spacing, NULL, flags);
- p += sp_style_write_ilengthornormal(p, c + BMAX - p, "word-spacing", &style->word_spacing, NULL, flags);
- p += sp_style_write_ienum(p, c + BMAX - p, "text-transform", enum_text_transform, &style->text_transform, NULL, flags);
- p += sp_style_write_ienum(p, c + BMAX - p, "direction", enum_direction, &style->direction, NULL, flags);
- p += sp_style_write_ienum(p, c + BMAX - p, "block-progression", enum_block_progression, &style->block_progression, NULL, flags);
- p += sp_style_write_ienum(p, c + BMAX - p, "writing-mode", enum_writing_mode, &style->writing_mode, NULL, flags);
-
- p += sp_style_write_ienum(p, c + BMAX - p, "text-anchor", enum_text_anchor, &style->text_anchor, NULL, flags);
- p += sp_style_write_ibaselineshift(p, c + BMAX - p, "baseline-shift", &style->baseline_shift, NULL, flags);
-
-
- /// \todo fixme: Per type methods need default flag too (lauris)
-
- if (style->opacity.value != SP_SCALE24_MAX) {
- p += sp_style_write_iscale24(p, c + BMAX - p, "opacity", &style->opacity, NULL, flags);
- }
-
- if (!style->color.noneSet) { // CSS does not permit "none" for color
- p += sp_style_write_ipaint(p, c + BMAX - p, "color", &style->color, NULL, flags);
- }
- p += sp_style_write_ienum(p, c + BMAX - p, "color-interpolation", enum_color_interpolation, &style->color_interpolation, NULL, flags);
- p += sp_style_write_ienum(p, c + BMAX - p, "color-interpolation-filters", enum_color_interpolation, &style->color_interpolation_filters, NULL, flags);
-
-
- p += sp_style_write_ipaint(p, c + BMAX - p, "fill", &style->fill, NULL, flags);
- // if fill:none, skip writing fill properties
- if (!style->fill.noneSet) {
- p += sp_style_write_iscale24(p, c + BMAX - p, "fill-opacity", &style->fill_opacity, NULL, flags);
- p += sp_style_write_ienum(p, c + BMAX - p, "fill-rule", enum_fill_rule, &style->fill_rule, NULL, flags);
- }
-
- p += sp_style_write_ipaint(p, c + BMAX - p, "stroke", &style->stroke, NULL, flags);
-
- // stroke width affects markers, so write it if there's stroke OR any markers
- if (!style->stroke.noneSet ||
- style->marker[SP_MARKER_LOC].set ||
- style->marker[SP_MARKER_LOC_START].set ||
- style->marker[SP_MARKER_LOC_MID].set ||
- style->marker[SP_MARKER_LOC_END].set) {
- p += sp_style_write_ilength(p, c + BMAX - p, "stroke-width", &style->stroke_width, NULL, flags);
- }
-
- // if stroke:none, skip writing stroke properties
- if (!style->stroke.noneSet) {
- p += sp_style_write_ienum(p, c + BMAX - p, "stroke-linecap", enum_stroke_linecap, &style->stroke_linecap, NULL, flags);
- p += sp_style_write_ienum(p, c + BMAX - p, "stroke-linejoin", enum_stroke_linejoin, &style->stroke_linejoin, NULL, flags);
- p += sp_style_write_ifloat(p, c + BMAX - p, "stroke-miterlimit", &style->stroke_miterlimit, NULL, flags);
- p += sp_style_write_iscale24(p, c + BMAX - p, "stroke-opacity", &style->stroke_opacity, NULL, flags);
- p += sp_style_write_idasharray(p, c + BMAX - p, "stroke-dasharray", &style->stroke_dasharray, NULL, flags);
- p += sp_style_write_ilength(p, c + BMAX - p, "stroke-dashoffset", &style->stroke_dashoffset, NULL, flags);
- }
-
- if (style->paint_order.set) {
- p += sp_style_write_ipaintorder(p, c + BMAX - p, "paint-order", &style->paint_order, NULL, flags);
- } else if (flags == SP_STYLE_FLAG_ALWAYS) {
- p += g_snprintf(p, c + BMAX - p, "paint-order:normal;");
- }
-
- bool marker_none = false;
- gchar *master = style->marker[SP_MARKER_LOC].value;
- if (style->marker[SP_MARKER_LOC].set) {
- p += g_snprintf(p, c + BMAX - p, "marker:%s;", style->marker[SP_MARKER_LOC].value);
- } else if (flags == SP_STYLE_FLAG_ALWAYS) {
- p += g_snprintf(p, c + BMAX - p, "marker:none;");
- marker_none = true;
- }
- if (style->marker[SP_MARKER_LOC_START].set
- && (!master || strcmp(master, style->marker[SP_MARKER_LOC_START].value))) {
- p += g_snprintf(p, c + BMAX - p, "marker-start:%s;", style->marker[SP_MARKER_LOC_START].value);
- } else if (flags == SP_STYLE_FLAG_ALWAYS && !marker_none) {
- p += g_snprintf(p, c + BMAX - p, "marker-start:none;");
- }
- if (style->marker[SP_MARKER_LOC_MID].set
- && (!master || strcmp(master, style->marker[SP_MARKER_LOC_MID].value))) {
- p += g_snprintf(p, c + BMAX - p, "marker-mid:%s;", style->marker[SP_MARKER_LOC_MID].value);
- } else if (flags == SP_STYLE_FLAG_ALWAYS && !marker_none) {
- p += g_snprintf(p, c + BMAX - p, "marker-mid:none;");
- }
- if (style->marker[SP_MARKER_LOC_END].set
- && (!master || strcmp(master, style->marker[SP_MARKER_LOC_END].value))) {
- p += g_snprintf(p, c + BMAX - p, "marker-end:%s;", style->marker[SP_MARKER_LOC_END].value);
- } else if (flags == SP_STYLE_FLAG_ALWAYS && !marker_none) {
- p += g_snprintf(p, c + BMAX - p, "marker-end:none;");
- }
-
- p += sp_style_write_ienum(p, c + BMAX - p, "visibility", enum_visibility, &style->visibility, NULL, flags);
- p += sp_style_write_ienum(p, c + BMAX - p, "display", enum_display, &style->display, NULL, flags);
- p += sp_style_write_ienum(p, c + BMAX - p, "overflow", enum_overflow, &style->overflow, NULL, flags);
- p += sp_style_write_ienum(p, c + BMAX - p, "isolation", enum_isolation, &style->isolation, NULL, flags);
- p += sp_style_write_ienum(p, c + BMAX - p, "mix-blend-mode", enum_blend_mode, &style->blend_mode, NULL, flags);
-
- /* filter: */
- p += sp_style_write_ifilter(p, c + BMAX - p, "filter", &style->filter, NULL, flags);
-
- p += sp_style_write_ienum(p, c + BMAX - p, "enable-background", enum_enable_background, &style->enable_background, NULL, flags);
-
- /* clipping */
- p += sp_style_write_ienum(p, c + BMAX - p, "clip-rule", enum_clip_rule, &style->clip_rule, NULL, flags);
-
- /* rendering */
- p += sp_style_write_ienum(p, c + BMAX - p, "color-rendering", enum_color_rendering, &style->color_rendering, NULL, flags);
- p += sp_style_write_ienum(p, c + BMAX - p, "image-rendering", enum_image_rendering, &style->image_rendering, NULL, flags);
- p += sp_style_write_ienum(p, c + BMAX - p, "shape-rendering", enum_shape_rendering, &style->shape_rendering, NULL, flags);
- p += sp_style_write_ienum(p, c + BMAX - p, "text-rendering", enum_text_rendering, &style->text_rendering, NULL, flags);
-
- /* fixme: */
- p += sp_text_style_write(p, c + BMAX - p, style->text, flags);
-
- /* Get rid of trailing `;'. */
- if (p != c) {
- --p;
- if (*p == ';') {
- *p = '\0';
- }
- }
-
- return g_strdup(c);
+ return g_strdup( style->write( flags ).c_str() );
}
-#define STYLE_BUF_MAX
-
-
+// Called in style.cpp, path-chemistry, NOT in text-editting.cpp (because of bug)
/**
* Dumps style to CSS string, see sp_style_write_string()
*
@@ -2855,2016 +1492,7 @@ sp_style_write_difference(SPStyle const *const from, SPStyle const *const to)
g_return_val_if_fail(from != NULL, NULL);
g_return_val_if_fail(to != NULL, NULL);
- gchar c[BMAX], *p = c;
- *p = '\0';
-
- p += sp_style_write_ifontsize(p, c + BMAX - p, "font-size", &from->font_size, &to->font_size, SP_STYLE_FLAG_IFDIFF);
- p += sp_style_write_ienum(p, c + BMAX - p, "font-style", enum_font_style, &from->font_style, &to->font_style, SP_STYLE_FLAG_IFDIFF);
- p += sp_style_write_ienum(p, c + BMAX - p, "font-variant", enum_font_variant, &from->font_variant, &to->font_variant, SP_STYLE_FLAG_IFDIFF);
- p += sp_style_write_ienum(p, c + BMAX - p, "font-weight", enum_font_weight, &from->font_weight, &to->font_weight, SP_STYLE_FLAG_IFDIFF);
- p += sp_style_write_ienum(p, c + BMAX - p, "font-stretch", enum_font_stretch, &from->font_stretch, &to->font_stretch, SP_STYLE_FLAG_IFDIFF);
-
- /* Text */
- p += sp_style_write_ilength(p, c + BMAX - p, "text-indent", &from->text_indent, &to->text_indent, SP_STYLE_FLAG_IFDIFF);
- p += sp_style_write_ienum(p, c + BMAX - p, "text-align", enum_text_align, &from->text_align, &to->text_align, SP_STYLE_FLAG_IFDIFF);
- p += sp_style_write_itextdecoration(p, c + BMAX - p, "text-decoration",
- &from->text_decoration_line, &from->text_decoration_style, &from->text_decoration_color,
- &to->text_decoration_line, &to->text_decoration_style, &to->text_decoration_color,
- SP_STYLE_FLAG_IFDIFF);
- p += sp_style_write_ilengthornormal(p, c + BMAX - p, "line-height", &from->line_height, &to->line_height, SP_STYLE_FLAG_IFDIFF);
- p += sp_style_write_ilengthornormal(p, c + BMAX - p, "letter-spacing", &from->letter_spacing, &to->letter_spacing, SP_STYLE_FLAG_IFDIFF);
- p += sp_style_write_ilengthornormal(p, c + BMAX - p, "word-spacing", &from->word_spacing, &to->word_spacing, SP_STYLE_FLAG_IFDIFF);
- p += sp_style_write_ienum(p, c + BMAX - p, "text-transform", enum_text_transform, &from->text_transform, &to->text_transform, SP_STYLE_FLAG_IFDIFF);
- p += sp_style_write_ienum(p, c + BMAX - p, "direction", enum_direction, &from->direction, &to->direction, SP_STYLE_FLAG_IFDIFF);
- p += sp_style_write_ienum(p, c + BMAX - p, "block-progression", enum_block_progression, &from->block_progression, &to->block_progression, SP_STYLE_FLAG_IFDIFF);
- p += sp_style_write_ienum(p, c + BMAX - p, "writing-mode", enum_writing_mode, &from->writing_mode, &to->writing_mode, SP_STYLE_FLAG_IFDIFF);
-
- p += sp_style_write_ienum(p, c + BMAX - p, "text-anchor", enum_text_anchor, &from->text_anchor, &to->text_anchor, SP_STYLE_FLAG_IFDIFF);
- p += sp_style_write_ibaselineshift(p, c + BMAX - p, "baseline-shift", &from->baseline_shift, &to->baseline_shift, SP_STYLE_FLAG_IFDIFF);
-
- /// \todo fixme: Per type methods need default flag too
- if (from->opacity.set && from->opacity.value != SP_SCALE24_MAX) {
- p += sp_style_write_iscale24(p, c + BMAX - p, "opacity", &from->opacity, &to->opacity, SP_STYLE_FLAG_IFSET);
- }
-
- if (!from->color.noneSet) { // CSS does not permit "none" for color
- p += sp_style_write_ipaint(p, c + BMAX - p, "color", &from->color, &to->color, SP_STYLE_FLAG_IFSET);
- }
- p += sp_style_write_ienum(p, c + BMAX - p, "color-interpolation", enum_color_interpolation, &from->color_interpolation, &to->color_interpolation, SP_STYLE_FLAG_IFDIFF);
- p += sp_style_write_ienum(p, c + BMAX - p, "color-interpolation-filters", enum_color_interpolation, &from->color_interpolation_filters, &to->color_interpolation_filters, SP_STYLE_FLAG_IFDIFF);
-
- p += sp_style_write_ipaint(p, c + BMAX - p, "fill", &from->fill, &to->fill, SP_STYLE_FLAG_IFDIFF);
- // if fill:none, skip writing fill properties
- if (!from->fill.noneSet) {
- p += sp_style_write_iscale24(p, c + BMAX - p, "fill-opacity", &from->fill_opacity, &to->fill_opacity, SP_STYLE_FLAG_IFDIFF);
- p += sp_style_write_ienum(p, c + BMAX - p, "fill-rule", enum_fill_rule, &from->fill_rule, &to->fill_rule, SP_STYLE_FLAG_IFDIFF);
- }
-
- p += sp_style_write_ipaint(p, c + BMAX - p, "stroke", &from->stroke, &to->stroke, SP_STYLE_FLAG_IFDIFF);
-
- // stroke width affects markers, so write it if there's stroke OR any markers
- if (!from->stroke.noneSet ||
- from->marker[SP_MARKER_LOC].set ||
- from->marker[SP_MARKER_LOC_START].set ||
- from->marker[SP_MARKER_LOC_MID].set ||
- from->marker[SP_MARKER_LOC_END].set) {
- p += sp_style_write_ilength(p, c + BMAX - p, "stroke-width", &from->stroke_width, &to->stroke_width, SP_STYLE_FLAG_IFDIFF);
- }
-
- // if stroke:none, skip writing stroke properties
- if (!from->stroke.noneSet) {
- p += sp_style_write_ienum(p, c + BMAX - p, "stroke-linecap", enum_stroke_linecap,
- &from->stroke_linecap, &to->stroke_linecap, SP_STYLE_FLAG_IFDIFF);
- p += sp_style_write_ienum(p, c + BMAX - p, "stroke-linejoin", enum_stroke_linejoin,
- &from->stroke_linejoin, &to->stroke_linejoin, SP_STYLE_FLAG_IFDIFF);
- p += sp_style_write_ifloat(p, c + BMAX - p, "stroke-miterlimit",
- &from->stroke_miterlimit, &to->stroke_miterlimit, SP_STYLE_FLAG_IFDIFF);
- p += sp_style_write_idasharray(p, c + BMAX - p, "stroke-dasharray",
- &from->stroke_dasharray, &to->stroke_dasharray, SP_STYLE_FLAG_IFDIFF);
- p += sp_style_write_ilength(p, c + BMAX - p, "stroke-dashoffset", &from->stroke_dashoffset, &to->stroke_dashoffset, SP_STYLE_FLAG_IFDIFF);
- p += sp_style_write_iscale24(p, c + BMAX - p, "stroke-opacity", &from->stroke_opacity, &to->stroke_opacity, SP_STYLE_FLAG_IFDIFF);
- }
-
- /* paint-order */
- if( from->paint_order.set) {
- p += sp_style_write_ipaintorder(p, c + BMAX - p, "paint-order", &from->paint_order, &to->paint_order, SP_STYLE_FLAG_IFDIFF);
- }
-
- /* markers */
- gchar *master = from->marker[SP_MARKER_LOC].value;
- if (master != NULL) {
- p += g_snprintf(p, c + BMAX - p, "marker:%s;", master);
- }
- if (from->marker[SP_MARKER_LOC_START].value != NULL && (!master || strcmp(master, from->marker[SP_MARKER_LOC_START].value))) {
- p += g_snprintf(p, c + BMAX - p, "marker-start:%s;", from->marker[SP_MARKER_LOC_START].value);
- }
- if (from->marker[SP_MARKER_LOC_MID].value != NULL && (!master || strcmp(master, from->marker[SP_MARKER_LOC_MID].value))) {
- p += g_snprintf(p, c + BMAX - p, "marker-mid:%s;", from->marker[SP_MARKER_LOC_MID].value);
- }
- if (from->marker[SP_MARKER_LOC_END].value != NULL && (!master || strcmp(master, from->marker[SP_MARKER_LOC_END].value))) {
- p += g_snprintf(p, c + BMAX - p, "marker-end:%s;", from->marker[SP_MARKER_LOC_END].value);
- }
-
- p += sp_style_write_ienum(p, c + BMAX - p, "visibility", enum_visibility, &from->visibility, &to->visibility, SP_STYLE_FLAG_IFSET);
- p += sp_style_write_ienum(p, c + BMAX - p, "display", enum_display, &from->display, &to->display, SP_STYLE_FLAG_IFSET);
- p += sp_style_write_ienum(p, c + BMAX - p, "overflow", enum_overflow, &from->overflow, &to->overflow, SP_STYLE_FLAG_IFSET);
- p += sp_style_write_ienum(p, c + BMAX - p, "isolation", enum_isolation, &from->isolation, &to->isolation, SP_STYLE_FLAG_IFSET);
- p += sp_style_write_ienum(p, c + BMAX - p, "mix-blend-mode", enum_blend_mode, &from->blend_mode, &to->blend_mode, SP_STYLE_FLAG_IFSET);
-
- /* filter: */
- p += sp_style_write_ifilter(p, c + BMAX - p, "filter", &from->filter, &to->filter, SP_STYLE_FLAG_IFDIFF);
-
- p += sp_style_write_ienum(p, c + BMAX - p, "enable-background", enum_enable_background, &from->enable_background, &to->enable_background, SP_STYLE_FLAG_IFSET);
-
- p += sp_text_style_write(p, c + BMAX - p, from->text, SP_STYLE_FLAG_IFDIFF);
-
- p += sp_style_write_ienum(p, c + BMAX - p, "clip-rule", enum_clip_rule, &from->clip_rule, &to->clip_rule, SP_STYLE_FLAG_IFDIFF);
-
- /* rendering */
- p += sp_style_write_ienum(p, c + BMAX - p, "color-rendering", enum_color_rendering, &from->color_rendering, &to->color_rendering, SP_STYLE_FLAG_IFDIFF);
- p += sp_style_write_ienum(p, c + BMAX - p, "image-rendering", enum_image_rendering, &from->image_rendering, &to->image_rendering, SP_STYLE_FLAG_IFDIFF);
- p += sp_style_write_ienum(p, c + BMAX - p, "shape-rendering", enum_shape_rendering, &from->shape_rendering, &to->shape_rendering, SP_STYLE_FLAG_IFDIFF);
- p += sp_style_write_ienum(p, c + BMAX - p, "text-rendering", enum_text_rendering, &from->text_rendering, &to->text_rendering, SP_STYLE_FLAG_IFDIFF);
-
- /** \todo
- * The reason we use IFSET rather than IFDIFF is the belief that the IFDIFF
- * flag is mainly only for attributes that don't handle explicit unset well.
- * We may need to revisit the behaviour of this routine.
- */
-
- /* Get rid of trailing `;'. */
- if (p != c) {
- --p;
- if (*p == ';') {
- *p = '\0';
- }
- }
-
- return g_strdup(c);
-}
-
-
-
-/**
- * Reset all style properties.
- */
-static void
-sp_style_clear(SPStyle *style)
-{
- g_return_if_fail(style != NULL);
-
- style->fill.clear();
- style->stroke.clear();
- sp_style_filter_clear(style);
-
- style->release_connection.disconnect();
-
- style->fill_ps_modified_connection.disconnect();
- if (style->fill.value.href) {
- delete style->fill.value.href;
- style->fill.value.href = NULL;
- }
- style->stroke_ps_modified_connection.disconnect();
- if (style->stroke.value.href) {
- delete style->stroke.value.href;
- style->stroke.value.href = NULL;
- }
- style->filter_modified_connection.disconnect();
- if (style->filter.href) {
- delete style->filter.href;
- style->filter.href = NULL;
- }
-
- style->stroke_dasharray.values.clear();
- style->stroke_dasharray.inherit = FALSE;
- style->stroke_dashoffset.inherit = FALSE;
-
- /** \todo fixme: Do that text manipulation via parents */
- SPObject *object = style->object;
- SPDocument *document = style->document;
- gint const refcount = style->refcount;
- SPTextStyle *text = style->text;
- unsigned const text_private = style->text_private;
-
-
- style->refcount = refcount;
- style->object = object;
- style->document = document;
-
- if (document) {
- style->filter.href = new SPFilterReference(document);
- style->filter.href->changedSignal().connect(sigc::bind(sigc::ptr_fun(sp_style_filter_ref_changed), style));
-
- style->fill.value.href = new SPPaintServerReference(document);
- style->fill.value.href->changedSignal().connect(sigc::bind(sigc::ptr_fun(sp_style_fill_paint_server_ref_changed), style));
-
- style->stroke.value.href = new SPPaintServerReference(document);
- style->stroke.value.href->changedSignal().connect(sigc::bind(sigc::ptr_fun(sp_style_stroke_paint_server_ref_changed), style));
- }
-
- style->text = text;
- style->text_private = text_private;
-
- style->text->font_specification.set = FALSE;
- style->text->font.set = FALSE;
- style->text->font_family.set = FALSE;
-
- style->font_size.set = FALSE;
- style->font_size.inherit = FALSE;
- style->font_size.type = SP_FONT_SIZE_LITERAL;
- style->font_size.unit = 0;
- style->font_size.literal = SP_CSS_FONT_SIZE_MEDIUM;
- style->font_size.value = 12.0;
- style->font_size.computed = 12.0;
- style->font_style.set = FALSE;
- style->font_style.inherit = FALSE;
- style->font_style.value = style->font_style.computed = SP_CSS_FONT_STYLE_NORMAL;
- style->font_variant.set = FALSE;
- style->font_variant.inherit = FALSE;
- style->font_variant.value = style->font_variant.computed = SP_CSS_FONT_VARIANT_NORMAL;
- style->font_weight.set = FALSE;
- style->font_weight.inherit = FALSE;
- style->font_weight.value = SP_CSS_FONT_WEIGHT_NORMAL;
- style->font_weight.computed = SP_CSS_FONT_WEIGHT_400;
- style->font_stretch.set = FALSE;
- style->font_stretch.inherit = FALSE;
- style->font_stretch.value = style->font_stretch.computed = SP_CSS_FONT_STRETCH_NORMAL;
-
- /* text */
- style->text_indent.set = FALSE;
- style->text_indent.inherit = FALSE;
- style->text_indent.unit = SP_CSS_UNIT_NONE;
- style->text_indent.computed = 0.0;
-
- style->text_align.set = FALSE;
- style->text_align.inherit = FALSE;
- style->text_align.value = style->text_align.computed = SP_CSS_TEXT_ALIGN_START;
-
- style->text_decoration_line.set = FALSE;
- style->text_decoration_line.inherit = FALSE;
- style->text_decoration_line.underline = FALSE;
- style->text_decoration_line.overline = FALSE;
- style->text_decoration_line.line_through = FALSE;
- style->text_decoration_line.blink = FALSE;
-
- style->text_decoration_style.set = FALSE;
- style->text_decoration_style.inherit = FALSE;
- style->text_decoration_style.solid = FALSE;
- style->text_decoration_style.isdouble = FALSE;
- style->text_decoration_style.dotted = FALSE;
- style->text_decoration_style.dashed = FALSE;
- style->text_decoration_style.wavy = FALSE;
-
- style->text_decoration_color.clear();
-
- style->line_height.set = FALSE;
- style->line_height.inherit = FALSE;
- style->line_height.unit = SP_CSS_UNIT_PERCENT;
- style->line_height.normal = TRUE;
- style->line_height.value = style->line_height.computed = 1.0;
-
- style->letter_spacing.set = FALSE;
- style->letter_spacing.inherit = FALSE;
- style->letter_spacing.unit = SP_CSS_UNIT_NONE;
- style->letter_spacing.normal = TRUE;
- style->letter_spacing.value = style->letter_spacing.computed = 0.0;
-
- style->word_spacing.set = FALSE;
- style->word_spacing.inherit = FALSE;
- style->word_spacing.unit = SP_CSS_UNIT_NONE;
- style->word_spacing.normal = TRUE;
- style->word_spacing.value = style->word_spacing.computed = 0.0;
-
- style->baseline_shift.set = FALSE;
- style->baseline_shift.inherit = FALSE;
- style->baseline_shift.type = SP_BASELINE_SHIFT_LITERAL;
- style->baseline_shift.unit = SP_CSS_UNIT_NONE;
- style->baseline_shift.literal = SP_CSS_BASELINE_SHIFT_BASELINE;
- style->baseline_shift.value = 0.0;
- style->baseline_shift.computed = 0.0;
-
- style->text_transform.set = FALSE;
- style->text_transform.inherit = FALSE;
- style->text_transform.value = style->text_transform.computed = SP_CSS_TEXT_TRANSFORM_NONE;
-
- style->direction.set = FALSE;
- style->direction.inherit = FALSE;
- style->direction.value = style->direction.computed = SP_CSS_DIRECTION_LTR;
-
- style->block_progression.set = FALSE;
- style->block_progression.inherit = FALSE;
- style->block_progression.value = style->block_progression.computed = SP_CSS_BLOCK_PROGRESSION_TB;
-
- style->writing_mode.set = FALSE;
- style->writing_mode.inherit = FALSE;
- style->writing_mode.value = style->writing_mode.computed = SP_CSS_WRITING_MODE_LR_TB;
-
- style->text_anchor.set = FALSE;
- style->text_anchor.inherit = FALSE;
- style->text_anchor.value = style->text_anchor.computed = SP_CSS_TEXT_ANCHOR_START;
-
- style->clip_set = FALSE;
- style->color_set = FALSE;
- style->cursor_set = FALSE;
- style->overflow_set = FALSE;
- style->clip_path_set = FALSE;
- style->mask_set = FALSE;
-
- style->clip_rule.set = FALSE;
- style->clip_rule.inherit = FALSE;
- style->clip_rule.value = style->clip_rule.computed = SP_WIND_RULE_NONZERO;
-
- style->opacity.set = FALSE;
- style->opacity.inherit = FALSE;
- style->opacity.value = SP_SCALE24_MAX;
- style->visibility.set = FALSE;
- style->visibility.inherit = FALSE;
- style->visibility.value = style->visibility.computed = SP_CSS_VISIBILITY_VISIBLE;
- style->display.set = FALSE;
- style->display.inherit = FALSE;
- style->display.value = style->display.computed = SP_CSS_DISPLAY_INLINE;
- style->overflow.set = FALSE;
- style->overflow.inherit = FALSE;
- style->overflow.value = style->overflow.computed = SP_CSS_OVERFLOW_VISIBLE;
- style->isolation.set = FALSE;
- style->isolation.inherit = FALSE;
- style->isolation.value = style->isolation.computed = SP_CSS_ISOLATION_AUTO;
- style->blend_mode.set = FALSE;
- style->blend_mode.inherit = FALSE;
- style->blend_mode.value = style->blend_mode.computed = SP_CSS_BLEND_NORMAL;
-
- style->color.clear();
- style->color.setColor(0.0, 0.0, 0.0);
- style->color_interpolation.set = FALSE;
- style->color_interpolation.inherit = FALSE;
- style->color_interpolation.value = style->color_interpolation.computed = SP_CSS_COLOR_INTERPOLATION_SRGB;
- style->color_interpolation_filters.set = FALSE;
- style->color_interpolation_filters.inherit = FALSE;
- style->color_interpolation_filters.value = style->color_interpolation_filters.computed = SP_CSS_COLOR_INTERPOLATION_LINEARRGB;
-
-
- style->fill.clear();
- style->fill.setColor(0.0, 0.0, 0.0);
- style->fill_opacity.set = FALSE;
- style->fill_opacity.inherit = FALSE;
- style->fill_opacity.value = SP_SCALE24_MAX;
- style->fill_rule.set = FALSE;
- style->fill_rule.inherit = FALSE;
- style->fill_rule.value = style->fill_rule.computed = SP_WIND_RULE_NONZERO;
-
- style->stroke.clear();
- style->stroke_opacity.set = FALSE;
- style->stroke_opacity.inherit = FALSE;
- style->stroke_opacity.value = SP_SCALE24_MAX;
-
- style->stroke_width.set = FALSE;
- style->stroke_width.inherit = FALSE;
- style->stroke_width.unit = SP_CSS_UNIT_NONE;
- style->stroke_width.value = style->stroke_width.computed = 1.0;
-
- style->stroke_linecap.set = FALSE;
- style->stroke_linecap.inherit = FALSE;
- style->stroke_linecap.value = style->stroke_linecap.computed = SP_STROKE_LINECAP_BUTT;
- style->stroke_linejoin.set = FALSE;
- style->stroke_linejoin.inherit = FALSE;
- style->stroke_linejoin.value = style->stroke_linejoin.computed = SP_STROKE_LINEJOIN_MITER;
-
- style->stroke_miterlimit.set = FALSE;
- style->stroke_miterlimit.inherit = FALSE;
- style->stroke_miterlimit.value = 4.0;
-
- style->stroke_dasharray.values.clear();
- style->stroke_dasharray.set = FALSE;
- style->stroke_dasharray.inherit = FALSE;
-
- style->stroke_dashoffset.value = style->stroke_dashoffset.computed = 0.0;
- style->stroke_dashoffset.set = FALSE;
- style->stroke_dashoffset.inherit = FALSE;
-
- for (unsigned i = SP_MARKER_LOC; i < SP_MARKER_LOC_QTY; i++) {
- g_free(style->marker[i].value);
- style->marker[i].set = FALSE;
- style->marker[i].inherit = FALSE;
- style->marker[i].data = 0;
- style->marker[i].value = NULL;
- }
-
- /* SVG 2 */
- style->paint_order.set = FALSE;
- style->paint_order.inherit = FALSE; // For now
- for (unsigned i = 0; i < PAINT_ORDER_LAYERS; ++i) {
- style->paint_order.layer[i] = SP_CSS_PAINT_ORDER_NORMAL;
- style->paint_order.layer_set[i] = false;
- }
- style->paint_order.value = NULL;
-
- style->filter.set = FALSE;
- style->filter.inherit = FALSE;
- style->filter.href = NULL;
-
- style->enable_background.value = SP_CSS_BACKGROUND_ACCUMULATE;
- style->enable_background.set = false;
- style->enable_background.inherit = false;
-
- style->filter_blend_mode.set = style->filter_blend_mode.inherit = false;
- style->filter_blend_mode.value = style->filter_blend_mode.computed = 0;
- style->filter_gaussianBlur_deviation.set = style->filter_gaussianBlur_deviation.inherit = false;
- style->filter_gaussianBlur_deviation.value = style->filter_gaussianBlur_deviation.computed = 0;
-
- style->color_rendering.set = style->color_rendering.inherit = false;
- style->color_rendering.value = style->color_rendering.computed = SP_CSS_COLOR_RENDERING_AUTO;
- style->image_rendering.set = style->image_rendering.inherit = false;
- style->image_rendering.value = style->image_rendering.computed = SP_CSS_IMAGE_RENDERING_AUTO;
- style->shape_rendering.set = style->shape_rendering.inherit = false;
- style->shape_rendering.value = style->shape_rendering.computed = SP_CSS_SHAPE_RENDERING_AUTO;
- style->text_rendering.set = style->text_rendering.inherit = false;
- style->text_rendering.value = style->text_rendering.computed = SP_CSS_TEXT_RENDERING_AUTO;
-
- style->cloned = false;
-}
-
-
-
-/**
- *
- */
-static void
-sp_style_read_dash(SPStyle *style, gchar const *str)
-{
- /* Ref: http://www.w3.org/TR/SVG11/painting.html#StrokeDasharrayProperty */
- style->stroke_dasharray.set = TRUE;
-
- if (strcmp(str, "inherit") == 0) {
- style->stroke_dasharray.inherit = true;
- return;
- }
- style->stroke_dasharray.inherit = false;
-
- style->stroke_dasharray.values.clear();
-
- if (strcmp(str, "none") == 0) {
- return;
- }
-
- gchar *e = NULL;
- bool LineSolid = true;
- while (e != str) {
- /* TODO: Should allow <length> rather than just a unitless (px) number. */
- double number = g_ascii_strtod(str, (char **) &e);
- style->stroke_dasharray.values.push_back( number );
- if (number > 0.00000001)
- LineSolid = false;
- if (e != str) {
- str = e;
- }
- while (str && *str && !isalnum(*str)) str += 1;
- }
-
- if (LineSolid) {
- style->stroke_dasharray.values.clear();
- }
-}
-
-
-/*#########################
-## SPTextStyle operations
-#########################*/
-
-
-/**
- * Return new SPTextStyle object with default settings.
- */
-static SPTextStyle *
-sp_text_style_new()
-{
- SPTextStyle *ts = g_new0(SPTextStyle, 1);
- ts->refcount = 1;
- sp_text_style_clear(ts);
-
- ts->font_specification.value = g_strdup("sans-serif");
- ts->font.value = g_strdup("sans-serif");
- ts->font_family.value = g_strdup("sans-serif");
-
- return ts;
-}
-
-
-/**
- * Clear text style settings.
- */
-static void
-sp_text_style_clear(SPTextStyle *ts)
-{
- ts->font_specification.set = FALSE;
- ts->font.set = FALSE;
- ts->font_family.set = FALSE;
-}
-
-
-
-/**
- * Reduce refcount of text style and possibly free it.
- */
-static SPTextStyle *
-sp_text_style_unref(SPTextStyle *st)
-{
- st->refcount -= 1;
-
- if (st->refcount < 1) {
- g_free(st->font_specification.value);
- g_free(st->font.value);
- g_free(st->font_family.value);
- g_free(st);
- }
-
- return NULL;
-}
-
-
-
-/**
- * Return duplicate of text style.
- */
-static SPTextStyle *
-sp_text_style_duplicate_unset(SPTextStyle *st)
-{
- SPTextStyle *nt = g_new0(SPTextStyle, 1);
- nt->refcount = 1;
-
- nt->font_specification.value = g_strdup(st->font_specification.value);
- nt->font.value = g_strdup(st->font.value);
- nt->font_family.value = g_strdup(st->font_family.value);
-
- return nt;
-}
-
-
-
-/**
- * Write SPTextStyle object into string.
- */
-static guint
-sp_text_style_write(gchar *p, guint const len, SPTextStyle const *const st, guint flags)
-{
- gint d = 0;
-
- // We do not do diffing for text style
- if (flags == SP_STYLE_FLAG_IFDIFF)
- flags = SP_STYLE_FLAG_IFSET;
-
- d += sp_style_write_istring(p + d, len - d, "font-family", &st->font_family, NULL, flags);
- d += sp_style_write_istring(p + d, len - d, "-inkscape-font-specification", &st->font_specification, NULL, flags);
- return d;
-}
-
-
-
-/* The following sp_tyle_read_* functions ignore invalid values, as per
- * http://www.w3.org/TR/REC-CSS2/syndata.html#parsing-errors.
- *
- * [However, the SVG spec is somewhat unclear as to whether the style attribute should
- * be handled as per CSS2 rules or whether it must simply be a set of PROPERTY:VALUE
- * pairs, in which case SVG's error-handling rules
- * http://www.w3.org/TR/SVG11/implnote.html#ErrorProcessing should instead be applied.]
- */
-
-
-/**
- * Set SPIFloat object from string.
- */
-static void
-sp_style_read_ifloat(SPIFloat *val, gchar const *str)
-{
- if (!strcmp(str, "inherit")) {
- val->set = TRUE;
- val->inherit = TRUE;
- } else {
- gfloat value;
- if (sp_svg_number_read_f(str, &value)) {
- val->set = TRUE;
- val->inherit = FALSE;
- val->value = value;
- }
- }
-}
-
-
-
-/**
- * Set SPIScale24 object from string.
- */
-static void
-sp_style_read_iscale24(SPIScale24 *val, gchar const *str)
-{
- if (!strcmp(str, "inherit")) {
- val->set = TRUE;
- val->inherit = TRUE;
- } else {
- gfloat value;
- if (sp_svg_number_read_f(str, &value)) {
- val->set = TRUE;
- val->inherit = FALSE;
- value = CLAMP(value, 0.0, 1.0);
- val->value = SP_SCALE24_FROM_FLOAT(value);
- }
- }
-}
-
-/**
- * Reads a style value and performs lookup based on the given style value enumerations.
- */
-static void
-sp_style_read_ienum(SPIEnum *val, gchar const *str, SPStyleEnum const *dict,
- bool const can_explicitly_inherit)
-{
- if ( can_explicitly_inherit && !strcmp(str, "inherit") ) {
- val->set = TRUE;
- val->inherit = TRUE;
- } else {
- for (unsigned i = 0; dict[i].key; i++) {
- if (!strcmp(str, dict[i].key)) {
- val->set = TRUE;
- val->inherit = FALSE;
- val->value = dict[i].value;
- /* Save copying for values not needing it */
- val->computed = val->value;
- break;
- }
- }
- }
- return;
-}
-
-
-
-/**
- * Set SPIString object from string.
- */
-static void
-sp_style_read_istring(SPIString *val, gchar const *str)
-{
- g_free(val->value);
-
- if (!strcmp(str, "inherit")) {
- val->set = TRUE;
- val->inherit = TRUE;
- val->value = NULL;
- } else {
- val->set = TRUE;
- val->inherit = FALSE;
- val->value = g_strdup(str);
- }
-}
-
-
-
-/**
- * Set SPILength object from string.
- */
-static void
-sp_style_read_ilength(SPILength *val, gchar const *str)
-{
- if (!strcmp(str, "inherit")) {
- val->set = TRUE;
- val->inherit = TRUE;
- } else {
- gdouble value;
- gchar *e;
- /** \todo fixme: Move this to standard place (Lauris) */
- value = g_ascii_strtod(str, &e);
- if ( !IS_FINITE(value) ) { // fix for bug lp:935157
- return;
- }
- if ((gchar const *) e != str) {
- /** \todo
- * Allow the number of px per inch to vary (document preferences,
- * X server or whatever). E.g. don't fill in computed here, do
- * it at the same time as percentage units are done.
- */
- val->value = value;
- if (!*e) {
- /* Userspace */
- val->unit = SP_CSS_UNIT_NONE;
- val->computed = value;
- } else if (!strcmp(e, "px")) {
- /* Userspace */
- val->unit = SP_CSS_UNIT_PX;
- val->computed = value;
- } else if (!strcmp(e, "pt")) {
- /* Userspace / DEVICESCALE */
- val->unit = SP_CSS_UNIT_PT;
- val->computed = Inkscape::Util::Quantity::convert(value, "pt", "px");
- } else if (!strcmp(e, "pc")) {
- val->unit = SP_CSS_UNIT_PC;
- val->computed = Inkscape::Util::Quantity::convert(value, "pc", "px");
- } else if (!strcmp(e, "mm")) {
- val->unit = SP_CSS_UNIT_MM;
- val->computed = Inkscape::Util::Quantity::convert(value, "mm", "px");
- } else if (!strcmp(e, "cm")) {
- val->unit = SP_CSS_UNIT_CM;
- val->computed = Inkscape::Util::Quantity::convert(value, "cm", "px");
- } else if (!strcmp(e, "in")) {
- val->unit = SP_CSS_UNIT_IN;
- val->computed = Inkscape::Util::Quantity::convert(value, "in", "px");
- } else if (!strcmp(e, "em")) {
- /* EM square */
- val->unit = SP_CSS_UNIT_EM;
- val->computed = value * SP_CSS_FONT_SIZE_DEFAULT;
- } else if (!strcmp(e, "ex")) {
- /* ex square */
- val->unit = SP_CSS_UNIT_EX;
- val->computed = value * 0.5 * SP_CSS_FONT_SIZE_DEFAULT;
- } else if (!strcmp(e, "%")) {
- /* Percentage */
- val->unit = SP_CSS_UNIT_PERCENT;
- val->value = value * 0.01;
- } else {
- /* Invalid */
- return;
- }
- val->set = TRUE;
- val->inherit = FALSE;
- }
- }
-}
-
-/**
- * Set SPILengthOrNormal object from string.
- */
-static void
-sp_style_read_ilengthornormal(SPILengthOrNormal *val, gchar const *str)
-{
- if (!strcmp(str, "normal")) {
- val->set = TRUE;
- val->inherit = FALSE;
- val->normal = TRUE;
- val->unit = SP_CSS_UNIT_NONE;
- val->value = val->computed = 0.0;
- } else {
- SPILength length;
- sp_style_read_ilength(&length, str);
- val->set = length.set;
- val->inherit = length.inherit;
- val->normal = FALSE;
- val->unit = length.unit;
- val->value = length.value;
- val->computed = length.computed;
- }
-}
-
-/**
- * Set SPIPaintOrder object from string.
- */
-static void
-sp_style_read_ipaintorder(SPIPaintOrder *val, gchar const *str)
-{
- g_free(val->value);
-
- if (!strcmp(str, "inherit")) {
- // NEED TO CHECK FINAL SPEC
- val->set = TRUE;
- val->inherit = TRUE;
- val->value = NULL;
- } else {
- val->set = TRUE;
- val->inherit = FALSE;
- val->value = g_strdup(str);
-
- if (!strcmp(str, "normal")) {
- val->layer[0] = SP_CSS_PAINT_ORDER_NORMAL;
- val->layer_set[0] = true;
- } else {
- // This certainly can be done more efficiently
- gchar** c = g_strsplit(str, " ", PAINT_ORDER_LAYERS + 1);
- bool used[3] = {false, false, false};
- unsigned int i = 0;
- for( ; i < PAINT_ORDER_LAYERS; ++i ) {
- if( c[i] ) {
- val->layer_set[i] = false;
- if( !strcmp( c[i], "fill")) {
- val->layer[i] = SP_CSS_PAINT_ORDER_FILL;
- val->layer_set[i] = true;
- used[0] = true;
- } else if( !strcmp( c[i], "stroke")) {
- val->layer[i] = SP_CSS_PAINT_ORDER_STROKE;
- val->layer_set[i] = true;
- used[1] = true;
- } else if( !strcmp( c[i], "markers")) {
- val->layer[i] = SP_CSS_PAINT_ORDER_MARKER;
- val->layer_set[i] = true;
- used[2] = true;
- } else {
- break;
- }
- } else {
- break;
- }
- }
- g_strfreev(c);
-
- // Fill out rest of the layers using the default order
- if( !used[0] && i < PAINT_ORDER_LAYERS ) {
- val->layer[i] = SP_CSS_PAINT_ORDER_FILL;
- val->layer_set[i] = false;
- ++i;
- }
- if( !used[1] && i < PAINT_ORDER_LAYERS ) {
- val->layer[i] = SP_CSS_PAINT_ORDER_STROKE;
- val->layer_set[i] = false;
- ++i;
- }
- if( !used[2] && i < PAINT_ORDER_LAYERS ) {
- val->layer[i] = SP_CSS_PAINT_ORDER_MARKER;
- val->layer_set[i] = false;
- }
- }
- }
-}
-
-
-
-/**
- * Set SPITextDecoration object from string.
- */
-static void
-sp_style_read_itextdecoration(SPITextDecorationLine *line, SPITextDecorationStyle *style, SPIPaint *color, gchar const *str){
- sp_style_read_itextdecorationLine(line, str); // scans all tokens for line types
- sp_style_read_itextdecorationStyle(style, str); // scans all tokens for style types
- // the color routine must be fed one token at a time - if multiple colors are found the LAST one is used
- const gchar *hstr = str;
- while (1) {
- if (*str == ' ' || *str == ',' || *str == '\0'){
- int slen = str - hstr;
- gchar *frag = g_strndup(hstr,slen+1); // only send one piece at a time, since keywords may be intermixed
- sp_style_read_itextdecorationColor(color, frag);
- g_free(frag);
- if(color->set)break;
- if(*str == '\0')break;
- hstr = str + 1;
- }
- str++;
- }
-}
-
-/**
- * Set SPITextDecorationLine object from string.
- * returns true if there was a match, false otherwise
- */
-static void
-sp_style_read_itextdecorationLine(SPITextDecorationLine *line, gchar const *str){
- if (!strcmp(str, "inherit")) {
- line->set = true;
- line->inherit = true;
- } else if (!strcmp(str, "none")) {
- line->set = true;
- line->inherit = false;
- line->underline = false;
- line->overline = false;
- line->line_through = false;
- line->blink = false;
- } else {
- bool found_one = false;
- bool hit_one = false;
-
- // CSS 2 keywords
- bool found_underline = false;
- bool found_overline = false;
- bool found_line_through = false;
- bool found_blink = false;
-
- // this method ignores inlineid keys and extra delimiters, so " ,,, blink hello" will set blink and ignore hello
- const gchar *hstr = str;
- while (1) {
- if (*str == ' ' || *str == ',' || *str == '\0'){
- int slen = str - hstr;
- // CSS 2 keywords
- while(1){ // not really a loop, used to avoid a goto
- hit_one = true; // most likely we will
- if ((slen == 9) && strneq(hstr, "underline", slen)){ found_underline = true; break; }
- if ((slen == 8) && strneq(hstr, "overline", slen)){ found_overline = true; break; }
- if ((slen == 12) && strneq(hstr, "line-through", slen)){ found_line_through = true; break; }
- if ((slen == 5) && strneq(hstr, "blink", slen)){ found_blink = true; break; }
- if ((slen == 4) && strneq(hstr, "none", slen)){ break; }
-
- hit_one = false; // whatever this thing is, we do not recognize it
- break;
- }
- found_one |= hit_one;
- if(*str == '\0')break;
- hstr = str + 1;
- }
- str++;
- }
- if (found_one) {
- line->set = true;
- line->inherit = false;
- line->underline = found_underline;
- line->overline = found_overline;
- line->line_through = found_line_through;
- line->blink = found_blink;
- }
- else {
- line->set = false;
- line->inherit = false;
- }
- }
-}
-
-/**
- * Set SPITextDecorationStyle object from string.
- * returns true if there was a match, false otherwise
-*/
-static void
-sp_style_read_itextdecorationStyle(SPITextDecorationStyle *style, gchar const *str){
- if (!strcmp(str, "inherit")) {
- style->set = true;
- style->inherit = true;
- } else if (!strcmp(str, "none")) {
- style->set = true;
- style->inherit = false;
- style->solid = false;
- style->isdouble = false;
- style->dotted = false;
- style->dashed = false;
- style->wavy = false;
- } else {
- // note, these are CSS 3 keywords
- bool found_solid = false;
- bool found_double = false;
- bool found_dotted = false;
- bool found_dashed = false;
- bool found_wavy = false;
- bool found_one = false;
-
- // this method ignores inlineid keys and extra delimiters, so " ,,, style hello" will set style and ignore hello
- // if more than one style is present, the first is used
- const gchar *hstr = str;
- while (1) {
- if (*str == ' ' || *str == ',' || *str == '\0'){
- int slen = str - hstr;
- if ( (slen == 5) && strneq(hstr, "solid", slen)){ found_solid = true; found_one = true; break; }
- else if ((slen == 6) && strneq(hstr, "double", slen)){ found_double = true; found_one = true; break; }
- else if ((slen == 6) && strneq(hstr, "dotted", slen)){ found_dotted = true; found_one = true; break; }
- else if ((slen == 6) && strneq(hstr, "dashed", slen)){ found_dashed = true; found_one = true; break; }
- else if ((slen == 4) && strneq(hstr, "wavy", slen)){ found_wavy = true; found_one = true; break; }
- if(*str == '\0')break; // nothing more to test
- hstr = str + 1;
- }
- str++;
- }
- if(found_one){
- style->set = true;
- style->inherit = false;
- style->solid = found_solid;
- style->isdouble = found_double;
- style->dotted = found_dotted;
- style->dashed = found_dashed;
- style->wavy = found_wavy;
- }
- else {
- style->set = false;
- style->inherit = false;
- }
- }
-}
-
-/**
- * Set SPIPaint object from string.
- */
-static void
-sp_style_read_itextdecorationColor(SPIPaint *color, gchar const *str){
- sp_style_read_icolor(color, str, NULL,NULL);
-}
-
-
-/**
- * Set SPIPaint object from string containing an integer value.
- * \param document Ignored
- */
-static void
-sp_style_read_icolor(SPIPaint *paint, gchar const *str, SPStyle *style, SPDocument *document)
-{
- (void)style; // TODO
- (void)document; // TODO
- paint->currentcolor = FALSE; /* currentColor not a valid <color>. */
- if (!strcmp(str, "inherit")) {
- paint->set = TRUE;
- paint->inherit = TRUE;
- } else {
- paint->inherit = FALSE;
- guint32 const rgb0 = sp_svg_read_color(str, 0xff);
- if (rgb0 != 0xff) {
- paint->setColor(rgb0);
- paint->set = TRUE;
- }
- }
-}
-
-
-/**
- * Set SPIPaint object from string.
- *
- * \pre paint == \&style.fill || paint == \&style.stroke.
- */
-void SPIPaint::read( gchar const *str, SPStyle &style, SPDocument *document )
-{
- while (g_ascii_isspace(*str)) {
- ++str;
- }
-
- clear();
-
- if (streq(str, "inherit")) {
- set = TRUE;
- inherit = TRUE;
- } else {
- if ( strneq(str, "url", 3) ) {
- gchar *uri = extract_uri( str, &str );
- while ( g_ascii_isspace(*str) ) {
- ++str;
- }
- // TODO check on and comment the comparrison "paint != &style->color".
- if ( uri && *uri && (this != &style.color) ) {
- set = TRUE;
-
- // it may be that this style's SPIPaint has not yet created its URIReference;
- // now that we have a document, we can create it here
- if (!value.href && document) {
- value.href = new SPPaintServerReference(document);
- value.href->changedSignal().connect(sigc::bind(sigc::ptr_fun((this == &style.fill)? sp_style_fill_paint_server_ref_changed : sp_style_stroke_paint_server_ref_changed), &style));
- }
-
- // TODO check what this does in light of move away from union
- sp_style_set_ipaint_to_uri_string (&style, this, uri);
- }
- g_free( uri );
- }
-
- if (streq(str, "currentColor") && (this != &style.color)) {
- set = TRUE;
- currentcolor = TRUE;
- } else if (streq(str, "none") && (this != &style.color)) {
- set = TRUE;
- noneSet = TRUE;
- } else {
- guint32 const rgb0 = sp_svg_read_color(str, &str, 0xff);
- if (rgb0 != 0xff) {
- setColor( rgb0 );
- set = TRUE;
-
- while (g_ascii_isspace(*str)) {
- ++str;
- }
- if (strneq(str, "icc-color(", 10)) {
- SVGICCColor* tmp = new SVGICCColor();
- if ( ! sp_svg_read_icc_color( str, &str, tmp ) ) {
- delete tmp;
- tmp = 0;
- }
- value.color.icc = tmp;
- }
- }
- }
- }
-}
-
-
-
-/**
- * Set SPIFontSize object from string.
- */
-static void
-sp_style_read_ifontsize(SPIFontSize *val, gchar const *str)
-{
- if (!strcmp(str, "inherit")) {
- val->set = TRUE;
- val->inherit = TRUE;
- } else if ((*str == 'x') || (*str == 's') || (*str == 'm') || (*str == 'l')) {
- // xx-small, x-small, etc.
- for (unsigned i = 0; enum_font_size[i].key; i++) {
- if (!strcmp(str, enum_font_size[i].key)) {
- val->set = TRUE;
- val->inherit = FALSE;
- val->type = SP_FONT_SIZE_LITERAL;
- val->literal = enum_font_size[i].value;
- return;
- }
- }
- /* Invalid */
- return;
- } else {
- SPILength length;
- length.set = FALSE;
- sp_style_read_ilength(&length, str);
- if( length.set ) {
- val->set = TRUE;
- val->inherit = length.inherit;
- val->unit = length.unit;
- val->value = length.value;
- val->computed = length.computed;
- if( val->unit == SP_CSS_UNIT_PERCENT ) {
- val->type = SP_FONT_SIZE_PERCENTAGE;
- } else {
- val->type = SP_FONT_SIZE_LENGTH;
- }
- }
- return;
- }
-}
-
-
-/**
- * Set SPIBaselineShift object from string.
- */
-static void
-sp_style_read_ibaselineshift(SPIBaselineShift *val, gchar const *str)
-{
- if (!strcmp(str, "inherit")) {
- val->set = TRUE;
- val->inherit = TRUE;
- } else if ((*str == 'b') || (*str == 's')) {
- // baseline or sub or super
- for (unsigned i = 0; enum_baseline_shift[i].key; i++) {
- if (!strcmp(str, enum_baseline_shift[i].key)) {
- val->set = TRUE;
- val->inherit = FALSE;
- val->type = SP_BASELINE_SHIFT_LITERAL;
- val->literal = enum_baseline_shift[i].value;
- return;
- }
- }
- /* Invalid */
- return;
- } else {
- SPILength length;
- sp_style_read_ilength(&length, str);
- val->set = length.set;
- val->inherit = length.inherit;
- val->unit = length.unit;
- val->value = length.value;
- val->computed = length.computed;
- if( val->unit == SP_CSS_UNIT_PERCENT ) {
- val->type = SP_BASELINE_SHIFT_PERCENTAGE;
- } else {
- val->type = SP_BASELINE_SHIFT_LENGTH;
- }
- return;
- }
-}
-
-
-/**
- * Set SPIFilter object from string.
- */
-static void
-sp_style_read_ifilter(gchar const *str, SPStyle * style, SPDocument *document)
-{
- SPIFilter *f = &(style->filter);
- /* Try all possible values: inherit, none, uri */
- if (streq(str, "inherit")) {
- f->set = TRUE;
- f->inherit = TRUE;
- if (f->href){
- if (f->href->getObject()){
- f->href->detach();
- }
- }
- } else if(streq(str, "none")) {
- f->set = TRUE;
- f->inherit = FALSE;
- if (f->href){
- if (f->href->getObject()){
- f->href->detach();
- }
- }
- } else if (strneq(str, "url", 3)) {
- char *uri = extract_uri(str);
- if(uri == NULL || uri[0] == '\0') {
- g_warning("Specified filter url is empty");
- f->set = TRUE;
- f->inherit = FALSE;
- return;
- }
- f->set = TRUE;
- f->inherit = FALSE;
- if (f->href){
- if (f->href->getObject()){
- f->href->detach();
- }
- }
-
- // it may be that this style has not yet created its SPFilterReference;
- // now that we have a document, we can create it here
- if (!f->href && document) {
- f->href = new SPFilterReference(document);
- f->href->changedSignal().connect(sigc::bind(sigc::ptr_fun(sp_style_filter_ref_changed), style));
- }
-
- try {
- f->href->attach(Inkscape::URI(uri));
- } catch (Inkscape::BadURIException &e) {
- g_warning("%s", e.what());
- f->href->detach();
- }
- g_free (uri);
-
- } else {
- /* We shouldn't reach this if SVG input is well-formed */
- f->set = FALSE;
- f->inherit = FALSE;
- if (f->href){
- if (f->href->getObject()){
- f->href->detach();
- }
- }
- }
-}
-
-/**
- * Set SPIEnum object from repr attribute.
- */
-static void
-sp_style_read_penum(SPIEnum *val, Inkscape::XML::Node *repr,
- gchar const *key, SPStyleEnum const *dict,
- bool const can_explicitly_inherit)
-{
- gchar const *str = repr->attribute(key);
- if (str) {
- sp_style_read_ienum(val, str, dict, can_explicitly_inherit);
- }
-}
-
-
-
-/**
- * Set SPILength object from repr attribute.
- */
-static void
-sp_style_read_plength(SPILength *val, Inkscape::XML::Node *repr, gchar const *key)
-{
- gchar const *str = repr->attribute(key);
- if (str) {
- sp_style_read_ilength(val, str);
- }
-}
-
-/**
- * Set SPIFontSize object from repr attribute.
- */
-static void
-sp_style_read_pfontsize(SPIFontSize *val, Inkscape::XML::Node *repr, gchar const *key)
-{
- gchar const *str = repr->attribute(key);
- if (str) {
- sp_style_read_ifontsize(val, str);
- }
-}
-
-
-/**
- * Set SPIBaselineShift object from repr attribute.
- */
-static void
-sp_style_read_pbaselineshift(SPIBaselineShift *val, Inkscape::XML::Node *repr, gchar const *key)
-{
- gchar const *str = repr->attribute(key);
- if (str) {
- sp_style_read_ibaselineshift(val, str);
- }
-}
-
-
-/**
- * Set SPIFloat object from repr attribute.
- */
-static void
-sp_style_read_pfloat(SPIFloat *val, Inkscape::XML::Node *repr, gchar const *key)
-{
- gchar const *str = repr->attribute(key);
- if (str) {
- sp_style_read_ifloat(val, str);
- }
-}
-
-
-/**
- * Write SPIFloat object into string.
- */
-static gint
-sp_style_write_ifloat(gchar *p, gint const len, gchar const *const key,
- SPIFloat const *const val, SPIFloat const *const base, guint const flags)
-{
- Inkscape::CSSOStringStream os;
-
- if ((flags & SP_STYLE_FLAG_ALWAYS)
- || ((flags & SP_STYLE_FLAG_IFSET) && val->set)
- || ((flags & SP_STYLE_FLAG_IFDIFF) && val->set
- && (!base->set || (val->value != base->value))))
- {
- if (val->inherit) {
- return g_snprintf(p, len, "%s:inherit;", key);
- } else {
- os << key << ":" << val->value << ";";
- return g_strlcpy(p, os.str().c_str(), len);
- }
- }
- return 0;
-}
-
-
-/**
- * Write SPIScale24 object into string.
- */
-static gint
-sp_style_write_iscale24(gchar *p, gint const len, gchar const *const key,
- SPIScale24 const *const val, SPIScale24 const *const base,
- guint const flags)
-{
- Inkscape::CSSOStringStream os;
-
- if ((flags & SP_STYLE_FLAG_ALWAYS)
- || ((flags & SP_STYLE_FLAG_IFSET) && val->set)
- || ((flags & SP_STYLE_FLAG_IFDIFF) && val->set
- && (!base->set || (val->value != base->value))))
- {
- if (val->inherit) {
- return g_snprintf(p, len, "%s:inherit;", key);
- } else {
- os << key << ":" << SP_SCALE24_TO_FLOAT(val->value) << ";";
- return g_strlcpy(p, os.str().c_str(), len);
- }
- }
- return 0;
-}
-
-
-/**
- * Write SPIEnum object into string.
- */
-static gint
-sp_style_write_ienum(gchar *p, gint const len, gchar const *const key,
- SPStyleEnum const *const dict,
- SPIEnum const *const val, SPIEnum const *const base, guint const flags)
-{
- if ((flags & SP_STYLE_FLAG_ALWAYS)
- || ((flags & SP_STYLE_FLAG_IFSET) && val->set)
- || ((flags & SP_STYLE_FLAG_IFDIFF) && val->set
- && (!base->set || (val->computed != base->computed))))
- {
- if (val->inherit) {
- return g_snprintf(p, len, "%s:inherit;", key);
- }
- for (unsigned i = 0; dict[i].key; i++) {
- if (dict[i].value == static_cast< gint > (val->value) ) {
- return g_snprintf(p, len, "%s:%s;", key, dict[i].key);
- }
- }
- }
- return 0;
-}
-
-
-
-/**
- * Write SPIString object into string.
- */
-static gint
-sp_style_write_istring(gchar *p, gint const len, gchar const *const key,
- SPIString const *const val, SPIString const *const base, guint const flags)
-{
- gint res = 0;
- if ((flags & SP_STYLE_FLAG_ALWAYS)
- || ((flags & SP_STYLE_FLAG_IFSET) && val->set)
- || ((flags & SP_STYLE_FLAG_IFDIFF) && val->set
- && (!base->set || strcmp(val->value, base->value))))
- {
- if (val->inherit) {
- res = g_snprintf(p, len, "%s:inherit;", key);
- } else {
- Glib::ustring val_quoted = css2_escape_quote(val->value);
- if (~val_quoted.empty()) {
- res = g_snprintf(p, len, "%s:%s;", key, val_quoted.c_str());
- }
- }
- }
- return res;
-}
-
-
-/**
- *
- */
-static bool
-sp_length_differ(SPILength const *const a, SPILength const *const b)
-{
- if (a->unit != b->unit) {
- if (a->unit == SP_CSS_UNIT_EM) return true;
- if (a->unit == SP_CSS_UNIT_EX) return true;
- if (a->unit == SP_CSS_UNIT_PERCENT) return true;
- if (b->unit == SP_CSS_UNIT_EM) return true;
- if (b->unit == SP_CSS_UNIT_EX) return true;
- if (b->unit == SP_CSS_UNIT_PERCENT) return true;
- }
-
- return (a->computed != b->computed);
-}
-
-
-
-/**
- * Write SPILength object into string.
- */
-static gint
-sp_style_write_ilength(gchar *p, gint const len, gchar const *const key,
- SPILength const *const val, SPILength const *const base, guint const flags)
-{
- Inkscape::CSSOStringStream os;
-
- if ((flags & SP_STYLE_FLAG_ALWAYS)
- || ((flags & SP_STYLE_FLAG_IFSET) && val->set)
- || ((flags & SP_STYLE_FLAG_IFDIFF) && val->set
- && (!base->set || sp_length_differ(val, base))))
- {
- if (val->inherit) {
- return g_snprintf(p, len, "%s:inherit;", key);
- } else {
- switch (val->unit) {
- case SP_CSS_UNIT_NONE:
- os << key << ":" << val->computed << ";";
- return g_strlcpy(p, os.str().c_str(), len);
- break;
- case SP_CSS_UNIT_PX:
- os << key << ":" << val->computed << "px;";
- return g_strlcpy(p, os.str().c_str(), len);
- break;
- case SP_CSS_UNIT_PT:
- os << key << ":" << Inkscape::Util::Quantity::convert(val->computed, "px", "pt") << "pt;";
- return g_strlcpy(p, os.str().c_str(), len);
- break;
- case SP_CSS_UNIT_PC:
- os << key << ":" << Inkscape::Util::Quantity::convert(val->computed, "px", "pc") << "pc;";
- return g_strlcpy(p, os.str().c_str(), len);
- break;
- case SP_CSS_UNIT_MM:
- os << key << ":" << Inkscape::Util::Quantity::convert(val->computed, "px", "mm") << "mm;";
- return g_strlcpy(p, os.str().c_str(), len);
- break;
- case SP_CSS_UNIT_CM:
- os << key << ":" << Inkscape::Util::Quantity::convert(val->computed, "px", "cm") << "cm;";
- return g_strlcpy(p, os.str().c_str(), len);
- break;
- case SP_CSS_UNIT_IN:
- os << key << ":" << Inkscape::Util::Quantity::convert(val->computed, "px", "in") << "in;";
- return g_strlcpy(p, os.str().c_str(), len);
- break;
- case SP_CSS_UNIT_EM:
- os << key << ":" << val->value << "em;";
- return g_strlcpy(p, os.str().c_str(), len);
- break;
- case SP_CSS_UNIT_EX:
- os << key << ":" << val->value << "ex;";
- return g_strlcpy(p, os.str().c_str(), len);
- break;
- case SP_CSS_UNIT_PERCENT:
- os << key << ":" << (val->value * 100.0) << "%;";
- return g_strlcpy(p, os.str().c_str(), len);
- break;
- default:
- /* Invalid */
- break;
- }
- }
- }
- return 0;
-}
-
-
-/**
- *
- */
-static bool
-sp_lengthornormal_differ(SPILengthOrNormal const *const a, SPILengthOrNormal const *const b)
-{
- if (a->normal != b->normal) return true;
- if (a->normal) return false;
-
- if (a->unit != b->unit) {
- if (a->unit == SP_CSS_UNIT_EM) return true;
- if (a->unit == SP_CSS_UNIT_EX) return true;
- if (a->unit == SP_CSS_UNIT_PERCENT) return true;
- if (b->unit == SP_CSS_UNIT_EM) return true;
- if (b->unit == SP_CSS_UNIT_EX) return true;
- if (b->unit == SP_CSS_UNIT_PERCENT) return true;
- }
-
- return (a->computed != b->computed);
-}
-
-/**
- * Write SPILengthOrNormal object into string.
- */
-static gint
-sp_style_write_ilengthornormal(gchar *p, gint const len, gchar const *const key,
- SPILengthOrNormal const *const val,
- SPILengthOrNormal const *const base,
- guint const flags)
-{
- if ((flags & SP_STYLE_FLAG_ALWAYS)
- || ((flags & SP_STYLE_FLAG_IFSET) && val->set)
- || ((flags & SP_STYLE_FLAG_IFDIFF) && val->set
- && (!base->set || sp_lengthornormal_differ(val, base))))
- {
- if (val->normal) {
- return g_snprintf(p, len, "%s:normal;", key);
- } else {
- SPILength length;
- length.set = val->set;
- length.inherit = val->inherit;
- length.unit = val->unit;
- length.value = val->value;
- length.computed = val->computed;
- return sp_style_write_ilength(p, len, key, &length, NULL, SP_STYLE_FLAG_ALWAYS);
- }
- }
- return 0;
-}
-
-/**
- * Write SPIDashArray object into string.
- */
-static gint
-sp_style_write_idasharray(gchar *p, gint const len, gchar const *const /*key*/,
- SPIDashArray const *const val, SPIDashArray const *const base, guint const flags)
-{
- if ((flags & SP_STYLE_FLAG_ALWAYS)
- || ((flags & SP_STYLE_FLAG_IFSET) && val->set)
- || ((flags & SP_STYLE_FLAG_IFDIFF) && val->set
- && (!base->set || (val->values != base->values))))
- {
- if (val->inherit) {
- return g_snprintf(p, len, "stroke-dasharray:inherit;");
- } else if ( !val->values.empty() ) {
- Inkscape::CSSOStringStream os;
- os << "stroke-dasharray:";
- for (unsigned i = 0; i < val->values.size(); i++) {
- if (i) {
- os << ", ";
- }
- os << val->values[i];
- }
- os << ";";
- return g_strlcpy(p, os.str().c_str(), len);
- } else {
- return g_snprintf(p, len, "stroke-dasharray:none;");
- }
- }
- return 0;
-}
-
-
-/**
- *
- */
-static bool
-sp_textdecorationLine_differ(SPITextDecorationLine const *const a, SPITextDecorationLine const *const b)
-{
- return( (a->underline != b->underline )
- || (a->overline != b->overline )
- || (a->line_through != b->line_through)
- || (a->blink != b->blink )
- );
-}
-
-/**
- *
- */
-static bool
-sp_textdecorationStyle_differ(SPITextDecorationStyle const *const a, SPITextDecorationStyle const *const b)
-{
- return( (a->solid != b->solid )
- || (a->isdouble != b->isdouble )
- || (a->dotted != b->dotted )
- || (a->dashed != b->dashed )
- || (a->wavy != b->wavy )
- );
-}
-
-/**
- *
- */
-static bool
-sp_textdecorationColor_differ(SPIPaint const *const a, SPIPaint const *const b)
-{
- bool status = (a->isPaintserver() == b->isPaintserver()) &&
- (a->colorSet == b->colorSet) &&
- (a->currentcolor == b->currentcolor);
- return(status);
-}
-
-/**
- * Write SPITextDecoration object into string.
- */
-static gint
-sp_style_write_itextdecoration(gchar *p, gint const len, gchar const *const key,
- SPITextDecorationLine const *const line,
- SPITextDecorationStyle const *const style,
- SPIPaint const *const color,
- SPITextDecorationLine const *const baseLine,
- SPITextDecorationStyle const *const baseStyle,
- SPIPaint const *const baseColor,
- guint const flags)
-{
- Inkscape::CSSOStringStream os;
-
- if ( (flags & SP_STYLE_FLAG_ALWAYS)
- || ((flags & SP_STYLE_FLAG_IFSET) && line->set)
- || ((flags & SP_STYLE_FLAG_IFDIFF) && line->set
- && ( !baseLine->set || sp_textdecorationLine_differ(line, baseLine)))
- || ((flags & SP_STYLE_FLAG_IFSET) && style->set)
- || ((flags & SP_STYLE_FLAG_IFDIFF) && style->set
- && ( !baseStyle->set || sp_textdecorationStyle_differ(style, baseStyle)))
- || ((flags & SP_STYLE_FLAG_IFSET) && color->set)
- || ((flags & SP_STYLE_FLAG_IFDIFF) && color->set
- && ( !baseColor->set || sp_textdecorationColor_differ(color, baseColor)))
- ){
- os << key << ":";
- if (line->inherit || style->inherit || color->inherit) {
- os << " inherit";
- }
- else if (line->underline || line->overline || line->line_through || line->blink) {
- if (line->underline) os << " underline";
- if (line->overline) os << " overline";
- if (line->line_through) os << " line-through";
- if (line->blink) os << " blink";
-
- if ( style->solid) os << " solid";
- else if (style->isdouble) os << " double";
- else if (style->dotted) os << " dotted";
- else if (style->dashed) os << " dashed";
- else if (style->wavy) os << " wavy";
- // color, if it is set, otherwise omit it
- if(color->set){
- char color_buf[8];
- sp_svg_write_color(color_buf, sizeof(color_buf), color->value.color.toRGBA32( 0 ));
- os << " ";
- os << color_buf;
- }
- }
- else {
- os << "none";
- }
- os << ";";
- return g_strlcpy(p, os.str().c_str(), len);
- }
- return 0;
-}
-
-/**
- *
- */
-static bool
-sp_paint_differ(SPIPaint const *const a, SPIPaint const *const b)
-{
- if ( (a->isColor() != b->isColor())
- || (a->isPaintserver() != b->isPaintserver())
- || (a->set != b->set)
- || (a->currentcolor != b->currentcolor)
- || (a->inherit!= b->inherit) ) {
- return true;
- }
-
- // TODO refactor to allow for mixed paints (rgb() *and* url(), etc)
-
- if ( a->isPaintserver() ) {
- return (a->value.href == NULL || b->value.href == NULL || a->value.href->getObject() != b->value.href->getObject());
- }
-
- if ( a->isColor() ) {
- return !( (a->value.color == b->value.color)
- && ((a->value.color.icc == b->value.color.icc)
- || (a->value.color.icc && b->value.color.icc
- && (a->value.color.icc->colorProfile == b->value.color.icc->colorProfile)
- && (a->value.color.icc->colors == b->value.color.icc->colors))));
- /* todo: Allow for epsilon differences in iccColor->colors, e.g. changes small enough not to show up
- * in the string representation. */
- }
-
- return false;
-}
-
-
-
-/**
- * Write SPIPaint object into string.
- */
-static gint
-sp_style_write_ipaint(gchar *b, gint const len, gchar const *const key,
- SPIPaint const *const paint, SPIPaint const *const base, guint const flags)
-{
- int retval = 0;
-
- if ((flags & SP_STYLE_FLAG_ALWAYS)
- || ((flags & SP_STYLE_FLAG_IFSET) && paint->set)
- || ((flags & SP_STYLE_FLAG_IFDIFF) && paint->set
- && (!base->set || sp_paint_differ(paint, base))))
- {
- CSSOStringStream css;
-
- if (paint->inherit) {
- css << "inherit";
- } else {
- if ( paint->value.href && paint->value.href->getURI() ) {
- const gchar* uri = paint->value.href->getURI()->toString();
- css << "url(" << uri << ")";
- g_free((void *)uri);
- }
-
- if ( paint->noneSet ) {
- if ( !css.str().empty() ) {
- css << " ";
- }
- css << "none";
- }
-
- if ( paint->currentcolor ) {
- if ( !css.str().empty() ) {
- css << " ";
- }
- css << "currentColor";
- }
-
- if ( paint->colorSet && !paint->currentcolor ) {
- if ( !css.str().empty() ) {
- css << " ";
- }
- char color_buf[8];
- sp_svg_write_color(color_buf, sizeof(color_buf), paint->value.color.toRGBA32( 0 ));
- css << color_buf;
- }
-
- if (paint->value.color.icc && !paint->currentcolor) {
- if ( !css.str().empty() ) {
- css << " ";
- }
- css << "icc-color(" << paint->value.color.icc->colorProfile;
- for (vector<double>::const_iterator i(paint->value.color.icc->colors.begin()),
- iEnd(paint->value.color.icc->colors.end());
- i != iEnd; ++i) {
- css << ", " << *i;
- }
- css << ')';
- }
- }
-
- if ( !css.str().empty() ) {
- retval = g_snprintf( b, len, "%s:%s;", key, css.str().c_str() );
- }
- }
-
- return retval;
-}
-
-
-/**
- *
- */
-static bool
-sp_paint_order_differ(SPIPaintOrder const *const a, SPIPaintOrder const *const b)
-{
- if( (a->set != b->set) ||
- (a->inherit!= b->inherit) ) {
- return true;
- }
-
- // Check this works when paint-order value is 'normal'
- for (unsigned i = 0; i < PAINT_ORDER_LAYERS; ++i ) {
- if( (a->layer[i] != b->layer[i]) ||
- (a->layer_set[i] != b->layer_set[i]) ) {
- return true;
- }
- }
- return false;
-}
-
-
-
-/**
- * Write SPIPaintOrder object into string.
- */
-static gint
-sp_style_write_ipaintorder(gchar *p, gint len, gchar const *key, SPIPaintOrder const *paint_order, SPIPaintOrder const *base, guint flags)
-{
- int retval = 0;
-
- if ((flags & SP_STYLE_FLAG_ALWAYS)
- || ((flags & SP_STYLE_FLAG_IFSET) && paint_order->set)
- || ((flags & SP_STYLE_FLAG_IFDIFF) && paint_order->set
- && (!base->set || sp_paint_order_differ(paint_order, base))))
- {
- CSSOStringStream css;
-
- if (paint_order->inherit) {
- css << "inherit";
- } else {
- for( unsigned i = 0; i < PAINT_ORDER_LAYERS; ++i ) {
- if( paint_order->layer_set[i] == true ) {
- switch (paint_order->layer[i]) {
- case SP_CSS_PAINT_ORDER_NORMAL:
- css << "normal";
- assert( i == 0 );
- break;
- case SP_CSS_PAINT_ORDER_FILL:
- if (i!=0) css << " ";
- css << "fill";
- break;
- case SP_CSS_PAINT_ORDER_STROKE:
- if (i!=0) css << " ";
- css << "stroke";
- break;
- case SP_CSS_PAINT_ORDER_MARKER:
- if (i!=0) css << " ";
- css << "markers";
- break;
- }
- } else {
- break;
- }
- }
- }
-
- if ( !css.str().empty() ) {
- retval = g_snprintf( p, len, "%s:%s;", key, css.str().c_str() );
- }
- }
-
- return retval;
-}
-
-/**
- *
- */
-static bool
-sp_fontsize_differ(SPIFontSize const *const a, SPIFontSize const *const b)
-{
- if (a->type != b->type)
- return true;
- if (a->type == SP_FONT_SIZE_LENGTH) {
- if (a->computed != b->computed)
- return true;
- } else {
- if (a->value != b->value)
- return true;
- }
- return false;
-}
-
-
-/**
- * Write SPIFontSize object into string.
- */
-static gint
-sp_style_write_ifontsize(gchar *p, gint const len, gchar const *key,
- SPIFontSize const *const val, SPIFontSize const *const base,
- guint const flags)
-{
- if ((flags & SP_STYLE_FLAG_ALWAYS)
- || ((flags & SP_STYLE_FLAG_IFSET) && val->set)
- || ((flags & SP_STYLE_FLAG_IFDIFF) && val->set
- && (!base->set || sp_fontsize_differ(val, base))))
- {
- if (val->inherit) {
- return g_snprintf(p, len, "%s:inherit;", key);
- } else if (val->type == SP_FONT_SIZE_LITERAL) {
- for (unsigned i = 0; enum_font_size[i].key; i++) {
- if (enum_font_size[i].value == static_cast< gint > (val->literal) ) {
- return g_snprintf(p, len, "%s:%s;", key, enum_font_size[i].key);
- }
- }
- } else if (val->type == SP_FONT_SIZE_LENGTH) {
- Inkscape::CSSOStringStream os;
- Inkscape::Preferences *prefs = Inkscape::Preferences::get();
- int unit = prefs->getInt("/options/font/unitType", SP_CSS_UNIT_PT);
- if (prefs->getBool("/options/font/textOutputPx", true)) {
- unit = SP_CSS_UNIT_PX;
- }
- os << key << ":" << sp_style_css_size_px_to_units(val->computed, unit) << sp_style_get_css_unit_string(unit) << ";";
- return g_strlcpy(p, os.str().c_str(), len);
- } else if (val->type == SP_FONT_SIZE_PERCENTAGE) {
- Inkscape::CSSOStringStream os;
- os << key << ":" << (val->value * 100.0) << "%;";
- return g_strlcpy(p, os.str().c_str(), len);
- }
- }
- return 0;
-}
-
-
-/*
- * baseline-shift is relative to parent. The only time it should
- * not be written out is if it is zero (or not set).
- */
-static bool
-sp_baseline_shift_notzero(SPIBaselineShift const *const a )
-{
- if( a->type == SP_BASELINE_SHIFT_LITERAL ) {
- if( a->literal == SP_CSS_BASELINE_SHIFT_BASELINE ) {
- return false;
- }
- } else {
- if( a->value == 0.0 ) {
- return false;
- }
- }
- return true;
-}
-
-/**
- * Write SPIBaselineShift object into string.
- */
-static gint
-sp_style_write_ibaselineshift(gchar *p, gint const len, gchar const *key,
- SPIBaselineShift const *const val, SPIBaselineShift const *const base,
- guint const flags)
-{
- if ((flags & SP_STYLE_FLAG_ALWAYS)
- || ((flags & SP_STYLE_FLAG_IFSET) && val->set)
- || ((flags & SP_STYLE_FLAG_IFDIFF) && val->set
- && (!base->set || sp_baseline_shift_notzero(val) )))
- {
- if (val->inherit) {
- return g_snprintf(p, len, "%s:inherit;", key);
- } else if (val->type == SP_BASELINE_SHIFT_LITERAL) {
- for (unsigned i = 0; enum_baseline_shift[i].key; i++) {
- if (enum_baseline_shift[i].value == static_cast< gint > (val->literal) ) {
- return g_snprintf(p, len, "%s:%s;", key, enum_baseline_shift[i].key);
- }
- }
- } else if (val->type == SP_BASELINE_SHIFT_LENGTH) {
- if( val->unit == SP_CSS_UNIT_EM || val->unit == SP_CSS_UNIT_EX ) {
- Inkscape::CSSOStringStream os;
- os << key << ":" << val->value << (val->unit == SP_CSS_UNIT_EM ? "em;" : "ex;");
- return g_strlcpy(p, os.str().c_str(), len);
- } else {
- Inkscape::CSSOStringStream os;
- os << key << ":" << val->computed << "px;"; // must specify px, see inkscape bug 1221626, mozilla bug 234789
- return g_strlcpy(p, os.str().c_str(), len);
- }
- } else if (val->type == SP_BASELINE_SHIFT_PERCENTAGE) {
- Inkscape::CSSOStringStream os;
- os << key << ":" << (val->value * 100.0) << "%;";
- return g_strlcpy(p, os.str().c_str(), len);
- }
- }
- return 0;
-}
-
-
-
-/**
- * Write SPIFilter object into string.
- */
-static gint
-sp_style_write_ifilter(gchar *p, gint const len, gchar const *key,
- SPIFilter const *const val, SPIFilter const *const base,
- guint const flags)
-{
- (void)base; // TODO
- if ((flags & SP_STYLE_FLAG_ALWAYS)
- || ((flags & SP_STYLE_FLAG_IFSET) && val->set)
- || ((flags & SP_STYLE_FLAG_IFDIFF) && val->set))
- {
- if (val->inherit) {
- return g_snprintf(p, len, "%s:inherit;", key);
- } else if (val->href && val->href->getURI()) {
- gchar *uri = val->href->getURI()->toString();
- gint ret = g_snprintf(p, len, "%s:url(%s);", key, uri);
- g_free(uri);
- return ret;
- }
- }
-
-
- return 0;
-}
-
-SPIPaint::SPIPaint() :
- set(false),
- inherit(0),
- currentcolor(0),
- colorSet(0),
- noneSet(0),
- value()
-{
- value.color.set( 0 );
- value.href = 0;
-}
-
-void SPIPaint::clear()
-{
- set = false;
- inherit = false;
- currentcolor = false;
- colorSet = false;
- noneSet = false;
- value.color.set( 0 );
- if (value.href){
- if (value.href->getObject()){
- value.href->detach();
- }
- }
-}
-
-/**
- * Clear filter object, and disconnect style from paintserver (if present).
- */
-static void
-sp_style_filter_clear(SPStyle *style)
-{
- if (style->filter.href){
- if (style->filter.href->getObject()){
- style->filter.href->detach();
- }
- }
+ return g_strdup( from->write( SP_STYLE_FLAG_IFDIFF, to ).c_str() );
}
@@ -4894,7 +1522,7 @@ sp_style_set_property_url (SPObject *item, gchar const *property, SPObject *link
sp_repr_css_attr_unref(css);
}
-
+// Called in sp-object.cpp
/**
* Clear all style property attributes in object.
*/
@@ -4948,16 +1576,16 @@ sp_style_unset_property_attrs(SPObject *o)
if (style->stroke_linejoin.set) {
repr->setAttribute("stroke-linejoin", NULL);
}
- if (style->marker[SP_MARKER_LOC].set) {
+ if (style->marker.set) {
repr->setAttribute("marker", NULL);
}
- if (style->marker[SP_MARKER_LOC_START].set) {
+ if (style->marker_start.set) {
repr->setAttribute("marker-start", NULL);
}
- if (style->marker[SP_MARKER_LOC_MID].set) {
+ if (style->marker_mid.set) {
repr->setAttribute("marker-mid", NULL);
}
- if (style->marker[SP_MARKER_LOC_END].set) {
+ if (style->marker_end.set) {
repr->setAttribute("marker-end", NULL);
}
if (style->stroke_opacity.set) {
@@ -4972,10 +1600,10 @@ sp_style_unset_property_attrs(SPObject *o)
if (style->paint_order.set) {
repr->setAttribute("paint-order", NULL);
}
- if (style->text_private && style->text->font_specification.set) {
+ if (style->font_specification.set) {
repr->setAttribute("-inkscape-font-specification", NULL);
}
- if (style->text_private && style->text->font_family.set) {
+ if (style->font_family.set) {
repr->setAttribute("font-family", NULL);
}
if (style->text_anchor.set) {
@@ -5025,7 +1653,8 @@ sp_css_attr_from_style(SPStyle const *const style, guint const flags)
return css;
}
-
+// Called in: selection-chemistry.cpp, widgets/stroke-marker-selector.cpp, widgets/stroke-style.cpp,
+// ui/tools/freehand-base.cpp
/**
* \pre object != NULL
* \pre flags in {IFSET, ALWAYS}.
@@ -5042,13 +1671,14 @@ SPCSSAttr *sp_css_attr_from_object(SPObject *object, guint const flags)
return result;
}
+// Called in: selection-chemistry.cpp, ui/dialog/inkscape-preferences.cpp
/**
* Unset any text-related properties
*/
SPCSSAttr *
sp_css_attr_unset_text(SPCSSAttr *css)
{
- sp_repr_css_set_property(css, "font", NULL); // not implemented yet
+ sp_repr_css_set_property(css, "font", NULL);
sp_repr_css_set_property(css, "-inkscape-font-specification", NULL);
sp_repr_css_set_property(css, "font-size", NULL);
sp_repr_css_set_property(css, "font-size-adjust", NULL); // not implemented yet
@@ -5076,6 +1706,7 @@ sp_css_attr_unset_text(SPCSSAttr *css)
return css;
}
+// Called in style.cpp
static bool
is_url(char const *p)
{
@@ -5088,6 +1719,7 @@ is_url(char const *p)
return (g_ascii_strncasecmp(p, "url(", 4) == 0);
}
+// Called in: ui/dialog/inkscape-preferences.cpp, ui/tools/tweek-tool.cpp
/**
* Unset any properties that contain URI values.
*
@@ -5113,6 +1745,7 @@ sp_css_attr_unset_uris(SPCSSAttr *css)
return css;
}
+// Called in style.cpp
/**
* Scale a single-value property.
*/
@@ -5137,6 +1770,7 @@ sp_css_attr_scale_property_single(SPCSSAttr *css, gchar const *property,
}
}
+// Called in style.cpp for stroke-dasharray
/**
* Scale a list-of-values property.
*/
@@ -5169,6 +1803,7 @@ sp_css_attr_scale_property_list(SPCSSAttr *css, gchar const *property, double ex
}
}
+// Called in: text-editing.cpp,
/**
* Scale any properties that may hold <length> by ex.
*/
@@ -5189,6 +1824,7 @@ sp_css_attr_scale(SPCSSAttr *css, double ex)
}
+// Called in style.cpp, xml/repr-css.cpp
/**
* Remove quotes and escapes from a string. Returned value must be g_free'd.
* Note: in CSS (in style= and in stylesheets), unquoting and unescaping is done
@@ -5215,6 +1851,7 @@ attribute_unquote(gchar const *val)
return (val? g_strdup (val) : NULL);
}
+// 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.
*/
diff --git a/src/style.h b/src/style.h
index 939ace0d3..9e592b78f 100644
--- a/src/style.h
+++ b/src/style.h
@@ -7,7 +7,9 @@
/* Authors:
* Lauris Kaplinski <lauris@kaplinski.com>
* Jon A. Cruz <jon@joncruz.org>
+ * Tavmjong Bah <tavmjong@free.fr>
*
+ * Copyright (C) 2014 Tavmjong Bah
* Copyright (C) 2010 Jon A. Cruz
* Copyright (C) 2001-2002 Lauris Kaplinski
* Copyright (C) 2001 Ximian, Inc.
@@ -20,6 +22,15 @@
#include <stddef.h>
#include <sigc++/connection.h>
+#include <iostream>
+#include <vector>
+// #include <map>
+
+// Define SPIBasePtr, a Pointer to a data member of SPStyle of type SPIBase;
+typedef SPIBase SPStyle::*SPIBasePtr;
+
+// Define SPPropMap, a map linking property name to property data
+// typedef std::map<std::string, SPIBasePtr> SPPropMap;
namespace Inkscape {
namespace XML {
@@ -27,24 +38,63 @@ class Node;
}
}
+#include "libcroco/cr-declaration.h"
+#include "libcroco/cr-prop-list.h"
+//struct CRDeclaration;
+//struct CRPropList;
+
+
/// An SVG style object.
-struct SPStyle {
- int refcount;
+class SPStyle {
+public:
+
+ SPStyle(SPDocument *document = NULL, SPObject *object = NULL);// document is ignored if valid object given
+ ~SPStyle();
+ void clear();
+ void read(SPObject *object, Inkscape::XML::Node *repr);
+ void readFromObject(SPObject *object);
+ void readFromPrefs(Glib::ustring const &path);
+ void readIfUnset( gint id, gchar const *val );
+ Glib::ustring write( guint const flags, SPStyle const *const base = NULL ) const;
+ void cascade( SPStyle const *const parent );
+ void merge( SPStyle const *const parent );
+ bool operator==(const SPStyle& rhs);
+
+ int ref() { ++_refcount; return _refcount; }
+ int unref() { --_refcount; return _refcount; }
+
+//FIXME: Make private
+public:
+ void _mergeString( gchar const *const p ); // Rename to readFromString?
+private:
+ void _mergeDeclList( CRDeclaration const *const decl_list );
+ void _mergeDecl( CRDeclaration const *const decl );
+ void _mergeProps( CRPropList *const props );
+ void _mergeObjectStylesheet( SPObject const *const object );
+
+private:
+ int _refcount;
+ static int _count; // Poor man's leak detector
+
+// FIXME: Make private
+public:
/** Object we are attached to */
SPObject *object;
/** Document we are associated with */
SPDocument *document;
- /** Our text style component */
- SPTextStyle *text;
- unsigned text_private : 1;
+private:
+ /// Pointers to all the properties (for looping through them)
+ std::vector<SPIBase *> _properties;
+ // static SPPropMap _propmap;
+
+public:
+
+ /* ----------------------- THE PROPERTIES ------------------------- */
- /* CSS2 */
/* Font */
- /** Size of the font */
- SPIFontSize font_size;
- /** Style of the font */
+ /** Font style */
SPIEnum font_style;
/** Which substyle of the font */
SPIEnum font_variant;
@@ -52,26 +102,34 @@ struct SPStyle {
SPIEnum font_weight;
/** Stretch of the font */
SPIEnum font_stretch;
+ /** Size of the font */
+ SPIFontSize font_size;
+ /** Line height (css2 10.8.1) */
+ SPILengthOrNormal line_height;
+ /** Font family */
+ SPIString font_family;
+ /** Font shorthand */
+ SPIFont font;
+ /** Full font name, as font_factory::ConstructFontSpecification would give, for internal use. */
+ SPIString font_specification;
/** First line indent of paragraphs (css2 16.1) */
SPILength text_indent;
/** text alignment (css2 16.2) (not to be confused with text-anchor) */
SPIEnum text_align;
- /** text decoration (css2 16.3.1) is now handled as a subset of css3 2.4 */
- // SPITextDecoration text_decoration;
-
+
+ /** text decoration (css2 16.3.1) */
+ SPITextDecoration text_decoration;
/** CSS 3 2.1, 2.2, 2.3 */
/** Not done yet, test_decoration3 = css3 2.4*/
SPITextDecorationLine text_decoration_line;
- SPIPaint text_decoration_color;
- SPITextDecorationStyle text_decoration_style;
-
+ SPITextDecorationStyle text_decoration_style; // SPIEnum? Only one can be set at time.
+ SPIColor text_decoration_color;
// used to implement text_decoration, not saved to or read from SVG file
SPITextDecorationData text_decoration_data;
// 16.3.2 is text-shadow. That's complicated.
- /** Line spacing (css2 10.8.1) */
- SPILengthOrNormal line_height;
+
/** letter spacing (css2 16.4) */
SPILengthOrNormal letter_spacing;
/** word spacing (also css2 16.4) */
@@ -93,14 +151,6 @@ struct SPStyle {
/** Anchor of the text (svg1.1 10.9.1) */
SPIEnum text_anchor;
- /* Misc attributes */
- unsigned clip_set : 1;
- unsigned color_set : 1;
- unsigned cursor_set : 1;
- unsigned overflow_set : 1;
- unsigned clip_path_set : 1;
- unsigned mask_set : 1;
-
/** clip-rule: 0 nonzero, 1 evenodd */
SPIEnum clip_rule;
@@ -121,8 +171,10 @@ struct SPStyle {
// Could be shared with Filter blending mode
SPIEnum blend_mode;
+ SPIPaintOrder paint_order;
+
/** color */
- SPIPaint color;
+ SPIColor color;
/** color-interpolation */
SPIEnum color_interpolation;
/** color-interpolation-filters */
@@ -153,18 +205,22 @@ struct SPStyle {
SPIScale24 stroke_opacity;
/** Marker list */
- SPIString marker[SP_MARKER_LOC_QTY];
-
- SPIPaintOrder paint_order;
+ SPIString marker;
+ SPIString marker_start;
+ SPIString marker_mid;
+ SPIString marker_end;
+ SPIString* marker_ptrs[SP_MARKER_LOC_QTY];
/** Filter effect */
SPIFilter filter;
-
+ /** Filter blend mode */
SPIEnum filter_blend_mode;
-
- /** normally not used, but duplicates the Gaussian blur deviation (if any) from the attached
+ /** normally not used, but duplicates the Gaussian blur deviation (if any) from the attached
filter when the style is used for querying */
SPILength filter_gaussianBlur_deviation;
+ /** enable-background, used for defining where filter effects get their background image */
+ SPIEnum enable_background;
+
/** hints on how to render: e.g. speed vs. accuracy.
* As of April, 2013, only image_rendering used. */
@@ -173,9 +229,7 @@ struct SPStyle {
SPIEnum shape_rendering;
SPIEnum text_rendering;
- /** enable-background, used for defining where filter effects get
- * their background image */
- SPIEnum enable_background;
+ /* ----------------------- END PROPERTIES ------------------------- */
/// style belongs to a cloned object
bool cloned;
@@ -186,46 +240,46 @@ struct SPStyle {
sigc::connection fill_ps_modified_connection;
sigc::connection stroke_ps_modified_connection;
- SPObject *getFilter() { return (filter.href) ? filter.href->getObject() : NULL; }
- SPObject const *getFilter() const { return (filter.href) ? filter.href->getObject() : NULL; }
- gchar const *getFilterURI() const { return (filter.href) ? filter.href->getURI()->toString() : NULL; }
+ SPObject *getFilter() { return (filter.href) ? filter.href->getObject() : NULL; }
+ SPObject const *getFilter() const { return (filter.href) ? filter.href->getObject() : NULL; }
+ gchar const *getFilterURI() const { return (filter.href) ? filter.href->getURI()->toString() : NULL; }
- SPPaintServer *getFillPaintServer() { return (fill.value.href) ? fill.value.href->getObject() : NULL; }
- SPPaintServer const *getFillPaintServer() const { return (fill.value.href) ? fill.value.href->getObject() : NULL; }
- gchar const *getFillURI() const { return (fill.value.href) ? fill.value.href->getURI()->toString() : NULL; }
+ SPPaintServer *getFillPaintServer() { return (fill.value.href) ? fill.value.href->getObject() : NULL; }
+ SPPaintServer const *getFillPaintServer() const { return (fill.value.href) ? fill.value.href->getObject() : NULL; }
+ gchar const *getFillURI() const { return (fill.value.href) ? fill.value.href->getURI()->toString() : NULL; }
- SPPaintServer *getStrokePaintServer() { return (stroke.value.href) ? stroke.value.href->getObject() : NULL; }
+ SPPaintServer *getStrokePaintServer() { return (stroke.value.href) ? stroke.value.href->getObject() : NULL; }
SPPaintServer const *getStrokePaintServer() const { return (stroke.value.href) ? stroke.value.href->getObject() : NULL; }
- gchar const *getStrokeURI() const { return (stroke.value.href) ? stroke.value.href->getURI()->toString() : NULL; }
+ gchar const *getStrokeURI() const { return (stroke.value.href) ? stroke.value.href->getURI()->toString() : NULL; }
};
-SPStyle *sp_style_new(SPDocument *document);
+SPStyle *sp_style_new(SPDocument *document); // SPStyle::SPStyle( SPDocument *document = NULL );
-SPStyle *sp_style_new_from_object(SPObject *object);
+SPStyle *sp_style_new_from_object(SPObject *object); // SPStyle::SPStyle( SPObject *object );
-SPStyle *sp_style_ref(SPStyle *style);
+SPStyle *sp_style_ref(SPStyle *style); // SPStyle::ref();
-SPStyle *sp_style_unref(SPStyle *style);
+SPStyle *sp_style_unref(SPStyle *style); // SPStyle::unref();
-void sp_style_read_from_object(SPStyle *style, SPObject *object);
+void sp_style_read_from_object(SPStyle *style, SPObject *object); //SPStyle::read( SPObject * object);
-void sp_style_read_from_prefs(SPStyle *style, Glib::ustring const &path);
+void sp_style_read_from_prefs(SPStyle *style, Glib::ustring const &path); // SPStyle::read( ... );
-void sp_style_merge_from_style_string(SPStyle *style, gchar const *p);
+void sp_style_merge_from_style_string(SPStyle *style, gchar const *p); // SPStyle::merge( ... );?
-void sp_style_merge_from_parent(SPStyle *style, SPStyle const *parent);
+void sp_style_merge_from_parent(SPStyle *style, SPStyle const *parent); // SPStyle::cascade( ... );
-void sp_style_merge_from_dying_parent(SPStyle *style, SPStyle const *parent);
+void sp_style_merge_from_dying_parent(SPStyle *style, SPStyle const *parent); // SPStyle::merge( ... )
-gchar *sp_style_write_string(SPStyle const *style, guint flags = SP_STYLE_FLAG_IFSET);
+gchar *sp_style_write_string(SPStyle const *style, guint flags = SP_STYLE_FLAG_IFSET);//SPStyle::write
-gchar *sp_style_write_difference(SPStyle const *from, SPStyle const *to);
+gchar *sp_style_write_difference(SPStyle const *from, SPStyle const *to); // SPStyle::write
-void sp_style_set_to_uri_string (SPStyle *style, bool isfill, const gchar *uri);
+void sp_style_set_to_uri_string (SPStyle *style, bool isfill, const gchar *uri); // ?
-gchar const *sp_style_get_css_unit_string(int unit);
-double sp_style_css_size_px_to_units(double size, int unit);
-double sp_style_css_size_units_to_px(double size, int unit);
+gchar const *sp_style_get_css_unit_string(int unit); // No change?
+double sp_style_css_size_px_to_units(double size, int unit); // No change?
+double sp_style_css_size_units_to_px(double size, int unit); // No change?
SPCSSAttr *sp_css_attr_from_style (SPStyle const *const style, guint flags);
@@ -254,3 +308,4 @@ Glib::ustring css2_escape_quote(gchar const *val);
End:
*/
// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :
+
diff --git a/src/text-editing.h b/src/text-editing.h
index 04ef6461d..290a39194 100644
--- a/src/text-editing.h
+++ b/src/text-editing.h
@@ -18,11 +18,11 @@
#include "libnrtype/Layout-TNG.h"
#include "text-tag-attributes.h"
-class SPCSSAttr;
-class SPDesktop;
-class SPItem;
-class SPObject;
-struct SPStyle;
+class SPCSSAttr;
+class SPDesktop;
+class SPItem;
+class SPObject;
+class SPStyle;
typedef std::pair<Inkscape::Text::Layout::iterator, Inkscape::Text::Layout::iterator> iterator_pair;
diff --git a/src/ui/dialog/font-substitution.cpp b/src/ui/dialog/font-substitution.cpp
index bf9133086..6e9ecc3c8 100644
--- a/src/ui/dialog/font-substitution.cpp
+++ b/src/ui/dialog/font-substitution.cpp
@@ -200,16 +200,16 @@ GSList * FontSubstitution::getFontReplacedItems(SPDocument* doc, Glib::ustring *
}
}
- if (style && style->text) {
+ if (style) {
gchar const *style_font = NULL;
- if (style->text->font_family.set)
- style_font = style->text->font_family.value;
- else if (style->text->font_specification.set)
- style_font = style->text->font_specification.value;
- else if (style->text->font_family.value)
- style_font = style->text->font_family.value;
- else if (style->text->font_specification.value)
- style_font = style->text->font_specification.value;
+ if (style->font_family.set)
+ style_font = style->font_family.value;
+ else if (style->font_specification.set)
+ style_font = style->font_specification.value;
+ else if (style->font_family.value)
+ style_font = style->font_family.value;
+ else if (style->font_specification.value)
+ style_font = style->font_specification.value;
if (style_font) {
if (has_visible_text(item)) {
diff --git a/src/ui/dialog/livepatheffect-add.cpp b/src/ui/dialog/livepatheffect-add.cpp
index b5f51d81d..c558eddaf 100644
--- a/src/ui/dialog/livepatheffect-add.cpp
+++ b/src/ui/dialog/livepatheffect-add.cpp
@@ -38,6 +38,7 @@ LivePathEffectAdd::LivePathEffectAdd() :
scrolled_window.set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC);
scrolled_window.set_shadow_type(Gtk::SHADOW_IN);
scrolled_window.set_size_request(250, 200);
+ scrolled_window.set_can_focus();
/**
* Effect Store and Tree
@@ -83,10 +84,12 @@ LivePathEffectAdd::LivePathEffectAdd() :
add_action_widget(close_button, Gtk::RESPONSE_CLOSE);
add_action_widget(add_button, Gtk::RESPONSE_APPLY);
+
/**
* Signal handlers
*/
effectlist_treeview.signal_button_press_event().connect_notify( sigc::mem_fun(*this, &LivePathEffectAdd::onButtonEvent) );
+ effectlist_treeview.signal_key_press_event().connect_notify(sigc::mem_fun(*this, &LivePathEffectAdd::onKeyEvent));
close_button.signal_clicked().connect(sigc::mem_fun(*this, &LivePathEffectAdd::onClose));
add_button.signal_clicked().connect(sigc::mem_fun(*this, &LivePathEffectAdd::onAdd));
signal_delete_event().connect( sigc::bind_return(sigc::hide(sigc::mem_fun(*this, &LivePathEffectAdd::onClose)), true ) );
@@ -107,6 +110,16 @@ void LivePathEffectAdd::onClose()
hide();
}
+void LivePathEffectAdd::onKeyEvent(GdkEventKey* evt)
+{
+ if (evt->keyval == GDK_KEY_Return) {
+ onAdd();
+ }
+ if (evt->keyval == GDK_KEY_Escape) {
+ onClose();
+ }
+}
+
void LivePathEffectAdd::onButtonEvent(GdkEventButton* evt)
{
// Double click on tree is same as clicking the add button
@@ -135,6 +148,7 @@ void LivePathEffectAdd::show(SPDesktop *desktop)
dial.set_modal(true);
desktop->setWindowTransient (dial.gobj());
dial.property_destroy_with_parent() = true;
+ dial.effectlist_treeview.grab_focus();
dial.run();
}
diff --git a/src/ui/dialog/livepatheffect-add.h b/src/ui/dialog/livepatheffect-add.h
index 7fa766272..99ead878c 100644
--- a/src/ui/dialog/livepatheffect-add.h
+++ b/src/ui/dialog/livepatheffect-add.h
@@ -74,6 +74,10 @@ protected:
*/
void onButtonEvent(GdkEventButton* evt);
+ /**
+ * Key event
+ */
+ void onKeyEvent(GdkEventKey* evt);
private:
Gtk::TreeView effectlist_treeview;
diff --git a/src/ui/widget/style-subject.h b/src/ui/widget/style-subject.h
index c2941d995..47da91732 100644
--- a/src/ui/widget/style-subject.h
+++ b/src/ui/widget/style-subject.h
@@ -20,7 +20,7 @@
class SPDesktop;
class SPObject;
class SPCSSAttr;
-struct SPStyle;
+class SPStyle;
namespace Inkscape {
class Selection;
diff --git a/src/ui/widget/style-swatch.h b/src/ui/widget/style-swatch.h
index 23ecbdfda..557ca82e2 100644
--- a/src/ui/widget/style-swatch.h
+++ b/src/ui/widget/style-swatch.h
@@ -29,7 +29,7 @@
#include "desktop.h"
#include "preferences.h"
-struct SPStyle;
+class SPStyle;
class SPCSSAttr;
namespace Gtk {
diff --git a/src/util/CMakeLists.txt b/src/util/CMakeLists.txt
index 924cab355..732e01b0c 100644
--- a/src/util/CMakeLists.txt
+++ b/src/util/CMakeLists.txt
@@ -35,10 +35,12 @@ set(util_SRC
reference.h
reverse-list.h
share.h
+ signal-blocker.h
tuple.h
ucompose.hpp
units.h
unordered-containers.h
+ ziptool.h
)
# add_inkscape_lib(util_LIB "${util_SRC}")
diff --git a/src/widgets/paint-selector.h b/src/widgets/paint-selector.h
index d3b3f4116..d6ad3f50c 100644
--- a/src/widgets/paint-selector.h
+++ b/src/widgets/paint-selector.h
@@ -23,7 +23,7 @@
class SPGradient;
class SPDesktop;
class SPPattern;
-struct SPStyle;
+class SPStyle;
#define SP_TYPE_PAINT_SELECTOR (sp_paint_selector_get_type ())
#define SP_PAINT_SELECTOR(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), SP_TYPE_PAINT_SELECTOR, SPPaintSelector))
diff --git a/src/widgets/stroke-style.cpp b/src/widgets/stroke-style.cpp
index a4cca9472..0e0a4fd72 100644
--- a/src/widgets/stroke-style.cpp
+++ b/src/widgets/stroke-style.cpp
@@ -581,7 +581,8 @@ StrokeStyle::forkMarker(SPObject *marker, int loc, SPItem *item)
Glib::ustring urlId = Glib::ustring::format("url(#", marker->getRepr()->attribute("id"), ")");
unsigned int refs = 0;
for (int i = SP_MARKER_LOC_START; i < SP_MARKER_LOC_QTY; i++) {
- if (item->style->marker[i].set && !strcmp(urlId.c_str(), item->style->marker[i].value)) {
+ if (item->style->marker_ptrs[i]->set &&
+ !strcmp(urlId.c_str(), item->style->marker_ptrs[i]->value)) {
refs++;
}
}
@@ -1176,11 +1177,11 @@ StrokeStyle::updateAllMarkers(GSList const *objects)
combo->setDesktop(desktop);
- if (object->style->marker[keyloc[i].loc].value != NULL && !all_texts) {
+ if (object->style->marker_ptrs[keyloc[i].loc]->value != NULL && !all_texts) {
// If the object has this type of markers,
// Extract the name of the marker that the object uses
- SPObject *marker = getMarkerObj(object->style->marker[keyloc[i].loc].value, object->document);
+ SPObject *marker = getMarkerObj(object->style->marker_ptrs[keyloc[i].loc]->value, object->document);
// Scroll the combobox to that marker
combo->set_current(marker);
diff --git a/src/widgets/text-toolbar.cpp b/src/widgets/text-toolbar.cpp
index 349fefa12..3a4f315da 100644
--- a/src/widgets/text-toolbar.cpp
+++ b/src/widgets/text-toolbar.cpp
@@ -72,20 +72,20 @@ using Inkscape::UI::PrefPusher;
static void sp_print_font( SPStyle *query ) {
- bool family_set = query->text->font_family.set;
+ bool family_set = query->font_family.set;
bool style_set = query->font_style.set;
- bool fontspec_set = query->text->font_specification.set;
+ bool fontspec_set = query->font_specification.set;
std::cout << " Family set? " << family_set
<< " Style set? " << style_set
<< " FontSpec set? " << fontspec_set
<< std::endl;
std::cout << " Family: "
- << (query->text->font_family.value ? query->text->font_family.value : "No value")
+ << (query->font_family.value ? query->font_family.value : "No value")
<< " Style: " << query->font_style.computed
<< " Weight: " << query->font_weight.computed
<< " FontSpec: "
- << (query->text->font_specification.value ? query->text->font_specification.value : "No value")
+ << (query->font_specification.value ? query->font_specification.value : "No value")
<< std::endl;
std::cout << " LineHeight: " << query->line_height.computed
<< " WordSpacing: " << query->word_spacing.computed
@@ -146,6 +146,13 @@ static void sp_text_fontfamily_value_changed( Ink_ComboBoxEntry_Action *act, GOb
std::cout << " New active: " << act->active << std::endl;
#endif
if( new_family.compare( fontlister->get_font_family() ) != 0 ) {
+ // Changed font-family
+
+ if( act->active == -1 ) {
+ // New font-family, not in document, not on system (could be fallback list)
+ fontlister->insert_font_family( new_family );
+ act->active = 0; // New family is always at top of list.
+ }
std::pair<Glib::ustring,Glib::ustring> ui = fontlister->set_font_family( act->active );
// active text set in sp_text_toolbox_selection_changed()
@@ -923,7 +930,6 @@ static void sp_text_toolbox_selection_changed(Inkscape::Selection */*selection*/
}
// If we have valid query data for text (font-family, font-specification) set toolbar accordingly.
- if (query->text)
{
// Size (average of text selected)
Inkscape::Preferences *prefs = Inkscape::Preferences::get();
@@ -1051,11 +1057,11 @@ static void sp_text_toolbox_selection_changed(Inkscape::Selection */*selection*/
ege_select_one_action_set_active( textOrientationAction, activeButton2 );
- } // if( query->text )
+ }
#ifdef DEBUG_TEXT
std::cout << " GUI: fontfamily.value: "
- << (query->text->font_family.value ? query->text->font_family.value : "No value")
+ << (query->font_family.value ? query->font_family.value : "No value")
<< std::endl;
std::cout << " GUI: font_size.computed: " << query->font_size.computed << std::endl;
std::cout << " GUI: font_weight.computed: " << query->font_weight.computed << std::endl;
@@ -1167,15 +1173,15 @@ static void sp_text_toolbox_select_cb( GtkEntry* entry, GtkEntryIconPosition /*p
SPItem *item = SP_ITEM(i->data);
SPStyle *style = item->style;
- if (style && style->text) {
+ if (style) {
Glib::ustring family_style;
- if (style->text->font_family.set) {
- family_style = style->text->font_family.value;
+ if (style->font_family.set) {
+ family_style = style->font_family.value;
//std::cout << " family style from font_family: " << family_style << std::endl;
}
- else if (style->text->font_specification.set) {
- family_style = style->text->font_specification.value;
+ else if (style->font_specification.set) {
+ family_style = style->font_specification.value;
//std::cout << " family style from font_spec: " << family_style << std::endl;
}