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.
Rotate boundaries
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 = 1000000; 88 public const double CANVAS_MIN = -1000000; 89 90 public Matrix view_matrix = Matrix.identity (); 91 public Matrix parent_matrix = Matrix.identity (); 92 93 public Object () { 94 } 95 96 public Object.create_copy (Object o) { 97 } 98 99 public virtual bool is_over (double x, double y) { 100 return left <= x <= right && top <= y <= bottom; 101 } 102 103 public void to_object_view (ref double x, ref double y) { 104 Matrix m = view_matrix; 105 m.invert (); 106 m.transform_point (ref x, ref y); 107 } 108 109 public void to_parent_distance (ref double x, ref double y) { 110 Matrix m = parent_matrix; 111 m.invert (); 112 m.transform_distance (ref x, ref y); 113 } 114 115 public void to_parent_view (ref double x, ref double y) { 116 Matrix m = parent_matrix; 117 m.invert (); 118 m.transform_point (ref x, ref y); 119 } 120 121 public void from_object_view (ref double x, ref double y) { 122 Matrix m = view_matrix; 123 m.transform_point (ref x, ref y); 124 } 125 126 public void to_object_distance (ref double x, ref double y) { 127 Matrix m = view_matrix; 128 m.invert (); 129 m.transform_distance (ref x, ref y); 130 } 131 132 public abstract void draw_outline (Context cr); 133 134 public abstract Object copy (); 135 public abstract bool is_empty (); 136 137 public virtual void move (double dx, double dy) { 138 Gradient g; 139 140 left += dx; 141 right += dx; 142 top += dy; 143 bottom += dy; 144 145 if (style.fill_gradient != null) { 146 g = (!) style.fill_gradient; 147 g.move (dx, dy); 148 } 149 150 if (style.stroke_gradient != null) { 151 g = (!) style.stroke_gradient; 152 g.move (dx, dy); 153 } 154 155 to_object_distance (ref dx, ref dy); 156 transforms.translate (dx, dy); 157 158 update_view_matrix (); 159 } 160 161 public void update_view_matrix () { 162 Matrix v = parent_matrix; 163 Matrix m = transforms.get_matrix (); 164 m.multiply (m, v); 165 view_matrix = m; 166 } 167 168 public Matrix get_parent_matrix () { 169 Matrix matrix = view_matrix; 170 Matrix object_matrix = transforms.get_matrix (); 171 object_matrix.invert (); 172 matrix.multiply (matrix, object_matrix); 173 return matrix; 174 } 175 176 public virtual void move_bounding_box (double dx, double dy) { 177 top += dy; 178 bottom += dy; 179 left += dx; 180 right += dx; 181 } 182 183 public static void copy_attributes (Object from, Object to) { 184 to.left = from.left; 185 to.right = from.right; 186 to.top = from.top; 187 to.bottom = from.bottom; 188 189 to.visible = from.visible; 190 to.style = from.style.copy (); 191 to.transforms = from.transforms.copy (); 192 193 if (from.clip_path != null) { 194 to.clip_path = ((!) from.clip_path).copy (); 195 } 196 } 197 198 public virtual string to_string () { 199 return "Object"; 200 } 201 202 public bool is_over_boundaries (double x, double y) { 203 return top <= y <= bottom && left <= x <= right; 204 } 205 206 public void paint (Context cr) { 207 Color fill, stroke; 208 bool need_fill = (style.fill_gradient != null || style.fill != null); 209 bool need_stroke = (style.stroke_gradient != null || style.stroke != null); 210 211 cr.set_line_width (style.stroke_width); 212 213 if (style.fill_gradient != null) { 214 apply_gradient (cr, (!) style.fill_gradient); 215 } else if (style.fill != null) { 216 fill = (!) style.fill; 217 cr.set_source_rgba (fill.r, fill.g, fill.b, fill.a); 218 } 219 220 if (need_fill) { 221 if (need_stroke) { 222 cr.fill_preserve (); 223 } else { 224 cr.fill (); 225 } 226 } 227 228 if (style.stroke_gradient != null) { 229 apply_gradient (cr, (!) style.stroke_gradient); 230 } else if (style.stroke != null) { 231 stroke = (!) style.stroke; 232 cr.set_source_rgba (stroke.r, stroke.g, stroke.b, stroke.a); 233 } 234 235 if (need_stroke) { 236 cr.stroke (); 237 } 238 } 239 240 public void apply_gradient (Context cr, Gradient? gradient) { 241 Cairo.Pattern pattern; 242 Gradient g; 243 LinearGradient linear; 244 RadialGradient radial; 245 246 if (gradient != null) { 247 g = (!) gradient; 248 249 if (g is LinearGradient) { 250 linear = (LinearGradient) g; 251 pattern = new Cairo.Pattern.linear (linear.x1, linear.y1, linear.x2, linear.y2); 252 } else if (g is RadialGradient) { 253 radial = (RadialGradient) g; 254 pattern = new Cairo.Pattern.radial (radial.cx, radial.cy, 0, radial.cx, radial.cy, radial.r); 255 } else { 256 warning ("Unknown gradient."); 257 pattern = new Cairo.Pattern.linear (0, 0, 0, 0); 258 } 259 260 Matrix gradient_matrix = g.get_matrix (); 261 gradient_matrix.invert (); 262 Matrix object_matrix = transforms.get_matrix (); 263 object_matrix.invert (); 264 gradient_matrix.multiply (gradient_matrix, object_matrix); 265 266 pattern.set_matrix (gradient_matrix); 267 268 g.parent_matrix = view_matrix; 269 g.view_matrix = gradient_matrix; 270 271 foreach (Stop s in g.stops) { 272 Color c = s.color; 273 pattern.add_color_stop_rgba (s.offset, c.r, c.g, c.b, c.a); 274 } 275 276 cr.set_source (pattern); 277 } 278 } 279 280 public virtual void apply_transform (Context cr) { 281 Matrix view_matrix = cr.get_matrix (); 282 Matrix object_matrix = transforms.get_matrix (); 283 284 object_matrix.multiply (object_matrix, view_matrix); 285 cr.set_matrix (object_matrix); 286 } 287 288 /** @return true if the object has an area. */ 289 public virtual bool update_boundaries (Context context) { 290 double x0, y0, x1, y1; 291 bool has_stroke = style.has_stroke (); 292 293 context.save (); 294 295 parent_matrix = copy_matrix (context.get_matrix ()); 296 apply_transform (context); 297 298 if (style.fill_gradient != null) { 299 apply_gradient (context, (!) style.fill_gradient); 300 } 301 302 if (style.stroke_gradient != null) { 303 apply_gradient (context, (!) style.stroke_gradient); 304 } 305 306 if (has_stroke) { 307 context.set_line_width (style.stroke_width); 308 } else { 309 context.set_line_width (0); 310 } 311 312 draw_outline (context); 313 314 view_matrix = copy_matrix (context.get_matrix ()); 315 context.set_matrix (Matrix.identity ()); 316 317 if (has_stroke) { 318 context.stroke_extents (out x0, out y0, out x1, out y1); 319 } else { 320 context.fill_extents (out x0, out y0, out x1, out y1); 321 } 322 323 context.fill (); 324 context.restore (); 325 326 left = x0; 327 top = y0; 328 right = x1; 329 bottom = y1; 330 331 return boundaries_width != 0; 332 } 333 334 public Matrix get_view_matrix () { 335 return view_matrix; 336 } 337 338 public virtual bool update_boundaries_for_object () { 339 ImageSurface surface = new Cairo.ImageSurface (Cairo.Format.ARGB32, 1, 1); 340 Context context = new Cairo.Context (surface); 341 context.set_matrix (parent_matrix); 342 return update_boundaries (context); 343 } 344 345 public Matrix copy_matrix (Matrix m) { 346 return new Matrix (m.xx, m.yx, m.xy, m.yy, m.x0, m.y0); 347 } 348 } 349 350 } 351