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.
Fix gradient matrix
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 Matrix view_matrix = Matrix.identity (); 104 105 public virtual void move_bounding_box (double dx, double dy) { 106 top += dy; 107 bottom += dy; 108 left += dx; 109 right += dx; 110 } 111 112 public static void copy_attributes (Object from, Object to) { 113 to.left = from.left; 114 to.right = from.right; 115 to.top = from.top; 116 to.bottom = from.bottom; 117 118 to.visible = from.visible; 119 to.style = from.style.copy (); 120 to.transforms = from.transforms.copy (); 121 122 if (from.clip_path != null) { 123 to.clip_path = ((!) from.clip_path).copy (); 124 } 125 } 126 127 public virtual string to_string () { 128 return "Object"; 129 } 130 131 public void paint (Context cr) { 132 Color fill, stroke; 133 bool need_fill = (style.fill_gradient != null || style.fill != null); 134 bool need_stroke = (style.stroke_gradient != null || style.stroke != null); 135 136 cr.set_line_width (style.stroke_width); 137 138 if (style.fill_gradient != null) { 139 apply_gradient (cr, (!) style.fill_gradient); 140 } else if (style.fill != null) { 141 fill = (!) style.fill; 142 cr.set_source_rgba (fill.r, fill.g, fill.b, fill.a); 143 } 144 145 if (need_fill) { 146 if (need_stroke) { 147 cr.fill_preserve (); 148 } else { 149 cr.fill (); 150 } 151 } 152 153 if (style.stroke_gradient != null) { 154 apply_gradient (cr, (!) style.stroke_gradient); 155 } else if (style.stroke != null) { 156 stroke = (!) style.stroke; 157 cr.set_source_rgba (stroke.r, stroke.g, stroke.b, stroke.a); 158 } 159 160 if (need_stroke) { 161 cr.stroke (); 162 } 163 } 164 165 public void apply_gradient (Context cr, Gradient? gradient) { 166 Cairo.Pattern pattern; 167 Gradient g; 168 LinearGradient linear; 169 RadialGradient radial; 170 171 if (gradient != null) { 172 g = (!) gradient; 173 174 if (g is LinearGradient) { 175 linear = (LinearGradient) g; 176 pattern = new Cairo.Pattern.linear (linear.x1, linear.y1, linear.x2, linear.y2); 177 } else if (g is RadialGradient) { 178 radial = (RadialGradient) g; 179 pattern = new Cairo.Pattern.radial (radial.cx, radial.cy, 0, radial.cx, radial.cy, radial.r); 180 } else { 181 warning ("Unknown gradient."); 182 pattern = new Cairo.Pattern.linear (0, 0, 0, 0); 183 } 184 185 Matrix gradient_matrix = g.get_matrix (); 186 gradient_matrix.invert (); 187 Matrix object_matrix = transforms.get_matrix (); 188 object_matrix.invert (); 189 gradient_matrix.multiply (gradient_matrix, object_matrix); 190 191 pattern.set_matrix (gradient_matrix); 192 193 g.view_matrix = gradient_matrix; 194 195 foreach (Stop s in g.stops) { 196 Color c = s.color; 197 pattern.add_color_stop_rgba (s.offset, c.r, c.g, c.b, c.a); 198 } 199 200 cr.set_source (pattern); 201 } 202 } 203 204 public virtual void apply_transform (Context cr) { 205 Matrix view_matrix = cr.get_matrix (); 206 Matrix object_matrix = transforms.get_matrix (); 207 208 object_matrix.multiply (object_matrix, view_matrix); 209 cr.set_matrix (object_matrix); 210 } 211 212 /** @return true if the object has an area. */ 213 public virtual bool update_boundaries (Context context) { 214 double x0, y0, x1, y1; 215 bool has_stroke = style.has_stroke (); 216 217 if (has_stroke) { 218 context.set_line_width (style.stroke_width); 219 } else { 220 context.set_line_width (0); 221 } 222 223 draw_outline (context); 224 225 context.save (); 226 227 context.set_matrix (Matrix.identity ()); 228 229 if (has_stroke) { 230 context.stroke_extents (out x0, out y0, out x1, out y1); 231 } else { 232 context.fill_extents (out x0, out y0, out x1, out y1); 233 } 234 235 context.restore (); 236 237 left = x0; 238 top = y0; 239 right = x1; 240 bottom = y1; 241 242 return boundaries_width != 0; 243 } 244 245 public Matrix get_view_matrix () { 246 return view_matrix; 247 } 248 249 public virtual bool update_boundaries_for_object () { 250 ImageSurface surface = new Cairo.ImageSurface (Cairo.Format.ARGB32, 1, 1); 251 Context context = new Cairo.Context (surface); 252 return update_boundaries (context); 253 } 254 255 } 256 257 } 258