require 'test/spec' # gem install test-spec require 'builder' require 'rexml/document' require 'svgtidy' describe "path" do it "should round" do tidy { |svg| svg.path :d => "M-3.7,-2.3 l7.1,8.9" }.elements['path/@d'].value.should == "M-4-2l7,9" end it "should truncate trailing zeros" do tidy(:grid=>false) { |svg| svg.path :d => "M-3.7,-2.0 l7.0,8.9" }.elements['path/@d'].value.should == "M-3.7-2l7,8.9" end it "should convert absolute segments to relative ones" do tidy { |svg| svg.path :d => "M10,20 L50,60" }.elements['path/@d'].value.should == "M10,20l40,40" end it "should convert absolute segments to relative ones" do tidy(:absolute=>true, :grid=>true) { |svg| svg.path :d => "M10,20 L50,60" }.elements['path/@d'].value.should == "M10,20L50,60" end it "should detect vertical lines" do tidy { |svg| svg.path :d => "M10,20 L10,60" }.elements['path/@d'].value.should == "M10,20v40" end it "should detect horizontal lines" do tidy { |svg| svg.path :d => "M10,20 L40,20" }.elements['path/@d'].value.should == "M10,20h30" end it "should eliminate empty segments" do tidy { |svg| svg.path :d => "M10,20 L10.2,20.2 L40,20" }.elements['path/@d'].value.should == "M10,20h30" end it "should eliminate last segment in a polygon" do tidy { |svg| svg.path :d => "M0,0 L0,10 L10,10 L0,0 Z" }.elements['path/@d'].value.should == "M0,0v10h10z" end it "should collapse straight curves" do tidy { |svg| svg.path :d => "M10,20 C20,20 30,20 40,20" }.elements['path/@d'].value.should == "M10,20h30" end it "should do quadratic Bezier curves" do tidy { |svg| svg.path :d => "M200,300 Q400,50 600,300 T1000,300" }.elements['path/@d'].value.should == "M200,300q200-250,400,0t400,0" end end describe "rect" do it "should scale x" do tidy { |svg| svg.g :transform => "scale(2)" do svg.rect :x => "10", :y => "20.8" end }.elements['g/rect/@x'].value.should == "20" end it "should scale y" do tidy { |svg| svg.g :transform => "scale(2)" do svg.rect :x => "10", :y => "20.8" end }.elements['g/rect/@y'].value.should == "42" end it "should scale width" do tidy { |svg| svg.g :transform => "scale(2)" do svg.rect :width => "10", :height => "20.8" end }.elements['g/rect/@width'].value.should == "20" end it "should scale height" do tidy { |svg| svg.g :transform => "scale(2)" do svg.rect :width => "10", :height => "20.8" end }.elements['g/rect/@height'].value.should == "42" end end describe "transform" do it "should matrix" do tidy { |svg| svg.g :transform => "matrix(0 1 1 0 1 2)" do svg.path :d => "M10,20" end }.elements['g/path/@d'].value.should == "M21,12" end it "should translate" do tidy { |svg| svg.g :transform => "translate(-5 +5)" do svg.path :d => "M10,20" end }.elements['g/path/@d'].value.should == "M5,25" end it "should scale" do tidy { |svg| svg.g :transform => "scale(2)" do svg.path :d => "M10,20" end }.elements['g/path/@d'].value.should == "M20,40" end it "should stretch" do tidy { |svg| svg.g :transform => "scale(2,3)" do svg.path :d => "M10,20" end }.elements['g/path/@d'].value.should == "M20,60" end it "should rotate" do tidy { |svg| svg.g :transform => "rotate(30)" do svg.path :d => "M-50,0h100" end }.elements['g/path/@d'].value.should == "M-43-25l86,50" end it "should compose" do tidy { |svg| svg.g :transform => "translate(-10,-10) scale(2)" do svg.path :d => "M10,20" end }.elements['g/path/@d'].value.should == "M10,30" end it "should nest" do tidy { |svg| svg.g :transform => "translate(-10,-10)" do svg.g :transform => "scale(2)" do svg.path :d => "M10,20" end end }.elements['g/g/path/@d'].value.should == "M10,30" end it "should curve" do tidy { |svg| svg.g :transform => "scale(2)" do svg.path :d => "M0,0c10,15,20,30,40,40" end }.elements['g/path/@d'].value.should == "M0,0c20,30,40,60,80,80" end end describe "redundancy elimination" do it "should remove stop-opacity:1" do tidy { |svg| svg.path 'stop-opacity' => '1' }.elements['path/@stop-opacity'].should == nil end it "should remove stroke-* when stroke='none'" do tidy { |svg| svg.path 'stroke' => 'none', 'stroke-linejoin' => 'miter' }.elements['path/@stroke-linejoin'].should == nil end end describe "viewBox" do it "should resize" do tidy(:size=>100) { |svg| svg.svg :viewBox => '0 0 200 800' }.elements['@viewBox'].value.should == "0 0 50 200" end it "should translate" do tidy(:size=>100, :grid=>true) { |svg| svg.svg :viewBox => '-50 -50 100 100' do svg.path :d => "M10,20" end }.elements['path/@d'].value.should == "M60,70" end it "should scale" do tidy(:size=>100, :grid=>true) { |svg| svg.svg :viewBox => '0 0 50 50' do svg.path :d => "M10,20" end }.elements['path/@d'].value.should == "M20,40" end it "should treat height, width as a viewBox" do tidy(:size=>100) { |svg| svg.svg :width => '200', :height => '800' }.elements['@viewBox'].value.should == "0 0 50 200" end end describe "polygon" do it "should become path" do tidy { |svg| svg.polygon :points => "10,20 20,30 20,40 10,50" }.elements['path/@d'].value.should == "M10,20l10,10v10l-10,10z" end end describe "style" do it "should convert known attributes to attributes" do tidy { |svg| svg.path :style => "color:#F00" }.elements['path/@color'].value.should == "#F00" end it "should leave unknown attributes as style properties" do tidy { |svg| svg.path :style => "color:#F00;position:absolute" }.elements['path/@style'].value.should == "position:absolute" end it "should delete style attribute if all properties are known" do tidy { |svg| svg.path :style => "color:#F00" }.elements['path/@style'].should == nil end end describe "strip inkscape" do it "should remove inkscape namespace" do tidy(:strip_inkscape => true) { |svg| svg.svg "xmlns:inkscape" => "http://www.inkscape.org/namespaces/inkscape" }.attributes['xmlns:inkscape'].should == nil end it "should remove sodipodi namespace" do tidy(:strip_inkscape => true) { |svg| svg.svg "xmlns:sodipodi" => "http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" }.attributes['xmlns:sodipodi'].should == nil end it "should remove inkscape elements" do tidy(:strip_inkscape => true) { |svg| svg.svg "xmlns:sodipodi" => "http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" do svg.sodipodi :namedview end }.children.length.should == 0 end it "should remove inkscape attributes" do tidy(:strip_inkscape => true) { |svg| svg.svg "xmlns:inkscape" => "http://www.inkscape.org/namespaces/inkscape" do svg.path 'inkscape:current-layer' =>'layer1' end }.elements['path'].attributes['inkscape:current-layer'].should == nil end end def tidy opts={:grid => true} # parse block svg = REXML::Document.new(yield(Builder::XmlMarkup.new)) # wrap in an svg element, if necessary if svg.root.name != 'svg' svg << REXML::Element.new('svg').add_element(svg.root).parent end # add the svg namespace svg.add_namespace 'http://www.w3.org/2001/svg' # invoke tidy Svg.tidy(svg, opts).root end