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