Inkscape
Vector Graphics Editor
Loading...
Searching...
No Matches
style-internal.cpp
Go to the documentation of this file.
1// SPDX-License-Identifier: GPL-2.0-or-later
7/* Authors:
8 * C++ conversion:
9 * Tavmjong Bah <tavmjong@free.fr>
10 * Legacy C implementation:
11 * Lauris Kaplinski <lauris@kaplinski.com>
12 * Peter Moulder <pmoulder@mail.csse.monash.edu.au>
13 * bulia byak <buliabyak@users.sf.net>
14 * Abhishek Sharma
15 * Kris De Gussem <Kris.DeGussem@gmail.com>
16 *
17 * Copyright (C) 2001-2002 Lauris Kaplinski
18 * Copyright (C) 2001 Ximian, Inc.
19 * Copyright (C) 2005 Monash University
20 * Copyright (C) 2012 Kris De Gussem
21 * Copyright (C) 2014, 2018 Tavmjong Bah
22 *
23 * Released under GNU GPL v2+, read the file 'COPYING' for more information.
24 */
25
26#include <algorithm>
27#include <cmath>
28#include <cstdlib>
29#include <sigc++/bind.h>
30#include <glibmm/regex.h>
31#include <glibmm/ustring.h>
32
33#include "style-enums.h"
34#include "style-internal.h"
35#include "style.h"
36
37#include "colors/color.h"
38#include "colors/document-cms.h"
39
40#include "document.h"
41
42#include "bad-uri-exception.h"
43#include "extract-uri.h"
44#include "preferences.h"
45#include "streq.h"
46#include "strneq.h"
47
48#include "object/object-set.h"
49
50#include "svg/svg.h"
52
53#include "util/units.h"
55
56// TODO REMOVE OR MAKE MEMBER FUNCTIONS
60void sp_style_set_ipaint_to_uri(SPStyle *style, SPIPaint *paint, const Inkscape::URI *uri, SPDocument *document);
61void sp_style_set_ipaint_to_uri_string (SPStyle *style, SPIPaint *paint, const gchar *uri);
62
64
65// SPIBase --------------------------------------------------------------
66
67Glib::ustring const &SPIBase::name() const
68{
69 static Glib::ustring names[(int)SPAttr::SPAttr_SIZE];
70 auto &name = names[(int)id()];
71 if (name.empty()) {
72 auto const *namecstr = sp_attribute_name(id());
73 name = namecstr ? namecstr : "anonymous";
74 }
75 return name;
76}
77
88bool SPIBase::shall_write(guint const flags, SPStyleSrc const &style_src_req, SPIBase const *const base) const
89{
90 // flags SP_STYLE_FLAG_IFSET and SP_STYLE_FLAG_IFDIFF are ignored, their
91 // information is redundant FIXME remove those flags
92
93 // pointer equality handled in SPStyle::write, not expected here
94 assert(base != this);
95
96 if ((flags & SP_STYLE_FLAG_ALWAYS)) {
97 assert(!(flags & SP_STYLE_FLAG_IFSRC));
98 assert(!base);
99 return true;
100 }
101
102 if (!set) {
103 return false;
104 }
105
106 if ((flags & SP_STYLE_FLAG_IFSRC) && style_src_req != style_src) {
107 return false;
108 }
109
110 if (base && inherits && *base == *this) {
111 return false;
112 }
113
114 return true;
115}
116
127const Glib::ustring SPIBase::write(guint const flags, SPStyleSrc const &style_src_req, SPIBase const *const base) const
128{
129 if (shall_write(flags, style_src_req, base)) {
130 auto value = this->get_value();
131 if ( !value.empty() ) {
132 return (name() + ":" + value + important_str() + ";");
133 }
134 }
135 return Glib::ustring("");
136}
137
138
143static bool strip_important(gchar const *str, std::string &stripped)
144{
145 assert(str != nullptr);
146
147 constexpr size_t N = 10; // strlen("!important")
148 auto pos = strlen(str);
149
150 if (pos >= N && strncmp(str + pos - N, "!important", N) == 0) {
151 pos -= N;
152
153 // strip whitespace from the right
154 while (pos > 0 && g_ascii_isspace(str[pos - 1])) {
155 --pos;
156 }
157
158 stripped.assign(str, pos);
159 return true;
160 }
161
162 return false;
163}
164
165void SPIBase::readIfUnset(gchar const *str, SPStyleSrc source)
166{
167 if (!str)
168 return;
169
170 if (source == SPStyleSrc::ATTRIBUTE && id() == SPAttr::D) {
171 return;
172 }
173
174 bool has_important = false;
175 std::string stripped;
176
177 // '!important' is invalid on attributes
178 if (source != SPStyleSrc::ATTRIBUTE) {
179 has_important = strip_important(str, stripped);
180 if (has_important) {
181 str = stripped.c_str();
182 }
183 }
184
185 if (!set || (has_important && !important)) {
186 read(str); // clears style_src
187 style_src = source;
188 if (set) {
189 if (has_important) {
190 important = true;
191 }
192 }
193 }
194}
195
196
197// SPIFloat -------------------------------------------------------------
198
199void
200SPIFloat::read( gchar const *str ) {
201
202 if( !str ) return;
203
204 if ( !strcmp(str, "inherit") ) {
205 set = true;
206 inherit = true;
207 } else {
208 gfloat value_tmp;
209 if (sp_svg_number_read_f(str, &value_tmp)) {
210 set = true;
211 inherit = false;
212 value = value_tmp;
213 }
214 }
215}
216
217const Glib::ustring SPIFloat::get_value() const
218{
219 if (this->inherit) return Glib::ustring("inherit");
221}
222
223void
225 if( const SPIFloat* p = dynamic_cast<const SPIFloat*>(parent) ) {
226 if( (inherits && !set) || inherit ) value = p->value;
227 } else {
228 std::cerr << "SPIFloat::cascade(): Incorrect parent type" << std::endl;
229 }
230}
231
232void
234 if( const SPIFloat* p = dynamic_cast<const SPIFloat*>(parent) ) {
235 if( inherits ) {
236 if( (!set || inherit) && p->set && !(p->inherit) ) {
237 set = p->set;
238 inherit = p->inherit;
239 value = p->value;
240 }
241 }
242 } else {
243 std::cerr << "SPIFloat::merge(): Incorrect parent type" << std::endl;
244 }
245}
246
247bool
248SPIFloat::equals(const SPIBase& rhs) const {
249 if( const SPIFloat* r = dynamic_cast<const SPIFloat*>(&rhs) ) {
250 return (value == r->value && SPIBase::equals(rhs));
251 } else {
252 return false;
253 }
254}
255
256
257
258// SPIScale24 -----------------------------------------------------------
259
260void
261SPIScale24::read( gchar const *str ) {
262
263 if( !str ) return;
264
265 if ( !strcmp(str, "inherit") ) {
266 set = true;
267 inherit = true;
268 } else {
269 gfloat value_in;
270 if (sp_svg_number_read_f(str, &value_in)) {
271 set = true;
272 inherit = false;
273 value_in = CLAMP(value_in, 0.0, 1.0);
274 value = SP_SCALE24_FROM_FLOAT( value_in );
275 }
276 }
277}
278
279const Glib::ustring SPIScale24::get_value() const
280{
281 if (this->inherit) return Glib::ustring("inherit");
282 return Inkscape::ustring::format_classic(SP_SCALE24_TO_FLOAT(this->value));
283}
284
285void
287 if( const SPIScale24* p = dynamic_cast<const SPIScale24*>(parent) ) {
288 if( (inherits && !set) || inherit ) value = p->value;
289 } else {
290 std::cerr << "SPIScale24::cascade(): Incorrect parent type" << std::endl;
291 }
292}
293
294void
296 if( const SPIScale24* p = dynamic_cast<const SPIScale24*>(parent) ) {
297 if( inherits ) {
298 if( (!set || inherit) && p->set && !(p->inherit) ) {
299 set = p->set;
300 inherit = p->inherit;
301 value = p->value;
302 }
303 } else {
304 // Needed only for 'opacity' and 'stop-opacity' which do not inherit. See comment at bottom of file.
305 if (id() != SPAttr::OPACITY && id() != SPAttr::STOP_OPACITY)
306 std::cerr << "SPIScale24::merge: unhandled property: " << name().raw() << std::endl;
307 if( !set || (!inherit && value == SP_SCALE24_MAX) ) {
308 value = p->value;
309 set = (value != SP_SCALE24_MAX);
310 } else {
311 if( inherit ) value = p->value; // Insures child is up-to-date
312 value = SP_SCALE24_MUL( value, p->value );
313 inherit = (inherit && p->inherit && (p->value == 0 || p->value == SP_SCALE24_MAX) );
315 }
316 }
317 } else {
318 std::cerr << "SPIScale24::merge(): Incorrect parent type" << std::endl;
319 }
320}
321
322bool
323SPIScale24::equals(const SPIBase& rhs) const {
324 if( const SPIScale24* r = dynamic_cast<const SPIScale24*>(&rhs) ) {
325 return (value == r->value && SPIBase::equals(rhs));
326 } else {
327 return false;
328 }
329}
330
331
332
333// SPILength ------------------------------------------------------------
334
335void
336SPILength::read( gchar const *str ) {
337
338 if( !str ) return;
339
340 if (!strcmp(str, "inherit")) {
341 set = true;
342 inherit = true;
344 value = computed = 0.0;
345 } else {
346 gdouble value_tmp;
347 gchar *e;
349 value_tmp = g_ascii_strtod(str, &e);
350 if ( !std::isfinite(value_tmp) ) { // fix for bug lp:935157
351 return;
352 }
353 if ((gchar const *) e != str) {
354
355 value = value_tmp;
356 if (!*e) {
357 /* Userspace */
359 computed = value;
360 } else if (!strcmp(e, "px")) {
361 /* Userspace */
363 computed = value;
364 } else if (!strcmp(e, "pt")) {
365 /* Userspace / DEVICESCALE */
368 } else if (!strcmp(e, "pc")) {
371 } else if (!strcmp(e, "mm")) {
374 } else if (!strcmp(e, "cm")) {
377 } else if (!strcmp(e, "in")) {
380 } else if (!strcmp(e, "em")) {
381 /* EM square */
383 if( style ) {
384 computed = value * style->font_size.computed;
385 } else {
387 }
388 } else if (!strcmp(e, "ex")) {
389 /* ex square */
391 if( style ) {
392 computed = value * style->font_size.computed * 0.5; // FIXME
393 } else {
395 }
396 } else if (!strcmp(e, "%")) {
397 /* Percentage */
399 value = value * 0.01;
400 if (id() == SPAttr::LINE_HEIGHT) {
401 // See: http://www.w3.org/TR/CSS2/visudet.html#propdef-line-height
402 if( style ) {
403 computed = value * style->font_size.computed;
404 } else {
406 }
407 }
408 } else {
409 /* Invalid */
410 return;
411 }
412 set = true;
413 inherit = false;
414 }
415 }
416}
417
418const Glib::ustring SPILength::get_value() const
419{
420 if (this->inherit) return Glib::ustring("inherit");
421 auto value = this->computed;
422 auto unit_out = Glib::ustring("");
423 switch (this->unit) {
424 case SP_CSS_UNIT_NONE:
425 break;
426 case SP_CSS_UNIT_PX:
427 unit_out = "px";
428 break;
429 case SP_CSS_UNIT_PT:
430 case SP_CSS_UNIT_PC:
431 case SP_CSS_UNIT_MM:
432 case SP_CSS_UNIT_CM:
433 case SP_CSS_UNIT_IN:
434 unit_out = sp_style_get_css_unit_string(this->unit);
435 value = Inkscape::Util::Quantity::convert(this->computed, "px", unit_out);
436 break;
437 case SP_CSS_UNIT_EM:
438 case SP_CSS_UNIT_EX:
439 unit_out = sp_style_get_css_unit_string(this->unit);
440 value = this->value;
441 break;
443 unit_out = "%";
444 value = this->value * 100.0;
445 break;
446 default:
447 /* Invalid */
448 break;
449 }
450 return Inkscape::ustring::format_classic(value) + unit_out;
451}
452
453void
455 if( const SPILength* p = dynamic_cast<const SPILength*>(parent) ) {
456 if( (inherits && !set) || inherit ) {
457 unit = p->unit;
458 value = p->value;
459 computed = p->computed;
460 } else {
461 // Recalculate based on new font-size, font-family inherited from parent
462 double const em = style->font_size.computed;
463 if (unit == SP_CSS_UNIT_EM) {
464 computed = value * em;
465 } else if (unit == SP_CSS_UNIT_EX) {
466 // FIXME: Get x height from libnrtype or pango.
467 computed = value * em * 0.5;
468 } else if (unit == SP_CSS_UNIT_PERCENT && id() == SPAttr::LINE_HEIGHT) {
469 // Special case
470 computed = value * em;
471 }
472 }
473 } else {
474 std::cerr << "SPILength::cascade(): Incorrect parent type" << std::endl;
475 }
476}
477
478void
480 if( const SPILength* p = dynamic_cast<const SPILength*>(parent) ) {
481 if( inherits ) {
482 if( (!set || inherit) && p->set && !(p->inherit) ) {
483 set = p->set;
484 inherit = p->inherit;
485 unit = p->unit;
486 value = p->value;
487 computed = p->computed;
488
489 // Fix up so values are correct
490 switch (p->unit) {
491 case SP_CSS_UNIT_EM:
492 case SP_CSS_UNIT_EX:
493 value *= p->style->font_size.computed / style->font_size.computed;
498 if (!std::isfinite(value)) {
499 value = computed;
501 }
502 break;
504 default:
505 break;
506 }
507 }
508 }
509 } else {
510 std::cerr << "SPIFloat::merge(): Incorrect parent type" << std::endl;
511 }
512}
515{
517 value = v;
518 computed = v;
519 value_default = v;
520}
521
522// Generate a string and allow emove name for parsing dasharray, etc.
523const Glib::ustring SPILength::toString(bool wname) const
526 if (wname) {
527 os << name() << ":";
528 }
529 os << this->get_value();
530 if (wname) {
531 os << important_str();
532 os << ";";
533 }
534 return os.str();
535}
536
537bool
538SPILength::equals(const SPIBase& rhs) const {
539 if( const SPILength* r = dynamic_cast<const SPILength*>(&rhs) ) {
540
541 if( unit != r->unit ) return false;
542
543 // If length depends on external parameter, lengths cannot be equal.
544 if (unit == SP_CSS_UNIT_EM) return false;
545 if (unit == SP_CSS_UNIT_EX) return false;
546 if (unit == SP_CSS_UNIT_PERCENT) return false;
547 if (r->unit == SP_CSS_UNIT_EM) return false;
548 if (r->unit == SP_CSS_UNIT_EX) return false;
549 if (r->unit == SP_CSS_UNIT_PERCENT) return false;
550
551 return (computed == r->computed );
552 } else {
553 return false;
554 }
555}
556
557// SPILengthOrNormal ----------------------------------------------------
558
559void
560SPILengthOrNormal::read( gchar const *str ) {
561
562 if( !str ) return;
563
564 if ( !strcmp(str, "normal") ) {
565 set = true;
566 inherit = false;
568 value = computed = 0.0;
569 normal = true;
570 } else {
571 SPILength::read( str );
572 normal = false;
573 }
574};
575
576const Glib::ustring SPILengthOrNormal::get_value() const
577{
578 if (this->normal) return Glib::ustring("normal");
579 return SPILength::get_value();
580}
581
582void
584 if( const SPILengthOrNormal* p = dynamic_cast<const SPILengthOrNormal*>(parent) ) {
585 if( (inherits && !set) || inherit ) {
586 normal = p->normal;
587 }
589 } else {
590 std::cerr << "SPILengthOrNormal::cascade(): Incorrect parent type" << std::endl;
591 }
592}
593
594void
596 if( const SPILengthOrNormal* p = dynamic_cast<const SPILengthOrNormal*>(parent) ) {
597 if( inherits ) {
598 if( (!set || inherit) && p->set && !(p->inherit) ) {
599 normal = p->normal;
601 }
602 }
603 }
604}
605
606bool
608 if( const SPILengthOrNormal* r = dynamic_cast<const SPILengthOrNormal*>(&rhs) ) {
609 if( normal && r->normal ) { return true; }
610 if( normal != r->normal ) { return false; }
611 return SPILength::equals(rhs);
612 } else {
613 return false;
614 }
615}
616
617
618// SPIFontVariationSettings ----------------------------------------------------
619
620void
622
623 if( !str ) return;
624
625 if ( !strcmp(str, "normal") ) {
626 set = true;
627 inherit = false;
628 normal = true;
629 axes.clear();
630 return;
631 }
632
633
634 std::vector<Glib::ustring> tokens = Glib::Regex::split_simple(",", str);
635
636 // Match a pattern of a CSS <string> of length 4, whitespace, CSS <number>.
637 // (CSS string is quoted with double quotes).
638
639 // Matching must use a Glib::ustring or matching may produce
640 // subtle errors which may be shown by an "Invalid byte sequence
641 // in conversion input" error.
642 Glib::RefPtr<Glib::Regex> regex = Glib::Regex::create(
643 "[\"'](\\w{4})[\"']"
644 "\\s+([-+]?\\d*\\.?\\d+([eE][-+]?\\d+)?)");
645 Glib::MatchInfo matchInfo;
646
647 for (auto token: tokens) {
648 regex->match(token, matchInfo);
649 if (matchInfo.matches()) {
650 float value = std::stod(matchInfo.fetch(2));
651 axes.insert(std::pair<Glib::ustring,float>(matchInfo.fetch(1), value));
652 }
653 }
654
655 if (!axes.empty()) {
656 set = true;
657 inherit = false;
658 normal = false;
659 }
660};
661
662const Glib::ustring SPIFontVariationSettings::get_value() const
663{
664 if (this->normal) return Glib::ustring("normal");
665 auto ret = Glib::ustring("");
666 for(auto it: axes) {
667 ret += "'" + it.first + "' " + Inkscape::ustring::format_classic(it.second) + ", ";
668 }
669 if (!ret.empty()) ret.erase(ret.size() - 2);
670 return ret;
671}
672
673void
675 if( const SPIFontVariationSettings* p = dynamic_cast<const SPIFontVariationSettings*>(parent) ) {
676 if( !set || inherit ) { // Always inherits
677 normal = p->normal;
678 axes.clear();
679 axes = p->axes;
680 }
681 } else {
682 std::cerr << "SPIFontVariationSettings::cascade(): Incorrect parent type" << std::endl;
683 }
684}
685
686void
688 if( const SPIFontVariationSettings* p = dynamic_cast<const SPIFontVariationSettings*>(parent) ) {
689 // if( inherits ) { 'font-variation-settings' always inherits.
690 if( (!set || inherit) && p->set && !(p->inherit) ) {
691 set = p->set;
692 inherit = p->inherit;
693 normal = p->normal;
694 axes = p->axes;
695 }
696 }
697}
698
699bool
701 if( const SPIFontVariationSettings* r = dynamic_cast<const SPIFontVariationSettings*>(&rhs) ) {
702 if( normal && r->normal ) { return true; }
703 if( normal != r->normal ) { return false; }
704 return axes == r->axes;
705 } else {
706 return false;
707 }
708}
709
710// Generate a string useful for passing to Pango, etc.
711const Glib::ustring
713
715 for (const auto & axe : axes){
716 os << axe.first << "=" << axe.second << ",";
717 }
718
719 std::string string = os.str(); // Glib::ustring doesn't have pop_back()
720 if (!string.empty()) {
721 string.pop_back(); // Delete extra comma at end
722 }
723
724 return string;
725}
726
727// Helpers for SPIEnum -----------------------------------------------------
728
729// The default exists to satisfy linking of derived classes but must never be called
730template <typename T> static SPStyleEnum const *get_enums() { g_assert_not_reached(); return nullptr; }
731
732template <> SPStyleEnum const *get_enums<SPBlendMode>() { return enum_blend_mode; }
735template <> SPStyleEnum const *get_enums<SPCSSBaseline>() { return enum_baseline; }
737template <> SPStyleEnum const *get_enums<SPCSSDisplay>() { return enum_display; }
745template <> SPStyleEnum const *get_enums<SPIsolation>() { return enum_isolation; }
746template <> SPStyleEnum const *get_enums<SPOverflow>() { return enum_overflow; }
754template <> SPStyleEnum const *get_enums<SPWindRule>() { return enum_clip_rule; }
761
762// SPIEnum --------------------------------------------------------------
763
764template <typename T>
766{
767 computed = value;
768}
769
770template <>
772{
773 // The following is defined in CSS 2.1
774 if (value == SP_CSS_FONT_WEIGHT_NORMAL) {
775 computed = SP_CSS_FONT_WEIGHT_400;
776 } else if (value == SP_CSS_FONT_WEIGHT_BOLD) {
777 computed = SP_CSS_FONT_WEIGHT_700;
778 } else {
779 computed = value;
780 }
781}
782
783template <typename T>
784void SPIEnum<T>::read(gchar const *str)
785{
786
787 if( !str ) return;
788
789 if( !strcmp(str, "inherit") ) {
790 set = true;
791 inherit = true;
792 } else {
793 auto const *enums = get_enums<T>();
794 for (unsigned i = 0; enums[i].key; i++) {
795 if (!strcmp(str, enums[i].key)) {
796 set = true;
797 inherit = false;
798 value = static_cast<T>(enums[i].value);
799 /* Save copying for values not needing it */
800 break;
801 }
802 }
803
804 // type-specialized subroutine
805 update_computed();
806 }
807}
808
809// special read() version for font-weight attribute to handle numerical values,
810// values which Pango supports and some fonts require
811template <>
812void SPIEnum<SPCSSFontWeight>::read(gchar const *str) {
813 if (!str) return;
814
815 if (!strcmp(str, "inherit")) {
816 set = true;
817 inherit = true;
818 } else {
819 auto const *enums = get_enums<SPCSSFontWeight>();
820 bool translated = false;
821 for (unsigned i = 0; enums[i].key; i++) {
822 if (!strcmp(str, enums[i].key)) {
823 set = true;
824 inherit = false;
825 value = static_cast<SPCSSFontWeight>(enums[i].value);
826 translated = true;
827 break;
828 }
829 }
830 // translate numbers only; no leading spaces or trailing characters accepted
831 // to make it as strict as key matching above
832 if (!translated && isdigit(*str)) {
833 char* end = nullptr;
834 auto weight = strtol(str, &end, 10);
835 if (end && (*end == '\0' || *end == ' ') && weight > 0 && weight <= 1000) {
836 set = true;
837 inherit = false;
838 value = static_cast<SPCSSFontWeight>(weight);
839 }
840 }
841
842 // type-specialized subroutine
843 update_computed();
844 }
845}
846
847template <>
848const Glib::ustring SPIEnum<SPCSSFontWeight>::get_value() const {
849 if (this->inherit) return Glib::ustring("inherit");
850 auto const *enums = get_enums<SPCSSFontWeight>();
851 auto val = static_cast<int>(value);
852 for (unsigned i = 0; enums[i].key; ++i) {
853 if (enums[i].value == val) {
854 return Glib::ustring(enums[i].key);
855 }
856 }
857 if (val > 0 && val <= 1000) {
858 return Glib::ustring::format(val);
859 }
860 return Glib::ustring("");
861}
862
863
864template <typename T>
865const Glib::ustring SPIEnum<T>::get_value() const
866{
867 if (this->inherit) return Glib::ustring("inherit");
868 auto const *enums = get_enums<T>();
869 for (unsigned i = 0; enums[i].key; ++i) {
870 if (enums[i].value == static_cast< gint > (this->value) ) {
871 return Glib::ustring(enums[i].key);
872 }
873 }
874 return Glib::ustring("");
875}
876
877template <>
879{
880 // strictly, 'bolder' and 'lighter' should go to the next weight
881 // expressible in the current font family, but that's difficult to
882 // find out, so jumping by 3 seems an appropriate approximation
883 if (value == SP_CSS_FONT_WEIGHT_LIGHTER) {
884 computed = static_cast<SPCSSFontWeight>(std::max<int>(SP_CSS_FONT_WEIGHT_100, int(p_computed) - 3 * 100));
885 } else if (value == SP_CSS_FONT_WEIGHT_BOLDER) {
886 computed = static_cast<SPCSSFontWeight>(std::min<int>(SP_CSS_FONT_WEIGHT_900, p_computed + 3 * 100));
887 }
888}
889
890template <>
892{
893 if (value == SP_CSS_FONT_STRETCH_NARROWER) {
894 computed =
895 static_cast<SPCSSFontStretch>(std::max<int>(SP_CSS_FONT_STRETCH_ULTRA_CONDENSED, int(p_computed) - 1));
896 } else if (value == SP_CSS_FONT_STRETCH_WIDER) {
897 computed = static_cast<SPCSSFontStretch>(std::min<int>(SP_CSS_FONT_STRETCH_ULTRA_EXPANDED, p_computed + 1));
898 }
899}
900
901template <typename T>
903{
904 if (const auto *p = dynamic_cast<const SPIEnum<T> *>(parent)) {
905 if( inherits && (!set || inherit) ) {
906 computed = p->computed;
907 } else {
908 // type-specialized subroutine
909 update_computed_cascade(p->computed);
910 }
911 } else {
912 std::cerr << "SPIEnum<T>::cascade(): Incorrect parent type" << std::endl;
913 }
914}
915
916// FIXME Handle font_stretch and font_weight (relative values) New derived class?
917template <typename T>
918void SPIEnum<T>::update_value_merge(SPIEnum<T> const &p, T smaller, T larger)
919{
920 g_assert(set);
921
922 if (value == p.value) {
923 // Leave as is, what does applying "wider" twice do?
924 } else if ((value == smaller && p.value == larger) || //
925 (value == larger && p.value == smaller)) {
926 // Values cancel, unset
927 set = false;
928 } else if (value == smaller || value == larger) {
929 value = computed;
930 inherit = false;
931 }
932}
933
934template <>
936{
938}
939
940template <>
942{
944}
945
946template <typename T>
948{
949 if (const auto *p = dynamic_cast<const SPIEnum<T> *>(parent)) {
950 if( inherits ) {
951 if( p->set && !p->inherit ) {
952 if( !set || inherit ) {
953 set = p->set;
954 inherit = p->inherit;
955 value = p->value;
956 computed = p->computed; // Different from value for font-weight and font-stretch
957 } else {
958 // type-specialized subroutine
959 update_value_merge(*p);
960 }
961 }
962 }
963 }
964}
965
966template <typename T>
967bool SPIEnum<T>::equals(const SPIBase &rhs) const
968{
969 if (auto *r = dynamic_cast<const SPIEnum<T> *>(&rhs)) {
970 return (computed == r->computed && SPIBase::equals(rhs));
971 } else {
972 return false;
973 }
974}
975
976
977#if 0
978// SPIEnumBits ----------------------------------------------------------
979// Used for 'font-variant-xxx'
980void
981SPIEnumBits::read( gchar const *str ) {
982
983 if( !str ) return;
984 if( !strcmp(str, "inherit") ) {
985 set = true;
986 inherit = true;
987 } else {
988 for (unsigned i = 0; enums[i].key; i++) {
989 if (!strcmp(str, enums[i].key)) {
990 set = true;
991 inherit = false;
992 value |= enums[i].value;
993 }
994 }
995 /* Save copying for values not needing it */
996 computed = value;
997 }
998}
999
1000const Glib::ustring SPIEnumBits::get_value() const
1001{
1002 if (this->inherit) return Glib::ustring("inherit");
1003 if (this->value == 0) return Glib::ustring("normal");
1004 auto ret = Glib::ustring("");
1005 for (unsigned i = 0; enums[i].key; ++i) {
1006 if (this->value & enums[i].value) {
1007 if (!ret.empty()) ret += " ";
1008 ret += enums[i].key;
1009 }
1010 }
1011 return ret;
1012}
1013#endif
1014
1015// SPILigatures -----------------------------------------------------
1016// Used for 'font-variant-ligatures'
1017void
1018SPILigatures::read( gchar const *str ) {
1019
1020 if( !str ) return;
1021
1023 if( !strcmp(str, "inherit") ) {
1024 set = true;
1025 inherit = true;
1026 } else if (!strcmp(str, "normal" )) {
1027 // Defaults for TrueType
1028 inherit = false;
1029 set = true;
1030 } else if (!strcmp(str, "none" )) {
1032 inherit = false;
1033 set = true;
1034 } else {
1035 // We need to parse in order
1036 std::vector<Glib::ustring> tokens = Glib::Regex::split_simple("\\s+", str );
1037 auto const *enums = enum_font_variant_ligatures;
1038 for(auto & token : tokens) {
1039 for (unsigned j = 0; enums[j].key; ++j ) {
1040 if (token.compare( enums[j].key ) == 0 ) {
1041 set = true;
1042 inherit = false;
1044 // Turn on
1045 value |= enums[j].value;
1046 } else {
1047 // Turn off
1048 value &= ~(enums[j].value >> 4);
1049 }
1050 }
1051 }
1052 }
1053 }
1054 computed = value;
1055}
1056
1057/* FIXME:: This whole class is bogus and should be an SPIBitEnum TODO */
1058
1059const Glib::ustring SPILigatures::get_value() const
1060{
1061 if (this->inherit) return Glib::ustring("inherit");
1062 if (this->value == SP_CSS_FONT_VARIANT_LIGATURES_NONE) return Glib::ustring("none");
1063 if (this->value == SP_CSS_FONT_VARIANT_LIGATURES_NORMAL) return Glib::ustring("normal");
1064 auto ret = Glib::ustring("");
1066 ret += "no-common-ligatures ";
1068 ret += "discretionary-ligatures ";
1070 ret += "historical-ligatures ";
1072 ret += "no-contextual ";
1073 ret.erase(ret.size() - 1);
1074 return ret;
1075}
1076
1077// SPINumeric -----------------------------------------------------
1078// Used for 'font-variant-numeric'
1079void
1080SPINumeric::read( gchar const *str ) {
1081
1082 if( !str ) return;
1083
1085 if( !strcmp(str, "inherit") ) {
1086 set = true;
1087 inherit = true;
1088 } else if (!strcmp(str, "normal" )) {
1089 // Defaults for TrueType
1090 inherit = false;
1091 set = true;
1092 } else {
1093 // We need to parse in order
1094 std::vector<Glib::ustring> tokens = Glib::Regex::split_simple("\\s+", str );
1095 auto const *enums = enum_font_variant_numeric;
1096 for(auto & token : tokens) {
1097 for (unsigned j = 0; enums[j].key; ++j ) {
1098 if (token.compare( enums[j].key ) == 0 ) {
1099 set = true;
1100 inherit = false;
1101 value |= enums[j].value;
1102
1103 // Must switch off incompatible value
1104 switch (enums[j].value ) {
1106 value &= ~SP_CSS_FONT_VARIANT_NUMERIC_OLDSTYLE_NUMS;
1107 break;
1109 value &= ~SP_CSS_FONT_VARIANT_NUMERIC_LINING_NUMS;
1110 break;
1111
1113 value &= ~SP_CSS_FONT_VARIANT_NUMERIC_TABULAR_NUMS;
1114 break;
1116 value &= ~SP_CSS_FONT_VARIANT_NUMERIC_PROPORTIONAL_NUMS;
1117 break;
1118
1120 value &= ~SP_CSS_FONT_VARIANT_NUMERIC_STACKED_FRACTIONS;
1121 break;
1123 value &= ~SP_CSS_FONT_VARIANT_NUMERIC_DIAGONAL_FRACTIONS;
1124 break;
1125
1129 // Do nothing
1130 break;
1131
1132 default:
1133 std::cerr << "SPINumeric::read(): Invalid value." << std::endl;
1134 break;
1135 }
1136 }
1137 }
1138 }
1139 }
1140 computed = value;
1141}
1142
1143/* FIXME:: This whole class is bogus and should be an SPIBitEnum TODO */
1144const Glib::ustring SPINumeric::get_value() const
1145{
1146 if (this->inherit) return Glib::ustring("inherit");
1147 if (this->value == 0) return Glib::ustring("normal");
1148 auto ret = Glib::ustring("");
1149 auto enums = enum_font_variant_numeric;
1150 for (unsigned i = 1; enums[i].key; ++i) {
1151 // Bitmap is shifted by 1 because normal is zero
1152 if (this->value & (1 << (i - 1))) {
1153 if (!ret.empty()) ret += " ";
1154 ret += enums[i].key;
1155 }
1156 }
1157 return ret;
1158}
1159
1160// SPIEastAsian ---------------------------------------------------
1161// Used for 'font-variant-east-asian'
1162void
1163SPIEastAsian::read( gchar const *str ) {
1164
1165 if( !str ) return;
1166
1168 if( !strcmp(str, "inherit") ) {
1169 set = true;
1170 inherit = true;
1171 } else if (!strcmp(str, "normal" )) {
1172 // Defaults for TrueType
1173 inherit = false;
1174 set = true;
1175 } else {
1176 // We need to parse in order
1177 std::vector<Glib::ustring> tokens = Glib::Regex::split_simple("\\s+", str );
1178 auto const *enums = enum_font_variant_east_asian;
1179 for(auto & token : tokens) {
1180 for (unsigned j = 0; enums[j].key; ++j ) {
1181 if (token.compare( enums[j].key ) == 0 ) {
1182 set = true;
1183 inherit = false;
1184
1185 // Must switch off incompatible value (turn on correct one below)
1186 switch (enums[j].value ) {
1193 value &= ~SP_CSS_FONT_VARIANT_EAST_ASIAN_JIS78;
1194 value &= ~SP_CSS_FONT_VARIANT_EAST_ASIAN_JIS83;
1195 value &= ~SP_CSS_FONT_VARIANT_EAST_ASIAN_JIS90;
1196 value &= ~SP_CSS_FONT_VARIANT_EAST_ASIAN_JIS04;
1197 value &= ~SP_CSS_FONT_VARIANT_EAST_ASIAN_SIMPLIFIED;
1198 value &= ~SP_CSS_FONT_VARIANT_EAST_ASIAN_TRADITIONAL;
1199 break;
1200
1202 value &= ~SP_CSS_FONT_VARIANT_EAST_ASIAN_PROPORTIONAL_WIDTH;
1203 break;
1205 value &= ~SP_CSS_FONT_VARIANT_EAST_ASIAN_FULL_WIDTH;
1206 break;
1207
1210 // Do nothing
1211 break;
1212
1213 default:
1214 std::cerr << "SPIEastasian::read(): Invalid value." << std::endl;
1215 break;
1216 }
1217
1218 value |= enums[j].value;
1219 }
1220 }
1221 }
1222 }
1223 computed = value;
1224}
1225
1226const Glib::ustring SPIEastAsian::get_value() const
1227{
1228 if (this->inherit) return Glib::ustring("inherit");
1229 if (this->value == 0) return Glib::ustring("normal");
1230 auto ret = Glib::ustring("");
1231 auto enums = enum_font_variant_east_asian;
1232 for (unsigned i = 0; enums[i].key; ++i) {
1233 if (this->value & (1 << i)) {
1234 if (!ret.empty()) ret += " ";
1235 ret += enums[i].key;
1236 }
1237 }
1238 return ret;
1239}
1240
1241// SPIString ------------------------------------------------------------
1242
1243void
1244SPIString::read( gchar const *str ) {
1245
1246 if( !str ) return;
1247
1248 clear();
1249
1250 if (!strcmp(str, "inherit")) {
1251 set = true;
1252 inherit = true;
1253 } else if (!g_strcmp0(str, get_default_value())) {
1254 // no need to copy string
1255 set = true;
1256 } else {
1257 Glib::ustring str_temp;
1258
1259 if (id() == SPAttr::FONT_FAMILY) {
1260 // Family names may be quoted in CSS, internally we use unquoted names.
1261 str_temp = str;
1262 css_font_family_unquote( str_temp );
1263 str = str_temp.c_str();
1264 } else if (id() == SPAttr::INKSCAPE_FONT_SPEC) {
1265 str_temp = str;
1266 css_unquote( str_temp );
1267 str = str_temp.c_str();
1268 }
1269
1270 set = true;
1271 _value = g_strdup(str);
1272 }
1273}
1274
1275
1279const Glib::ustring SPIString::get_value() const
1280{
1281 Glib::ustring val;
1282
1283 if (set && inherit) {
1284 val = "inherit";
1285 } else if (auto *v = value()) {
1286 val = v;
1287
1288 if (id() == SPAttr::FONT_FAMILY) {
1290 } else if (id() == SPAttr::INKSCAPE_FONT_SPEC) {
1291 css_quote(val);
1292 }
1293 }
1294
1295 return val;
1296}
1297
1298char const *SPIString::value() const
1299{
1300 return _value ? _value : get_default_value();
1301}
1302
1304{
1305 switch (id()) {
1307 return "sans-serif";
1309 return "normal";
1310 default:
1311 return nullptr;
1312 }
1313}
1314
1315
1316void
1319 g_free(_value);
1320 _value = nullptr;
1321}
1322
1323void
1325 if( const SPIString* p = dynamic_cast<const SPIString*>(parent) ) {
1326 if( inherits && (!set || inherit) ) {
1327 g_free(_value);
1328 _value = g_strdup(p->_value);
1329 }
1330 } else {
1331 std::cerr << "SPIString::cascade(): Incorrect parent type" << std::endl;
1332 }
1333}
1334
1335void
1337 if( const SPIString* p = dynamic_cast<const SPIString*>(parent) ) {
1338 if( inherits ) {
1339 if( (!set || inherit) && p->set && !(p->inherit) ) {
1340 set = p->set;
1341 inherit = p->inherit;
1342 g_free(_value);
1343 _value = g_strdup(p->_value);
1344 }
1345 }
1346 }
1347}
1348
1349bool
1350SPIString::equals(const SPIBase& rhs) const {
1351 if( const SPIString* r = dynamic_cast<const SPIString*>(&rhs) ) {
1352 return g_strcmp0(_value, r->_value) == 0 && SPIBase::equals(rhs);
1353 } else {
1354 return false;
1355 }
1356}
1357
1358
1359// SPIShapes ------------------------------------------------------------
1360
1364
1366 : SPIString(false)
1367{
1368}
1369
1380 for (auto ref : hrefs) {
1381 if (set->includes(ref->getObject())) {
1382 return true;
1383 }
1384 }
1385
1386 return false;
1387}
1388
1389// Used to add/remove listeners for text wrapped in shapes.
1390// Note: this is done differently than for patterns, etc. where presentation attributes can be used.
1391// 'shape-inside' and 'shape-subtract' are only properties.
1392void
1393SPIShapes::read( gchar const *str) {
1394
1395 if (!style) {
1396 std::cerr << "SPIShapes::read: no style!" << std::endl;
1397 return;
1398 }
1399
1400 if( !str ) return;
1401
1402 SPIString::read(str);
1403 assert(set);
1404
1405 // The object/repr this property is connected to..
1406 SPObject* object = style->object;
1407 if (!object) {
1408 std::cerr << " No object" << std::endl;
1409 return;
1410 }
1411
1412 // clear(); // Already cleared! (In SPStyle::read.) Calling again causes segfault.
1413
1414 // Add new listeners
1415 std::vector<Glib::ustring> shapes_url = Glib::Regex::split_simple(" ", str);
1416 for (auto shape_url : shapes_url) {
1417 if ( shape_url.compare(0,5,"url(#") != 0 || shape_url.compare(shape_url.size()-1,1,")") != 0 ){
1418 std::cerr << "SPIShapes::read: Invalid shape value: " << shape_url.raw() << std::endl;
1419 } else {
1420 auto uri = extract_uri(shape_url.c_str()); // Do before we erase "url(#"
1421
1422 // This ups the href count of the shape. This is required so that vacuuming a
1423 // document does not delete shapes stored in <defs>.
1424 SPShapeReference *href = new SPShapeReference(object);
1425
1426 if (href->try_attach(uri.c_str())) {
1427 hrefs.emplace_back(href);
1428 } else {
1429 delete href;
1430 }
1431 }
1432 }
1433}
1434
1435void
1437
1439
1440 hrefs_clear();
1441}
1442
1444{
1445 for (auto href : hrefs) {
1446 delete href;
1447 }
1448 hrefs.clear();
1449}
1450
1451// SPIColor -------------------------------------------------------------
1452
1454 : SPIBase(inherits)
1455{}
1456
1458{
1459 return style && style->document;
1460}
1461
1463{
1464 if (!style || !style->document) {
1465 g_error("Can not get Document CMS manager.");
1466 }
1467 return style->document->getDocumentCMS();
1468}
1469
1471{
1472 SPIBase::operator=(rhs);
1474 _color = rhs._color;
1475 return *this;
1476}
1477
1479{
1480 auto copy = rhs;
1481 setColor(copy);
1482 return *this;
1483}
1484
1486{
1487 currentcolor = false;
1488 _color = other;
1489 set = true;
1490}
1491
1493{
1494 static auto default_color = Colors::Color(0x0); // Transparent RGB black
1495 return _color ? *_color : default_color;
1496}
1497
1498// Used for 'color', 'text-decoration-color', 'flood-color', 'lighting-color', and 'stop-color'.
1499// CSS3: 'currentcolor' is allowed value and is equal to inherit for the 'color' property.
1500
1501void SPIColor::read(gchar const *str)
1502{
1503 if(!str) return;
1504
1505 set = false;
1506 inherit = false;
1507 currentcolor = false;
1508 if ( !strcmp(str, "inherit") ) {
1509 set = true;
1510 inherit = true;
1511 } else if ( !strcmp(str, "currentColor") ) {
1512 set = true;
1513 currentcolor = true;
1514 if (id() == SPAttr::COLOR) {
1515 inherit = true; // CSS3
1516 } else if (style) {
1517 _color = style->color._color;
1518 } else {
1519 std::cerr << "SPIColor::read(): value is 'currentColor' but 'color' not available." << std::endl;
1520 }
1521 } else {
1522 if (canHaveCMS()) {
1523 _color = getCMS().parse(str);
1524 } else {
1525 if (str) { // DEBUG
1526 if (std::string(str).find("icc") != std::string::npos) {
1527 g_error("CMS color '%s' not parsed, no CMS document available.", str);
1528 }
1529 }
1530 _color = Colors::Color::parse(str);
1531 }
1532 set = (bool)_color;
1533 }
1534}
1535
1536const Glib::ustring SPIColor::get_value() const
1537{
1538 // currentcolor goes first to handle special case for 'color' property
1539 if (this->currentcolor) return Glib::ustring("currentColor");
1540 if (this->inherit) return Glib::ustring("inherit");
1541 return _color ? _color->toString() : "";
1542}
1543
1544void
1546 if( const SPIColor* p = dynamic_cast<const SPIColor*>(parent) ) {
1547 if( (inherits && !set) || inherit) { // FIXME verify for 'color'
1548 if (!(inherit && currentcolor))
1549 currentcolor = p->currentcolor;
1550 _color = p->_color;
1551 } else {
1552 // Add CSS4 Color: Lighter, Darker
1553 }
1554 } else {
1555 std::cerr << "SPIColor::cascade(): Incorrect parent type" << std::endl;
1556 }
1557
1558}
1559
1560void
1562 if( const SPIColor* p = dynamic_cast<const SPIColor*>(parent) ) {
1563 if( inherits ) {
1564 if( (!set || inherit) && p->set && !(p->inherit) ) {
1565 set = p->set;
1566 inherit = p->inherit;
1567 currentcolor = p->currentcolor;
1568 _color = p->_color;
1569 }
1570 }
1571 }
1572}
1573
1574bool
1575SPIColor::equals(const SPIBase& rhs) const {
1576 if( const SPIColor* r = dynamic_cast<const SPIColor*>(&rhs) ) {
1577
1578 if (currentcolor != r->currentcolor) {
1579 return false;
1580 }
1581 if ((_color && !r->_color) || (!_color && r->_color)) {
1582 return false;
1583 }
1584 if (_color && r->_color && *_color != *r->_color) {
1585 return false;
1586 }
1587 return SPIBase::equals(rhs);
1588
1589 } else {
1590 return false;
1591 }
1592}
1593
1594
1595
1596// SPIPaint -------------------------------------------------------------
1597
1598// Paint is used for 'fill' and 'stroke'. SPIPaint perhaps should be derived from SPIColor.
1599// 'style' is set in SPStyle::SPStyle or in the legacy SPIPaint::read( gchar, style, document )
1600// It is needed for computed value when value is 'currentColor'. It is also needed to
1601// find the object for creating an href (this is done through document but should be done
1602// directly so document not needed.. FIXME).
1603
1605{
1606 clear();
1607}
1608
1610{
1611 return style && style->document;
1612}
1613
1615{
1616 if (!style || !style->document) {
1617 g_error("Can not get Document CMS manager.");
1618 }
1619 return style->document->getDocumentCMS();
1620}
1621
1627void
1628SPIPaint::read( gchar const *str ) {
1629
1630 // std::cout << "SPIPaint::read: Entrance: " << " |" << (str?str:"null") << "|" << std::endl;
1631 // if( style ) {
1632 // std::cout << " document: " << (void*)style->document << std::endl;
1633 // std::cout << " object: " << (style->object?"present":"null") << std::endl;
1634 // if( style->object )
1635 // std::cout << " : " << (style->object->getId()?style->object->getId():"no ID")
1636 // << " document: " << (style->object->document?"yes":"no") << std::endl;
1637 // }
1638
1639 if(!str ) return;
1640
1641 reset( false ); // Do not init
1642
1643 // Is this necessary?
1644 while (g_ascii_isspace(*str)) {
1645 ++str;
1646 }
1647
1648 if (streq(str, "inherit")) {
1649 set = true;
1650 inherit = true;
1651 } else {
1652 // Read any URL first. The other values can be stand-alone or backup to the URL.
1653
1654 if ( strneq(str, "url", 3) ) {
1655
1656 // FIXME: THE FOLLOWING CODE SHOULD BE PUT IN A PRIVATE FUNCTION FOR REUSE
1657 auto uri = extract_uri(str, &str); // std::string
1658 if(uri.empty()) {
1659 if (!str) {
1660 std::cerr << "SPIPaint::read: url is invalid" << std::endl;
1661 return;
1662 } else {
1663 std::cerr << "SPIPaint::read: url is empty" << std::endl;
1664 }
1665 } else if (!style ) {
1666 std::cerr << "SPIPaint::read: url with empty SPStyle pointer" << std::endl;
1667 } else {
1668 set = true;
1669 SPDocument *document = (style->object) ? style->object->document : nullptr;
1670
1671 // Create href if not done already
1672 if (!href) {
1673
1674 if (style->object) {
1675 href = std::make_shared<SPPaintServerReference>(style->object);
1676 } else if (document) {
1677 href = std::make_shared<SPPaintServerReference>(document);
1678 } else {
1679 std::cerr << "SPIPaint::read: No valid object or document!" << std::endl;
1680 return;
1681 }
1682
1683 if (this == &style->fill) {
1684 style->fill_ps_changed_connection = href->changedSignal().connect(sigc::bind(sigc::ptr_fun(sp_style_fill_paint_server_ref_changed), style));
1685 } else {
1686 style->stroke_ps_changed_connection = href->changedSignal().connect(sigc::bind(sigc::ptr_fun(sp_style_stroke_paint_server_ref_changed), style));
1687 }
1688 }
1689
1690 // TODO check what this does in light of move away from union
1691 sp_style_set_ipaint_to_uri_string(style, this, uri.c_str());
1692 }
1693 }
1694
1695 // Continue to parse after url for fallback colors.
1696 while ( g_ascii_isspace(*str) ) {
1697 ++str;
1698 }
1699
1700 if (streq(str, "currentColor")) {
1701 set = true;
1704 if (style) {
1705 setColor(style->color.getColor());
1706 } else {
1707 // Normally an SPIPaint is part of an SPStyle and the value of 'color' is
1708 // available. SPIPaint can be used 'stand-alone' (e.g. to parse color values) in
1709 // which case a value of 'currentColor' is meaningless, thus we shouldn't reach
1710 // here.
1711 std::cerr << "SPIPaint::read(): value is 'currentColor' but 'color' not available." << std::endl;
1712 setColor(Colors::Color(0x000000ff));
1713 }
1714 } else if (streq(str, "context-fill")) {
1715 set = true;
1718 } else if (streq(str, "context-stroke")) {
1719 set = true;
1722 } else if (streq(str, "none")) {
1723 set = true;
1724 noneSet = true;
1725 } else if (auto color = canHaveCMS() ? getCMS().parse(str) : Colors::Color::parse(str)) {
1726 set = true;
1727 _color = color;
1728 }
1729 }
1730}
1731
1732const Glib::ustring SPIPaint::get_value() const
1733{
1734 if (this->inherit) return Glib::ustring("inherit");
1735 if (this->noneSet) return Glib::ustring("none");
1736 // url must go first as other values can serve as fallbacks
1737 auto ret = Glib::ustring("");
1738 if (this->href && this->href->getURI()) {
1739 ret += this->href->getURI()->cssStr();
1740 }
1741 switch(this->paintSource) {
1743 if (!ret.empty()) ret += " ";
1744 ret += "currentColor";
1745 break;
1747 if (!ret.empty()) ret += " ";
1748 ret += "context-fill";
1749 break;
1751 if (!ret.empty()) ret += " ";
1752 ret += "context-stroke";
1753 break;
1755 if (_color) {
1756 if (!ret.empty()) ret += " ";
1757 ret += _color->toString();
1758 }
1759 break;
1760 }
1761 return ret;
1762}
1763
1765{
1766 _color = other;
1767 set = true;
1768}
1769
1771{
1772 static auto default_color = Colors::Color(0x0); // Transparent RGB black
1773 if (_color)
1774 return *_color;
1775 return default_color;
1776}
1777
1778void
1780 // std::cout << "SPIPaint::clear(): " << name << std::endl;
1781 reset( true ); // Reset and Init
1782}
1783
1784void
1786
1787 // std::cout << "SPIPaint::reset(): " << name << " " << init << std::endl;
1791 noneSet = false;
1792 _color.reset();
1793 tag = nullptr;
1794 href.reset();
1795
1796 if (init && id() == SPAttr::FILL) {
1797 _color = Inkscape::Colors::Color(0x000000ff); // 'black' is default for 'fill'
1798 }
1799}
1800
1801void
1803
1804 // std::cout << "SPIPaint::cascade" << std::endl;
1805 if( const SPIPaint* p = dynamic_cast<const SPIPaint*>(parent) ) {
1806 if (!set || inherit) { // Always inherits
1807
1808 reset( false ); // Do not init
1809
1810 if( p->isPaintserver() ) {
1811 if( p->href) {
1812 // Why can we use p->document ?
1813 sp_style_set_ipaint_to_uri( style, this, p->href->getURI(), p->href->getOwnerDocument());
1814 } else {
1815 std::cerr << "SPIPaint::cascade: Expected paint server not found." << std::endl;
1816 }
1817 } else if( p->isColor() ) {
1818 _color = p->_color;
1819 } else if( p->isNoneSet() ) {
1820 noneSet = true;
1821 } else if( p->paintOrigin == SP_CSS_PAINT_ORIGIN_CURRENT_COLOR ) {
1823 _color = style->color.getColor();
1824 } else if( p->paintOrigin != SP_CSS_PAINT_ORIGIN_NORMAL ) {
1825 paintOrigin = p->paintOrigin; // context fill/stroke
1826 } else if( isNone() ) {
1827 //
1828 } else {
1829 g_assert_not_reached();
1830 }
1831 } else {
1833 // Update in case color value changed.
1834 _color = style->color.getColor();
1835 }
1836 }
1837
1838 } else {
1839 std::cerr << "SPIPaint::cascade(): Incorrect parent type" << std::endl;
1840 }
1841
1842}
1843
1844void
1846 if( const SPIPaint* p = dynamic_cast<const SPIPaint*>(parent) ) {
1847 // if( inherits ) { Paint always inherits
1848 if( (!set || inherit) && p->set && !(p->inherit) ) {
1849 this->cascade( parent ); // Must call before setting 'set'
1850 set = p->set;
1851 inherit = p->inherit;
1852 }
1853 }
1854}
1855
1856bool
1857SPIPaint::equals(const SPIBase& rhs) const {
1858
1859 if( const SPIPaint* r = dynamic_cast<const SPIPaint*>(&rhs) ) {
1860
1861 if ( (this->isColor() != r->isColor() ) ||
1862 (this->isPaintserver() != r->isPaintserver() ) ||
1863 (this->paintOrigin != r->paintOrigin ) ||
1864 (this->paintSource != r->paintSource )) {
1865 return false;
1866 }
1867
1868 if ( this->isPaintserver() ) {
1869 if( this->href == nullptr || r->href == nullptr ||
1870 this->href->getObject() != r->href->getObject() ) {
1871 return false;
1872 }
1873 }
1874
1875 if (this->isColor() && *_color != *r->_color) {
1876 return false;
1877 }
1878
1879 return SPIBase::equals(rhs);
1880
1881 } else {
1882 return false;
1883 }
1884}
1885
1886
1887
1888// SPIPaintOrder --------------------------------------------------------
1889
1890void
1891SPIPaintOrder::read( gchar const *str ) {
1892
1893 if( !str ) return;
1894
1895 g_free(value);
1896 set = false;
1897 inherit = false;
1898
1899 if (!strcmp(str, "inherit")) {
1900 set = true;
1901 inherit = true;
1902 } else {
1903 set = true;
1904 value = g_strdup(str);
1905
1906 if (!strcmp(value, "normal")) {
1908 layer_set[0] = true;
1909 } else {
1910 // This certainly can be done more efficiently
1911 gchar** c = g_strsplit(value, " ", PAINT_ORDER_LAYERS + 1);
1912 bool used[3] = {false, false, false};
1913 unsigned int i = 0;
1914 for( ; i < PAINT_ORDER_LAYERS; ++i ) {
1915 if( c[i] ) {
1916 layer_set[i] = false;
1917 if( !strcmp( c[i], "fill")) {
1919 layer_set[i] = true;
1920 used[0] = true;
1921 } else if( !strcmp( c[i], "stroke")) {
1923 layer_set[i] = true;
1924 used[1] = true;
1925 } else if( !strcmp( c[i], "markers")) {
1927 layer_set[i] = true;
1928 used[2] = true;
1929 } else {
1930 std::cerr << "sp_style_read_ipaintorder: illegal value: " << c[i] << std::endl;
1931 break;
1932 }
1933 } else {
1934 break;
1935 }
1936 }
1937 g_strfreev(c);
1938
1939 // Fill out rest of the layers using the default order
1940 if( !used[0] && i < PAINT_ORDER_LAYERS ) {
1942 layer_set[i] = false;
1943 ++i;
1944 }
1945 if( !used[1] && i < PAINT_ORDER_LAYERS ) {
1947 layer_set[i] = false;
1948 ++i;
1949 }
1950 if( !used[2] && i < PAINT_ORDER_LAYERS ) {
1952 layer_set[i] = false;
1953 }
1954 }
1955 }
1956}
1957
1962{
1963 for( unsigned i = 0; i < PAINT_ORDER_LAYERS; ++i) {
1964 if (layer[i] == paint_order)
1965 return i;
1966 }
1967 // Default/normal (see SPIPaintOrder::read for expected state)
1968 return paint_order - 1;
1969}
1970
1974std::array<SPPaintOrderLayer, PAINT_ORDER_LAYERS> SPIPaintOrder::get_layers() const
1975{
1976 std::array<SPPaintOrderLayer, PAINT_ORDER_LAYERS> ret = {SP_CSS_PAINT_ORDER_FILL, SP_CSS_PAINT_ORDER_STROKE, SP_CSS_PAINT_ORDER_MARKER};
1977 for (unsigned i = 0; i < 3; i++) {
1978 if (layer[i] != SP_CSS_PAINT_ORDER_NORMAL) {
1979 ret[i] = layer[i];
1980 }
1981 }
1982 return ret;
1983}
1984
1985const Glib::ustring SPIPaintOrder::get_value() const
1986{
1987 if (this->inherit) return Glib::ustring("inherit");
1988 auto ret = Glib::ustring("");
1989 for( unsigned i = 0; i < PAINT_ORDER_LAYERS; ++i ) {
1990 if (layer_set[i]) {
1991 if (!ret.empty()) ret += " ";
1992 switch (this->layer[i]) {
1994 ret += "normal";
1995 assert( i == 0 );
1996 break;
1998 ret += "fill";
1999 break;
2001 ret += "stroke";
2002 break;
2004 ret += "markers";
2005 break;
2006 }
2007 } else {
2008 break;
2009 }
2010 }
2011 return ret;
2012}
2013
2014void
2016 if( const SPIPaintOrder* p = dynamic_cast<const SPIPaintOrder*>(parent) ) {
2017 if (!set || inherit) { // Always inherits
2018 for( unsigned i = 0; i < PAINT_ORDER_LAYERS; ++i ) {
2019 layer[i] = p->layer[i];
2020 layer_set[i] = p->layer_set[i];
2021 }
2022 g_free( value );
2023 value = g_strdup(p->value);
2024 }
2025 } else {
2026 std::cerr << "SPIPaintOrder::cascade(): Incorrect parent type" << std::endl;
2027 }
2028}
2029
2030void
2032 if( const SPIPaintOrder* p = dynamic_cast<const SPIPaintOrder*>(parent) ) {
2033 // if( inherits ) { PaintOrder always inherits
2034 if( (!set || inherit) && p->set && !(p->inherit) ) {
2035 this->cascade( parent ); // Must call be setting 'set'
2036 set = p->set;
2037 inherit = p->inherit;
2038 }
2039 }
2040}
2041
2042bool
2044 if( const SPIPaintOrder* r = dynamic_cast<const SPIPaintOrder*>(&rhs) ) {
2045 if( layer[0] == SP_CSS_PAINT_ORDER_NORMAL &&
2046 r->layer[0] == SP_CSS_PAINT_ORDER_NORMAL ) return SPIBase::equals(rhs);
2047 for (unsigned i = 0; i < PAINT_ORDER_LAYERS; ++i ) {
2048 if( layer[i] != r->layer[i] ) return false;
2049 }
2050 return SPIBase::equals(rhs);
2051 } else {
2052 return false;
2053 }
2054}
2055
2056
2057
2058// SPIFilter ------------------------------------------------------------
2059
2061 if( href ) {
2062 clear();
2063 delete href;
2064 href = nullptr;
2065 }
2066}
2067
2068void
2069SPIFilter::read( gchar const *str ) {
2070
2071 if( !str ) return;
2072
2073 clear();
2074
2075 if ( streq(str, "inherit") ) {
2076 set = true;
2077 inherit = true;
2078 } else if (streq(str, "none")) {
2079 set = true;
2080 } else if (strneq(str, "url", 3)) {
2081 auto uri = extract_uri(str);
2082 if (uri.empty()) {
2083 std::cerr << "SPIFilter::read: url is empty or invalid" << std::endl;
2084 return;
2085 } else if (!style) {
2086 std::cerr << "SPIFilter::read: url with empty SPStyle pointer" << std::endl;
2087 return;
2088 }
2089 set = true;
2090
2091 // Create href if not already done.
2092 if (!href) {
2093 if (style->object) {
2095 }
2096 // Do we have href now?
2097 if ( href ) {
2098 style->filter_changed_connection = href->changedSignal().connect(sigc::bind(sigc::ptr_fun(sp_style_filter_ref_changed), style));
2099 } else {
2100 std::cerr << "SPIFilter::read(): Could not allocate 'href'" << std::endl;
2101 return;
2102 }
2103 }
2104
2105 // We have href
2106 try {
2107 href->attach(Inkscape::URI(uri.c_str()));
2108 } catch (Inkscape::BadURIException &e) {
2109 std::cerr << "SPIFilter::read() " << e.what() << std::endl;
2110 delete href;
2111 href = nullptr;
2112 }
2113
2114 } else {
2115 std::cerr << "SPIFilter::read(): malformed value: " << str << std::endl;
2116 }
2117}
2118
2119const Glib::ustring SPIFilter::get_value() const
2120{
2121 if (this->inherit) return Glib::ustring("inherit");
2122 if (this->href && this->href->getURI()) return this->href->getURI()->cssStr();
2123 return Glib::ustring("");
2124}
2125
2126void
2128
2130 if( href ) {
2131 if( href->getObject() ) {
2132 href->detach();
2133 }
2134 }
2135}
2136
2137void
2139 if( const SPIFilter* p = dynamic_cast<const SPIFilter*>(parent) ) {
2140 if( inherit ) { // Only inherits if 'inherit' true/
2141 // FIXME: This is rather unlikely so ignore for now.
2142 (void)p;
2143 std::cerr << "SPIFilter::cascade: value 'inherit' not supported." << std::endl;
2144 } else {
2145 // Do nothing
2146 }
2147 } else {
2148 std::cerr << "SPIFilter::cascade(): Incorrect parent type" << std::endl;
2149 }
2150}
2151
2152void
2154 if( const SPIFilter* p = dynamic_cast<const SPIFilter*>(parent) ) {
2155 // The "correct" thing to do is to combine the filter primitives.
2156 // The next best thing is to keep any filter on this object. If there
2157 // is no filter on this object, then use any filter on the parent.
2158 if( (!set || inherit) && p->href && p->href->getObject() ) { // is the getObject() needed?
2159 set = p->set;
2160 inherit = p->inherit;
2161 if( href ) {
2162 // If we already have an href, use it (unlikely but heck...)
2163 if( href->getObject() ) {
2164 href->detach();
2165 }
2166 } else {
2167 // If we don't have an href, create it
2168 if (style->object) {
2170 } else if (style->document) { // FIXME
2172 //href->changedSignal().connect(sigc::bind(sigc::ptr_fun(sp_style_filter_ref_changed), style));
2173 }
2174 }
2175 if( href ) {
2176 // If we now have an href, try to attach parent filter
2177 try {
2178 href->attach(*p->href->getURI());
2179 } catch (Inkscape::BadURIException &e) {
2180 std::cerr << "SPIFilter::merge: " << e.what() << std::endl;
2181 href->detach();
2182 }
2183 }
2184 }
2185 }
2186}
2187
2188// FIXME
2189bool
2190SPIFilter::equals(const SPIBase& rhs) const {
2191 if( const SPIFilter* r = dynamic_cast<const SPIFilter*>(&rhs) ) {
2192 (void)r;
2193 return true;
2194 } else {
2195 return false;
2196 }
2197}
2198
2199
2200
2201// SPIDashArray ---------------------------------------------------------
2202
2203void
2204SPIDashArray::read( gchar const *str ) {
2205
2206 if( !str ) return;
2207
2208 set = true;
2209
2210 if( strcmp( str, "inherit") == 0 ) {
2211 inherit = true;
2212 return;
2213 }
2214
2215 values.clear();
2216
2217 if( strcmp(str, "none") == 0) {
2218 return;
2219 }
2220
2221 std::vector<Glib::ustring> tokens = Glib::Regex::split_simple("[(,\\s|\\s)]+", str);
2222
2223 bool LineSolid = true;
2224
2225 for (auto token : tokens) {
2226 SPILength spilength;
2227 spilength.read(token.c_str());
2228 if (spilength.value > 0.00000001)
2229 LineSolid = false;
2230 values.push_back(spilength);
2231 }
2232
2233 if (LineSolid) {
2234 values.clear();
2235 }
2236 return;
2237}
2238
2239const Glib::ustring SPIDashArray::get_value() const
2240{
2241 if (this->inherit) return Glib::ustring("inherit");
2242 if (this->values.empty()) return Glib::ustring("none");
2243 auto ret = Glib::ustring("");
2244 for(auto value: this->values) {
2245 if (!ret.empty()) ret += ", ";
2246 ret += value.toString();
2247 }
2248 return ret;
2249}
2250
2251void
2253 if( const SPIDashArray* p = dynamic_cast<const SPIDashArray*>(parent) ) {
2254 if( !set || inherit ) values = p->values; // Always inherits
2255 } else {
2256 std::cerr << "SPIDashArray::cascade(): Incorrect parent type" << std::endl;
2257 }
2258}
2259
2260void
2262 if( const SPIDashArray* p = dynamic_cast<const SPIDashArray*>(parent) ) {
2263 if( inherits ) {
2264 if( (!set || inherit) && p->set && !(p->inherit) ) {
2265 set = p->set;
2266 inherit = p->inherit;
2267 values = p->values;
2268 }
2269 }
2270 } else {
2271 std::cerr << "SPIDashArray::merge(): Incorrect parent type" << std::endl;
2272 }
2273}
2274
2275bool
2277 if (const SPIDashArray *r = dynamic_cast<const SPIDashArray *>(&rhs)) {
2278 if (values.size() != r->values.size()) {
2279 return false;
2280 }
2281 for (int i = 0; i < values.size(); i++) {
2282 if (values[i] != r->values[i]) {
2283 return false;
2284 }
2285 }
2286 }
2287 return SPIBase::equals(rhs);
2288}
2289
2291 // If any value in the list is negative, the <dasharray> value is invalid.
2292 // https://svgwg.org/svg2-draft/painting.html#StrokeDashing
2293
2294 bool invalid = std::any_of(values.begin(), values.end(), [](const SPILength& len){
2295 return len.value < 0 || !std::isfinite(len.value);
2296 });
2297 return !invalid;
2298}
2299
2300// SPIFontSize ----------------------------------------------------------
2301
2303float const SPIFontSize::font_size_table[] = {6.0, 8.0, 10.0, 12.0, 14.0, 18.0, 24.0};
2304float const SPIFontSize::font_size_default = 12.0;
2305
2306void
2307SPIFontSize::read( gchar const *str ) {
2308
2309 if( !str ) return;
2310
2311 if (!strcmp(str, "inherit")) {
2312 set = true;
2313 inherit = true;
2314 } else if ((*str == 'x') || (*str == 's') || (*str == 'm') || (*str == 'l')) {
2315 // xx-small, x-small, etc.
2316 for (unsigned i = 0; enum_font_size[i].key; i++) {
2317 if (!strcmp(str, enum_font_size[i].key)) {
2318 set = true;
2319 inherit = false;
2322 return;
2323 }
2324 }
2325 /* Invalid */
2326 return;
2327 } else {
2328 SPILength length;
2329 length.set = false;
2330 length.read( str );
2331 if( length.set ) {
2332 set = true;
2333 inherit = length.inherit;
2334 unit = length.unit;
2335 value = length.value;
2336 computed = length.computed;
2337 /* Set a minimum font size to something much smaller than should ever (ever!) be encountered in a real file.
2338 If a bad SVG file is encountered and this is zero odd things
2339 might happen because the inverse is used in some scaling actions.
2340 */
2341 if ( computed <= 1.0e-32 ) { computed = 1.0e-32; }
2342 if( unit == SP_CSS_UNIT_PERCENT ) {
2344 } else {
2346 }
2347 }
2348 return;
2349 }
2350}
2351
2352const Glib::ustring SPIFontSize::get_value() const
2353{
2354 if (this->inherit) return Glib::ustring("inherit");
2356 int unit = prefs->getInt("/options/font/unitType", SP_CSS_UNIT_PT);
2357 auto ret = Glib::ustring("");
2358 switch (this->type) {
2360 for (unsigned i = 0; enum_font_size[i].key; i++) {
2361 if (enum_font_size[i].value == static_cast< gint > (this->literal) ) {
2362 if (!ret.empty()) ret += " ";
2363 ret += enum_font_size[i].key;
2364 }
2365 }
2366 break;
2368 if (prefs->getBool("/options/font/textOutputPx", true)) {
2370 }
2373 break;
2375 return Inkscape::ustring::format_classic(this->value * 100.0) + "%";
2376 default:
2377 g_error("Invalid FontSize value, not writing it.");
2378 }
2379 return ret;
2380}
2381
2382void
2384 if( const SPIFontSize* p = dynamic_cast<const SPIFontSize*>(parent) ) {
2385 if( !set || inherit ) { // Always inherits
2386 computed = p->computed;value = p->value;
2387
2388
2389 // Calculate computed based on parent as needed
2390 } else if( type == SP_FONT_SIZE_LITERAL ) {
2393 } else if( literal == SP_CSS_FONT_SIZE_SMALLER ) {
2394 computed = p->computed / 1.2;
2395 } else if( literal == SP_CSS_FONT_SIZE_LARGER ) {
2396 computed = p->computed * 1.2;
2397 } else {
2398 std::cerr << "SPIFontSize::cascade: Illegal literal value" << std::endl;
2399 }
2400 } else if( type == SP_FONT_SIZE_PERCENTAGE ) {
2401 // Percentage for font size is relative to parent computed (rather than viewport)
2402 computed = p->computed * value;
2403 } else if( type == SP_FONT_SIZE_LENGTH ) {
2404 switch ( unit ) {
2405 case SP_CSS_UNIT_EM:
2406 /* Relative to parent font size */
2407 computed = p->computed * value;
2408 break;
2409 case SP_CSS_UNIT_EX:
2410 /* Relative to parent font size */
2411 computed = p->computed * value * 0.5; /* Hack FIXME */
2412 break;
2413 default:
2414 /* No change */
2415 break;
2416 }
2417 }
2418 /* Set a minimum font size to something much smaller than should ever (ever!) be encountered in a real file.
2419 If a bad SVG file is encountered and this is zero odd things
2420 might happen because the inverse is used in some scaling actions.
2421 */
2422 if ( computed <= 1.0e-32 ) { computed = 1.0e-32; }
2423 } else {
2424 std::cerr << "SPIFontSize::cascade(): Incorrect parent type" << std::endl;
2425 }
2426}
2427
2428double
2430
2431 switch (type) {
2432 case SP_FONT_SIZE_LITERAL: {
2433 switch (literal) {
2435 return 5.0 / 6.0;
2436
2438 return 6.0 / 5.0;
2439
2440 default:
2441 g_assert_not_reached();
2442 }
2443 }
2444
2446 return value;
2447
2448 case SP_FONT_SIZE_LENGTH: {
2449 switch (unit ) {
2450 case SP_CSS_UNIT_EM:
2451 return value;
2452
2453 case SP_CSS_UNIT_EX:
2454 return value * 0.5;
2455
2456 default:
2457 g_assert_not_reached();
2458 }
2459 }
2460 }
2461 g_assert_not_reached();
2462 return 1; // Make -Wreturn-type happy
2463}
2464
2465void
2467 if( const SPIFontSize* p = dynamic_cast<const SPIFontSize*>(parent) ) {
2468 if( p->set && !(p->inherit) ) {
2469 // Parent has definined font-size
2470 if( (!set || inherit) ) {
2471 // Computed value same as parent
2472 set = p->set;
2473 inherit = p->inherit;
2474 type = p->type;
2475 unit = p->unit;
2476 literal = p->literal;
2477 value = p->value;
2478 computed = p->computed; // Just to be sure
2479 } else if ( type == SP_FONT_SIZE_LENGTH &&
2480 unit != SP_CSS_UNIT_EM &&
2481 unit != SP_CSS_UNIT_EX ) {
2482 // Absolute size, computed value already set
2483 } else if ( type == SP_FONT_SIZE_LITERAL &&
2485 // Absolute size, computed value already set
2486 //g_assert( literal < G_N_ELEMENTS(font_size_table) );
2487 g_assert( computed == font_size_table[literal] );
2488 } else {
2489 // Relative size
2490 double const child_frac( relative_fraction() );
2491 set = true;
2492 inherit = false;
2493 computed = p->computed * child_frac;
2494
2495 if ( ( p->type == SP_FONT_SIZE_LITERAL &&
2496 p->literal < SP_CSS_FONT_SIZE_SMALLER ) ||
2497 ( p->type == SP_FONT_SIZE_LENGTH &&
2498 p->unit != SP_CSS_UNIT_EM &&
2499 p->unit != SP_CSS_UNIT_EX ) ) {
2500 // Parent absolute size
2502
2503 } else {
2504 // Parent relative size
2505 double const parent_frac( p->relative_fraction() );
2506 if( type == SP_FONT_SIZE_LENGTH ) {
2507 // ex/em
2508 value *= parent_frac;
2509 } else {
2510 value = parent_frac * child_frac;
2512 }
2513 }
2514 } // Relative size
2515 /* Set a minimum font size to something much smaller than should ever (ever!) be encountered in a real file.
2516 If a bad SVG file is encountered and this is zero odd things
2517 might happen because the inverse is used in some scaling actions.
2518 */
2519 if ( computed <= 1.0e-32 ) { computed = 1.0e-32; }
2520 } // Parent set and not inherit
2521 } else {
2522 std::cerr << "SPIFontSize::merge(): Incorrect parent type" << std::endl;
2523 }
2524}
2525
2526// What about different SVG units?
2527bool
2528SPIFontSize::equals(const SPIBase& rhs) const {
2529 if( const SPIFontSize* r = dynamic_cast<const SPIFontSize*>(&rhs) ) {
2530 if( type != r->type ) { return false;}
2531 if( type == SP_FONT_SIZE_LENGTH ) {
2532 if( computed != r->computed ) { return false;}
2533 } else if (type == SP_FONT_SIZE_LITERAL ) {
2534 if( literal != r->literal ) { return false;}
2535 } else {
2536 if( value != r->value ) { return false;}
2537 }
2538 return SPIBase::equals(rhs);
2539 } else {
2540 return false;
2541 }
2542}
2543
2544
2545
2546// SPIFont ----------------------------------------------------------
2547
2548void
2549SPIFont::read( gchar const *str ) {
2550
2551 if( !str ) return;
2552
2553 if( !style ) {
2554 std::cerr << "SPIFont::read(): style is void" << std::endl;
2555 return;
2556 }
2557
2558 if ( !strcmp(str, "inherit") ) {
2559 set = true;
2560 inherit = true;
2561 } else {
2562
2563 // Break string into white space separated tokens
2564 std::stringstream os( str );
2565 Glib::ustring param;
2566
2567 while (os >> param) {
2568
2569 // CSS is case insensitive but we're comparing against lowercase strings
2570 Glib::ustring lparam = param.lowercase();
2571
2572 if (lparam == "/" ) {
2573 // line_height follows... note: font-size already read
2574
2575 os >> param;
2576 lparam = param.lowercase();
2577 style->line_height.readIfUnset( lparam.c_str() );
2578
2579 } else {
2580 // Try to parse each property in turn
2581
2582 decltype(style->font_style) test_style;
2583 test_style.read( lparam.c_str() );
2584 if( test_style.set ) {
2585 style->font_style = test_style;
2586 continue;
2587 }
2588
2589 // font-variant (Note: only CSS2.1 value small-caps is valid in shortcut.)
2590 decltype(style->font_variant) test_variant;
2591 test_variant.read( lparam.c_str() );
2592 if( test_variant.set ) {
2593 style->font_variant = test_variant;
2594 continue;
2595 }
2596
2597 // font-weight
2598 decltype(style->font_weight) test_weight;
2599 test_weight.read( lparam.c_str() );
2600 if( test_weight.set ) {
2601 style->font_weight = test_weight;
2602 continue;
2603 }
2604
2605 // font-stretch (added in CSS 3 Fonts)
2606 decltype(style->font_stretch) test_stretch;
2607 test_stretch.read( lparam.c_str() );
2608 if( test_stretch.set ) {
2609 style->font_stretch = test_stretch;
2610 continue;
2611 }
2612
2613 // font-size
2614 decltype(style->font_size) test_size;
2615 test_size.read( lparam.c_str() );
2616 if( test_size.set ) {
2617 style->font_size = test_size;
2618 continue;
2619 }
2620
2621 // No valid property value found.
2622 break;
2623 }
2624 } // params
2625
2626 // The rest must be font-family...
2627 std::string str_s = str; // Why this extra step?
2628 std::string family = str_s.substr( str_s.find( param ) );
2629
2630 style->font_family.readIfUnset( family.c_str() );
2631
2632 // Everything in shorthand is set per CSS rules, this works since
2633 // properties are read backwards from end to start.
2634 style->font_style.set = true;
2635 style->font_variant.set = true;
2636 style->font_weight.set = true;
2637 style->font_stretch.set = true;
2638 style->font_size.set = true;
2639 style->line_height.set = true;
2640 style->font_family.set = true;
2641 // style->font_size_adjust.set = true;
2642 // style->font_kerning.set = true;
2643 // style->font_language_override.set = true;;
2644 }
2645}
2646
2647const Glib::ustring SPIFont::get_value() const
2648{
2649 if (this->inherit) return Glib::ustring("inherit");
2650 // At the moment, do nothing. We could add a preference to write out
2651 // 'font' shorthand rather than longhand properties.
2652 /* SPIFontSize const *const my_base = dynamic_cast<const SPIFontSize*>(base);
2653 if ( (flags & SP_STYLE_FLAG_ALWAYS) ||
2654 ((flags & SP_STYLE_FLAG_IFSET) && this->set) ||
2655 ((flags & SP_STYLE_FLAG_IFDIFF) && this->set
2656 && (!my_base->set || this != my_base )))
2657 {
2658 }*/
2659
2660 return Glib::ustring("");
2661}
2662
2663// void
2664// SPIFont::cascade( const SPIBase* const parent ) {
2665// }
2666
2667// void
2668// SPIFont::merge( const SPIBase* const parent ) {
2669// }
2670
2671// Does nothing...
2672bool
2673SPIFont::equals(const SPIBase& rhs) const {
2674 if( /* const SPIFont* r = */ dynamic_cast<const SPIFont*>(&rhs) ) {
2675 return SPIBase::equals(rhs);
2676 } else {
2677 return false;
2678 }
2679}
2680
2681
2682
2683// SPIBaselineShift -----------------------------------------------------
2684
2685void
2686SPIBaselineShift::read( gchar const *str ) {
2687
2688 if( !str ) return;
2689
2690 if (!strcmp(str, "inherit")) {
2691 set = true;
2692 inherit = true;
2693 } else if ((*str == 'b') || (*str == 's')) {
2694 // baseline or sub or super
2695 for (unsigned i = 0; enum_baseline_shift[i].key; i++) {
2696 if (!strcmp(str, enum_baseline_shift[i].key)) {
2697 set = true;
2698 inherit = false;
2701 return;
2702 }
2703 }
2704 /* Invalid */
2705 return;
2706 } else {
2707 SPILength length;
2708 length.read( str );
2709 set = length.set;
2710 inherit = length.inherit;
2711 unit = length.unit;
2712 value = length.value;
2713 computed = length.computed;
2714 if( unit == SP_CSS_UNIT_PERCENT ) {
2716 } else {
2718 }
2719 return;
2720 }
2721}
2722
2723const Glib::ustring SPIBaselineShift::get_value() const
2724{
2725 if (this->inherit) return Glib::ustring("inherit");
2726 auto ret = Glib::ustring("");
2727 switch (this->type) {
2729 for (unsigned i = 0; enum_baseline_shift[i].key; i++) {
2730 if (enum_baseline_shift[i].value == static_cast< gint > (this->literal) ) {
2731 if (!ret.empty()) ret += " ";
2732 ret += enum_baseline_shift[i].key;
2733 }
2734 }
2735 break;
2737 if( this->unit == SP_CSS_UNIT_EM || this->unit == SP_CSS_UNIT_EX ) {
2739 ret += (this->unit == SP_CSS_UNIT_EM ? "em" : "ex");
2740 } else {
2741 // must specify px, see inkscape bug 1221626, mozilla bug 234789
2742 ret += Inkscape::ustring::format_classic(this->computed) + "px";
2743 }
2744 break;
2746 return Inkscape::ustring::format_classic(this->value * 100.0) + "%";
2747 }
2748 return ret;
2749}
2750
2751void
2753 if( const SPIBaselineShift* p = dynamic_cast<const SPIBaselineShift*>(parent) ) {
2754 SPIFontSize *pfont_size = &(p->style->font_size);
2755 g_assert( pfont_size != nullptr );
2756
2757 if( !set || inherit ) {
2758 computed = p->computed; // Shift relative to parent shift, corrected below
2759 } else if (type == SP_BASELINE_SHIFT_LITERAL) {
2761 computed = 0; // No change
2762 } else if (literal == SP_CSS_BASELINE_SHIFT_SUB ) {
2763 // Should use subscript position from font relative to alphabetic baseline
2764 // OpenOffice, Adobe: -0.33, Word -0.14, LaTex about -0.2.
2765 computed = -0.2 * pfont_size->computed;
2766 } else if (literal == SP_CSS_BASELINE_SHIFT_SUPER ) {
2767 // Should use superscript position from font relative to alphabetic baseline
2768 // OpenOffice, Adobe: 0.33, Word 0.35, LaTex about 0.45.
2769 computed = 0.4 * pfont_size->computed;
2770 } else {
2771 /* Illegal value */
2772 }
2773 } else if (type == SP_BASELINE_SHIFT_PERCENTAGE) {
2774 // Percentage for baseline shift is relative to computed "line-height"
2775 // which is just font-size (see SVG1.1 'font').
2776 computed = pfont_size->computed * value;
2777 } else if (type == SP_BASELINE_SHIFT_LENGTH) {
2778 switch (unit) {
2779 case SP_CSS_UNIT_EM:
2780 computed = value * pfont_size->computed;
2781 break;
2782 case SP_CSS_UNIT_EX:
2783 computed = value * 0.5 * pfont_size->computed;
2784 break;
2785 default:
2786 /* No change */
2787 break;
2788 }
2789 }
2790 // baseline-shifts are relative to parent baseline
2791 computed += p->computed;
2792
2793 } else {
2794 std::cerr << "SPIBaselineShift::cascade(): Incorrect parent type" << std::endl;
2795 }
2796}
2797
2798// This was not defined in the legacy C code, it needs some serious thinking (but is low priority).
2799// FIX ME
2800void
2802 if( const SPIBaselineShift* p = dynamic_cast<const SPIBaselineShift*>(parent) ) {
2803 if( (!set || inherit) && p->set && !(p->inherit) ) {
2804 set = p->set;
2805 inherit = p->inherit;
2806 value = p->value;
2807 }
2808 } else {
2809 std::cerr << "SPIBaselineShift::merge(): Incorrect parent type" << std::endl;
2810 }
2811}
2812
2813// This is not used but we have it for completeness, it has not been tested.
2814bool
2816 if( const SPIBaselineShift* r = dynamic_cast<const SPIBaselineShift*>(&rhs) ) {
2817 if( type != r->type ) return false;
2819 if( computed != r->computed ) return false;
2820 } else if ( type == SP_BASELINE_SHIFT_LITERAL ) {
2821 if( literal != r->literal ) return false;
2822 } else {
2823 if( value != r->value ) return false;
2824 }
2825 return SPIBase::equals(rhs);
2826 } else {
2827 return false;
2828 }
2829}
2830
2831bool
2834 if( literal == SP_CSS_BASELINE_SHIFT_BASELINE ) return true;
2835 } else {
2836 if( value == 0.0 ) return true;
2837 }
2838 return false;
2839}
2840
2841
2842
2843// SPITextDecorationLine ------------------------------------------------
2844
2845void
2846SPITextDecorationLine::read( gchar const *str ) {
2847
2848 if( !str ) return;
2849
2850 if (!strcmp(str, "inherit")) {
2851 set = true;
2852 inherit = true;
2853 } else if (!strcmp(str, "none")) {
2854 set = true;
2855 inherit = false;
2856 underline = false;
2857 overline = false;
2858 line_through = false;
2859 blink = false;
2860 } else {
2861 bool found_one = false;
2862 bool hit_one = false;
2863
2864 // CSS 2 keywords
2865 bool found_underline = false;
2866 bool found_overline = false;
2867 bool found_line_through = false;
2868 bool found_blink = false;
2869
2870 // This method ignores inlineid keys and extra delimiters, so " ,,, blink hello" will set
2871 // blink and ignore hello
2872 const gchar *hstr = str;
2873 while (true) {
2874 if (*str == ' ' || *str == ',' || *str == '\0'){
2875 int slen = str - hstr;
2876 // CSS 2 keywords
2877 while(true){ // not really a loop, used to avoid a goto
2878 hit_one = true; // most likely we will
2879 if ((slen == 9) && strneq(hstr, "underline", slen)){ found_underline = true; break; }
2880 if ((slen == 8) && strneq(hstr, "overline", slen)){ found_overline = true; break; }
2881 if ((slen == 12) && strneq(hstr, "line-through", slen)){ found_line_through = true; break; }
2882 if ((slen == 5) && strneq(hstr, "blink", slen)){ found_blink = true; break; }
2883 if ((slen == 4) && strneq(hstr, "none", slen)){ break; }
2884
2885 hit_one = false; // whatever this thing is, we do not recognize it
2886 break;
2887 }
2888 found_one |= hit_one;
2889 if(*str == '\0')break;
2890 hstr = str + 1;
2891 }
2892 str++;
2893 }
2894 if (found_one) {
2895 set = true;
2896 inherit = false;
2897 underline = found_underline;
2898 overline = found_overline;
2899 line_through = found_line_through;
2900 blink = found_blink;
2901 }
2902 else {
2903 set = false;
2904 inherit = false;
2905 }
2906 }
2907}
2908
2909const Glib::ustring SPITextDecorationLine::get_value() const
2910{
2911 if (this->inherit) return Glib::ustring("inherit");
2912 auto ret = Glib::ustring("");
2913 if (underline) ret += "underline ";
2914 if (overline) ret += "overline ";
2915 if (line_through) ret += "line-through ";
2916 if (blink) ret += "blink "; // Deprecated
2917 if (ret.empty()) {
2918 ret = "none";
2919 } else {
2920 assert(ret.raw().back() == ' ');
2921 ret.resize(ret.size() - 1);
2922 }
2923 return ret;
2924}
2925
2926void
2928 if( const SPITextDecorationLine* p = dynamic_cast<const SPITextDecorationLine*>(parent) ) {
2929 if( inherits && (!set || inherit) ) {
2930 underline = p->underline;
2931 overline = p->overline;
2932 line_through = p->line_through;
2933 blink = p->blink;
2934 }
2935 } else {
2936 std::cerr << "SPITextDecorationLine::cascade(): Incorrect parent type" << std::endl;
2937 }
2938}
2939
2940void
2942 if( const SPITextDecorationLine* p = dynamic_cast<const SPITextDecorationLine*>(parent) ) {
2943 if( inherits ) { // Always inherits... but special rules?
2944 if( (!set || inherit) && p->set && !(p->inherit) ) {
2945 set = p->set;
2946 inherit = p->inherit;
2947 underline = p->underline;
2948 overline = p->overline;
2949 line_through = p->line_through;
2950 blink = p->blink;
2951 }
2952 }
2953 }
2954}
2955
2956bool
2958 if( const SPITextDecorationLine* r = dynamic_cast<const SPITextDecorationLine*>(&rhs) ) {
2959 return
2960 (underline == r->underline ) &&
2961 (overline == r->overline ) &&
2962 (line_through == r->line_through ) &&
2963 (blink == r->blink ) &&
2964 SPIBase::equals(rhs);
2965 } else {
2966 return false;
2967 }
2968}
2969
2970
2971
2972// SPITextDecorationStyle -----------------------------------------------
2973
2974void
2975SPITextDecorationStyle::read( gchar const *str ) {
2976
2977 if( !str ) return;
2978
2979 set = false;
2980 inherit = false;
2981
2982 solid = true; // Default
2983 isdouble = false;
2984 dotted = false;
2985 dashed = false;
2986 wavy = false;
2987
2988 if (!strcmp(str, "inherit")) {
2989 set = true;
2990 inherit = true;
2991 solid = false;
2992 } else {
2993 // note, these are CSS 3 keywords
2994 bool found_solid = false;
2995 bool found_double = false;
2996 bool found_dotted = false;
2997 bool found_dashed = false;
2998 bool found_wavy = false;
2999 bool found_one = false;
3000
3001 // this method ignores inlineid keys and extra delimiters, so " ,,, style hello" will set style and ignore hello
3002 // if more than one style is present, the first is used
3003 const gchar *hstr = str;
3004 while (true) {
3005 if (*str == ' ' || *str == ',' || *str == '\0'){
3006 int slen = str - hstr;
3007 if ( (slen == 5) && strneq(hstr, "solid", slen)){ found_solid = true; found_one = true; break; }
3008 else if ((slen == 6) && strneq(hstr, "double", slen)){ found_double = true; found_one = true; break; }
3009 else if ((slen == 6) && strneq(hstr, "dotted", slen)){ found_dotted = true; found_one = true; break; }
3010 else if ((slen == 6) && strneq(hstr, "dashed", slen)){ found_dashed = true; found_one = true; break; }
3011 else if ((slen == 4) && strneq(hstr, "wavy", slen)){ found_wavy = true; found_one = true; break; }
3012 if(*str == '\0')break; // nothing more to test
3013 hstr = str + 1;
3014 }
3015 str++;
3016 }
3017 if(found_one){
3018 set = true;
3019 solid = found_solid;
3020 isdouble = found_double;
3021 dotted = found_dotted;
3022 dashed = found_dashed;
3023 wavy = found_wavy;
3024 }
3025 else {
3026 set = false;
3027 inherit = false;
3028 }
3029 }
3030}
3031
3032const Glib::ustring SPITextDecorationStyle::get_value() const
3033{
3034 if (this->inherit) return Glib::ustring("inherit");
3035 if (this->solid) return Glib::ustring("solid");
3036 if (this->isdouble) return Glib::ustring("double");
3037 if (this->dotted) return Glib::ustring("dotted");
3038 if (this->dashed) return Glib::ustring("dashed");
3039 if (this->wavy) return Glib::ustring("wavy");
3040 g_error("SPITextDecorationStyle::write(): No valid value for property");
3041 return Glib::ustring("");
3042}
3043
3044void
3046 if( const SPITextDecorationStyle* p = dynamic_cast<const SPITextDecorationStyle*>(parent) ) {
3047 if( inherits && (!set || inherit) ) {
3048 solid = p->solid;
3049 isdouble = p->isdouble;
3050 dotted = p->dotted;
3051 dashed = p->dashed;
3052 wavy = p->wavy;
3053 }
3054 } else {
3055 std::cerr << "SPITextDecorationStyle::cascade(): Incorrect parent type" << std::endl;
3056 }
3057}
3058
3059void
3061 if( const SPITextDecorationStyle* p = dynamic_cast<const SPITextDecorationStyle*>(parent) ) {
3062 if( inherits ) { // Always inherits... but special rules?
3063 if( (!set || inherit) && p->set && !(p->inherit) ) {
3064 set = p->set;
3065 inherit = p->inherit;
3066 solid = p->solid;
3067 isdouble = p->isdouble;
3068 dotted = p->dotted;
3069 dashed = p->dashed;
3070 wavy = p->wavy;
3071 }
3072 }
3073 }
3074}
3075
3076bool
3078 if( const SPITextDecorationStyle* r = dynamic_cast<const SPITextDecorationStyle*>(&rhs) ) {
3079 return
3080 (solid == r->solid ) &&
3081 (isdouble == r->isdouble ) &&
3082 (dotted == r->dotted ) &&
3083 (dashed == r->dashed ) &&
3084 (wavy == r->wavy ) &&
3085 SPIBase::equals(rhs);
3086 } else {
3087 return false;
3088 }
3089}
3090
3091
3092
3093// TextDecorationColor is handled by SPIPaint (should be SPIColor), default value is "currentColor"
3094// FIXME
3095
3096
3097
3098// SPITextDecoration ----------------------------------------------------
3099
3100void
3101SPITextDecoration::read( gchar const *str ) {
3102
3103 if( !str ) return;
3104
3105 bool is_css3 = false;
3106
3107 decltype(style->text_decoration_line) test_line;
3108 test_line.read( str );
3109 if( test_line.set ) {
3110 if (!style->text_decoration_line.set) {
3111 style->text_decoration_line = test_line;
3112 }
3113 set = true;
3114 }
3115
3116 decltype(style->text_decoration_style) test_style;
3117 test_style.read( str );
3118 if( test_style.set ) {
3119 style->text_decoration_style = test_style;
3120 is_css3 = true;
3121 }
3122
3123 // the color routine must be fed one token at a time - if multiple colors are found the LAST
3124 // one is used ???? then why break on set?
3125
3126 // This could certainly be designed better
3127 decltype(style->text_decoration_color) test_color;
3128 test_color.setStylePointer( style );
3129 test_color.read( "currentColor" ); // Default value
3130 test_color.set = false;
3131 const gchar *hstr = str;
3132 while (true) {
3133 if (*str == ' ' || *str == ',' || *str == '\0'){
3134 int slen = str - hstr;
3135 gchar *frag = g_strndup(hstr,slen+1); // only send one piece at a time, since keywords may be intermixed
3136
3137 if( strcmp( frag, "none" ) != 0 ) { // 'none' not allowed
3138 test_color.read( frag );
3139 }
3140
3141 free(frag);
3142 if( test_color.set ) {
3143 style->text_decoration_color = test_color;
3144 is_css3 = true;
3145 break;
3146 }
3147 test_color.read( "currentColor" ); // Default value
3148 test_color.set = false;
3149 if( *str == '\0' )break;
3150 hstr = str + 1;
3151 }
3152 str++;
3153 }
3154
3155 // If we read a style or color then we have CSS3 which require any non-set values to be
3156 // set to their default values.
3157 if( is_css3 ) {
3158 style->text_decoration_line.set = true;
3159 style->text_decoration_style.set = true;
3160 style->text_decoration_color.set = true;
3161 set = true;
3162 }
3163
3164 // If we set text_decoration_line, then update style_td (for CSS2 text-decoration)
3165 if( style->text_decoration_line.set ) {
3166 style_td = style;
3167 }
3168}
3169
3170// Returns CSS2 'text-decoration' (using settings in SPTextDecorationLine)
3171// This is required until all SVG renderers support CSS3 'text-decoration'
3172const Glib::ustring SPITextDecoration::get_value() const
3173{
3174 if (this->inherit) return Glib::ustring("inherit");
3175 return style->text_decoration_line.get_value();
3176}
3177const Glib::ustring
3178SPITextDecoration::write( guint const flags, SPStyleSrc const &style_src_req, SPIBase const *const base) const {
3179 SPITextDecoration const *const my_base = dynamic_cast<const SPITextDecoration*>(base);
3180 assert(!base || my_base);
3181 // proxy for text-decoration-line, but only if set
3182 if (set && style &&
3183 style->text_decoration_line.shall_write(flags, style_src_req,
3184 my_base ? &my_base->style->text_decoration_line : nullptr)) {
3185 return (name() + ":" + this->get_value() + important_str() + ";");
3186 }
3187 return Glib::ustring("");
3188}
3189
3190void
3192 if( const SPITextDecoration* p = dynamic_cast<const SPITextDecoration*>(parent) ) {
3193 if( style_td == nullptr ) {
3194 style_td = p->style_td;
3195 }
3196 } else {
3197 std::cerr << "SPITextDecoration::cascade(): Incorrect parent type" << std::endl;
3198 }
3199
3200}
3201
3202void
3204 if( const SPITextDecoration* p = dynamic_cast<const SPITextDecoration*>(parent) ) {
3205 if( style_td == nullptr ) {
3206 style_td = p->style_td;
3207 }
3208 } else {
3209 std::cerr << "SPITextDecoration::merge(): Incorrect parent type" << std::endl;
3210 }
3211
3212}
3213
3214// Use CSS2 value
3215bool
3217 if( const SPITextDecoration* r = dynamic_cast<const SPITextDecoration*>(&rhs) ) {
3218 return (style->text_decoration_line == r->style->text_decoration_line &&
3219 SPIBase::equals(rhs));
3220 } else {
3221 return false;
3222 }
3223}
3224
3225// SPIVectorEffect ------------------------------------------------
3226
3227void
3228SPIVectorEffect::read( gchar const *str ) {
3229
3230 if( !str ) return;
3231
3232 if (!strcmp(str, "none")) {
3233 set = true;
3234 stroke = false;
3235 size = false;
3236 rotate = false;
3237 fixed = false;
3238 } else {
3239 bool found_one = false;
3240 bool hit_one = false;
3241
3242 bool found_stroke = false;
3243 bool found_size = false;
3244 bool found_rotate = false;
3245 bool found_fixed = false;
3246
3247 const gchar *hstr = str;
3248 while (true) {
3249 if (*str == ' ' || *str == ',' || *str == '\0'){
3250 int slen = str - hstr;
3251
3252 while(true){ // not really a loop, used to avoid a goto
3253 hit_one = true; // most likely we will
3254 if ((slen == 18) && strneq(hstr, "non-scaling-stroke", slen)){ found_stroke = true; break; }
3255 if ((slen == 16) && strneq(hstr, "non-scaling-size", slen)){ found_size = true; break; }
3256 if ((slen == 12) && strneq(hstr, "non-rotation", slen)){ found_rotate = true; break; }
3257 if ((slen == 14) && strneq(hstr, "fixed-position", slen)){ found_fixed = true; break; }
3258 if ((slen == 4) && strneq(hstr, "none", slen)){ break; }
3259
3260 hit_one = false; // whatever this thing is, we do not recognize it
3261 break;
3262 }
3263 found_one |= hit_one;
3264 if(*str == '\0')break;
3265 hstr = str + 1;
3266 }
3267 str++;
3268 }
3269 if (found_one) {
3270 set = true;
3271 stroke = found_stroke;
3272 size = found_size;
3273 rotate = found_rotate;
3274 fixed = found_fixed;
3275 }
3276 else {
3277 set = false;
3278 }
3279 }
3280
3281 // std::cout << " stroke: " << stroke
3282 // << " size: " << size
3283 // << " rotate: " << rotate
3284 // << " fixed: " << fixed
3285 // << std::endl;
3286}
3287
3288const Glib::ustring SPIVectorEffect::get_value() const
3289{
3290 if (this->inherit) return Glib::ustring("inherit");
3291 auto ret = Glib::ustring("");
3292 if (this->stroke) ret += " non-scaling-stroke";
3293 if (this->size) ret += " non-scaling-size";
3294 if (this->rotate) ret += " non-rotation";
3295 if (this->fixed) ret += " fixed-position";
3296 if (ret.empty()) {
3297 ret += "none";
3298 } else {
3299 ret.erase(0, 1);
3300 }
3301 return ret;
3302}
3303
3304// Does not inherit!
3305// void
3306// SPIVectorEffect::cascade( const SPIBase* const parent ) {
3307// }
3308
3309// void
3310// SPIVectorEffect::merge( const SPIBase* const parent ) {
3311// }
3312
3313bool
3315 if( const SPIVectorEffect* r = dynamic_cast<const SPIVectorEffect*>(&rhs) ) {
3316 return
3317 (stroke == r->stroke) &&
3318 (size == r->size ) &&
3319 (rotate == r->rotate) &&
3320 (fixed == r->fixed ) &&
3321 SPIBase::equals(rhs);
3322 } else {
3323 return false;
3324 }
3325}
3326
3327// SPIStrokeExtensions ------------------------------------------------
3328
3329void
3330SPIStrokeExtensions::read( gchar const *str ) {
3331
3332 if( !str ) return;
3333
3334 set = false;
3335 hairline = false;
3336 if (!strcmp(str, "none")) {
3337 set = true;
3338 } else if (!strcmp(str, "hairline")) {
3339 set = true;
3340 hairline = true;
3341 }
3342}
3343
3344const Glib::ustring SPIStrokeExtensions::get_value() const
3345{
3346 if (this->inherit) return Glib::ustring("inherit");
3347 if (this->hairline) return Glib::ustring("hairline");
3348 return Glib::ustring("none");
3349}
3350
3351// Does not inherit!
3352// void
3353// SPIStrokeExtensions::cascade( const SPIBase* const parent ) {
3354// }
3355
3356// void
3357// SPIStrokeExtensions::merge( const SPIBase* const parent ) {
3358// }
3359
3360bool
3362 if( const SPIStrokeExtensions* r = dynamic_cast<const SPIStrokeExtensions*>(&rhs) ) {
3363 return
3364 (hairline == r->hairline ) &&
3365 SPIBase::equals(rhs);
3366 } else {
3367 return false;
3368 }
3369}
3370
3371// template instantiation
3372template class SPIEnum<SPBlendMode>;
3373template class SPIEnum<SPColorInterpolation>;
3374template class SPIEnum<SPColorRendering>;
3375template class SPIEnum<SPCSSBaseline>;
3376template class SPIEnum<SPCSSDirection>;
3377template class SPIEnum<SPCSSDisplay>;
3379template class SPIEnum<SPCSSTextAlign>;
3380template class SPIEnum<SPCSSTextOrientation>;
3381template class SPIEnum<SPCSSTextTransform>;
3382template class SPIEnum<SPCSSWritingMode>;
3383template class SPIEnum<SPEnableBackground>;
3384template class SPIEnum<SPImageRendering>;
3385template class SPIEnum<SPIsolation>;
3386template class SPIEnum<SPOverflow>;
3387template class SPIEnum<SPShapeRendering>;
3388template class SPIEnum<SPStrokeCapType>;
3389template class SPIEnum<SPStrokeJoinType>;
3390template class SPIEnum<SPTextAnchor>;
3391template class SPIEnum<SPTextRendering>;
3392template class SPIEnum<SPVisibility>;
3393template class SPIEnum<SPWhiteSpace>;
3394template class SPIEnum<SPWindRule>;
3395template class SPIEnum<SPCSSFontStretch>;
3396template class SPIEnum<SPCSSFontStyle>;
3397template class SPIEnum<SPCSSFontVariant>;
3399template class SPIEnum<SPCSSFontVariantCaps>;
3400template class SPIEnum<SPCSSFontWeight>;
3401template class SPIEnum<uint_least16_t>;
3402template class SPIEnum<uint_least8_t>;
3403
3404
3405
3406/* ---------------------------- NOTES ----------------------------- */
3407
3408/*
3409 * opacity's effect is cumulative; we set the new value to the combined effect. The default value
3410 * for opacity is 1.0, not inherit. stop-opacity also does not inherit. (Note that stroke-opacity
3411 * and fill-opacity are quite different from opacity, and don't need any special handling.)
3412 *
3413 * Cases:
3414 * - parent & child were each previously unset, in which case the effective
3415 * opacity value is 1.0, and style should remain unset.
3416 * - parent was previously unset (so computed opacity value of 1.0)
3417 * and child was set to inherit. The merged child should
3418 * get a value of 1.0, and shouldn't inherit (lest the new parent
3419 * has a different opacity value). Given that opacity's default
3420 * value is 1.0 (rather than inherit), we might as well have the
3421 * merged child's opacity be unset.
3422 * - parent was previously unset (so opacity 1.0), and child was set to a number.
3423 * The merged child should retain its existing settings (though it doesn't matter
3424 * if we make it unset if that number was 1.0).
3425 * - parent was inherit and child was unset. Merged child should be set to inherit.
3426 * - parent was inherit and child was inherit. (We can't in general reproduce this
3427 * effect (short of introducing a new group), but setting opacity to inherit is rare.)
3428 * If the inherited value was strictly between 0.0 and 1.0 (exclusive) then the merged
3429 * child's value should be set to the product of the two, i.e. the square of the
3430 * inherited value, and should not be marked as inherit. (This decision assumes that it
3431 * is more important to retain the effective opacity than to retain the inheriting
3432 * effect, and assumes that the inheriting effect either isn't important enough to create
3433 * a group or isn't common enough to bother maintaining the code to create a group.) If
3434 * the inherited value was 0.0 or 1.0, then marking the merged child as inherit comes
3435 * closer to maintaining the effect.
3436 * - parent was inherit and child was set to a numerical value. If the child's value
3437 * was 1.0, then the merged child should have the same settings as the parent.
3438 * If the child's value was 0, then the merged child should also be set to 0.
3439 * If the child's value was anything else, then we do the same as for the inherit/inherit
3440 * case above: have the merged child set to the product of the two opacities and not
3441 * marked as inherit, for the same reasons as for that case.
3442 * - parent was set to a value, and child was unset. The merged child should have
3443 * parent's settings.
3444 * - parent was set to a value, and child was inherit. The merged child should
3445 * be set to the product, i.e. the square of the parent's value.
3446 * - parent & child are each set to a value. The merged child should be set to the
3447 * product.
3448 */
3449
3450
3451/*
3452 Local Variables:
3453 mode:c++
3454 c-file-style:"stroustrup"
3455 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
3456 indent-tabs-mode:nil
3457 fill-column:99
3458 End:
3459*/
3460// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :
gchar const * sp_attribute_name(SPAttr id)
Get attribute name by id.
@ INKSCAPE_FONT_SPEC
@ LINE_HEIGHT
@ SPAttr_SIZE
@ STOP_OPACITY
@ FONT_FAMILY
@ FONT_FEATURE_SETTINGS
TODO: insert short description here.
A thin wrapper around std::ostringstream, but writing floating point numbers in the format required b...
Preference storage class.
Definition preferences.h:66
bool getBool(Glib::ustring const &pref_path, bool def=false)
Retrieve a Boolean value.
static Preferences * get()
Access the singleton Preferences object.
int getInt(Glib::ustring const &pref_path, int def=0)
Retrieve an integer.
URI const * getURI() const
Returns a pointer to a URI containing the currently attached URI, or NULL if no URI is currently atta...
void detach()
Detaches from the currently attached URI target, if any; the current referrent is signaled as NULL.
bool try_attach(char const *uri)
Try to attach to a URI.
sigc::signal< void(SPObject *, SPObject *)> changedSignal()
Accessor for the referrent change notification signal; this signal is emitted whenever the URIReferen...
void attach(URI const &uri)
Attaches to a URI, relative to the specified document.
Represents an URI as per RFC 2396.
Definition uri.h:36
std::string cssStr(char const *baseuri=nullptr) const
Return a CSS formatted url value.
Definition uri.h:176
static double convert(double from_dist, Unit const *from, Unit const *to)
Convert distances.
Definition units.cpp:525
Typed SVG document implementation.
Definition document.h:103
Inkscape::Colors::DocumentCMS & getDocumentCMS()
Definition document.h:167
SPFilter * getObject() const
Virtual base class for all SPStyle internal classes.
virtual const Glib::ustring write(guint const flags=SP_STYLE_FLAG_IFSET, SPStyleSrc const &style_src_req=SPStyleSrc::STYLE_PROP, SPIBase const *const base=nullptr) const
Compile this style conditionally into a 'name: value' string suitable for css attrs.
Glib::ustring const & name() const
SPIBase & operator=(const SPIBase &rhs)=default
char const * important_str() const
virtual bool equals(const SPIBase &rhs) const
SPStyleSrc style_src
SPStyle * style
virtual void read(gchar const *str)=0
void readIfUnset(gchar const *str, SPStyleSrc source=SPStyleSrc::STYLE_PROP)
bool shall_write(guint const flags=SP_STYLE_FLAG_IFSET, SPStyleSrc const &style_src_req=SPStyleSrc::STYLE_PROP, SPIBase const *const base=nullptr) const
Check if this property should be written.
virtual const Glib::ustring get_value() const =0
virtual void clear()
Baseline shift type internal to SPStyle. (This is actually just like SPIFontSize)
void cascade(const SPIBase *const parent) override
const Glib::ustring get_value() const override
bool equals(const SPIBase &rhs) const override
void merge(const SPIBase *const parent) override
void read(gchar const *str) override
std::optional< Colors::Color > _color
Colors::DocumentCMS const & getCMS() const
SPIColor(bool inherits=true)
void setColor(Colors::Color const &other)
void read(gchar const *str) override
Colors::Color const & getColor() const
void cascade(const SPIBase *const parent) override
SPIColor & operator=(const SPIColor &rhs)
void merge(const SPIBase *const parent) override
bool canHaveCMS() const
const Glib::ustring get_value() const override
bool currentcolor
bool equals(const SPIBase &rhs) const override
Filter type internal to SPStyle.
const Glib::ustring get_value() const override
bool equals(const SPIBase &rhs) const override
bool is_valid() const
std::vector< SPILength > values
void cascade(const SPIBase *const parent) override
void merge(const SPIBase *const parent) override
void read(gchar const *str) override
void read(gchar const *str) override
const Glib::ustring get_value() const override
void read(gchar const *str) override
const Glib::ustring get_value() const override
Enum type internal to SPStyle.
void update_computed()
Update computed from value.
void merge(const SPIBase *const parent) override
void cascade(const SPIBase *const parent) override
const Glib::ustring get_value() const override
bool equals(const SPIBase &rhs) const override
void update_computed_cascade(T const &parent_computed)
Update computed from parent computed.
void read(gchar const *str) override
void update_value_merge(SPIEnum< T > const &)
Update value from parent.
Filter type internal to SPStyle.
void cascade(const SPIBase *const parent) override
void merge(const SPIBase *const parent) override
const Glib::ustring get_value() const override
void read(gchar const *str) override
SPFilterReference * href
~SPIFilter() override
void clear() override
bool equals(const SPIBase &rhs) const override
Float type internal to SPStyle. (Only 'stroke-miterlimit')
void read(gchar const *str) override
const Glib::ustring get_value() const override
void merge(const SPIBase *const parent) override
bool equals(const SPIBase &rhs) const override
void cascade(const SPIBase *const parent) override
Fontsize type internal to SPStyle (also used by libnrtype/Layout-TNG-Input.cpp).
unsigned literal
void cascade(const SPIBase *const parent) override
void read(gchar const *str) override
double relative_fraction() const
static float const font_size_default
bool equals(const SPIBase &rhs) const override
const Glib::ustring get_value() const override
static float const font_size_table[]
Indexed by SP_CSS_FONT_SIZE_blah.
void merge(const SPIBase *const parent) override
Extended length type internal to SPStyle.
void read(gchar const *str) override
bool equals(const SPIBase &rhs) const override
virtual const Glib::ustring toString() const
void merge(const SPIBase *const parent) override
const Glib::ustring get_value() const override
void cascade(const SPIBase *const parent) override
std::map< Glib::ustring, float > axes
Font type internal to SPStyle ('font' shorthand)
void read(gchar const *str) override
const Glib::ustring get_value() const override
bool equals(const SPIBase &rhs) const override
Extended length type internal to SPStyle.
void cascade(const SPIBase *const parent) override
bool equals(const SPIBase &rhs) const override
void read(gchar const *str) override
const Glib::ustring get_value() const override
void merge(const SPIBase *const parent) override
Length type internal to SPStyle.
void cascade(const SPIBase *const parent) override
float value_default
const Glib::ustring get_value() const override
void setDouble(double v)
void read(gchar const *str) override
unsigned unit
virtual const Glib::ustring toString(bool wname=false) const
void merge(const SPIBase *const parent) override
bool equals(const SPIBase &rhs) const override
void read(gchar const *str) override
const Glib::ustring get_value() const override
void read(gchar const *str) override
const Glib::ustring get_value() const override
Paint order type internal to SPStyle.
unsigned get_order(SPPaintOrderLayer paint_order) const
Return the index of the given paint order.
void read(gchar const *str) override
void cascade(const SPIBase *const parent) override
std::array< SPPaintOrderLayer, PAINT_ORDER_LAYERS > get_layers() const
Get the actual layer order, converting "normal" to layers.
bool layer_set[PAINT_ORDER_LAYERS]
bool equals(const SPIBase &rhs) const override
const Glib::ustring get_value() const override
SPPaintOrderLayer layer[PAINT_ORDER_LAYERS]
void merge(const SPIBase *const parent) override
Paint type internal to SPStyle.
bool equals(const SPIBase &rhs) const override
void merge(const SPIBase *const parent) override
SPObject * tag
bool isPaintserver() const
const Glib::ustring get_value() const override
void clear() override
std::optional< Colors::Color > _color
bool isColor() const
void cascade(const SPIBase *const parent) override
bool isNone() const
bool canHaveCMS() const
virtual void reset(bool init)
std::shared_ptr< SPPaintServerReference > href
Colors::DocumentCMS const & getCMS() const
SPPaintOrigin paintSource
SPPaintOrigin paintOrigin
void read(gchar const *str) override
Set SPIPaint object from string.
void setColor(Colors::Color const &other)
Colors::Color const & getColor() const
24 bit data type internal to SPStyle.
const Glib::ustring get_value() const override
void read(gchar const *str) override
unsigned value
bool equals(const SPIBase &rhs) const override
void merge(const SPIBase *const parent) override
void cascade(const SPIBase *const parent) override
bool containsAnyShape(Inkscape::ObjectSet *set)
Check if a Shape object exists in the selection Needed for when user selects multiple objects and.
std::vector< SPShapeReference * > hrefs
~SPIShapes() override
void clear() override
void read(gchar const *str) override
String type internal to SPStyle.
char const * get_default_value() const
const Glib::ustring get_value() const override
Value as it should be written to CSS representation, including quotes if needed.
gchar * _value
void clear() override
void merge(const SPIBase *const parent) override
void read(gchar const *str) override
bool equals(const SPIBase &rhs) const override
void cascade(const SPIBase *const parent) override
char const * value() const
Get value if set, or inherited value, or default value (may be NULL)
Custom stroke properties. Only used for -inkscape-stroke: hairline.
const Glib::ustring get_value() const override
void read(gchar const *str) override
bool equals(const SPIBase &rhs) const override
Text decoration line type internal to SPStyle. THIS SHOULD BE A GENERIC CLASS.
void read(gchar const *str) override
void cascade(const SPIBase *const parent) override
const Glib::ustring get_value() const override
void merge(const SPIBase *const parent) override
bool equals(const SPIBase &rhs) const override
Text decoration style type internal to SPStyle. THIS SHOULD JUST BE SPIEnum!
void cascade(const SPIBase *const parent) override
const Glib::ustring get_value() const override
bool equals(const SPIBase &rhs) const override
void merge(const SPIBase *const parent) override
void read(gchar const *str) override
Text decoration type internal to SPStyle.
void cascade(const SPIBase *const parent) override
const Glib::ustring write(guint const flags=SP_STYLE_FLAG_IFSET, SPStyleSrc const &style_src_req=SPStyleSrc::STYLE_PROP, SPIBase const *const base=nullptr) const override
Compile this style conditionally into a 'name: value' string suitable for css attrs.
void read(gchar const *str) override
bool equals(const SPIBase &rhs) const override
const Glib::ustring get_value() const override
void merge(const SPIBase *const parent) override
Vector Effects. THIS SHOULD BE A GENERIC CLASS.
const Glib::ustring get_value() const override
bool equals(const SPIBase &rhs) const override
void read(gchar const *str) override
SPObject is an abstract base class of all of the document nodes at the SVG document level.
Definition sp-object.h:160
SPDocument * document
Definition sp-object.h:188
An SVG style object.
Definition style.h:45
T< SPAttr::TEXT_DECORATION_LINE, SPITextDecorationLine > text_decoration_line
CSS 3 2.1, 2.2, 2.3.
Definition style.h:191
T< SPAttr::COLOR, SPIColor > color
color
Definition style.h:225
T< SPAttr::FONT_WEIGHT, SPIEnum< SPCSSFontWeight > > font_weight
Weight of the font.
Definition style.h:112
T< SPAttr::TEXT_DECORATION_STYLE, SPITextDecorationStyle > text_decoration_style
Definition style.h:192
sigc::connection fill_ps_changed_connection
Definition style.h:312
T< SPAttr::FILL, SPIPaint > fill
fill
Definition style.h:240
T< SPAttr::LINE_HEIGHT, SPILengthOrNormal > line_height
Line height (css2 10.8.1)
Definition style.h:118
SPObject * object
Object we are attached to.
Definition style.h:84
T< SPAttr::FONT_FAMILY, SPIString > font_family
Font family.
Definition style.h:120
T< SPAttr::TEXT_DECORATION_COLOR, SPIColor > text_decoration_color
Definition style.h:193
T< SPAttr::FONT_STYLE, SPIEnum< SPCSSFontStyle > > font_style
Font style.
Definition style.h:108
T< SPAttr::FONT_VARIANT, SPIEnum< SPCSSFontVariant > > font_variant
Which substyle of the font (CSS 2.
Definition style.h:110
T< SPAttr::FONT_STRETCH, SPIEnum< SPCSSFontStretch > > font_stretch
Stretch of the font.
Definition style.h:114
sigc::connection filter_changed_connection
Definition style.h:311
sigc::connection stroke_ps_changed_connection
Definition style.h:313
T< SPAttr::FONT_SIZE, SPIFontSize > font_size
Size of the font.
Definition style.h:116
SPDocument * document
Document we are associated with.
Definition style.h:86
TODO: insert short description here.
double c[8][4]
static char const *const parent
Definition dir-util.cpp:70
std::string extract_uri(char const *s, char const **endptr)
Parse functional URI notation, as per 4.3.4 of CSS 2.1.
TODO: insert short description here.
Geom::Point end
Glib::ustring format_classic(T const &... args)
static cairo_user_data_key_t key
bool used
Singleton class to access the preferences file in a convenient way.
unsigned long weight
Definition quantize.cpp:37
Ocnode ** ref
Definition quantize.cpp:32
auto len
Definition safe-printf.h:21
size_t N
static Inkscape::Colors::Color default_color(SPItem *item)
Find default color based on colors in existing fill.
TODO: insert short description here.
bool streq(char const *a, char const *b)
Convenience/readability wrapper for strcmp(a,b)==0.
Definition streq.h:17
TODO: insert short description here.
bool strneq(char const *a, char const *b, size_t n)
Convenience/readability wrapper for strncmp(a,b,n)==0.
Definition strneq.h:17
char const * key
SPStyle enums: named public enums that correspond to SVG property values.
static SPStyleEnum const enum_writing_mode[]
static SPStyleEnum const enum_baseline_shift[]
static SPStyleEnum const enum_font_variant_position[]
static SPStyleEnum const enum_font_variant_east_asian[]
static SPStyleEnum const enum_font_size[]
static SPStyleEnum const enum_direction[]
@ SP_CSS_FONT_VARIANT_LIGATURES_NORMAL
@ SP_CSS_FONT_VARIANT_LIGATURES_CONTEXTUAL
@ SP_CSS_FONT_VARIANT_LIGATURES_DISCRETIONARY
@ SP_CSS_FONT_VARIANT_LIGATURES_HISTORICAL
@ SP_CSS_FONT_VARIANT_LIGATURES_COMMON
@ SP_CSS_FONT_VARIANT_LIGATURES_NONE
@ SP_CSS_FONT_VARIANT_LIGATURES_NOCOMMON
@ SP_CSS_BASELINE_SHIFT_BASELINE
@ SP_CSS_BASELINE_SHIFT_SUPER
@ SP_CSS_BASELINE_SHIFT_SUB
@ SP_CSS_FONT_SIZE_SMALLER
Definition style-enums.h:56
@ SP_CSS_FONT_SIZE_LARGER
Definition style-enums.h:57
static SPStyleEnum const enum_overflow[]
static SPStyleEnum const enum_shape_rendering[]
@ SP_CSS_FONT_VARIANT_NUMERIC_TABULAR_NUMS
@ SP_CSS_FONT_VARIANT_NUMERIC_NORMAL
@ SP_CSS_FONT_VARIANT_NUMERIC_STACKED_FRACTIONS
@ SP_CSS_FONT_VARIANT_NUMERIC_OLDSTYLE_NUMS
@ SP_CSS_FONT_VARIANT_NUMERIC_SLASHED_ZERO
@ SP_CSS_FONT_VARIANT_NUMERIC_DIAGONAL_FRACTIONS
@ SP_CSS_FONT_VARIANT_NUMERIC_PROPORTIONAL_NUMS
@ SP_CSS_FONT_VARIANT_NUMERIC_ORDINAL
@ SP_CSS_FONT_VARIANT_NUMERIC_LINING_NUMS
static SPStyleEnum const enum_color_rendering[]
static SPStyleEnum const enum_visibility[]
static SPStyleEnum const enum_stroke_linecap[]
static SPStyleEnum const enum_image_rendering[]
static SPStyleEnum const enum_font_variant_alternates[]
static SPStyleEnum const enum_white_space[]
static SPStyleEnum const enum_display[]
static SPStyleEnum const enum_stroke_linejoin[]
static SPStyleEnum const enum_clip_rule[]
static SPStyleEnum const enum_font_variant_ligatures[]
static SPStyleEnum const enum_blend_mode[]
static SPStyleEnum const enum_isolation[]
SPCSSFontStretch
Definition style-enums.h:87
@ SP_CSS_FONT_STRETCH_ULTRA_EXPANDED
Definition style-enums.h:96
@ SP_CSS_FONT_STRETCH_NARROWER
Definition style-enums.h:97
@ SP_CSS_FONT_STRETCH_WIDER
Definition style-enums.h:98
@ SP_CSS_FONT_STRETCH_ULTRA_CONDENSED
Definition style-enums.h:88
static SPStyleEnum const enum_baseline[]
static SPStyleEnum const enum_text_align[]
static SPStyleEnum const enum_enable_background[]
static SPStyleEnum const enum_font_variant_caps[]
@ SP_CSS_FONT_VARIANT_EAST_ASIAN_RUBY
@ SP_CSS_FONT_VARIANT_EAST_ASIAN_JIS04
@ SP_CSS_FONT_VARIANT_EAST_ASIAN_PROPORTIONAL_WIDTH
@ SP_CSS_FONT_VARIANT_EAST_ASIAN_JIS78
@ SP_CSS_FONT_VARIANT_EAST_ASIAN_JIS90
@ SP_CSS_FONT_VARIANT_EAST_ASIAN_TRADITIONAL
@ SP_CSS_FONT_VARIANT_EAST_ASIAN_NORMAL
@ SP_CSS_FONT_VARIANT_EAST_ASIAN_FULL_WIDTH
@ SP_CSS_FONT_VARIANT_EAST_ASIAN_JIS83
@ SP_CSS_FONT_VARIANT_EAST_ASIAN_SIMPLIFIED
static SPStyleEnum const enum_font_style[]
static SPStyleEnum const enum_font_variant_numeric[]
static SPStyleEnum const enum_text_rendering[]
static SPStyleEnum const enum_font_weight[]
static SPStyleEnum const enum_text_orientation[]
static SPStyleEnum const enum_color_interpolation[]
static SPStyleEnum const enum_font_stretch[]
static SPStyleEnum const enum_text_anchor[]
static SPStyleEnum const enum_text_transform[]
SPCSSFontWeight
Definition style-enums.h:71
@ SP_CSS_FONT_WEIGHT_LIGHTER
Definition style-enums.h:83
@ SP_CSS_FONT_WEIGHT_NORMAL
Definition style-enums.h:81
@ SP_CSS_FONT_WEIGHT_BOLD
Definition style-enums.h:82
@ SP_CSS_FONT_WEIGHT_400
Definition style-enums.h:75
@ SP_CSS_FONT_WEIGHT_100
Definition style-enums.h:72
@ SP_CSS_FONT_WEIGHT_900
Definition style-enums.h:80
@ SP_CSS_FONT_WEIGHT_700
Definition style-enums.h:78
@ SP_CSS_FONT_WEIGHT_BOLDER
Definition style-enums.h:84
static SPStyleEnum const enum_font_variant[]
SPStyleEnum const * get_enums< SPIsolation >()
SPStyleEnum const * get_enums< SPOverflow >()
void sp_style_filter_ref_changed(SPObject *old_ref, SPObject *ref, SPStyle *style)
Gets called when the filter is (re)attached to the style.
Definition style.cpp:1147
SPStyleEnum const * get_enums< SPCSSDirection >()
void sp_style_set_ipaint_to_uri_string(SPStyle *style, SPIPaint *paint, const gchar *uri)
Definition style.cpp:1287
SPStyleEnum const * get_enums< SPCSSFontStretch >()
SPStyleEnum const * get_enums< SPImageRendering >()
SPStyleEnum const * get_enums< SPCSSFontVariantPosition >()
SPStyleEnum const * get_enums< SPStrokeCapType >()
SPStyleEnum const * get_enums< SPCSSFontVariantCaps >()
SPStyleEnum const * get_enums< SPStrokeJoinType >()
SPStyleEnum const * get_enums< SPVisibility >()
SPStyleEnum const * get_enums< SPBlendMode >()
SPStyleEnum const * get_enums< SPCSSBaseline >()
SPStyleEnum const * get_enums< SPCSSDisplay >()
void sp_style_fill_paint_server_ref_changed(SPObject *old_ref, SPObject *ref, SPStyle *style)
Gets called when the paintserver is (re)attached to the style.
Definition style.cpp:1193
SPStyleEnum const * get_enums< SPCSSFontVariant >()
SPStyleEnum const * get_enums< SPCSSTextOrientation >()
SPStyleEnum const * get_enums< SPCSSFontStyle >()
SPStyleEnum const * get_enums< SPCSSFontVariantAlternates >()
SPStyleEnum const * get_enums< SPCSSTextAlign >()
SPStyleEnum const * get_enums< SPCSSTextTransform >()
void sp_style_stroke_paint_server_ref_changed(SPObject *old_ref, SPObject *ref, SPStyle *style)
Gets called when the paintserver is (re)attached to the style.
Definition style.cpp:1210
static SPStyleEnum const * get_enums()
SPStyleEnum const * get_enums< SPShapeRendering >()
SPStyleEnum const * get_enums< SPWindRule >()
SPStyleEnum const * get_enums< SPEnableBackground >()
SPStyleEnum const * get_enums< SPTextRendering >()
SPStyleEnum const * get_enums< SPCSSWritingMode >()
SPStyleEnum const * get_enums< SPTextAnchor >()
void sp_style_set_ipaint_to_uri(SPStyle *style, SPIPaint *paint, const Inkscape::URI *uri, SPDocument *document)
Definition style.cpp:1249
SPStyleEnum const * get_enums< SPColorRendering >()
SPStyleEnum const * get_enums< SPCSSFontWeight >()
static bool strip_important(gchar const *str, std::string &stripped)
If str.endswith("!important") then assign stripped = str[:-10].rstrip() and return true.
SPStyleEnum const * get_enums< SPColorInterpolation >()
SPStyleEnum const * get_enums< SPWhiteSpace >()
SPStyle internal: classes that are internal to SPStyle.
SPStyleSrc
@ SP_FONT_SIZE_LITERAL
@ SP_FONT_SIZE_LENGTH
@ SP_FONT_SIZE_PERCENTAGE
constexpr size_t PAINT_ORDER_LAYERS
@ SP_CSS_PAINT_ORIGIN_CONTEXT_STROKE
@ SP_CSS_PAINT_ORIGIN_CURRENT_COLOR
@ SP_CSS_PAINT_ORIGIN_NORMAL
@ SP_CSS_PAINT_ORIGIN_CONTEXT_FILL
static const unsigned SP_SCALE24_MAX
SPPaintOrderLayer
@ SP_CSS_PAINT_ORDER_STROKE
@ SP_CSS_PAINT_ORDER_MARKER
@ SP_CSS_PAINT_ORDER_FILL
@ SP_CSS_PAINT_ORDER_NORMAL
@ SP_BASELINE_SHIFT_PERCENTAGE
@ SP_BASELINE_SHIFT_LENGTH
@ SP_BASELINE_SHIFT_LITERAL
static const unsigned SP_STYLE_FLAG_ALWAYS(1<< 2)
static const unsigned SP_STYLE_FLAG_IFSRC(1<< 3)
@ SP_CSS_UNIT_IN
@ SP_CSS_UNIT_PT
@ SP_CSS_UNIT_PX
@ SP_CSS_UNIT_PC
@ SP_CSS_UNIT_MM
@ SP_CSS_UNIT_PERCENT
@ SP_CSS_UNIT_NONE
@ SP_CSS_UNIT_EM
@ SP_CSS_UNIT_CM
@ SP_CSS_UNIT_EX
void css_font_family_unquote(Glib::ustring &val)
Remove paired single and double quotes from font names in font-family lists, changing string in place...
Definition style.cpp:1724
void css_quote(Glib::ustring &val)
Quote and/or escape string for writing to CSS, changing strings in place.
Definition style.cpp:1648
double sp_style_css_size_px_to_units(double size, int unit, double font_size)
Definition style.cpp:1332
void css_unquote(Glib::ustring &val)
Remove paired single and double quotes from a string, changing string in place.
Definition style.cpp:1706
void css_font_family_quote(Glib::ustring &val)
Quote font names in font-family lists, changing string in place.
Definition style.cpp:1687
gchar const * sp_style_get_css_unit_string(int unit)
Definition style.cpp:1305
SPStyle - a style object for SPItem objects.
unsigned int sp_svg_number_read_f(gchar const *str, float *val)
void init(int argc, char **argv, Toy *t, int width=600, int height=600)