1 // SPDX-License-Identifier: GPL-2.0-or-later
2 #ifndef SEEN_SP_STYLE_INTERNAL_H
3 #define SEEN_SP_STYLE_INTERNAL_H
4 
5 /** \file
6  * SPStyle internal: classes that are internal to SPStyle
7  */
8 /* Authors:
9  *   Lauris Kaplinski <lauris@kaplinski.com>
10  *   Jon A. Cruz <jon@joncruz.org>
11  *   Tavmjong Bah <tavmjong@free.fr>
12  *
13  * Copyright (C) 2014, 2018 Tavmjong Bah
14  * Copyright (C) 2010 Jon A. Cruz
15  * Copyright (C) 2001-2002 Lauris Kaplinski
16  * Copyright (C) 2001 Ximian, Inc.
17  *
18  * Released under GNU GPL v2+, read the file 'COPYING' for more information.
19  */
20 
21 #include <utility>
22 #include <vector>
23 #include <map>
24 
25 #include "attributes.h"
26 #include "style-enums.h"
27 
28 #include "color.h"
29 
30 #include "object/sp-marker-loc.h"
31 #include "object/sp-filter.h"
32 #include "object/sp-filter-reference.h"
33 #include "object/sp-paint-server-reference.h"
34 #include "object/sp-shape-reference.h"
35 
36 #include "object/uri.h"
37 
38 #include "svg/svg-icc-color.h"
39 
40 #include "xml/repr.h"
41 
42 
43 static const unsigned SP_STYLE_FLAG_ALWAYS (1 << 2);
44 static const unsigned SP_STYLE_FLAG_IFSET  (1 << 0);
45 static const unsigned SP_STYLE_FLAG_IFDIFF (1 << 1);
46 static const unsigned SP_STYLE_FLAG_IFSRC  (1 << 3); // If source matches
47 
48 // for the bitfield in SPStyle::style_src this must be an unsigned type
49 enum class SPStyleSrc : unsigned
50 {
51     UNSET,
52     ATTRIBUTE,   // fill="red"
53     STYLE_PROP,  // style="fill:red"
54     STYLE_SHEET, // .red { fill:red; }
55 };
56 
57 /* General comments:
58  *
59  * This code is derived from the original C style code in style.cpp.
60  *
61  * Overview:
62  *   Style can be obtained (in order of precedence) [CHECK]
63  *     1. "style" property in an element (style="fill:red").
64  *     2. Style sheet, internal or external (<style> rect {fill:red;}</style>).
65  *     3. Attributes in an element (fill="red").
66  *     4. Parent's style.
67  *   A later property overrides an earlier property. This is implemented by
68  *   reading in the properties backwards. If a property is already set, it
69  *   prevents an earlier property from being read.
70  *
71  *   A declaration with an "!important" rule overrides any other declarations (except those that
72  *   also have an "!important" rule). Attributes can not use the "!important" rule and the rule
73  *   is not inherited.
74  *
75  *   In order for cascading to work, each element in the tree must be read in from top to bottom
76  *   (parent before child). At each step, if a style property is not explicitly set, the property
77  *   value is taken from the parent. Some properties have "computed" values that depend on:
78  *      the parent's value (e.g. "font-size:larger"),
79  *      another property value ("stroke-width":1em"), or
80  *      an external value ("stroke-width:5%").
81  *
82  * To summarize:
83  *
84  *   An explicitly set value (including 'inherit') has a 'true' "set" flag.
85  *   The "value" is either explicitly set or inherited.
86  *   The "computed" value (if present) is calculated from "value" and some other input.
87  *
88  * Functions:
89  *   write():    Write a property and its value to a string.
90  *     Flags:
91  *       ALWAYS: Always write out property.
92  *       IFSET:  Write a property if 'set' flag is true, otherwise return empty string.
93  *       IFDIFF: Write a property if computed values are different, otherwise return empty string,
94  *               This is only used for text!!
95  *       IFSRC   Write a property if the source matches the requested source (style sheet, etc.).
96  *
97  *   read():     Set a property value from a string.
98  *   clear():    Set a property to its default value and set the 'set' flag to false.
99  *   cascade():  Cascade the parent's property values to the child if the child's property
100  *               is unset (and it allows inheriting) or the value is 'inherit'.
101  *               Calculate computed values that depend on parent.
102  *               This requires that the parent already be updated.
103  *   merge():    Merge the property values of a child and a parent that is being deleted,
104  *               attempting to preserve the style of the child.
105  *   operator=:  Assignment operator required due to use of templates (in original C code).
106  *   operator==: True if computed values are equal.  TO DO: DEFINE EXACTLY WHAT THIS MEANS
107  *   operator!=: Inverse of operator==.
108  *
109  *
110  * Outside dependencies:
111  *
112  *   The C structures that these classes are evolved from were designed to be embedded in to the
113  *   style structure (i.e they are "internal" and thus have an "I" in the SPI prefix). However,
114  *   they should be reasonably stand-alone and can provide some functionality outside of the style
115  *   structure (i.e. reading and writing style strings). Some properties do need access to other
116  *   properties from the same object (e.g. SPILength sometimes needs to know font size) to
117  *   calculate 'computed' values. Inheritance, of course, requires access to the parent object's
118  *   style class.
119  *
120  *   The only real outside dependency is SPObject... which is needed in the cases of SPIPaint and
121  *   SPIFilter for setting up the "href". (Currently, SPDocument is needed but this dependency
122  *   should be removed as an "href" only needs the SPDocument for attaching an external document to
123  *   the XML tree [see uri-references.cpp]. If SPDocument is really needed, it can be obtained from
124  *   SPObject.)
125  *
126  */
127 
128 /// Virtual base class for all SPStyle internal classes
129 class SPIBase
130 {
131 
132 public:
133     SPIBase(bool inherits_ = true)
inherits(inherits_)134         : inherits(inherits_),
135           set(false),
136           inherit(false),
137           important(false),
138           style_src(SPStyleSrc::STYLE_PROP), // Default to property, see bug 1662285.
139           style(nullptr)
140     {}
141 
142     virtual ~SPIBase()
143     = default;
144 
145     virtual void read( gchar const *str ) = 0;
146     void readIfUnset(gchar const *str, SPStyleSrc source = SPStyleSrc::STYLE_PROP);
147 
148 protected:
important_str()149     char const *important_str() const { return important ? " !important" : ""; }
150 
151 public:
readAttribute(Inkscape::XML::Node * repr)152     void readAttribute(Inkscape::XML::Node *repr)
153     {
154         readIfUnset(repr->attribute(name().c_str()), SPStyleSrc::ATTRIBUTE);
155     }
156 
157     virtual const Glib::ustring get_value() const = 0;
158     bool shall_write( guint const flags = SP_STYLE_FLAG_IFSET,
159                       SPStyleSrc const &style_src_req = SPStyleSrc::STYLE_PROP,
160                       SPIBase const *const base = nullptr ) const;
161     virtual const Glib::ustring write( guint const flags = SP_STYLE_FLAG_IFSET,
162                                        SPStyleSrc const &style_src_req = SPStyleSrc::STYLE_PROP,
163                                        SPIBase const *const base = nullptr ) const;
clear()164     virtual void clear() {
165         set = false, inherit = false, important = false;
166         // Attr::D is a special case where the best default for it is actually ATTRIBUTE
167         // and not STYLE_PROP, this exception allows us to not have to refactor more.
168         if (id() != SPAttr::D) {
169             style_src = SPStyleSrc::STYLE_PROP;
170         }
171     }
172 
173     virtual void cascade( const SPIBase* const parent ) = 0;
174     virtual void merge(   const SPIBase* const parent ) = 0;
175 
setStylePointer(SPStyle * style_in)176     void setStylePointer(SPStyle *style_in) { style = style_in; }
177 
178     // Explicit assignment operator required due to templates.
179     SPIBase& operator=(const SPIBase& rhs) = default;
180 
181     // Check apples being compared to apples
182     virtual bool operator==(const SPIBase& rhs) const {
183         return id() == rhs.id();
184     }
185 
186     bool operator!=(const SPIBase& rhs) const {
187         return !(*this == rhs);
188     }
189 
id()190     virtual SPAttr id() const { return SPAttr::INVALID; }
191     Glib::ustring const &name() const;
192 
193   // To do: make private
194 public:
195     bool inherits : 1;    // Property inherits by default from parent.
196     bool set : 1;         // Property has been explicitly set (vs. inherited).
197     bool inherit : 1;     // Property value set to 'inherit'.
198     bool important : 1;   // Property rule 'important' has been explicitly set.
199     SPStyleSrc style_src : 2; // Source (attribute, style attribute, style-sheet).
200 
201 protected:
202     SPStyle* style;       // Used by SPIPaint, SPIFilter... to find values of other properties
203 };
204 
205 
206 /**
207  * Decorator which overrides SPIBase::id()
208  */
209 template <SPAttr Id, class Base>
210 class TypedSPI : public Base {
211   public:
212     using Base::Base;
213 
214     /**
215      * Get the attribute enum
216      */
id()217     SPAttr id() const override { return Id; }
static_id()218     static SPAttr static_id() { return Id; }
219 
220     /**
221      * Upcast to the base class
222      */
upcast()223     Base *upcast() { return static_cast<Base *>(this); }
upcast()224     Base const *upcast() const { return static_cast<Base const *>(this); }
225 };
226 
227 
228 /// Float type internal to SPStyle. (Only 'stroke-miterlimit')
229 class SPIFloat : public SPIBase
230 {
231 
232 public:
233     SPIFloat(float value_default = 0.0 )
value(value_default)234         : value(value_default),
235           value_default(value_default)
236     {}
237 
238     ~SPIFloat() override = default;
239     void read( gchar const *str ) override;
240     const Glib::ustring get_value() const override;
clear()241     void clear() override {
242         SPIBase::clear();
243         value = value_default;
244     }
245 
246     void cascade( const SPIBase* const parent ) override;
247     void merge(   const SPIBase* const parent ) override;
248 
249     SPIFloat& operator=(const SPIFloat& rhs) = default;
250 
251     bool operator==(const SPIBase& rhs) const override;
252 
253   // To do: make private
254 public:
255     float value = 0.0;
256 
257 private:
258     float value_default = 0.0;
259 };
260 
261 /*
262  * One might think that the best value for SP_SCALE24_MAX would be ((1<<24)-1), which allows the
263  * greatest possible precision for fitting [0, 1] fractions into 24 bits.
264  *
265  * However, in practice, that gives a problem with 0.5, which falls half way between two fractions
266  * of ((1<<24)-1).  What's worse is that casting double(1<<23) / ((1<<24)-1) to float on x86
267  * produces wrong rounding behaviour, resulting in a fraction of ((1<<23)+2.0f) / (1<<24) rather
268  * than ((1<<23)+1.0f) / (1<<24) as one would expect, let alone ((1<<23)+0.0f) / (1<<24) as one
269  * would ideally like for this example.
270  *
271  * The value (1<<23) is thus best if one considers float conversions alone.
272  *
273  * The value 0xff0000 can exactly represent all 8-bit alpha channel values,
274  * and can exactly represent all multiples of 0.1.  I haven't yet tested whether
275  * rounding bugs still get in the way of conversions to & from float, but my instinct is that
276  * it's fairly safe because 0xff fits three times inside float's significand.
277  *
278  * We should probably use the value 0xffff00 once we support 16 bits per channel and/or LittleCMS,
279  * though that might need to be accompanied by greater use of double instead of float for
280  * colours and opacities, to be safe from rounding bugs.
281  */
282 static const unsigned SP_SCALE24_MAX = 0xff0000;
283 #define SP_SCALE24_TO_FLOAT(v) ((double) (v) / SP_SCALE24_MAX)
284 #define SP_SCALE24_FROM_FLOAT(v) unsigned(((v) * SP_SCALE24_MAX) + .5)
285 
286 /** Returns a scale24 for the product of two scale24 values. */
287 #define SP_SCALE24_MUL(_v1, _v2) unsigned((double)(_v1) * (_v2) / SP_SCALE24_MAX + .5)
288 
289 
290 /// 24 bit data type internal to SPStyle.
291 // Used only for opacity, fill-opacity, stroke-opacity.
292 // Opacity does not inherit but stroke-opacity and fill-opacity do.
293 class SPIScale24 : public SPIBase
294 {
get_default()295     static unsigned get_default() { return SP_SCALE24_MAX; }
296 
297 public:
298     SPIScale24(bool inherits = true )
SPIBase(inherits)299         : SPIBase(inherits),
300           value(get_default())
301     {}
302 
303     ~SPIScale24() override
304     = default;
305 
306     void read( gchar const *str ) override;
307     const Glib::ustring get_value() const override;
clear()308     void clear() override {
309         SPIBase::clear();
310         value = get_default();
311     }
312 
313     void cascade( const SPIBase* const parent ) override;
314     void merge(   const SPIBase* const parent ) override;
315 
316     SPIScale24& operator=(const SPIScale24& rhs) = default;
317 
318     bool operator==(const SPIBase& rhs) const override;
319 
320 
321   // To do: make private
322 public:
323     unsigned value : 24;
324 };
325 
326 
327 enum SPCSSUnit {
328     SP_CSS_UNIT_NONE,
329     SP_CSS_UNIT_PX,
330     SP_CSS_UNIT_PT,
331     SP_CSS_UNIT_PC,
332     SP_CSS_UNIT_MM,
333     SP_CSS_UNIT_CM,
334     SP_CSS_UNIT_IN,
335     SP_CSS_UNIT_EM,
336     SP_CSS_UNIT_EX,
337     SP_CSS_UNIT_PERCENT
338 };
339 
340 
341 /// Length type internal to SPStyle.
342 // Needs access to 'font-size' and 'font-family' for computed values.
343 // Used for 'stroke-width' 'stroke-dash-offset' ('none' not handled), text-indent
344 class SPILength : public SPIBase
345 {
346 
347 public:
348     SPILength(float value = 0)
unit(SP_CSS_UNIT_NONE)349         : unit(SP_CSS_UNIT_NONE),
350           value(value),
351           computed(value),
352           value_default(value)
353     {}
354 
355     ~SPILength() override
356     = default;
357 
358     void read( gchar const *str ) override;
359     const Glib::ustring get_value() const override;
clear()360     void clear() override {
361         SPIBase::clear();
362         unit = SP_CSS_UNIT_NONE, value = value_default;
363         computed = value_default;
364     }
365 
366     void cascade( const SPIBase* const parent ) override;
367     void merge(   const SPIBase* const parent ) override;
368 
369     SPILength& operator=(const SPILength& rhs) = default;
370 
371     bool operator==(const SPIBase& rhs) const override;
372     void setDouble(double v);
373     virtual const Glib::ustring toString(bool wname = false) const;
374 
375     // To do: make private
376   public:
377     unsigned unit : 4;
378     float value = 0.f;
379     float computed = 0.f;
380 
381 private:
382     float value_default = 0.f;
383 };
384 
385 
386 /// Extended length type internal to SPStyle.
387 // Used for: line-height, letter-spacing, word-spacing
388 class SPILengthOrNormal : public SPILength
389 {
390 
391 public:
392     SPILengthOrNormal(float value = 0)
SPILength(value)393         : SPILength(value),
394           normal(true)
395     {}
396 
397     ~SPILengthOrNormal() override
398     = default;
399 
400     void read( gchar const *str ) override;
401     const Glib::ustring get_value() const override;
clear()402     void clear() override {
403         SPILength::clear();
404         normal = true;
405     }
406 
407     void cascade( const SPIBase* const parent ) override;
408     void merge(   const SPIBase* const parent ) override;
409 
410     SPILengthOrNormal& operator=(const SPILengthOrNormal& rhs) = default;
411 
412     bool operator==(const SPIBase& rhs) const override;
413 
414   // To do: make private
415 public:
416     bool normal : 1;
417 };
418 
419 
420 /// Extended length type internal to SPStyle.
421 // Used for: font-variation-settings
422 class SPIFontVariationSettings : public SPIBase
423 {
424 
425 public:
SPIFontVariationSettings()426     SPIFontVariationSettings()
427         : normal(true)
428     {}
429 
430     ~SPIFontVariationSettings() override
431     = default;
432 
433     void read( gchar const *str ) override;
434     const Glib::ustring get_value() const override;
clear()435     void clear() override {
436         SPIBase::clear();
437         axes.clear();
438         normal = true;
439     }
440 
441     void cascade( const SPIBase* const parent ) override;
442     void merge(   const SPIBase* const parent ) override;
443 
444     SPIFontVariationSettings& operator=(const SPIFontVariationSettings& rhs) {
445         SPIBase::operator=(rhs);
446         axes = rhs.axes;
447         normal = rhs.normal;
448         return *this;
449     }
450 
451     bool operator==(const SPIBase& rhs) const override;
452 
453     virtual const Glib::ustring toString() const;
454 
455   // To do: make private
456 public:
457     bool normal : 1;
458     bool inherit : 1;
459     std::map<Glib::ustring, float> axes;
460 };
461 
462 
463 /// Enum type internal to SPStyle.
464 // Used for many properties. 'font-stretch' and 'font-weight' must be special cased.
465 template <typename T>
466 class SPIEnum : public SPIBase
467 {
468 
469 public:
470     SPIEnum(T value = T(), bool inherits = true) :
SPIBase(inherits)471         SPIBase(inherits),
472         value(value),
473         value_default(value)
474     {
475         update_computed();
476     }
477 
478     ~SPIEnum() override
479     = default;
480 
481     void read( gchar const *str ) override;
482     const Glib::ustring get_value() const override;
clear()483     void clear() override {
484         SPIBase::clear();
485         value = value_default;
486         update_computed();
487     }
488 
489     void cascade( const SPIBase* const parent ) override;
490     void merge(   const SPIBase* const parent ) override;
491 
492     SPIEnum& operator=(const SPIEnum& rhs) {
493         SPIBase::operator=(rhs);
494         value            = rhs.value;
495         computed         = rhs.computed;
496         value_default    = rhs.value_default;
497         return *this;
498     }
499 
500     bool operator==(const SPIBase& rhs) const override;
501 
502   // To do: make private
503 public:
504     T value{};
505     T computed{};
506 
507 private:
508     T value_default{};
509 
510     //! Update computed from value
511     void update_computed();
512     //! Update computed from parent computed
update_computed_cascade(T const & parent_computed)513     void update_computed_cascade(T const &parent_computed) {}
514     //! Update value from parent
515     //! @pre computed is up to date
update_value_merge(SPIEnum<T> const &)516     void update_value_merge(SPIEnum<T> const &) {}
517     void update_value_merge(SPIEnum<T> const &, T, T);
518 };
519 
520 
521 #if 0
522 /// SPIEnum w/ bits, allows values with multiple key words.
523 class SPIEnumBits : public SPIEnum
524 {
525 
526 public:
527     SPIEnumBits( Glib::ustring const &name, SPStyleEnum const *enums, unsigned value = 0, bool inherits = true ) :
528         SPIEnum( name, enums, value, inherits )
529     {}
530 
531     ~SPIEnumBits() override
532     = default;
533 
534     void read( gchar const *str ) override;
535     const Glib::ustring get_value() const override;
536 };
537 #endif
538 
539 
540 /// SPIEnum w/ extra bits. The 'font-variants-ligatures' property is a complete mess that needs
541 /// special handling. For OpenType fonts the values 'common-ligatures', 'contextual',
542 /// 'no-discretionary-ligatures', and 'no-historical-ligatures' are not useful but we still must be
543 /// able to parse them.
544 using _SPCSSFontVariantLigatures_int = typename std::underlying_type<SPCSSFontVariantLigatures>::type;
545 class SPILigatures : public SPIEnum<_SPCSSFontVariantLigatures_int>
546 {
547 
548 public:
SPILigatures()549     SPILigatures() :
550         SPIEnum<_SPCSSFontVariantLigatures_int>(SP_CSS_FONT_VARIANT_LIGATURES_NORMAL)
551     {}
552 
553     ~SPILigatures() override
554     = default;
555 
556     void read( gchar const *str ) override;
557     const Glib::ustring get_value() const override;
558 };
559 
560 
561 /// SPIEnum w/ extra bits. The 'font-variants-numeric' property is a complete mess that needs
562 /// special handling. Multiple key words can be specified, some exclusive of others.
563 using _SPCSSFontVariantNumeric_int = typename std::underlying_type<SPCSSFontVariantNumeric>::type;
564 class SPINumeric : public SPIEnum<_SPCSSFontVariantNumeric_int>
565 {
566 
567 public:
SPINumeric()568     SPINumeric() :
569         SPIEnum<_SPCSSFontVariantNumeric_int>(SP_CSS_FONT_VARIANT_NUMERIC_NORMAL)
570     {}
571 
572     ~SPINumeric() override
573     = default;
574 
575     void read( gchar const *str ) override;
576     const Glib::ustring get_value() const override;
577 };
578 
579 
580 /// SPIEnum w/ extra bits. The 'font-variants-east-asian' property is a complete mess that needs
581 /// special handling. Multiple key words can be specified, some exclusive of others.
582 using _SPCSSFontVariantEastAsian_int = typename std::underlying_type<SPCSSFontVariantEastAsian>::type;
583 class SPIEastAsian : public SPIEnum<_SPCSSFontVariantEastAsian_int>
584 {
585 
586 public:
SPIEastAsian()587     SPIEastAsian() :
588         SPIEnum<_SPCSSFontVariantEastAsian_int>(SP_CSS_FONT_VARIANT_EAST_ASIAN_NORMAL)
589     {}
590 
591     ~SPIEastAsian() override
592     = default;
593 
594     void read( gchar const *str ) override;
595     const Glib::ustring get_value() const override;
596 };
597 
598 
599 /// String type internal to SPStyle.
600 // Used for 'marker', ..., 'font', 'font-family', 'inkscape-font-specification'
601 class SPIString : public SPIBase
602 {
603 
604 public:
605     SPIString(bool inherits = true)
SPIBase(inherits)606         : SPIBase(inherits)
607     {}
608 
SPIString(const SPIString & rhs)609     SPIString(const SPIString &rhs) { *this = rhs; }
610 
~SPIString()611     ~SPIString() override {
612         g_free(_value);
613     }
614 
615     void read( gchar const *str ) override;
616     const Glib::ustring get_value() const override;
617     void clear() override; // TODO check about value and value_default
618     void cascade( const SPIBase* const parent ) override;
619     void merge(   const SPIBase* const parent ) override;
620 
621     SPIString& operator=(const SPIString& rhs) {
622         if (this == &rhs) {
623             return *this;
624         }
625         SPIBase::operator=(rhs);
626         g_free(_value);
627         _value = g_strdup(rhs._value);
628         return *this;
629     }
630 
631     bool operator==(const SPIBase& rhs) const override;
632 
633     //! Get value if set, or inherited value, or default value (may be NULL)
634     char const *value() const;
635 
636   private:
637     char const *get_default_value() const;
638 
639     gchar *_value = nullptr;
640 };
641 
642 /// Shapes type internal to SPStyle.
643 // Used for 'shape-inside', shape-subtract'
644 // Differs from SPIString by creating/deleting listeners on referenced shapes.
645 class SPIShapes : public SPIString
646 {
647     void hrefs_clear();
648 
649 public:
650     ~SPIShapes() override;
651     SPIShapes();
652     SPIShapes(const SPIShapes &) = delete; // Copying causes problems with hrefs.
653     void read( gchar const *str ) override;
654     void clear() override;
655 
656 public:
657     std::vector<SPShapeReference *> hrefs;
658 };
659 
660 /// Color type internal to SPStyle, FIXME Add string value to store SVG named color.
661 class SPIColor : public SPIBase
662 {
663 
664 public:
665     SPIColor(bool inherits = true)
SPIBase(inherits)666         : SPIBase(inherits)
667         , currentcolor(false)
668     {
669         value.color.set(0);
670     }
671 
672     ~SPIColor() override
673     = default;
674 
675     void read( gchar const *str ) override;
676     const Glib::ustring get_value() const override;
clear()677     void clear() override {
678         SPIBase::clear();
679         value.color.set(0);
680     }
681 
682     void cascade( const SPIBase* const parent ) override;
683     void merge(   const SPIBase* const parent ) override;
684 
685     SPIColor& operator=(const SPIColor& rhs) {
686         SPIBase::operator=(rhs);
687         currentcolor = rhs.currentcolor;
688         value.color  = rhs.value.color;
689         return *this;
690     }
691 
692     bool operator==(const SPIBase& rhs) const override;
693 
setColor(float r,float g,float b)694     void setColor( float r, float g, float b ) {
695         value.color.set( r, g, b );
696     }
697 
setColor(guint32 val)698     void setColor( guint32 val ) {
699         value.color.set( val );
700     }
701 
setColor(SPColor const & color)702     void setColor( SPColor const& color ) {
703         value.color = color;
704     }
705 
706 public:
707     bool currentcolor : 1;
708     // FIXME: remove structure and derive SPIPaint from this class.
709     struct {
710          SPColor color;
711     } value;
712 };
713 
714 
715 
716 #define SP_STYLE_FILL_SERVER(s) ((const_cast<SPStyle *> (s))->getFillPaintServer())
717 #define SP_STYLE_STROKE_SERVER(s) ((const_cast<SPStyle *> (s))->getStrokePaintServer())
718 
719 // SVG 2
720 enum SPPaintOrigin {
721     SP_CSS_PAINT_ORIGIN_NORMAL,
722     SP_CSS_PAINT_ORIGIN_CURRENT_COLOR,
723     SP_CSS_PAINT_ORIGIN_CONTEXT_FILL,
724     SP_CSS_PAINT_ORIGIN_CONTEXT_STROKE
725 };
726 
727 
728 /// Paint type internal to SPStyle.
729 class SPIPaint : public SPIBase
730 {
731 
732 public:
SPIPaint()733     SPIPaint()
734         : paintOrigin(SP_CSS_PAINT_ORIGIN_NORMAL),
735           colorSet(false),
736           noneSet(false) {
737         value.href = nullptr;
738         clear();
739     }
740 
741     ~SPIPaint() override;  // Clear and delete href.
742     void read( gchar const *str ) override;
743     virtual void read( gchar const *str, SPStyle &style, SPDocument *document = nullptr);
744     const Glib::ustring get_value() const override;
745     void clear() override;
746     virtual void reset( bool init ); // Used internally when reading or cascading
747     void cascade( const SPIBase* const parent ) override;
748     void merge(   const SPIBase* const parent ) override;
749 
750     SPIPaint& operator=(const SPIPaint& rhs) {
751         SPIBase::operator=(rhs);
752         paintOrigin     = rhs.paintOrigin;
753         colorSet        = rhs.colorSet;
754         noneSet         = rhs.noneSet;
755         value.color     = rhs.value.color;
756         value.href      = rhs.value.href;
757         return *this;
758     }
759 
760     bool operator==(const SPIBase& rhs) const override;
761 
isSameType(SPIPaint const & other)762     bool isSameType( SPIPaint const & other ) const {
763         return (isPaintserver() == other.isPaintserver()) && (colorSet == other.colorSet) && (paintOrigin == other.paintOrigin);
764     }
765 
isNoneSet()766     bool isNoneSet() const {
767         return noneSet;
768     }
769 
isNone()770     bool isNone() const {
771         return !colorSet && !isPaintserver() && (paintOrigin == SP_CSS_PAINT_ORIGIN_NORMAL);
772     } // TODO refine
773 
isColor()774     bool isColor() const {
775         return colorSet && !isPaintserver();
776     }
777 
isPaintserver()778     bool isPaintserver() const {
779         return value.href && value.href->getObject() != nullptr;
780     }
781 
setColor(float r,float g,float b)782     void setColor( float r, float g, float b ) {
783         value.color.set( r, g, b ); colorSet = true;
784     }
785 
setColor(guint32 val)786     void setColor( guint32 val ) {
787         value.color.set( val ); colorSet = true;
788     }
789 
setColor(SPColor const & color)790     void setColor( SPColor const& color ) {
791         value.color = color; colorSet = true;
792     }
793 
setNone()794     void setNone() {noneSet = true; colorSet=false;}
795 
796   // To do: make private
797 public:
798     SPPaintOrigin paintOrigin : 2;
799     bool colorSet : 1;
800     bool noneSet : 1;
801     struct {
802          SPPaintServerReference *href;
803          SPColor color;
804     } value;
805 };
806 
807 
808 // SVG 2
809 enum SPPaintOrderLayer {
810     SP_CSS_PAINT_ORDER_NORMAL,
811     SP_CSS_PAINT_ORDER_FILL,
812     SP_CSS_PAINT_ORDER_STROKE,
813     SP_CSS_PAINT_ORDER_MARKER
814 };
815 
816 // Normal maybe should be moved out as is done in other classes.
817 // This could be replaced by a generic enum class where multiple keywords are allowed and
818 // where order matters (in contrast to 'text-decoration-line' where order does not matter).
819 
820 // Each layer represents a layer of paint which can be a fill, a stroke, or markers.
821 const size_t PAINT_ORDER_LAYERS = 3;
822 
823 /// Paint order type internal to SPStyle
824 class SPIPaintOrder : public SPIBase
825 {
826 
827 public:
SPIPaintOrder()828     SPIPaintOrder() {
829         this->clear();
830     }
831 
SPIPaintOrder(const SPIPaintOrder & rhs)832     SPIPaintOrder(const SPIPaintOrder &rhs) { *this = rhs; }
833 
~SPIPaintOrder()834     ~SPIPaintOrder() override {
835         g_free( value );
836     }
837 
838     void read( gchar const *str ) override;
839     const Glib::ustring get_value() const override;
clear()840     void clear() override {
841         SPIBase::clear();
842         for( unsigned i = 0; i < PAINT_ORDER_LAYERS; ++i ) {
843             layer[i]     = SP_CSS_PAINT_ORDER_NORMAL;
844             layer_set[i] = false;
845         }
846         g_free(value);
847         value = nullptr;
848     }
849     void cascade( const SPIBase* const parent ) override;
850     void merge(   const SPIBase* const parent ) override;
851 
852     SPIPaintOrder& operator=(const SPIPaintOrder& rhs) {
853         if (this == &rhs) {
854             return *this;
855         }
856         SPIBase::operator=(rhs);
857         for( unsigned i = 0; i < PAINT_ORDER_LAYERS; ++i ) {
858             layer[i]     = rhs.layer[i];
859             layer_set[i] = rhs.layer_set[i];
860         }
861         g_free(value);
862         value            = g_strdup(rhs.value);
863         return *this;
864     }
865 
866     bool operator==(const SPIBase& rhs) const override;
867 
868 
869   // To do: make private
870 public:
871     SPPaintOrderLayer layer[PAINT_ORDER_LAYERS];
872     bool layer_set[PAINT_ORDER_LAYERS];
873     gchar *value = nullptr; // Raw string
874 };
875 
876 
877 /// Filter type internal to SPStyle
878 class SPIDashArray : public SPIBase
879 {
880 
881 public:
882     SPIDashArray() = default;
883 
884     ~SPIDashArray() override
885     = default;
886 
887     void read( gchar const *str ) override;
888     const Glib::ustring get_value() const override;
clear()889     void clear() override {
890         SPIBase::clear();
891         values.clear();
892     }
893 
894     void cascade( const SPIBase* const parent ) override;
895     void merge(   const SPIBase* const parent ) override;
896 
897     SPIDashArray& operator=(const SPIDashArray& rhs) = default;
898 
899     bool operator==(const SPIBase& rhs) const override;
900 
901   // To do: make private, change double to SVGLength
902 public:
903   std::vector<SPILength> values;
904 };
905 
906 /// Filter type internal to SPStyle
907 class SPIFilter : public SPIBase
908 {
909 
910 public:
SPIFilter()911     SPIFilter()
912         : SPIBase(false)
913     {}
914 
915     ~SPIFilter() override;
916     void read( gchar const *str ) override;
917     const Glib::ustring get_value() const override;
918     void clear() override;
919     void cascade( const SPIBase* const parent ) override;
920     void merge(   const SPIBase* const parent ) override;
921 
922     SPIFilter& operator=(const SPIFilter& rhs) = default;
923 
924     bool operator==(const SPIBase& rhs) const override;
925 
926   // To do: make private
927 public:
928     SPFilterReference *href = nullptr;
929 };
930 
931 
932 
933 enum {
934     SP_FONT_SIZE_LITERAL,
935     SP_FONT_SIZE_LENGTH,
936     SP_FONT_SIZE_PERCENTAGE
937 };
938 
939 /// Fontsize type internal to SPStyle (also used by libnrtype/Layout-TNG-Input.cpp).
940 class SPIFontSize : public SPIBase
941 {
942 
943 public:
SPIFontSize()944     SPIFontSize() {
945         this->clear();
946     }
947 
948     ~SPIFontSize() override
949     = default;
950 
951     void read( gchar const *str ) override;
952     const Glib::ustring get_value() const override;
clear()953     void clear() override {
954         SPIBase::clear();
955         type = SP_FONT_SIZE_LITERAL, unit = SP_CSS_UNIT_NONE,
956             literal = SP_CSS_FONT_SIZE_MEDIUM, value = 12.0, computed = 12.0;
957     }
958 
959     void cascade( const SPIBase* const parent ) override;
960     void merge(   const SPIBase* const parent ) override;
961 
962     SPIFontSize& operator=(const SPIFontSize& rhs) = default;
963 
964     bool operator==(const SPIBase& rhs) const override;
965 
966 public:
967     static float const font_size_default;
968 
969   // To do: make private
970 public:
971     unsigned type : 2;
972     unsigned unit : 4;
973     unsigned literal : 4;
974     float value;
975     float computed;
976 
977 private:
978     double relative_fraction() const;
979     static float const font_size_table[];
980 };
981 
982 
983 /// Font type internal to SPStyle ('font' shorthand)
984 class SPIFont : public SPIBase
985 {
986 
987 public:
988     SPIFont() = default;
989 
990     ~SPIFont() override
991     = default;
992 
993     void read( gchar const *str ) override;
994     const Glib::ustring get_value() const override;
clear()995     void clear() override {
996         SPIBase::clear();
997     }
998 
cascade(const SPIBase * const)999     void cascade( const SPIBase* const /*parent*/ ) override
1000     {} // Done in dependent properties
1001 
merge(const SPIBase * const)1002     void merge(   const SPIBase* const /*parent*/ ) override
1003     {}
1004 
1005     SPIFont& operator=(const SPIFont& rhs) = default;
1006 
1007     bool operator==(const SPIBase& rhs) const override;
1008 };
1009 
1010 
1011 enum {
1012     SP_BASELINE_SHIFT_LITERAL,
1013     SP_BASELINE_SHIFT_LENGTH,
1014     SP_BASELINE_SHIFT_PERCENTAGE
1015 };
1016 
1017 /// Baseline shift type internal to SPStyle. (This is actually just like SPIFontSize)
1018 class SPIBaselineShift : public SPIBase
1019 {
1020 
1021 public:
SPIBaselineShift()1022     SPIBaselineShift()
1023         : SPIBase(false) {
1024         this->clear();
1025     }
1026 
1027     ~SPIBaselineShift() override
1028     = default;
1029 
1030     void read( gchar const *str ) override;
1031     const Glib::ustring get_value() const override;
clear()1032     void clear() override {
1033         SPIBase::clear();
1034         type=SP_BASELINE_SHIFT_LITERAL, unit=SP_CSS_UNIT_NONE,
1035             literal = SP_CSS_BASELINE_SHIFT_BASELINE, value = 0.0, computed = 0.0;
1036     }
1037 
1038     void cascade( const SPIBase* const parent ) override;
1039     void merge(   const SPIBase* const parent ) override;
1040 
1041     SPIBaselineShift& operator=(const SPIBaselineShift& rhs) = default;
1042 
1043     // This is not used but we have it for completeness, it has not been tested.
1044     bool operator==(const SPIBase& rhs) const override;
1045 
1046     bool isZero() const;
1047 
1048   // To do: make private
1049 public:
1050     unsigned type : 2;
1051     unsigned unit : 4;
1052     unsigned literal: 2;
1053     float value; // Can be negative
1054     float computed;
1055 };
1056 
1057 // CSS 2.  Changes in CSS 3, where description is for TextDecorationLine, NOT TextDecoration
1058 // See http://www.w3.org/TR/css-text-decor-3/
1059 
1060 // CSS3 2.2
1061 /// Text decoration line type internal to SPStyle.  THIS SHOULD BE A GENERIC CLASS
1062 class SPITextDecorationLine : public SPIBase
1063 {
1064 
1065 public:
SPITextDecorationLine()1066     SPITextDecorationLine() {
1067         this->clear();
1068     }
1069 
1070     ~SPITextDecorationLine() override
1071     = default;
1072 
1073     void read( gchar const *str ) override;
1074     const Glib::ustring get_value() const override;
clear()1075     void clear() override {
1076         SPIBase::clear();
1077         underline = false, overline = false, line_through = false, blink = false;
1078     }
1079 
1080     void cascade( const SPIBase* const parent ) override;
1081     void merge(   const SPIBase* const parent ) override;
1082 
1083     SPITextDecorationLine& operator=(const SPITextDecorationLine& rhs) = default;
1084 
1085     bool operator==(const SPIBase& rhs) const override;
1086 
1087   // To do: make private
1088 public:
1089     bool underline : 1;
1090     bool overline : 1;
1091     bool line_through : 1;
1092     bool blink : 1;    // "Conforming user agents are not required to support this value." yay!
1093 };
1094 
1095 // CSS3 2.2
1096 /// Text decoration style type internal to SPStyle.  THIS SHOULD JUST BE SPIEnum!
1097 class SPITextDecorationStyle : public SPIBase
1098 {
1099 
1100 public:
SPITextDecorationStyle()1101     SPITextDecorationStyle() {
1102         this->clear();
1103     }
1104 
1105     ~SPITextDecorationStyle() override
1106     = default;
1107 
1108     void read( gchar const *str ) override;
1109     const Glib::ustring get_value() const override;
clear()1110     void clear() override {
1111         SPIBase::clear();
1112         solid = true, isdouble = false, dotted = false, dashed = false, wavy = false;
1113     }
1114 
1115     void cascade( const SPIBase* const parent ) override;
1116     void merge(   const SPIBase* const parent ) override;
1117 
1118     SPITextDecorationStyle& operator=(const SPITextDecorationStyle& rhs) = default;
1119 
1120     bool operator==(const SPIBase& rhs) const override;
1121 
1122   // To do: make private
1123 public:
1124     bool solid : 1;
1125     bool isdouble : 1;  // cannot use "double" as it is a reserved keyword
1126     bool dotted : 1;
1127     bool dashed : 1;
1128     bool wavy : 1;
1129 };
1130 
1131 
1132 
1133 // This class reads in both CSS2 and CSS3 'text-decoration' property. It passes the line, style,
1134 // and color parts to the appropriate CSS3 long-hand classes for reading and storing values.  When
1135 // writing out data, we write all four properties, with 'text-decoration' being written out with
1136 // the CSS2 format. This allows CSS1/CSS2 renderers to at least render lines, even if they are not
1137 // the right style. (See http://www.w3.org/TR/css-text-decor-3/#text-decoration-property )
1138 
1139 /// Text decoration type internal to SPStyle.
1140 class SPITextDecoration : public SPIBase
1141 {
1142 
1143 public:
1144     SPITextDecoration() = default;
1145 
1146     ~SPITextDecoration() override
1147     = default;
1148 
1149     void read( gchar const *str ) override;
1150     const Glib::ustring get_value() const override;
1151     const Glib::ustring write( guint const flags = SP_STYLE_FLAG_IFSET,
1152                                        SPStyleSrc const &style_src_req = SPStyleSrc::STYLE_PROP,
1153                                        SPIBase const *const base = nullptr ) const override;
clear()1154     void clear() override {
1155         SPIBase::clear();
1156         style_td = nullptr;
1157     }
1158 
1159     void cascade( const SPIBase* const parent ) override;
1160     void merge(   const SPIBase* const parent ) override;
1161 
1162     SPITextDecoration& operator=(const SPITextDecoration& rhs) {
1163         SPIBase::operator=(rhs);
1164         return *this;
1165     }
1166 
1167     // Use CSS2 value
1168     bool operator==(const SPIBase& rhs) const override;
1169 
1170 public:
1171     SPStyle* style_td = nullptr;   // Style to be used for drawing CSS2 text decorations
1172 };
1173 
1174 
1175 // These are used to implement text_decoration. The values are not saved to or read from SVG file
1176 struct SPITextDecorationData {
1177     float   phase_length;          // length along text line,used for phase for dot/dash/wavy
1178     bool    tspan_line_start;      // is first  span on a line
1179     bool    tspan_line_end;        // is last span on a line
1180     float   tspan_width;           // from libnrtype, when it calculates spans
1181     float   ascender;              // the rest from tspan's font
1182     float   descender;
1183     float   underline_thickness;
1184     float   underline_position;
1185     float   line_through_thickness;
1186     float   line_through_position;
1187 };
1188 
1189 /// Vector Effects.  THIS SHOULD BE A GENERIC CLASS
1190 class SPIVectorEffect : public SPIBase
1191 {
1192 
1193 public:
SPIVectorEffect()1194     SPIVectorEffect()
1195         : SPIBase(false)
1196     {
1197         this->clear();
1198     }
1199 
1200     ~SPIVectorEffect() override
1201     = default;
1202 
1203     void read( gchar const *str ) override;
1204     const Glib::ustring get_value() const override;
clear()1205     void clear() override {
1206         SPIBase::clear();
1207         stroke = false;
1208         size   = false;
1209         rotate = false;
1210         fixed  = false;
1211     }
1212 
1213     // Does not inherit
cascade(const SPIBase * const parent)1214     void cascade( const SPIBase* const parent ) override {};
merge(const SPIBase * const parent)1215     void merge(   const SPIBase* const parent ) override {};
1216 
1217     SPIVectorEffect& operator=(const SPIVectorEffect& rhs) = default;
1218 
1219     bool operator==(const SPIBase& rhs) const override;
1220 
1221   // To do: make private
1222 public:
1223     bool stroke : 1;
1224     bool size   : 1;
1225     bool rotate : 1;
1226     bool fixed  : 1;
1227 };
1228 
1229 /// Custom stroke properties. Only used for -inkscape-stroke: hairline.
1230 class SPIStrokeExtensions : public SPIBase
1231 {
1232 
1233 public:
SPIStrokeExtensions()1234     SPIStrokeExtensions()
1235         : hairline(false)
1236     {}
1237 
1238     ~SPIStrokeExtensions() override = default;
1239     void read( gchar const *str ) override;
1240     const Glib::ustring get_value() const override;
clear()1241     void clear() override {
1242         SPIBase::clear();
1243         hairline = false;
1244     }
1245 
1246     // Does not inherit
cascade(const SPIBase * const parent)1247     void cascade( const SPIBase* const parent ) override {};
merge(const SPIBase * const parent)1248     void merge(   const SPIBase* const parent ) override {};
1249 
1250     SPIStrokeExtensions& operator=(const SPIStrokeExtensions& rhs) = default;
1251 
1252     bool operator==(const SPIBase& rhs) const override;
1253 
1254   // To do: make private
1255 public:
1256     bool hairline : 1;
1257 };
1258 
1259 #endif // SEEN_SP_STYLE_INTERNAL_H
1260 
1261 
1262 /*
1263   Local Variables:
1264   mode:c++
1265   c-file-style:"stroustrup"
1266   c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
1267   indent-tabs-mode:nil
1268   fill-column:99
1269   End:
1270 */
1271 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :
1272