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