The Birdfont Source Code


All Repositories / birdfont.git / blob – RSS feed

Object.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

Revisions

View the latest version of libsvgbird/Object.vala.
Parse SVG view box
1 /* 2 Copyright (C) 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 Cairo; 16 using Math; 17 18 namespace SvgBird { 19 20 public abstract class Object : GLib.Object { 21 public bool visible = true; 22 public SvgStyle style = new SvgStyle (); 23 public SvgTransforms transforms = new SvgTransforms (); 24 public ClipPath? clip_path = null; 25 public string id = ""; 26 public string css_class = ""; 27 28 /** Path boundaries */ 29 public virtual double left { get; set; } 30 public virtual double right { get; set; } 31 public virtual double top { get; set; } 32 public virtual double bottom { get; set; } 33 34 public virtual double boundaries_height { 35 get { 36 return bottom - top; 37 } 38 } 39 40 public virtual double boundaries_width { 41 get { 42 return right - left; 43 } 44 } 45 46 /** Cartesian coordinates for the old BirdFont system. */ 47 public double xmax { 48 get { 49 return right; 50 } 51 52 set { 53 right = value; 54 } 55 } 56 57 public double xmin { 58 get { 59 return left; 60 } 61 62 set { 63 left = value; 64 } 65 } 66 67 public double ymin { 68 get { 69 return -top - boundaries_height; 70 } 71 72 set { 73 top = boundaries_height - value; 74 } 75 } 76 77 public double ymax { 78 get { 79 return -top; 80 } 81 82 set { 83 top = -value; 84 } 85 } 86 87 public const double CANVAS_MAX = 100000; 88 public const double CANVAS_MIN = -100000; 89 90 public Object () { 91 } 92 93 public Object.create_copy (Object o) { 94 } 95 96 public abstract bool is_over (double x, double y); 97 public abstract void draw_outline (Context cr); 98 99 public abstract Object copy (); 100 public abstract bool is_empty (); 101 public abstract void move (double dx, double dy); 102 103 public virtual void move_bounding_box (double dx, double dy) { 104 top += dy; 105 bottom += dy; 106 left += dx; 107 right += dx; 108 } 109 110 public static void copy_attributes (Object from, Object to) { 111 to.left = from.left; 112 to.right = from.right; 113 to.top = from.top; 114 to.bottom = from.bottom; 115 116 to.style = from.style.copy (); 117 to.transforms = from.transforms.copy (); 118 119 if (from.clip_path != null) { 120 to.clip_path = ((!) from.clip_path).copy (); 121 } 122 } 123 124 public virtual string to_string () { 125 return "Object"; 126 } 127 128 public void paint (Context cr) { 129 Color fill, stroke; 130 bool need_fill = style.fill_gradient != null || style.fill != null; 131 bool need_stroke = style.stroke_gradient != null || style.stroke != null; 132 133 cr.set_line_width (style.stroke_width); 134 135 if (style.fill_gradient != null) { 136 apply_gradient (cr, (!) style.fill_gradient); 137 } else if (style.fill != null) { 138 fill = (!) style.fill; 139 cr.set_source_rgba (fill.r, fill.g, fill.b, fill.a); 140 } 141 142 if (need_fill) { 143 if (need_stroke) { 144 cr.fill_preserve (); 145 } else { 146 cr.fill (); 147 } 148 } 149 150 if (style.stroke_gradient != null) { 151 apply_gradient (cr, (!) style.stroke_gradient); 152 } else if (style.stroke != null) { 153 stroke = (!) style.stroke; 154 cr.set_source_rgba (stroke.r, stroke.g, stroke.b, stroke.a); 155 } 156 157 if (need_stroke) { 158 cr.stroke (); 159 } 160 } 161 162 public void apply_gradient (Context cr, Gradient? gradient) { 163 Cairo.Pattern pattern; 164 Gradient g; 165 LinearGradient linear; 166 RadialGradient radial; 167 168 if (gradient != null) { 169 g = (!) gradient; 170 171 if (g is LinearGradient) { 172 linear = (LinearGradient) g; 173 pattern = new Cairo.Pattern.linear (linear.x1, linear.y1, linear.x2, linear.y2); 174 } else if (g is RadialGradient) { 175 radial = (RadialGradient) g; 176 pattern = new Cairo.Pattern.radial (radial.cx, radial.cy, 0, radial.cx, radial.cy, radial.r); 177 } else { 178 warning ("Unknown gradient."); 179 pattern = new Cairo.Pattern.linear (0, 0, 0, 0); 180 } 181 182 Matrix gradient_matrix = g.get_matrix (); 183 gradient_matrix.invert (); 184 pattern.set_matrix (gradient_matrix); 185 186 foreach (Stop s in g.stops) { 187 Color c = s.color; 188 pattern.add_color_stop_rgba (s.offset, c.r, c.g, c.b, c.a); 189 } 190 191 cr.set_source (pattern); 192 } 193 } 194 195 public void apply_transform (Context cr) { 196 Matrix view_matrix = cr.get_matrix (); 197 Matrix object_matrix = transforms.get_matrix (); 198 199 object_matrix.multiply (object_matrix, view_matrix); 200 cr.set_matrix (object_matrix); 201 } 202 203 /** @return true if the object has an area. */ 204 public virtual bool update_boundaries (Context context) { 205 double x0, y0, x1, y1; 206 bool has_stroke = style.has_stroke (); 207 208 if (has_stroke) { 209 context.set_line_width (style.stroke_width); 210 } else { 211 context.set_line_width (0); 212 } 213 214 draw_outline (context); 215 216 context.save (); 217 218 context.set_matrix (Matrix.identity ()); 219 220 if (has_stroke) { 221 context.stroke_extents (out x0, out y0, out x1, out y1); 222 } else { 223 context.fill_extents (out x0, out y0, out x1, out y1); 224 } 225 226 context.restore (); 227 228 left = x0; 229 top = y0; 230 right = x1; 231 bottom = y1; 232 233 return boundaries_width != 0; 234 } 235 236 public virtual bool update_boundaries_for_object () { 237 ImageSurface surface = new Cairo.ImageSurface (Cairo.Format.ARGB32, 1, 1); 238 Context context = new Cairo.Context (surface); 239 return update_boundaries (context); 240 } 241 242 } 243 244 } 245