diff options
Diffstat (limited to '')
-rw-r--r-- | src/style-internal.h | 1278 |
1 files changed, 1278 insertions, 0 deletions
diff --git a/src/style-internal.h b/src/style-internal.h new file mode 100644 index 0000000..41b246e --- /dev/null +++ b/src/style-internal.h @@ -0,0 +1,1278 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +#ifndef SEEN_SP_STYLE_INTERNAL_H +#define SEEN_SP_STYLE_INTERNAL_H + +/** \file + * SPStyle internal: classes that are internal to SPStyle + */ +/* Authors: + * Lauris Kaplinski <lauris@kaplinski.com> + * Jon A. Cruz <jon@joncruz.org> + * Tavmjong Bah <tavmjong@free.fr> + * + * Copyright (C) 2014, 2018 Tavmjong Bah + * Copyright (C) 2010 Jon A. Cruz + * Copyright (C) 2001-2002 Lauris Kaplinski + * Copyright (C) 2001 Ximian, Inc. + * + * Released under GNU GPL v2+, read the file 'COPYING' for more information. + */ + +#include <utility> +#include <vector> +#include <map> + +#include "attributes.h" +#include "style-enums.h" + +#include "color.h" + +#include "object/sp-marker-loc.h" +#include "object/sp-filter.h" +#include "object/sp-filter-reference.h" +#include "object/sp-paint-server-reference.h" +#include "object/sp-shape-reference.h" + +#include "object/uri.h" + +#include "svg/svg-icc-color.h" + +#include "xml/repr.h" + +namespace Inkscape { +class ObjectSet; +}; + +static const unsigned SP_STYLE_FLAG_ALWAYS (1 << 2); +static const unsigned SP_STYLE_FLAG_IFSET (1 << 0); +static const unsigned SP_STYLE_FLAG_IFDIFF (1 << 1); +static const unsigned SP_STYLE_FLAG_IFSRC (1 << 3); // If source matches + +enum class SPStyleSrc : unsigned char +{ + UNSET, + ATTRIBUTE, // fill="red" + STYLE_PROP, // style="fill:red" + STYLE_SHEET, // .red { fill:red; } +}; + +/* General comments: + * + * This code is derived from the original C style code in style.cpp. + * + * Overview: + * Style can be obtained (in order of precedence) [CHECK] + * 1. "style" property in an element (style="fill:red"). + * 2. Style sheet, internal or external (<style> rect {fill:red;}</style>). + * 3. Attributes in an element (fill="red"). + * 4. Parent's style. + * A later property overrides an earlier property. This is implemented by + * reading in the properties backwards. If a property is already set, it + * prevents an earlier property from being read. + * + * A declaration with an "!important" rule overrides any other declarations (except those that + * also have an "!important" rule). Attributes can not use the "!important" rule and the rule + * is not inherited. + * + * In order for cascading to work, each element in the tree must be read in from top to bottom + * (parent before child). At each step, if a style property is not explicitly set, the property + * value is taken from the parent. Some properties have "computed" values that depend on: + * the parent's value (e.g. "font-size:larger"), + * another property value ("stroke-width":1em"), or + * an external value ("stroke-width:5%"). + * + * To summarize: + * + * An explicitly set value (including 'inherit') has a 'true' "set" flag. + * The "value" is either explicitly set or inherited. + * The "computed" value (if present) is calculated from "value" and some other input. + * + * Functions: + * write(): Write a property and its value to a string. + * Flags: + * ALWAYS: Always write out property. + * IFSET: Write a property if 'set' flag is true, otherwise return empty string. + * IFDIFF: Write a property if computed values are different, otherwise return empty string, + * This is only used for text!! + * IFSRC Write a property if the source matches the requested source (style sheet, etc.). + * + * read(): Set a property value from a string. + * clear(): Set a property to its default value and set the 'set' flag to false. + * cascade(): Cascade the parent's property values to the child if the child's property + * is unset (and it allows inheriting) or the value is 'inherit'. + * Calculate computed values that depend on parent. + * This requires that the parent already be updated. + * merge(): Merge the property values of a child and a parent that is being deleted, + * attempting to preserve the style of the child. + * operator=: Assignment operator required due to use of templates (in original C code). + * operator==: True if computed values are equal. TO DO: DEFINE EXACTLY WHAT THIS MEANS + * operator!=: Inverse of operator==. + * + * + * Outside dependencies: + * + * The C structures that these classes are evolved from were designed to be embedded in to the + * style structure (i.e they are "internal" and thus have an "I" in the SPI prefix). However, + * they should be reasonably stand-alone and can provide some functionality outside of the style + * structure (i.e. reading and writing style strings). Some properties do need access to other + * properties from the same object (e.g. SPILength sometimes needs to know font size) to + * calculate 'computed' values. Inheritance, of course, requires access to the parent object's + * style class. + * + * The only real outside dependency is SPObject... which is needed in the cases of SPIPaint and + * SPIFilter for setting up the "href". (Currently, SPDocument is needed but this dependency + * should be removed as an "href" only needs the SPDocument for attaching an external document to + * the XML tree [see uri-references.cpp]. If SPDocument is really needed, it can be obtained from + * SPObject.) + * + */ + +/// Virtual base class for all SPStyle internal classes +class SPIBase +{ + +public: + SPIBase(bool inherits_ = true) + : inherits(inherits_), + set(false), + inherit(false), + important(false), + style_src(SPStyleSrc::STYLE_PROP), // Default to property, see bug 1662285. + style(nullptr) + {} + + virtual ~SPIBase() + = default; + + virtual void read( gchar const *str ) = 0; + void readIfUnset(gchar const *str, SPStyleSrc source = SPStyleSrc::STYLE_PROP); + +protected: + char const *important_str() const { return important ? " !important" : ""; } + +public: + void readAttribute(Inkscape::XML::Node *repr) + { + readIfUnset(repr->attribute(name().c_str()), SPStyleSrc::ATTRIBUTE); + } + + virtual const Glib::ustring get_value() const = 0; + bool shall_write( guint const flags = SP_STYLE_FLAG_IFSET, + SPStyleSrc const &style_src_req = SPStyleSrc::STYLE_PROP, + SPIBase const *const base = nullptr ) const; + 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; + virtual void clear() { + set = false, inherit = false, important = false; + // Attr::D is a special case where the best default for it is actually ATTRIBUTE + // and not STYLE_PROP, this exception allows us to not have to refactor more. + if (id() != SPAttr::D) { + style_src = SPStyleSrc::STYLE_PROP; + } + } + + virtual void cascade( const SPIBase* const parent ) = 0; + virtual void merge( const SPIBase* const parent ) = 0; + + void setStylePointer(SPStyle *style_in) { style = style_in; } + + // Explicit assignment operator required due to templates. + SPIBase& operator=(const SPIBase& rhs) = default; + + // Check apples being compared to apples + virtual bool operator==(const SPIBase& rhs) const { + return id() == rhs.id(); + } + + bool operator!=(const SPIBase& rhs) const { + return !(*this == rhs); + } + + virtual SPAttr id() const { return SPAttr::INVALID; } + Glib::ustring const &name() const; + + // To do: make private +public: + bool inherits : 1; // Property inherits by default from parent. + bool set : 1; // Property has been explicitly set (vs. inherited). + bool inherit : 1; // Property value set to 'inherit'. + bool important : 1; // Property rule 'important' has been explicitly set. + SPStyleSrc style_src; // Source (attribute, style attribute, style-sheet). + +protected: + SPStyle* style; // Used by SPIPaint, SPIFilter... to find values of other properties +}; + + +/** + * Decorator which overrides SPIBase::id() + */ +template <SPAttr Id, class Base> +class TypedSPI : public Base { + public: + using Base::Base; + + /** + * Get the attribute enum + */ + SPAttr id() const override { return Id; } + static SPAttr static_id() { return Id; } + + /** + * Upcast to the base class + */ + Base *upcast() { return static_cast<Base *>(this); } + Base const *upcast() const { return static_cast<Base const *>(this); } +}; + + +/// Float type internal to SPStyle. (Only 'stroke-miterlimit') +class SPIFloat : public SPIBase +{ + +public: + SPIFloat(float value_default = 0.0 ) + : value(value_default), + value_default(value_default) + {} + + ~SPIFloat() override = default; + void read( gchar const *str ) override; + const Glib::ustring get_value() const override; + void clear() override { + SPIBase::clear(); + value = value_default; + } + + void cascade( const SPIBase* const parent ) override; + void merge( const SPIBase* const parent ) override; + + SPIFloat& operator=(const SPIFloat& rhs) = default; + + bool operator==(const SPIBase& rhs) const override; + + // To do: make private +public: + float value = 0.0; + +private: + float value_default = 0.0; +}; + +/* + * One might think that the best value for SP_SCALE24_MAX would be ((1<<24)-1), which allows the + * greatest possible precision for fitting [0, 1] fractions into 24 bits. + * + * However, in practice, that gives a problem with 0.5, which falls half way between two fractions + * of ((1<<24)-1). What's worse is that casting double(1<<23) / ((1<<24)-1) to float on x86 + * produces wrong rounding behaviour, resulting in a fraction of ((1<<23)+2.0f) / (1<<24) rather + * than ((1<<23)+1.0f) / (1<<24) as one would expect, let alone ((1<<23)+0.0f) / (1<<24) as one + * would ideally like for this example. + * + * The value (1<<23) is thus best if one considers float conversions alone. + * + * The value 0xff0000 can exactly represent all 8-bit alpha channel values, + * and can exactly represent all multiples of 0.1. I haven't yet tested whether + * rounding bugs still get in the way of conversions to & from float, but my instinct is that + * it's fairly safe because 0xff fits three times inside float's significand. + * + * We should probably use the value 0xffff00 once we support 16 bits per channel and/or LittleCMS, + * though that might need to be accompanied by greater use of double instead of float for + * colours and opacities, to be safe from rounding bugs. + */ +static const unsigned SP_SCALE24_MAX = 0xff0000; +#define SP_SCALE24_TO_FLOAT(v) ((double) (v) / SP_SCALE24_MAX) +#define SP_SCALE24_FROM_FLOAT(v) unsigned(((v) * SP_SCALE24_MAX) + .5) + +/** Returns a scale24 for the product of two scale24 values. */ +#define SP_SCALE24_MUL(_v1, _v2) unsigned((double)(_v1) * (_v2) / SP_SCALE24_MAX + .5) + + +/// 24 bit data type internal to SPStyle. +// Used only for opacity, fill-opacity, stroke-opacity. +// Opacity does not inherit but stroke-opacity and fill-opacity do. +class SPIScale24 : public SPIBase +{ + static unsigned get_default() { return SP_SCALE24_MAX; } + +public: + SPIScale24(bool inherits = true ) + : SPIBase(inherits), + value(get_default()) + {} + + ~SPIScale24() override + = default; + + void read( gchar const *str ) override; + const Glib::ustring get_value() const override; + void clear() override { + SPIBase::clear(); + value = get_default(); + } + + void cascade( const SPIBase* const parent ) override; + void merge( const SPIBase* const parent ) override; + + SPIScale24& operator=(const SPIScale24& rhs) = default; + + bool operator==(const SPIBase& rhs) const override; + + + // To do: make private +public: + unsigned value : 24; +}; + + +enum SPCSSUnit { + SP_CSS_UNIT_NONE, + SP_CSS_UNIT_PX, + SP_CSS_UNIT_PT, + SP_CSS_UNIT_PC, + SP_CSS_UNIT_MM, + SP_CSS_UNIT_CM, + SP_CSS_UNIT_IN, + SP_CSS_UNIT_EM, + SP_CSS_UNIT_EX, + SP_CSS_UNIT_PERCENT +}; + + +/// Length type internal to SPStyle. +// Needs access to 'font-size' and 'font-family' for computed values. +// Used for 'stroke-width' 'stroke-dash-offset' ('none' not handled), text-indent +class SPILength : public SPIBase +{ + +public: + SPILength(float value = 0) + : unit(SP_CSS_UNIT_NONE), + value(value), + computed(value), + value_default(value) + {} + + ~SPILength() override + = default; + + void read( gchar const *str ) override; + const Glib::ustring get_value() const override; + void clear() override { + SPIBase::clear(); + unit = SP_CSS_UNIT_NONE, value = value_default; + computed = value_default; + } + + void cascade( const SPIBase* const parent ) override; + void merge( const SPIBase* const parent ) override; + + SPILength& operator=(const SPILength& rhs) = default; + + bool operator==(const SPIBase& rhs) const override; + void setDouble(double v); + virtual const Glib::ustring toString(bool wname = false) const; + + // To do: make private + public: + unsigned unit : 4; + float value = 0.f; + float computed = 0.f; + +private: + float value_default = 0.f; +}; + + +/// Extended length type internal to SPStyle. +// Used for: line-height, letter-spacing, word-spacing +class SPILengthOrNormal : public SPILength +{ + +public: + SPILengthOrNormal(float value = 0) + : SPILength(value), + normal(true) + {} + + ~SPILengthOrNormal() override + = default; + + void read( gchar const *str ) override; + const Glib::ustring get_value() const override; + void clear() override { + SPILength::clear(); + normal = true; + } + + void cascade( const SPIBase* const parent ) override; + void merge( const SPIBase* const parent ) override; + + SPILengthOrNormal& operator=(const SPILengthOrNormal& rhs) = default; + + bool operator==(const SPIBase& rhs) const override; + + // To do: make private +public: + bool normal : 1; +}; + + +/// Extended length type internal to SPStyle. +// Used for: font-variation-settings +class SPIFontVariationSettings : public SPIBase +{ + +public: + SPIFontVariationSettings() + : normal(true) + {} + + ~SPIFontVariationSettings() override + = default; + + void read( gchar const *str ) override; + const Glib::ustring get_value() const override; + void clear() override { + SPIBase::clear(); + axes.clear(); + normal = true; + } + + void cascade( const SPIBase* const parent ) override; + void merge( const SPIBase* const parent ) override; + + SPIFontVariationSettings& operator=(const SPIFontVariationSettings& rhs) { + SPIBase::operator=(rhs); + axes = rhs.axes; + normal = rhs.normal; + return *this; + } + + bool operator==(const SPIBase& rhs) const override; + + virtual const Glib::ustring toString() const; + + // To do: make private +public: + bool normal : 1; + std::map<Glib::ustring, float> axes; +}; + + +/// Enum type internal to SPStyle. +// Used for many properties. 'font-stretch' and 'font-weight' must be special cased. +template <typename T> +class SPIEnum : public SPIBase +{ + +public: + SPIEnum(T value = T(), bool inherits = true) : + SPIBase(inherits), + value(value), + value_default(value) + { + update_computed(); + } + + ~SPIEnum() override + = default; + + void read( gchar const *str ) override; + const Glib::ustring get_value() const override; + void clear() override { + SPIBase::clear(); + value = value_default; + update_computed(); + } + + void cascade( const SPIBase* const parent ) override; + void merge( const SPIBase* const parent ) override; + + SPIEnum& operator=(const SPIEnum& rhs) { + SPIBase::operator=(rhs); + value = rhs.value; + computed = rhs.computed; + value_default = rhs.value_default; + return *this; + } + + bool operator==(const SPIBase& rhs) const override; + + // To do: make private +public: + T value{}; + T computed{}; + +private: + T value_default{}; + + //! Update computed from value + void update_computed(); + //! Update computed from parent computed + void update_computed_cascade(T const &parent_computed) {} + //! Update value from parent + //! @pre computed is up to date + void update_value_merge(SPIEnum<T> const &) {} + void update_value_merge(SPIEnum<T> const &, T, T); +}; + + +#if 0 +/// SPIEnum w/ bits, allows values with multiple key words. +class SPIEnumBits : public SPIEnum +{ + +public: + SPIEnumBits( Glib::ustring const &name, SPStyleEnum const *enums, unsigned value = 0, bool inherits = true ) : + SPIEnum( name, enums, value, inherits ) + {} + + ~SPIEnumBits() override + = default; + + void read( gchar const *str ) override; + const Glib::ustring get_value() const override; +}; +#endif + + +/// SPIEnum w/ extra bits. The 'font-variants-ligatures' property is a complete mess that needs +/// special handling. For OpenType fonts the values 'common-ligatures', 'contextual', +/// 'no-discretionary-ligatures', and 'no-historical-ligatures' are not useful but we still must be +/// able to parse them. +using _SPCSSFontVariantLigatures_int = typename std::underlying_type<SPCSSFontVariantLigatures>::type; +class SPILigatures : public SPIEnum<_SPCSSFontVariantLigatures_int> +{ + +public: + SPILigatures() : + SPIEnum<_SPCSSFontVariantLigatures_int>(SP_CSS_FONT_VARIANT_LIGATURES_NORMAL) + {} + + ~SPILigatures() override + = default; + + void read( gchar const *str ) override; + const Glib::ustring get_value() const override; +}; + + +/// SPIEnum w/ extra bits. The 'font-variants-numeric' property is a complete mess that needs +/// special handling. Multiple key words can be specified, some exclusive of others. +using _SPCSSFontVariantNumeric_int = typename std::underlying_type<SPCSSFontVariantNumeric>::type; +class SPINumeric : public SPIEnum<_SPCSSFontVariantNumeric_int> +{ + +public: + SPINumeric() : + SPIEnum<_SPCSSFontVariantNumeric_int>(SP_CSS_FONT_VARIANT_NUMERIC_NORMAL) + {} + + ~SPINumeric() override + = default; + + void read( gchar const *str ) override; + const Glib::ustring get_value() const override; +}; + + +/// SPIEnum w/ extra bits. The 'font-variants-east-asian' property is a complete mess that needs +/// special handling. Multiple key words can be specified, some exclusive of others. +using _SPCSSFontVariantEastAsian_int = typename std::underlying_type<SPCSSFontVariantEastAsian>::type; +class SPIEastAsian : public SPIEnum<_SPCSSFontVariantEastAsian_int> +{ + +public: + SPIEastAsian() : + SPIEnum<_SPCSSFontVariantEastAsian_int>(SP_CSS_FONT_VARIANT_EAST_ASIAN_NORMAL) + {} + + ~SPIEastAsian() override + = default; + + void read( gchar const *str ) override; + const Glib::ustring get_value() const override; +}; + + +/// String type internal to SPStyle. +// Used for 'marker', ..., 'font', 'font-family', 'inkscape-font-specification' +class SPIString : public SPIBase +{ + +public: + SPIString(bool inherits = true) + : SPIBase(inherits) + {} + + SPIString(const SPIString &rhs) { *this = rhs; } + + ~SPIString() override { + g_free(_value); + } + + void read( gchar const *str ) override; + const Glib::ustring get_value() const override; + void clear() override; // TODO check about value and value_default + void cascade( const SPIBase* const parent ) override; + void merge( const SPIBase* const parent ) override; + + SPIString& operator=(const SPIString& rhs) { + if (this == &rhs) { + return *this; + } + SPIBase::operator=(rhs); + g_free(_value); + _value = g_strdup(rhs._value); + return *this; + } + + bool operator==(const SPIBase& rhs) const override; + + //! Get value if set, or inherited value, or default value (may be NULL) + char const *value() const; + + private: + char const *get_default_value() const; + + gchar *_value = nullptr; +}; + +/// Shapes type internal to SPStyle. +// Used for 'shape-inside', shape-subtract' +// Differs from SPIString by creating/deleting listeners on referenced shapes. +class SPIShapes : public SPIString +{ + void hrefs_clear(); + +public: + ~SPIShapes() override; + SPIShapes(); + SPIShapes(const SPIShapes &) = delete; // Copying causes problems with hrefs. + void read( gchar const *str ) override; + void clear() override; + +public: + std::vector<SPShapeReference *> hrefs; + bool containsAnyShape(Inkscape::ObjectSet *set); +}; + +/// Color type internal to SPStyle, FIXME Add string value to store SVG named color. +class SPIColor : public SPIBase +{ + +public: + SPIColor(bool inherits = true) + : SPIBase(inherits) + , currentcolor(false) + { + value.color.set(0); + } + + ~SPIColor() override + = default; + + void read( gchar const *str ) override; + const Glib::ustring get_value() const override; + void clear() override { + SPIBase::clear(); + value.color.set(0); + } + + void cascade( const SPIBase* const parent ) override; + void merge( const SPIBase* const parent ) override; + + SPIColor& operator=(const SPIColor& rhs) { + SPIBase::operator=(rhs); + currentcolor = rhs.currentcolor; + value.color = rhs.value.color; + return *this; + } + + bool operator==(const SPIBase& rhs) const override; + + void setColor( float r, float g, float b ) { + value.color.set( r, g, b ); + } + + void setColor( guint32 val ) { + value.color.set( val ); + } + + void setColor( SPColor const& color ) { + value.color = color; + } + +public: + bool currentcolor : 1; + // FIXME: remove structure and derive SPIPaint from this class. + struct { + SPColor color; + } value; +}; + + + +#define SP_STYLE_FILL_SERVER(s) ((const_cast<SPStyle *> (s))->getFillPaintServer()) +#define SP_STYLE_STROKE_SERVER(s) ((const_cast<SPStyle *> (s))->getStrokePaintServer()) + +// SVG 2 +enum SPPaintOrigin { + SP_CSS_PAINT_ORIGIN_NORMAL, + SP_CSS_PAINT_ORIGIN_CURRENT_COLOR, + SP_CSS_PAINT_ORIGIN_CONTEXT_FILL, + SP_CSS_PAINT_ORIGIN_CONTEXT_STROKE +}; + + +/// Paint type internal to SPStyle. +class SPIPaint : public SPIBase +{ + +public: + SPIPaint() + : paintOrigin(SP_CSS_PAINT_ORIGIN_NORMAL), + colorSet(false), + noneSet(false) { + value.href = nullptr; + tag = nullptr; + clear(); + } + + ~SPIPaint() override; // Clear and delete href. + void read( gchar const *str ) override; + virtual void read( gchar const *str, SPStyle &style, SPDocument *document = nullptr); + const Glib::ustring get_value() const override; + void clear() override; + virtual void reset( bool init ); // Used internally when reading or cascading + void cascade( const SPIBase* const parent ) override; + void merge( const SPIBase* const parent ) override; + + SPIPaint& operator=(const SPIPaint& rhs) { + SPIBase::operator=(rhs); + paintOrigin = rhs.paintOrigin; + colorSet = rhs.colorSet; + noneSet = rhs.noneSet; + value.color = rhs.value.color; + value.href = rhs.value.href; + return *this; + } + + bool operator==(const SPIBase& rhs) const override; + + bool isSameType( SPIPaint const & other ) const { + return (isPaintserver() == other.isPaintserver()) && (colorSet == other.colorSet) && (paintOrigin == other.paintOrigin); + } + + bool isNoneSet() const { + return noneSet; + } + + bool isNone() const { + return !colorSet && !isPaintserver() && (paintOrigin == SP_CSS_PAINT_ORIGIN_NORMAL); + } // TODO refine + + bool isColor() const { + return colorSet && !isPaintserver(); + } + + bool isPaintserver() const { + return value.href && value.href->getObject() != nullptr; + } + + void setColor( float r, float g, float b ) { + value.color.set( r, g, b ); colorSet = true; + } + + void setColor( guint32 val ) { + value.color.set( val ); colorSet = true; + } + + void setColor( SPColor const& color ) { + value.color = color; colorSet = true; + } + + void setNone() {noneSet = true; colorSet=false;} + + void setTag(SPObject* tag) { this->tag = tag; } + SPObject* getTag() { return tag; } + + // To do: make private +public: + SPPaintOrigin paintOrigin : 2; + bool colorSet : 1; + bool noneSet : 1; + struct { + SPPaintServerReference *href; + SPColor color; + } value; + SPObject* tag; +}; + + +// SVG 2 +enum SPPaintOrderLayer { + SP_CSS_PAINT_ORDER_NORMAL, + SP_CSS_PAINT_ORDER_FILL, + SP_CSS_PAINT_ORDER_STROKE, + SP_CSS_PAINT_ORDER_MARKER +}; + +// Normal maybe should be moved out as is done in other classes. +// This could be replaced by a generic enum class where multiple keywords are allowed and +// where order matters (in contrast to 'text-decoration-line' where order does not matter). + +// Each layer represents a layer of paint which can be a fill, a stroke, or markers. +const size_t PAINT_ORDER_LAYERS = 3; + +/// Paint order type internal to SPStyle +class SPIPaintOrder : public SPIBase +{ + +public: + SPIPaintOrder() { + this->clear(); + } + + SPIPaintOrder(const SPIPaintOrder &rhs) { *this = rhs; } + + ~SPIPaintOrder() override { + g_free( value ); + } + + void read( gchar const *str ) override; + const Glib::ustring get_value() const override; + void clear() override { + SPIBase::clear(); + for( unsigned i = 0; i < PAINT_ORDER_LAYERS; ++i ) { + layer[i] = SP_CSS_PAINT_ORDER_NORMAL; + layer_set[i] = false; + } + g_free(value); + value = nullptr; + } + void cascade( const SPIBase* const parent ) override; + void merge( const SPIBase* const parent ) override; + + SPIPaintOrder& operator=(const SPIPaintOrder& rhs) { + if (this == &rhs) { + return *this; + } + SPIBase::operator=(rhs); + for( unsigned i = 0; i < PAINT_ORDER_LAYERS; ++i ) { + layer[i] = rhs.layer[i]; + layer_set[i] = rhs.layer_set[i]; + } + g_free(value); + value = g_strdup(rhs.value); + return *this; + } + + bool operator==(const SPIBase& rhs) const override; + + + // To do: make private +public: + SPPaintOrderLayer layer[PAINT_ORDER_LAYERS]; + bool layer_set[PAINT_ORDER_LAYERS]; + gchar *value = nullptr; // Raw string +}; + + +/// Filter type internal to SPStyle +class SPIDashArray : public SPIBase +{ + +public: + SPIDashArray() = default; + + ~SPIDashArray() override + = default; + + void read( gchar const *str ) override; + const Glib::ustring get_value() const override; + void clear() override { + SPIBase::clear(); + values.clear(); + } + + void cascade( const SPIBase* const parent ) override; + void merge( const SPIBase* const parent ) override; + + SPIDashArray& operator=(const SPIDashArray& rhs) = default; + + bool operator==(const SPIBase& rhs) const override; + + // To do: make private, change double to SVGLength +public: + std::vector<SPILength> values; +}; + +/// Filter type internal to SPStyle +class SPIFilter : public SPIBase +{ + +public: + SPIFilter() + : SPIBase(false) + {} + + ~SPIFilter() override; + void read( gchar const *str ) override; + const Glib::ustring get_value() const override; + void clear() override; + void cascade( const SPIBase* const parent ) override; + void merge( const SPIBase* const parent ) override; + + SPIFilter& operator=(const SPIFilter& rhs) = default; + + bool operator==(const SPIBase& rhs) const override; + + // To do: make private +public: + SPFilterReference *href = nullptr; +}; + + + +enum { + SP_FONT_SIZE_LITERAL, + SP_FONT_SIZE_LENGTH, + SP_FONT_SIZE_PERCENTAGE +}; + +/// Fontsize type internal to SPStyle (also used by libnrtype/Layout-TNG-Input.cpp). +class SPIFontSize : public SPIBase +{ + +public: + SPIFontSize() { + this->clear(); + } + + ~SPIFontSize() override + = default; + + void read( gchar const *str ) override; + const Glib::ustring get_value() const override; + void clear() override { + SPIBase::clear(); + type = SP_FONT_SIZE_LITERAL, unit = SP_CSS_UNIT_NONE, + literal = SP_CSS_FONT_SIZE_MEDIUM, value = 12.0, computed = 12.0; + } + + void cascade( const SPIBase* const parent ) override; + void merge( const SPIBase* const parent ) override; + + SPIFontSize& operator=(const SPIFontSize& rhs) = default; + + bool operator==(const SPIBase& rhs) const override; + +public: + static float const font_size_default; + + // To do: make private +public: + unsigned type : 2; + unsigned unit : 4; + unsigned literal : 4; + float value; + float computed; + +private: + double relative_fraction() const; + static float const font_size_table[]; +}; + + +/// Font type internal to SPStyle ('font' shorthand) +class SPIFont : public SPIBase +{ + +public: + SPIFont() = default; + + ~SPIFont() override + = default; + + void read( gchar const *str ) override; + const Glib::ustring get_value() const override; + void clear() override { + SPIBase::clear(); + } + + void cascade( const SPIBase* const /*parent*/ ) override + {} // Done in dependent properties + + void merge( const SPIBase* const /*parent*/ ) override + {} + + SPIFont& operator=(const SPIFont& rhs) = default; + + bool operator==(const SPIBase& rhs) const override; +}; + + +enum { + SP_BASELINE_SHIFT_LITERAL, + SP_BASELINE_SHIFT_LENGTH, + SP_BASELINE_SHIFT_PERCENTAGE +}; + +/// Baseline shift type internal to SPStyle. (This is actually just like SPIFontSize) +class SPIBaselineShift : public SPIBase +{ + +public: + SPIBaselineShift() + : SPIBase(false) { + this->clear(); + } + + ~SPIBaselineShift() override + = default; + + void read( gchar const *str ) override; + const Glib::ustring get_value() const override; + void clear() override { + SPIBase::clear(); + type=SP_BASELINE_SHIFT_LITERAL, unit=SP_CSS_UNIT_NONE, + literal = SP_CSS_BASELINE_SHIFT_BASELINE, value = 0.0, computed = 0.0; + } + + void cascade( const SPIBase* const parent ) override; + void merge( const SPIBase* const parent ) override; + + SPIBaselineShift& operator=(const SPIBaselineShift& rhs) = default; + + // This is not used but we have it for completeness, it has not been tested. + bool operator==(const SPIBase& rhs) const override; + + bool isZero() const; + + // To do: make private +public: + unsigned type : 2; + unsigned unit : 4; + unsigned literal: 2; + float value; // Can be negative + float computed; +}; + +// CSS 2. Changes in CSS 3, where description is for TextDecorationLine, NOT TextDecoration +// See http://www.w3.org/TR/css-text-decor-3/ + +// CSS3 2.2 +/// Text decoration line type internal to SPStyle. THIS SHOULD BE A GENERIC CLASS +class SPITextDecorationLine : public SPIBase +{ + +public: + SPITextDecorationLine() { + this->clear(); + } + + ~SPITextDecorationLine() override + = default; + + void read( gchar const *str ) override; + const Glib::ustring get_value() const override; + void clear() override { + SPIBase::clear(); + underline = false, overline = false, line_through = false, blink = false; + } + + void cascade( const SPIBase* const parent ) override; + void merge( const SPIBase* const parent ) override; + + SPITextDecorationLine& operator=(const SPITextDecorationLine& rhs) = default; + + bool operator==(const SPIBase& rhs) const override; + + // To do: make private +public: + bool underline : 1; + bool overline : 1; + bool line_through : 1; + bool blink : 1; // "Conforming user agents are not required to support this value." yay! +}; + +// CSS3 2.2 +/// Text decoration style type internal to SPStyle. THIS SHOULD JUST BE SPIEnum! +class SPITextDecorationStyle : public SPIBase +{ + +public: + SPITextDecorationStyle() { + this->clear(); + } + + ~SPITextDecorationStyle() override + = default; + + void read( gchar const *str ) override; + const Glib::ustring get_value() const override; + void clear() override { + SPIBase::clear(); + solid = true, isdouble = false, dotted = false, dashed = false, wavy = false; + } + + void cascade( const SPIBase* const parent ) override; + void merge( const SPIBase* const parent ) override; + + SPITextDecorationStyle& operator=(const SPITextDecorationStyle& rhs) = default; + + bool operator==(const SPIBase& rhs) const override; + + // To do: make private +public: + bool solid : 1; + bool isdouble : 1; // cannot use "double" as it is a reserved keyword + bool dotted : 1; + bool dashed : 1; + bool wavy : 1; +}; + + + +// This class reads in both CSS2 and CSS3 'text-decoration' property. It passes the line, style, +// and color parts to the appropriate CSS3 long-hand classes for reading and storing values. When +// writing out data, we write all four properties, with 'text-decoration' being written out with +// the CSS2 format. This allows CSS1/CSS2 renderers to at least render lines, even if they are not +// the right style. (See http://www.w3.org/TR/css-text-decor-3/#text-decoration-property ) + +/// Text decoration type internal to SPStyle. +class SPITextDecoration : public SPIBase +{ + +public: + SPITextDecoration() = default; + + ~SPITextDecoration() override + = default; + + void read( gchar const *str ) override; + const Glib::ustring get_value() const 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; + void clear() override { + SPIBase::clear(); + style_td = nullptr; + } + + void cascade( const SPIBase* const parent ) override; + void merge( const SPIBase* const parent ) override; + + SPITextDecoration& operator=(const SPITextDecoration& rhs) { + SPIBase::operator=(rhs); + return *this; + } + + // Use CSS2 value + bool operator==(const SPIBase& rhs) const override; + +public: + SPStyle* style_td = nullptr; // Style to be used for drawing CSS2 text decorations +}; + + +// These are used to implement text_decoration. The values are not saved to or read from SVG file +struct SPITextDecorationData { + float phase_length; // length along text line,used for phase for dot/dash/wavy + bool tspan_line_start; // is first span on a line + bool tspan_line_end; // is last span on a line + float tspan_width; // from libnrtype, when it calculates spans + float ascender; // the rest from tspan's font + float descender; + float underline_thickness; + float underline_position; + float line_through_thickness; + float line_through_position; +}; + +/// Vector Effects. THIS SHOULD BE A GENERIC CLASS +class SPIVectorEffect : public SPIBase +{ + +public: + SPIVectorEffect() + : SPIBase(false) + { + this->clear(); + } + + ~SPIVectorEffect() override + = default; + + void read( gchar const *str ) override; + const Glib::ustring get_value() const override; + void clear() override { + SPIBase::clear(); + stroke = false; + size = false; + rotate = false; + fixed = false; + } + + // Does not inherit + void cascade( const SPIBase* const parent ) override {}; + void merge( const SPIBase* const parent ) override {}; + + SPIVectorEffect& operator=(const SPIVectorEffect& rhs) = default; + + bool operator==(const SPIBase& rhs) const override; + + // To do: make private +public: + bool stroke : 1; + bool size : 1; + bool rotate : 1; + bool fixed : 1; +}; + +/// Custom stroke properties. Only used for -inkscape-stroke: hairline. +class SPIStrokeExtensions : public SPIBase +{ + +public: + SPIStrokeExtensions() + : hairline(false) + {} + + ~SPIStrokeExtensions() override = default; + void read( gchar const *str ) override; + const Glib::ustring get_value() const override; + void clear() override { + SPIBase::clear(); + hairline = false; + } + + // Does not inherit + void cascade( const SPIBase* const parent ) override {}; + void merge( const SPIBase* const parent ) override {}; + + SPIStrokeExtensions& operator=(const SPIStrokeExtensions& rhs) = default; + + bool operator==(const SPIBase& rhs) const override; + + // To do: make private +public: + bool hairline : 1; +}; + +#endif // SEEN_SP_STYLE_INTERNAL_H + + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 : |