The Birdfont Source Code


All Repositories / birdfont.git / commitdiff – RSS feed

Clipping of SVG paths

These changes was commited to the Birdfont repository Fri, 15 Jan 2016 20:15:15 +0000.

Contributing

Send patches or pull requests to johan.mattsson.m@gmail.com.
Clone this repository: git clone https://github.com/johanmattssonm/birdfont.git
[Fri, 15 Jan 2016 20:15:15 +0000]

Updated Files

birdui/Component.vala
libbirdfont/EmbeddedSvg.vala
libbirdfont/Glyph.vala
libbirdfont/PathObject.vala
libsvgbird/Circle.vala
libsvgbird/Defs.vala
libsvgbird/Ellipse.vala
libsvgbird/Layer.vala
libsvgbird/Line.vala
libsvgbird/Object.vala
libsvgbird/Polygon.vala
libsvgbird/Polyline.vala
libsvgbird/Rectangle.vala
libsvgbird/Selector.vala
libsvgbird/SelectorPattern.vala
libsvgbird/SelectorTag.vala
libsvgbird/StyleSheet.vala
libsvgbird/SvgDrawing.vala
libsvgbird/SvgFile.vala
libsvgbird/SvgPath.vala
libsvgbird/SvgStyle.vala
--- a/birdui/Component.vala +++ b/birdui/Component.vala @@ -52,23 +52,39 @@ string? css_class = null; string? id = null; + + Overflow overflow = Overflow.VISIBLE; public Component (XmlElement component_tag, Defs defs) { this.defs = defs; this.component_tag = component_tag; + set_identification (); parse (component_tag); } public Component.embedded (XmlElement component_tag, Defs defs) { this.defs = defs; this.component_tag = component_tag; + set_identification (); + } + + void set_identification () { + foreach (Attribute attribute in component_tag.get_attributes ()) { + string attribute_name = attribute.get_name (); + + if (attribute_name == "id") { + id = attribute.get_content (); + } else if (attribute_name == "class") { + css_class = attribute.get_content (); + } + } } public Component.load (string file_name) { load_file (file_name); } - private void inherit_style (Defs defs) { + private void inherit_styles_sheet (Defs defs) { this.defs = defs; } @@ -76,12 +92,9 @@ } protected void parse_style (XmlElement style_tag) { - Defs definitions = new Defs (); - definitions.style_sheet = StyleSheet.parse (definitions, style_tag); - - Defs subscope_definitions = defs.shallow_copy (); - subscope_definitions.style_sheet.merge (definitions.style_sheet); - defs = subscope_definitions; + defs = defs.shallow_copy (); + StyleSheet style_sheet = StyleSheet.parse (defs, style_tag); + defs.style_sheet.merge (style_sheet); } protected void parse_svg (XmlElement svg_tag) { @@ -90,7 +103,7 @@ if (attribute_name == "file") { string file_name = attribute.get_content (); - SvgComponent svg = new SvgComponent (component_tag, defs, file_name); + SvgComponent svg = new SvgComponent (svg_tag, defs, file_name); add_component (svg); } } @@ -98,36 +111,47 @@ protected void add_component (Component component) { components.add (component); - component.inherit_style (defs); - component.style = SvgStyle.parse (defs, style, (!) component.component_tag); + component.inherit_styles_sheet (defs); + component.style = SvgStyle.parse (defs, style, component.component_tag); + + component.set_overflow_property_from_css (); + component.set_identification (); + } + + protected void set_overflow_property_from_css () { + string? css_overflow = style.get_css_property ("overflow"); + + if (css_overflow != null) { + string overflow_property = (!) css_overflow; + + if (overflow_property == "hidden") { + overflow = Overflow.HIDDEN; + } else if (overflow_property == "visible") { + overflow = Overflow.VISIBLE; + } + } } protected void parse_layout (XmlElement layout_tag) { - bool parse_style = false; + string type = ""; foreach (Attribute attribute in layout_tag.get_attributes ()) { string attribute_name = attribute.get_name (); if (attribute_name == "type") { - if (attribute.get_content () == "hbox") { - HBox hbox = new HBox (layout_tag, defs); - add_component (hbox); - } else if (attribute.get_content () == "vbox") { - VBox hbox = new VBox (layout_tag, defs); - add_component (hbox); - } else { - warning ("Layout of type " + attribute.get_content () - + " is not implemented in this verison."); - } - } else if (attribute_name == "id") { - id = attribute.get_content (); - } else if (attribute_name == "class") { - css_class = attribute.get_content (); - } else if (attribute_name == "style") { - // style will be parsed later in add_component - } else { - unused_attribute (attribute_name); + type = attribute.get_content (); } + } + + if (type == "hbox") { + HBox hbox = new HBox (layout_tag, defs); + add_component (hbox); + } else if (type == "vbox") { + VBox vbox = new VBox (layout_tag, defs); + add_component (vbox); + } else { + warning ("Layout of type " + type + + " is supported in this verison."); } } @@ -237,6 +261,12 @@ foreach (Component component in components) { cairo.save (); cairo.translate (component.x, component.y); + + if (component.overflow == Overflow.HIDDEN) { + cairo.rectangle (0, 0, component.width, component.height); + cairo.clip (); + } + component.draw (cairo); cairo.restore (); }
--- a/libbirdfont/EmbeddedSvg.vala +++ b/libbirdfont/EmbeddedSvg.vala @@ -76,7 +76,7 @@ && (this.y - drawing.height <= y <= this.y); } - public override void draw (Context cr) { + public override void draw_outline (Context cr) { cr.save (); cr.translate (Glyph.xc () + x, Glyph.yc () - y); drawing.draw (cr);
--- a/libbirdfont/Glyph.vala +++ b/libbirdfont/Glyph.vala @@ -1857,7 +1857,7 @@ g.add_line (line.copy ()); } - g.layers = layers.copy (); + g.layers = (Layer) layers.copy (); foreach (SvgBird.Object o in active_paths) { g.active_paths.add (o); @@ -1930,7 +1930,7 @@ void set_glyph_data (Glyph g) { current_layer = g.current_layer; - layers = g.layers.copy (); + layers = (Layer) g.layers.copy (); left_limit = g.left_limit; right_limit = g.right_limit;
--- a/libbirdfont/PathObject.vala +++ b/libbirdfont/PathObject.vala @@ -88,7 +88,7 @@ return path.is_over_coordinate (x, y); } - public override void draw (Context cr) { + public override void draw_outline (Context cr) { draw_path (cr); }
--- a/libsvgbird/Circle.vala +++ b/libsvgbird/Circle.vala @@ -36,12 +36,8 @@ return false; } - public override void draw (Context cr) { - cr.save (); + public override void draw_outline (Context cr) { cr.arc (cx, cy, r, 0, 2 * Math.PI); - apply_transform (cr); - paint (cr); - cr.restore (); } public override void move (double dx, double dy) {
--- a/libsvgbird/Defs.vala +++ b/libsvgbird/Defs.vala @@ -18,42 +18,71 @@ namespace SvgBird { public class Defs { + public Gee.ArrayList<ClipPath> clip_paths = new Gee.ArrayList<ClipPath> (); public Gee.ArrayList<Gradient> gradients = new Gee.ArrayList<Gradient> (); public StyleSheet style_sheet = new StyleSheet (); public void add (Gradient g) { gradients.add (g); } - - public Gradient? get_gradient_for_url (string? url) { + + public ClipPath? get_clip_path_for_url (string? url) { if (url == null) { return null; } - string tag_id = (!) url; - - if (unlikely (!is_url (tag_id))) { - return null; + string tag_id = get_id_from_url ((!) url); + return get_clip_path_for_id (tag_id); + } + + public ClipPath? get_clip_path_for_id (string id) { + string tag_id; + + if (id.has_prefix ("#")) { + tag_id = id.substring ("#".length); + } else { + tag_id = id; + } + + foreach (ClipPath clip_path in clip_paths) { + if (clip_path.id == tag_id) { + return clip_path; + } + } + + return null; + } + + public static string get_id_from_url (string url) { + if (unlikely (!is_url (url))) { + return ""; } - int p1 = tag_id.index_of ("("); + int p1 = url.index_of ("("); if (unlikely (p1 == -1)) { - warning ("Not an URL: " + tag_id); - return null; + warning ("Not an URL: " + url); + return ""; } - int p2 = tag_id.index_of (")"); + int p2 = url.index_of (")"); if (unlikely (p2 == -1 || p2 < p1)) { - warning ("Not an URL: " + tag_id); - return null; + warning ("Not an URL: " + url); + return ""; } p1 += "(".length; int length = p2 - p1; - tag_id = tag_id.substring (p1, length); + return url.substring (p1, length); + } + + public Gradient? get_gradient_for_url (string? url) { + if (url == null) { + return null; + } + string tag_id = get_id_from_url ((!) url); return get_gradient_for_id (tag_id); - } + } public Gradient? get_gradient_for_id (string id) { string tag_id;
--- a/libsvgbird/Ellipse.vala +++ b/libsvgbird/Ellipse.vala @@ -39,17 +39,12 @@ return false; } - public override void draw (Context cr) { + public override void draw_outline (Context cr) { cr.save (); cr.translate (cx, cy); cr.scale (rx, ry); cr.arc (0, 0, 1, 0, 2 * PI); - cr.restore (); - - cr.save (); - apply_transform (cr); - paint (cr); - cr.restore (); + cr.restore (); } public override void move (double dx, double dy) {
--- a/libsvgbird/Layer.vala +++ b/libsvgbird/Layer.vala @@ -11,18 +11,17 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. */ + + using Cairo; namespace SvgBird { - public class Layer : GLib.Object { + public class Layer : Object { public ObjectGroup objects; - public Gee.ArrayList<Layer> subgroups; - public bool visible = true; + public Gee.ArrayList<Layer> subgroups; // FIXME: delete public string name = "Layer"; - - public SvgTransforms transforms; - + public Layer () { objects = new ObjectGroup (); subgroups = new Gee.ArrayList<Layer> (); @@ -86,16 +85,17 @@ public static void copy_layer (Layer from, Layer to) { to.name = from.name; to.objects = from.objects.copy (); - to.visible = from.visible; foreach (Layer l in from.subgroups) { - to.subgroups.add (l.copy ()); + Layer layer = (Layer) l.copy (); + to.subgroups.add (layer); } } - - public Layer copy () { + + public override Object copy () { Layer layer = new Layer (); copy_layer (this, layer); + Object.copy_attributes (this, layer); return layer; } @@ -164,8 +164,39 @@ stdout.printf ("%s\n", l.name); l.print (indent + 1); } + } + + + public override bool is_over (double x, double y) { + return false; + } + + public override void draw_outline (Context cr) { + foreach (Object object in objects) { + object.draw_outline (cr); + } + } + + public override void move (double dx, double dy) { + } + + public override void update_region_boundaries () { + } + + public override void rotate (double theta, double xc, double yc) { + } + + public override bool is_empty () { + return false; + } + + public override void resize (double ratio_x, double ratio_y) { + } + + public override string to_string () { + return "Layer: " + name; } } }
--- a/libsvgbird/Line.vala +++ b/libsvgbird/Line.vala @@ -38,14 +38,10 @@ return false; } - public override void draw (Context cr) { - cr.save (); + public override void draw_outline (Context cr) { cr.move_to (x1, y1); cr.line_to (x1, y1); cr.line_to (x2, y2); - apply_transform (cr); - paint (cr); - cr.restore (); } public override void move (double dx, double dy) {
--- a/libsvgbird/Object.vala +++ b/libsvgbird/Object.vala @@ -23,6 +23,9 @@ public bool visible = true; public SvgStyle style = new SvgStyle (); public SvgTransforms transforms = new SvgTransforms (); + public ClipPath? clip_path = null; + public string id = ""; + public string css_class = ""; public virtual Color? color { get; set; } // FIXME: keep this in svg style public virtual Color? stroke_color { get; set; } @@ -56,7 +59,22 @@ public abstract void update_region_boundaries (); public abstract bool is_over (double x, double y); - public abstract void draw (Context cr); + public abstract void draw_outline (Context cr); + + public void draw (Context cr) { + cr.save (); + apply_transform (cr); + + if (clip_path != null) { + ClipPath clipping = (!) clip_path; + clipping.apply (cr); + } + + draw_outline (cr); + paint (cr); + cr.restore (); + } + public abstract Object copy (); public abstract void move (double dx, double dy); public abstract void rotate (double theta, double xc, double yc);
--- a/libsvgbird/Polygon.vala +++ b/libsvgbird/Polygon.vala @@ -27,11 +27,8 @@ public override bool is_over (double x, double y) { return false; } - - public override void draw (Context cr) { - cr.save (); - apply_transform (cr); - + + public override void draw_outline (Context cr) { if (points.size > 2) { cr.move_to (points.data[0].value, points.data[1].value); @@ -40,10 +37,7 @@ } cr.close_path (); - } - - paint (cr); - cr.restore (); + } } public override void move (double dx, double dy) {
--- a/libsvgbird/Polyline.vala +++ b/libsvgbird/Polyline.vala @@ -28,10 +28,7 @@ return false; } - public override void draw (Context cr) { - cr.save (); - apply_transform (cr); - + public override void draw_outline (Context cr) { if (points.size > 2) { cr.move_to (points.data[0].value, points.data[1].value); @@ -39,9 +36,6 @@ cr.line_to (points.data[i].value, points.data[i + 1].value); } } - - paint (cr); - cr.restore (); } public override void move (double dx, double dy) {
--- a/libsvgbird/Rectangle.vala +++ b/libsvgbird/Rectangle.vala @@ -33,18 +33,12 @@ return false; } - public override void draw (Context cr) { - cr.save (); - apply_transform (cr); - + public override void draw_outline (Context cr) { if (rx == 0 && ry == 0) { cr.rectangle (x, y, width, height); } else { draw_rounded_corners (cr); } - - paint (cr); - cr.restore (); } public void draw_rounded_corners (Context cr) {
--- a/libsvgbird/Selector.vala +++ b/libsvgbird/Selector.vala @@ -36,8 +36,22 @@ style = selector.style.copy (); foreach (SelectorPattern pattern in selector.patterns) { - selector.patterns.add (pattern.copy ()); + patterns.add (pattern.copy ()); } + } + + public string to_string () { + StringBuilder s = new StringBuilder (); + + foreach (SelectorPattern pattern in patterns) { + if (s.str != "") { + s.append (", "); + } + + s.append (pattern.to_string ()); + } + + return s.str; } public Selector copy () {
--- a/libsvgbird/SelectorPattern.vala +++ b/libsvgbird/SelectorPattern.vala @@ -23,7 +23,7 @@ public SelectorPattern.empty () { } - + public SelectorPattern (string pattern) { string p = pattern.strip (); string[] elements = p.split (" "); @@ -34,7 +34,20 @@ } } } - + + public string to_string () { + StringBuilder s = new StringBuilder (); + + foreach (SelectorTag tag in tags) { + if (s.str != "") { + s.append (" "); + } + + s.append (tag.to_string ()); + } + + return s.str; + } public SelectorPattern copy () { SelectorPattern pattern = new SelectorPattern.empty ();
--- a/libsvgbird/SelectorTag.vala +++ b/libsvgbird/SelectorTag.vala @@ -63,7 +63,7 @@ } } } - + public SelectorTag copy () { SelectorTag tag = new SelectorTag.empty();
--- a/libsvgbird/StyleSheet.vala +++ b/libsvgbird/StyleSheet.vala @@ -20,10 +20,9 @@ public class StyleSheet : GLib.Object { - public Gee.ArrayList<Selector> styles; + public Gee.ArrayList<Selector> styles = new Gee.ArrayList<Selector> (); public StyleSheet () { - styles = new Gee.ArrayList<Selector> (); } /** Copy references to all selectors in this style sheet. */ @@ -70,7 +69,7 @@ public void merge (StyleSheet style_sheet) { foreach (Selector selector in style_sheet.styles) { - styles.add (selector); + styles.add (selector.copy ()); } }
--- a/libsvgbird/SvgDrawing.vala +++ b/libsvgbird/SvgDrawing.vala @@ -25,7 +25,19 @@ public double x = 0; public double y = 0; - public double width = 0; + + public double width { + get { + return svg_width; + } + + set { + svg_width = value; + } + } + public double svg_width = 0; + + public double height = 0; public override void update_region_boundaries () { @@ -36,21 +48,27 @@ && (this.y <= y <= this.y + height); } - public override void draw (Context cr) { + public override void draw_outline (Context cr) { cr.save (); cr.translate (x, y); - + root_layer.draw_outline (cr); + + // FIXME: update layer structure foreach (Object o in root_layer.get_visible_objects ().objects) { o.draw (cr); } - + cr.restore (); } public override Object copy () { SvgDrawing drawing = new SvgDrawing (); - drawing.root_layer = root_layer.copy (); + drawing.root_layer = (Layer) root_layer.copy (); drawing.defs = defs.copy (); + drawing.x = x; + drawing.y = y; + drawing.width = width; + drawing.height = height; return drawing; } @@ -67,8 +85,12 @@ } public override void resize (double ratio_x, double ratio_y) { + } + + public override string to_string () { + return @"SvgDrawing x: $x, y: $y, width: $width, height: $height"; } } }
--- a/libsvgbird/SvgFile.vala +++ b/libsvgbird/SvgFile.vala @@ -24,7 +24,7 @@ public SvgFile () { } - + public SvgDrawing parse_svg_data (string xml_data) { XmlTree tree = new XmlTree (xml_data); return parse_svg_file (tree.get_root ()); @@ -63,31 +63,13 @@ parse_object (drawing.root_layer, style, t); } + + set_object_properties (drawing, new SvgStyle (), svg_tag); return drawing; } - private void parse_layer (Layer layer, SvgStyle parent_style, XmlElement tag) { - bool hidden = false; - - foreach (Attribute attr in tag.get_attributes ()) { - if (attr.get_name () == "display" && attr.get_content () == "none") { - hidden = true; - } - - if (attr.get_name () == "visibility" - && (attr.get_content () == "hidden" - || attr.get_content () == "collapse")) { - hidden = true; - } - } - - if (hidden) { - layer.visible = !hidden; - } - - SvgStyle style = SvgStyle.parse (drawing.defs, parent_style, tag); - + private void parse_layer (Layer layer, SvgStyle parent_style, XmlElement tag) { foreach (XmlElement t in tag) { string name = t.get_name (); @@ -98,17 +80,23 @@ } if (name == "a") { - parse_link (layer, style, t); + parse_link (layer, parent_style, t); } - parse_object (layer, style, t); + parse_object (layer, parent_style, t); } - foreach (Attribute attr in tag.get_attributes ()) { - if (attr.get_name () == "transform") { - layer.transforms = parse_transform (attr.get_content ()); - } - } + set_object_properties (layer, parent_style, tag); + } + + void parse_clip_path (SvgDrawing drawing, XmlElement tag) { + ClipPath clip_path; + + Layer layer = new Layer (); + parse_layer (layer, new SvgStyle (), tag); + clip_path = new ClipPath (layer); + + drawing.defs.clip_paths.add (clip_path); } void parse_defs (SvgDrawing drawing, XmlElement tag) { @@ -118,6 +106,8 @@ if (name == "linearGradient") { parse_linear_gradient (drawing, t); + } else if (name == "clipPath") { + parse_clip_path (drawing, t); } } @@ -284,12 +274,37 @@ } } - polygon.transforms = get_transform (tag.get_attributes ()); - polygon.style = SvgStyle.parse (drawing.defs, parent_style, tag); - polygon.visible = is_visible (tag); - + set_object_properties (polygon, parent_style, tag); layer.add_object (polygon); - + } + + void set_object_properties (Object object, SvgStyle parent_style, XmlElement tag) { + Attributes attributes = tag.get_attributes (); + + foreach (Attribute attribute in attributes) { + string name = attribute.get_name (); + + if (name == "id") { + object.id = attribute.get_content (); + } else if (name == "class") { + object.css_class = attribute.get_content (); + } + } + + object.clip_path = get_clip_path (attributes); + object.transforms = get_transform (attributes); + object.style = SvgStyle.parse (drawing.defs, parent_style, tag); + object.visible = is_visible (tag); + } + + ClipPath? get_clip_path (Attributes attributes) { + foreach (Attribute attribute in attributes) { + if (attribute.get_name () == "clip-path") { + return drawing.defs.get_clip_path_for_url (attribute.get_content ()); + } + } + + return null; } private void parse_polyline (Layer layer, SvgStyle parent_style, XmlElement tag) { @@ -306,10 +321,7 @@ } } - polyline.transforms = get_transform (tag.get_attributes ()); - polyline.style = SvgStyle.parse (drawing.defs, parent_style, tag); - polyline.visible = is_visible (tag); - + set_object_properties (polyline, parent_style, tag); layer.add_object (polyline); } @@ -344,10 +356,7 @@ } } - rectangle.transforms = get_transform (tag.get_attributes ()); - rectangle.style = SvgStyle.parse (drawing.defs, parent_style, tag); - rectangle.visible = is_visible (tag); - + set_object_properties (rectangle, parent_style, tag); layer.add_object (rectangle); } @@ -370,10 +379,7 @@ } } - circle.transforms = get_transform (tag.get_attributes ()); - circle.style = SvgStyle.parse (drawing.defs, parent_style, tag); - circle.visible = is_visible (tag); - + set_object_properties (circle, parent_style, tag); layer.add_object (circle); } @@ -400,10 +406,7 @@ } } - ellipse.transforms = get_transform (tag.get_attributes ()); - ellipse.style = SvgStyle.parse (drawing.defs, parent_style, tag); - ellipse.visible = is_visible (tag); - + set_object_properties (ellipse, parent_style, tag); layer.add_object (ellipse); } @@ -430,10 +433,7 @@ } } - line.transforms = get_transform (tag.get_attributes ()); - line.style = SvgStyle.parse (drawing.defs, parent_style, tag); - line.visible = is_visible (tag); - + set_object_properties (line, parent_style, tag); layer.add_object (line); } @@ -627,10 +627,7 @@ } } - path.transforms = get_transform (tag.get_attributes ()); - path.style = SvgStyle.parse (drawing.defs, parent_style, tag); - path.visible = is_visible (tag); - + set_object_properties (path, parent_style, tag); layer.add_object (path); } @@ -684,7 +681,6 @@ double angle_extent; double center_x; double center_y; - //double rotation = Math.PI * (b.angle / 180.0); double rotation = b.angle; get_arc_arguments (b.x0, b.y0, b.rx, b.ry,
--- a/libsvgbird/SvgPath.vala +++ b/libsvgbird/SvgPath.vala @@ -30,10 +30,7 @@ return false; } - public override void draw (Context cr) { - cr.save (); - cr.new_path (); - + public override void draw_outline (Context cr) { foreach (Points p in points) { cr.move_to (p.x, p.y); draw_points (cr, p); @@ -42,10 +39,6 @@ cr.close_path (); } } - - apply_transform (cr); - paint (cr); - cr.restore (); } public void draw_points (Context cr, Points path) {
--- a/libsvgbird/SvgStyle.vala +++ b/libsvgbird/SvgStyle.vala @@ -31,6 +31,17 @@ private static Mutex inheritance_mutex = new Mutex (); public SvgStyle () { + } + + public bool property_equals (string property, string value) { + string? p = get_css_property (property); + + if (p == null) { + return false; + } + + string css_property = (!) p; + return css_property == value; } public bool has_css_property (string property) { @@ -85,7 +96,7 @@ public SvgStyle copy () { SvgStyle style = new SvgStyle (); - style.inherit (this); + style.apply (this); return style; }