The Birdfont Source Code


All Repositories / birdfont.git / blob – RSS feed

SvgStyle.vala in /libsvgbird

This file is a part of the Birdfont project.

Contributing

Send patches or pull requests to johan.mattsson.m@gmail.com.
Clone this repository: git clone https://github.com/johanmattssonm/birdfont.git
Circle boundaries heads/master
1 /* 2 Copyright (C) 2015 2016 Johan Mattsson 3 4 This library is free software; you can redistribute it and/or modify 5 it under the terms of the GNU Lesser General Public License as 6 published by the Free Software Foundation; either version 3 of the 7 License, or (at your option) any later version. 8 9 This library is distributed in the hope that it will be useful, but 10 WITHOUT ANY WARRANTY; without even the implied warranty of 11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 Lesser General Public License for more details. 13 */ 14 15 using B; 16 using Math; 17 18 namespace SvgBird { 19 20 public class SvgStyle : GLib.Object { 21 public Gee.HashMap<string, string> style = new Gee.HashMap<string, string> (); 22 23 public Color? stroke = null; 24 public Color? fill = null; 25 public Gradient? stroke_gradient = null; 26 public Gradient? fill_gradient = null; 27 public LineCap line_cap = LineCap.BUTT; 28 29 public bool visible = true; 30 31 public double padding_top { 32 get { 33 return SvgFile.parse_number (get_css_property ("padding-top")); 34 } 35 36 set { 37 set_style ("padding-top", Doubles.round (value) + "px"); 38 } 39 } 40 41 public double padding_right { 42 get { 43 return SvgFile.parse_number (get_css_property ("padding-right")); 44 } 45 46 set { 47 set_style ("padding-right", Doubles.round (value) + "px"); 48 } 49 } 50 51 public double padding_bottom { 52 get { 53 return SvgFile.parse_number (get_css_property ("padding-bottom")); 54 } 55 56 set { 57 set_style ("padding-bottom", Doubles.round (value) + "px"); 58 } 59 } 60 61 public double padding_left { 62 get { 63 return SvgFile.parse_number (get_css_property ("padding-left")); 64 } 65 66 set { 67 set_style ("padding-left", Doubles.round (value) + "px"); 68 } 69 } 70 71 public double stroke_width = 0; 72 73 private static Gee.HashMap<string, string>? inheritance; 74 private static Mutex inheritance_mutex = new Mutex (); 75 76 public SvgStyle () { 77 } 78 79 public SvgStyle.for_properties (Defs? defs, string style) { 80 parse_key_value_pairs (style); 81 set_style_properties (defs, this); 82 } 83 84 public void set_style (string property, string style) { 85 this.style.set (property, style); 86 } 87 88 public bool property_equals (string property, string value) { 89 string? p = get_css_property (property); 90 91 if (p == null) { 92 return false; 93 } 94 95 string css_property = (!) p; 96 return css_property == value; 97 } 98 99 public bool has_css_property (string property) { 100 return style.has_key (property); 101 } 102 103 public string? get_css_property (string property) { 104 string p = property.down (); 105 106 if (!has_css_property (p)) { 107 return null; 108 } 109 110 return style.get (p); 111 } 112 113 public double get_double_property (string property) { 114 string p = property.down (); 115 116 if (!has_css_property (p)) { 117 return 0; 118 } 119 120 return SvgFile.parse_number (style.get (p)); 121 } 122 123 public static bool is_inherited (string property) { 124 inheritance_mutex.lock (); 125 if (unlikely (inheritance == null)) { 126 create_inheritance_table (); 127 } 128 129 Gee.HashMap<string, string> inheritance = (!) inheritance; 130 string? inherited = inheritance.get (property); 131 inheritance_mutex.unlock (); 132 133 if (inherited == null) { 134 return false; 135 } 136 137 string inherited_property = (!) inherited; 138 return inherited_property == "yes"; 139 } 140 141 /** Specify inheritance for a CSS property. */ 142 public static void set_inheritance (string property, bool inherit) { 143 inheritance_mutex.lock (); 144 if (unlikely (inheritance == null)) { 145 create_inheritance_table (); 146 } 147 148 Gee.HashMap<string, string> inheritance = (!) inheritance; 149 string inherit_property = inherit ? "yes" : "no"; 150 inheritance.set (property, inherit_property); 151 inheritance_mutex.unlock (); 152 } 153 154 public SvgStyle copy () { 155 SvgStyle style_copy = new SvgStyle (); 156 157 foreach (string key in style.keys) { 158 style_copy.style.set (key, style.get (key)); 159 } 160 161 if (stroke != null) { 162 style_copy.stroke = ((!) stroke).copy (); 163 } 164 165 if (fill != null) { 166 style_copy.fill = ((!) fill).copy (); 167 } 168 169 if (stroke_gradient != null) { 170 style_copy.stroke_gradient = ((!) stroke_gradient).copy (); 171 } 172 173 if (fill_gradient != null) { 174 style_copy.fill_gradient = ((!) fill_gradient).copy (); 175 } 176 177 style_copy.stroke_width = stroke_width; 178 179 return style_copy; 180 } 181 182 public LineCap get_line_cap () { 183 string l; 184 185 if (!style.has_key ("stroke-linecap")) { 186 return LineCap.BUTT; 187 } 188 189 l = style.get ("stroke-linecap"); 190 191 if (l == "round") { 192 return LineCap.ROUND; 193 } else if (l == "square") { 194 return LineCap.SQUARE; 195 } 196 197 return LineCap.BUTT; 198 } 199 200 public bool has_stroke () { 201 bool has_stroke = true; 202 203 if (style.has_key ("stroke")) { 204 has_stroke = style.get ("stroke") != "none"; 205 } 206 207 if (stroke != null) { 208 Color c = (!) stroke; 209 210 if (c.a == 0) { 211 return false; 212 } 213 } 214 215 return stroke_width > 0 && has_stroke; 216 } 217 218 public double get_stroke_width () { 219 return stroke_width; 220 } 221 222 public string to_string () { 223 StringBuilder description = new StringBuilder (); 224 225 description.append ("SvgStyle: "); 226 227 foreach (string key in style.keys) { 228 description.append (key); 229 description.append (": "); 230 description.append (style.get (key)); 231 description.append ("; "); 232 } 233 234 return description.str.strip (); 235 } 236 237 public void inherit (SvgStyle inherited) { 238 foreach (string key in inherited.style.keys) { 239 if (is_inherited (key)) { 240 style.set (key, inherited.style.get (key)); 241 } 242 } 243 } 244 245 public void apply (SvgStyle inherited) { 246 foreach (string key in inherited.style.keys) { 247 style.set (key, inherited.style.get (key)); 248 } 249 } 250 251 public static SvgStyle parse (Defs? d, SvgStyle inherited, XmlElement tag, string? psuedo_class) { 252 SvgStyle s = new SvgStyle (); 253 Attributes attributes = tag.get_attributes (); 254 255 s.style.set ("fill", "#000000"); // default fill value 256 s.inherit (inherited); 257 258 if (d != null) { 259 StyleSheet style_sheet = ((!) d).style_sheet; 260 style_sheet.apply_style (tag, s, psuedo_class); 261 } 262 263 foreach (Attribute a in attributes) { 264 if (a.get_name () == "style") { 265 s.parse_key_value_pairs (a.get_content ()); 266 } 267 268 if (a.get_name () == "stroke-width") { 269 s.style.set ("stroke-width", a.get_content ()); 270 } 271 272 if (a.get_name () == "stroke") { 273 s.style.set ("stroke", a.get_content ()); 274 } 275 276 if (a.get_name () == "fill") { 277 s.style.set ("fill", a.get_content ()); 278 } 279 280 if (a.get_name () == "fill-opacity") { 281 s.style.set ("fill-opacity", a.get_content ()); 282 } 283 284 if (a.get_name () == "stroke-opacity") { 285 s.style.set ("stroke-opacity", a.get_content ()); 286 } 287 } 288 289 set_style_properties (d, s); 290 return s; 291 } 292 293 public static void set_style_properties (Defs? d, SvgStyle s) { 294 double fill_opacity = 1; 295 double stroke_opacity = 1; 296 297 s.stroke_width = SvgFile.parse_number (s.style.get ("stroke-width")); 298 s.stroke = Color.parse (s.style.get ("stroke")); 299 s.fill = Color.parse (s.style.get ("fill")); 300 301 string? opacity = s.style.get ("fill-opacity"); 302 if (opacity != null) { 303 fill_opacity = SvgFile.parse_number ((!) opacity); 304 } 305 306 opacity = s.style.get ("stroke-opacity"); 307 if (opacity != null) { 308 stroke_opacity = SvgFile.parse_number ((!) opacity); 309 } 310 311 if (d != null) { 312 Defs defs = (!) d; 313 314 s.stroke_gradient = defs.get_gradient_for_url (s.style.get ("stroke")); 315 s.fill_gradient = defs.get_gradient_for_url (s.style.get ("fill")); 316 } 317 318 if (s.fill != null) { 319 Color color = (!) s.fill; 320 color.a = fill_opacity; 321 } 322 323 if (s.stroke != null) { 324 Color color = (!) s.stroke; 325 color.a = stroke_opacity; 326 } 327 328 string? v = s.get_css_property ("visibility"); 329 if (v != null) { 330 string visible = (!) v; 331 if (visible == "hidden" || visible == "collapse") { 332 s.visible = false; 333 } 334 } 335 } 336 337 void parse_key_value_pairs (string svg_style) { 338 string[] p = svg_style.strip ().split (";"); 339 string[] pair; 340 string k, v; 341 342 foreach (string kv in p) { 343 if (kv.index_of (":") != -1) { 344 pair = kv.split (":"); 345 346 if (pair.length != 2) { 347 warning ("pair.length != 2 in " + svg_style); 348 continue; 349 } 350 351 k = pair[0].strip ().down (); 352 v = pair[1].strip ().down (); 353 354 if (k == "padding") { 355 parse_padding_shorthand (v); 356 } else if (k == "margin") { 357 parse_margin_shorthand (v); 358 } else { 359 style.set (k, v); 360 } 361 } 362 } 363 } 364 365 void parse_margin_shorthand (string arguments) { 366 string[] args = StyleSheet.replace_whitespace (arguments).split (" "); 367 368 if (args.length > 0) { 369 style.set ("margin-top", args[0]); 370 } 371 372 if (args.length > 1) { 373 style.set ("margin-right", args[1]); 374 } 375 376 if (args.length > 2) { 377 style.set ("margin-bottom", args[2]); 378 } 379 380 if (args.length > 3) { 381 style.set ("margin-left", args[3]); 382 } 383 } 384 385 void parse_padding_shorthand (string arguments) { 386 string[] args = StyleSheet.replace_whitespace (arguments).split (" "); 387 388 if (args.length > 0) { 389 style.set ("padding-top", args[0]); 390 } 391 392 if (args.length > 1) { 393 style.set ("padding-right", args[1]); 394 } 395 396 if (args.length > 2) { 397 style.set ("padding-bottom", args[2]); 398 } 399 400 if (args.length > 3) { 401 style.set ("padding-left", args[3]); 402 } 403 } 404 405 private static void create_inheritance_table () { 406 inheritance = new Gee.HashMap<string, string> (); 407 408 Gee.HashMap<string, string> inherited = (!) inheritance; 409 410 inherited.set ("azimuth", "yes"); 411 inherited.set ("background-attachment", "no"); 412 inherited.set ("background-color", "no"); 413 inherited.set ("background-image", "no"); 414 inherited.set ("background-position", "no"); 415 inherited.set ("background-repeat", "no"); 416 inherited.set ("background", "no"); 417 inherited.set ("border-collapse", "yes"); 418 inherited.set ("border-color", "no"); 419 inherited.set ("border-spacing", "yes"); 420 inherited.set ("border-style", "no"); 421 inherited.set ("border-top", "no"); 422 inherited.set ("border-right", "no"); 423 inherited.set ("border-bottom", "no"); 424 inherited.set ("border-left", "no"); 425 inherited.set ("border-top-color", "no"); 426 inherited.set ("border-right-color", "no"); 427 inherited.set ("border-bottom-color", "no"); 428 inherited.set ("border-left-color", "no"); 429 inherited.set ("border-top-style", "no"); 430 inherited.set ("border-right-style", "no"); 431 inherited.set ("border-bottom-style", "no"); 432 inherited.set ("border-left-style", "no"); 433 inherited.set ("border-top-width", "no"); 434 inherited.set ("border-right-width", "no"); 435 inherited.set ("border-bottom-width", "no"); 436 inherited.set ("border-left-width", "no"); 437 inherited.set ("border-width", "no"); 438 inherited.set ("border", "no"); 439 inherited.set ("bottom", "no"); 440 inherited.set ("caption-side", "yes"); 441 inherited.set ("clear", "no"); 442 inherited.set ("clip", "no"); 443 inherited.set ("color", "yes"); 444 inherited.set ("content", "no"); 445 inherited.set ("counter-increment", "no"); 446 inherited.set ("counter-reset", "no"); 447 inherited.set ("cue-after", "no"); 448 inherited.set ("cue-before", "no"); 449 inherited.set ("cue", "no"); 450 inherited.set ("cursor", "yes"); 451 inherited.set ("direction", "yes"); 452 inherited.set ("display", "no"); 453 inherited.set ("elevation", "yes"); 454 inherited.set ("empty-cells", "yes"); 455 inherited.set ("float", "no"); 456 inherited.set ("font-family", "yes"); 457 inherited.set ("font-size", "yes"); 458 inherited.set ("font-style", "yes"); 459 inherited.set ("font-variant", "yes"); 460 inherited.set ("font-weight", "yes"); 461 inherited.set ("font", "yes"); 462 inherited.set ("height", "no"); 463 inherited.set ("left", "no"); 464 inherited.set ("letter-spacing", "yes"); 465 inherited.set ("line-height", "yes"); 466 inherited.set ("list-style-image", "yes"); 467 inherited.set ("list-style-position", "yes"); 468 inherited.set ("list-style-type", "yes"); 469 inherited.set ("list-style", "yes"); 470 inherited.set ("margin-right", "no"); 471 inherited.set ("margin-left", "no"); 472 inherited.set ("margin-top", "no"); 473 inherited.set ("margin-bottom", "no"); 474 inherited.set ("margin", "no"); 475 inherited.set ("max-height", "no"); 476 inherited.set ("max-width", "no"); 477 inherited.set ("min-height", "no"); 478 inherited.set ("min-width", "no"); 479 inherited.set ("orphans", "yes"); 480 inherited.set ("outline-color", "no"); 481 inherited.set ("outline-style", "no"); 482 inherited.set ("outline-width", "no"); 483 inherited.set ("outline", "no"); 484 inherited.set ("overflow", "no"); 485 inherited.set ("padding-top", "no"); 486 inherited.set ("padding-right", "no"); 487 inherited.set ("padding-bottom", "no"); 488 inherited.set ("padding-left", "no"); 489 inherited.set ("padding", "no"); 490 inherited.set ("page-break-after", "no"); 491 inherited.set ("page-break-before", "no"); 492 inherited.set ("page-break-inside", "no"); 493 inherited.set ("pause-after", "no"); 494 inherited.set ("pause-before", "no"); 495 inherited.set ("pause", "no"); 496 inherited.set ("pitch-range", "yes"); 497 inherited.set ("pitch", "yes"); 498 inherited.set ("play-during", "no"); 499 inherited.set ("position", "no"); 500 inherited.set ("quotes", "yes"); 501 inherited.set ("richness", "yes"); 502 inherited.set ("right", "no"); 503 inherited.set ("speak-header", "yes"); 504 inherited.set ("speak-numeral", "yes"); 505 inherited.set ("speak-punctuation", "yes"); 506 inherited.set ("speak", "yes"); 507 inherited.set ("speech-rate", "yes"); 508 inherited.set ("stress", "yes"); 509 inherited.set ("table-layout", "no"); 510 inherited.set ("text-align", "yes"); 511 inherited.set ("text-decoration", "no"); 512 inherited.set ("text-indent", "yes"); 513 inherited.set ("text-transform", "yes"); 514 inherited.set ("top", "no"); 515 inherited.set ("unicode-bidi", "no"); 516 inherited.set ("vertical-align", "no"); 517 inherited.set ("visibility", "yes"); 518 inherited.set ("voice-family", "yes"); 519 inherited.set ("volume", "yes"); 520 inherited.set ("white-space", "yes"); 521 inherited.set ("widows", "yes"); 522 inherited.set ("width", "no"); 523 inherited.set ("word-spacing", "yes"); 524 inherited.set ("z-index", "no"); 525 } 526 } 527 528 } 529