Changeset 335

Show
Ignore:
Timestamp:
03/02/08 15:12:12 (6 months ago)
Author:
nperriault
Message:

Clever Svg:

  • refs #40: more tests
  • added csDocument::getElementById() and csDocument::dropElementById() methods
  • fixed csDocument::swapDepths() bug

Warning: breaks BC from 0.5.

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • cleversvg/trunk/base/csBaseElement.class.php

    r326 r335  
    109109  public function getDepth() 
    110110  { 
    111     if (isset($this->attributes['depth'])) 
    112     { 
    113       return (int) $this->attributes['depth']; 
     111    if (array_key_exists('style', $this->attributes) && 
     112        array_key_exists('z-index', $this->attributes['style'])) 
     113    { 
     114      return (int) $this->attributes['style']['z-index']; 
    114115    } 
    115116    else 
     
    139140   * @return string 
    140141   */ 
    141   protected function getElementName($embedded=false) 
     142  public function getElementName($embedded = false) 
    142143  { 
    143144    if ($embedded === true) 
  • cleversvg/trunk/document/csDocument.class.php

    r326 r335  
    1010{ 
    1111 
    12   protected 
    13     $attributes       = array(), 
    14     $definitions      = array(), 
    15     $scripts          = array(), 
    16     $embed_styles     = array(), 
    17     $external_styles  = array(), 
    18     $used_definitions = array(), 
    19     $elements         = array(), 
    20     $dom_ids          = array(), 
    21     $description      = NULL, 
    22     $dom_document     = NULL, 
    23     $maxdepth         = 0, 
    24     $title            = 'Untitled SVG Document', 
    25     $embedded         = false, 
    26     $strict_mode      = false; 
     12  /** 
     13   * Document attributes container 
     14   * @var array 
     15   */ 
     16  protected $attributes = array(); 
     17 
     18  /** 
     19   * Definitions container 
     20   * @var array 
     21   */ 
     22  protected $definitions = array(); 
     23 
     24  /** 
     25   * Scripts container 
     26   * @var array 
     27   */ 
     28  protected $scripts = array(); 
     29 
     30  /** 
     31   * Embeded styles container 
     32   * @var array 
     33   */ 
     34  protected $embed_styles = array(); 
     35 
     36  /** 
     37   * External styles references container 
     38   * @var array 
     39   */ 
     40  protected $external_styles = array(); 
     41 
     42  /** 
     43   * Used definitions references container 
     44   * @var array 
     45   */ 
     46  protected $used_definitions = array(); 
     47 
     48  /** 
     49   * Document elements container 
     50   * @var array 
     51   */ 
     52  protected $elements = array(); 
     53 
     54  /** 
     55   * DOM document unique id attributes container 
     56   * @var array 
     57   */ 
     58  protected $dom_ids = array(); 
     59 
     60  /** 
     61   * Document description 
     62   * @var string 
     63   */ 
     64  protected $description = NULL; 
     65 
     66  /** 
     67   * DOMDocument instance 
     68   * @var DOMDocument 
     69   */ 
     70  protected $dom_document = NULL; 
     71 
     72  /** 
     73   * Max depth 
     74   * @var int 
     75   */ 
     76  protected $maxdepth = 0; 
     77 
     78  /** 
     79   * Document title 
     80   * @var string 
     81   */ 
     82  protected $title = 'Untitled SVG Document'; 
     83 
     84  /** 
     85   * Embeded SVG flag 
     86   * @var boolean 
     87   */ 
     88  protected $embedded = false; 
     89 
     90  /** 
     91   * Strict mode flag 
     92   * @var boolean 
     93   */ 
     94  protected $strict_mode = false; 
    2795 
    2896  /** 
     
    34102   * @param  array  $attrs  Attributes array 
    35103   */ 
    36   public function __construct($width=null, $height=null, $title=null, $attrs=array()) 
     104  public function __construct($width=null, $height=null, $title=null, $attrs = array()) 
    37105  { 
    38106    $this->setWidth($width); 
     
    46114   * Adds a SVG shape or group to current SVG Document at a certain depth 
    47115   * 
    48    * @param  mixed  $element  SVG element to add 
    49    * @param  mixed  $depth    Depth (default: auto when set to NULL) 
    50    */ 
    51   public function addElement($element, $depth=null) 
    52   { 
    53     if (is_null($element->getDepth())) 
    54     { 
    55       if (!is_int($depth) || isset($this->elements[$depth])) 
    56       { 
    57         $depth = ++$this->maxdepth; 
    58       } 
    59     } 
    60     else 
    61     { 
    62       $depth = $element->getDepth(); 
    63     } 
    64     $this->elements[$depth] = $element; 
    65  
     116   * @param  mixed    $element  SVG element to add 
     117   * @param  mixed    $depth    Depth (default: auto when set to NULL) 
     118   * @param  boolean  $replace_at_depth Replace element at depth if exist ? 
     119   * @throws csException 
     120   */ 
     121  public function addElement($element, $depth = null, $replace_at_depth = false) 
     122  { 
    66123    // Add DOM id to document list, if any 
    67124    $id = $element->getId(); 
    68125    if (!is_null($id)) 
    69126    { 
     127      if (in_array($id, $this->dom_ids)) 
     128      { 
     129        throw new csException( 
     130          sprintf('Document has already an element with id "%s"', $id)); 
     131      } 
    70132      $this->dom_ids[] = $id; 
    71133    } 
     134 
     135    if (is_null($element->getDepth())) 
     136    { 
     137      if (!$replace_at_depth && array_key_exists($depth, $this->elements)) 
     138      { 
     139        throw new csException( 
     140          sprintf('Unable to add element at depth "%d", a "%s" element already'. 
     141                  ' exist at this index', 
     142                  $depth, $this->elements[$depth]->getElementName(false))); 
     143      } 
     144      elseif (!is_int($depth)) 
     145      { 
     146        $depth = ++$this->maxdepth; 
     147      } 
     148    } 
     149    else 
     150    { 
     151      $depth = $element->getDepth(); 
     152    } 
     153    $this->elements[$depth] = $element; 
     154  } 
     155 
     156  /** 
     157   * Create an svg element and returns its instance 
     158   * 
     159   * @param  string $name 
     160   * @return csBaseElement 
     161   */ 
     162  public function createElement($name) 
     163  { 
     164    $class_name = sprintf('cs%s', ucfirst($name)); 
     165    if (!class_exists($class_name)) 
     166    { 
     167      throw new csException(sprintf('Element class "%s" does not exist', 
     168                                   $class_name)); 
     169    } 
     170    return new $class_name; 
     171  } 
     172 
     173  /** 
     174   * Drop an element from document by its DOM id 
     175   * 
     176   * @param  string  $id 
     177   * @throws csException 
     178   */ 
     179  public function dropElementById($id) 
     180  { 
     181    foreach ($this->getElements() as $index => $element) 
     182    { 
     183      if ($element->getId() == $id) 
     184      { 
     185        foreach ($this->dom_ids as $dom_index => $dom_id) 
     186        { 
     187          if ($dom_id == $id) 
     188          { 
     189            unset($this->dom_ids[$dom_index]); 
     190          } 
     191        } 
     192        unset($this->elements[$index]); 
     193        return; 
     194      } 
     195    } 
     196  } 
     197 
     198  /** 
     199   * Retrieve an element instance by its DOM id 
     200   * 
     201   * @param  string  $id 
     202   * @return csBaseElement 
     203   * @throw  csException 
     204   */ 
     205  public function getElementById($id) 
     206  { 
     207    foreach ($this->elements as $element) 
     208    { 
     209      if ($element->getId() == $id) 
     210      { 
     211        return $element; 
     212      } 
     213    } 
     214    throw new csException(sprintf('No element with id "%s"', $id)); 
    72215  } 
    73216 
     
    103246   * @param  string  $content_type 
    104247   */ 
    105   public function addScript($content, $type='text/ecmascript') 
     248  public function addScript($content, $type = 'text/ecmascript') 
    106249  { 
    107250    $this->scripts[] = array($content, $type); 
     
    116259   * @param  mixed   $title 
    117260   */ 
    118   public function addStyleDeclaration($content, $type='text/css', $media=null, $title=null) 
    119   { 
    120     $this->embed_styles[] = array('content'   => $content, 
    121                                   'type'      => $type, 
    122                                   'media'     => $media, 
    123                                   'title'     => $title); 
     261  public function addStyleDeclaration($content, $type = 'text/css', $media = null, $title = null) 
     262  { 
     263    $this->embed_styles[] = array('content' => $content, 
     264                                  'type'    => $type, 
     265                                  'media'   => $media, 
     266                                  'title'   => $title); 
    124267  } 
    125268 
     
    132275   * @param  mixed   $title 
    133276   */ 
    134   public function addStylesheetLink($href, $type='text/css', $alternate='no', $media=null, $title=null) 
     277  public function addStylesheetLink($href, $type = 'text/css', $alternate = 'no', $media = null, $title = null) 
    135278  { 
    136279    $this->external_styles[] = array('href'      => $href, 
     
    148291   * TODO: implement definitions and references 
    149292   */ 
    150   public function addAsDefinition($definition, $id=null) 
     293  public function addAsDefinition($definition, $id = null) 
    151294  { 
    152295    $is_element = is_callable(array($definition, 'setId')); 
     
    241384        break; 
    242385      } 
    243       if ($this->embedded === true
     386      if (true === $this->embedded
    244387      { 
    245388        $dom = new DOMDocument('1.0', 'UTF-8'); 
     
    263406   * @param  array  $attrs    More atributes to add to <use/> tag 
    264407   */ 
    265   public function useDefinition($id, $attrs=array()) 
     408  public function useDefinition($id, $attrs = array()) 
    266409  { 
    267410    $this->used_definitions[] = array($this->getDefinition($id), $attrs); 
     
    269412 
    270413  /** 
    271    * Swap respective depths of two elements 
    272    * 
    273    * @param  sfSvgElement  $element1 
    274    * @param  sfSvgElement  $element2 
    275    */ 
    276   public function swapDepths($element1, $element2) 
    277   { 
    278     $tmpdepth = $this->maxdepth + 1; 
    279     $e1depth  = $element1->getDepth(); 
    280     $e2depth  = $element2->getDepth(); 
    281     $element1->setDepth($tmpdepth); 
    282     $element2->setDepth($e1depth); 
    283     $element1->setDepth($e2depth); 
     414   * Swap respective depths of two elements. Both elements are retrieved by 
     415   * their DOM id. 
     416   * 
     417   * @param  string $id1 
     418   * @param  string $id2 
     419   * @throws csException 
     420   */ 
     421  public function swapDepths($id1, $id2) 
     422  { 
     423    if ($id1 == $id2) 
     424    { 
     425      return; 
     426    } 
     427    $e1 = $this->getElementById($id1); 
     428    $e2 = $this->getElementById($id2); 
     429    $e1depth = $e1->getDepth(); 
     430    $e2depth = $e2->getDepth(); 
     431    $e2->setDepth($e1depth); 
     432    $e1->setDepth($e2depth); 
     433    $this->dropElementById($id1); 
     434    $this->dropElementById($id2); 
     435    $this->addElement($e1, $e1depth, true); 
     436    $this->addElement($e2, $e2depth, true); 
    284437  } 
    285438 
     
    359512   * Standard XML attribute for identifying an XML namespace. 
    360513   * 
    361    */ 
    362   public function setXmlns($xmlns='http://www.w3.org/2000/svg') 
     514   * @param  string  $xmlns  XML namespace url 
     515   */ 
     516  public function setXmlns($xmlns = 'http://www.w3.org/2000/svg') 
    363517  { 
    364518    $this->attributes['xmlns'] = $xmlns; 
     
    413567   * 
    414568   */ 
    415   public function setVersion($version='1.1') 
     569  public function setVersion($version = '1.1') 
    416570  { 
    417571    $this->attributes['version'] = (string)$version; 
     
    433587   * necessary to correctly render the content. This can be considered metadata. 
    434588   * 
     589   * @param  string  $base_profile 
    435590   */ 
    436591  public function setBaseProfile($base_profile) 
     
    446601   * @return string 
    447602   */ 
    448   public function toXML($embedded=null) 
     603  public function toXML($embedded = null) 
    449604  { 
    450605    if (!is_null($embedded) && is_bool($embedded)) 
  • cleversvg/trunk/tests/csBaseTestCase.class.php

    r334 r335  
    4848    { 
    4949      throw new PHPUnit_Framework_ExpectationFailedException( 
    50         sprintf('XPath query "%s" does not match value "%s". Source: %s', 
    51                 $xpath_query, $value, "\n".$doc->toXML())); 
     50        sprintf('XPath query "%s" does not match value "%s", but "%s". Source: %s', 
     51                $xpath_query, $value, $attr_value, "\n".$doc->toXML())); 
    5252    } 
    5353    return true; 
     54  } 
     55 
     56  protected function assertNodeExists($doc, $xpath_query) 
     57  { 
     58    $result = $this->documentXpath($doc, $xpath_query); 
     59    return !is_null($result->item(0)); 
     60  } 
     61 
     62  protected function assertNodeDoesNotExist($doc, $xpath_query) 
     63  { 
     64    return !$this->assertNodeExists($doc, $xpath_query); 
    5465  } 
    5566 
  • cleversvg/trunk/tests/csDocumentTest.php

    r334 r335  
    1111{ 
    1212 
     13  public function testConstructor() 
     14  { 
     15    $doc = new csDocument(320, 240, 'Blah', array('baseProfile' => 'foo/bar')); 
     16    $this->assertAttrValueEquals($doc, '/svg:svg/@width', 320); 
     17    $this->assertAttrValueEquals($doc, '/svg:svg/@height', 240); 
     18    $this->assertTextNodeEquals($doc, '/svg:svg/svg:title', 'Blah'); 
     19    $this->assertAttrValueEquals($doc, '/svg:svg/@baseProfile', 'foo/bar'); 
     20  } 
     21 
     22  public function testCreateElement() 
     23  { 
     24    $doc = new csDocument(320, 240, 'Blah'); 
     25    $this->assertType('csCircle', $doc->createElement('circle')); 
     26    $this->assertType('csRect', $doc->createElement('rect')); 
     27    $this->assertType('csLinearGradient', $doc->createElement('linearGradient')); 
     28  } 
     29 
     30  public function testDropElementById() 
     31  { 
     32    $doc = new csDocument(320, 240, 'Blah'); 
     33    $c = new csCircle(); 
     34    $c->setRadius(10); 
     35    $c->setStroke('red'); 
     36    $c->setId('circle1'); 
     37    $doc->addElement($c); 
     38    $this->assertNodeExists($doc, '/svg:svg/svg:circle[@id = "circle1"]'); 
     39    $doc->dropElementById('circle1'); 
     40    $this->assertNodeDoesNotExist($doc, '/svg:svg/svg:circle[@id = "circle1"]'); 
     41  } 
     42 
     43  public function testHasId() 
     44  { 
     45    $doc = new csDocument(320, 240, 'Blah'); 
     46    $c = new csCircle(); 
     47    $c->setRadius(10); 
     48    $c->setStroke('red'); 
     49    $c->setId('circle1'); 
     50    $c2 = clone($c); 
     51    $c2->setId('circle2'); 
     52    $doc->addElement($c); 
     53    $doc->addElement($c2); 
     54    $this->assertTrue($doc->hasId('circle1')); 
     55    $this->assertTrue($doc->hasId('circle2')); 
     56    $this->assertFalse($doc->hasId('jfhkjsdfh')); 
     57  } 
     58 
    1359  public function testSetDescription() 
    1460  { 
     
    1864    $doc->setDescription('Changed description'); 
    1965    $this->assertTextNodeEquals($doc, '/svg:svg/svg:desc', 'Changed description'); 
     66  } 
     67 
     68  /** 
     69   * @expectedException csException 
     70   * 
     71   */ 
     72  public function testNoDuplicateId() 
     73  { 
     74    $doc = new csDocument(320, 240, 'Blah'); 
     75    $c = new csCircle(); 
     76    $c->setId('circle1'); 
     77    $c2 = new csCircle(); 
     78    $c2->setId('circle1'); 
     79    $doc->addElement($c); 
     80    $doc->addElement($c2); 
    2081  } 
    2182 
     
    2990  } 
    3091 
     92  public function testSwapDepths() 
     93  { 
     94    $doc = new csDocument(320, 240, 'Test depths'); 
     95    $c1 = new csCircle(160, 120, 40); 
     96    $c1->setDepth(20); 
     97    $c1->setId('c1'); 
     98    $c2 = new csCircle(140, 100, 40); 
     99    $c2->setDepth(40); 
     100    $c2->setId('c2'); 
     101    $doc->addElement($c1); 
     102    $doc->addElement($c2); 
     103    $doc->swapDepths('c1', 'c2'); 
     104    $this->assertAttrValueEquals($doc, '/svg:svg/svg:circle[@id = "c1"]/@style', 'z-index: 40'); 
     105    $this->assertAttrValueEquals($doc, '/svg:svg/svg:circle[@id = "c2"]/@style', 'z-index: 20'); 
     106  } 
     107 
     108  public function testViewBox() 
     109  { 
     110    $doc = new csDocument(); 
     111    $doc->setViewBox(10, 10, 320, 240); 
     112    $this->assertAttrValueEquals($doc, '/svg:svg/@viewBox', '10 10 320 240'); 
     113  } 
     114 
    31115  public function testToXml() 
    32116  {