scour.py: Modify optimizeTransform to remove superfluous []s and ()s.

testscour.py: Add unit tests for Johan Sundström's fix for bug 722544, "SVG transform matrix() arg order is a1 b1 a2 b2 a3 b3, not a1 a2 a3 b1 b2 b3".

unittests/: Edit the unit tests' support files not to have a second line with the correct transformation. This is customarily in testscour.py.
This commit is contained in:
Louis Simard 2011-02-21 20:51:35 -05:00
parent 338e56f1b1
commit ba3371e282
15 changed files with 102 additions and 29 deletions

View file

@ -2315,7 +2315,7 @@ def optimizeTransform(transform):
# | b d f | translating them | B1 B2 B3 | # | b d f | translating them | B1 B2 B3 |
# |_ 0 0 1 _| to more readable |_ 0 0 1 _| # |_ 0 0 1 _| to more readable |_ 0 0 1 _|
if len(transform) == 1 and transform[0][0] == 'matrix': if len(transform) == 1 and transform[0][0] == 'matrix':
matrix = [A1, B1, A2, B2, A3, B3] = transform[0][1] matrix = A1, B1, A2, B2, A3, B3 = transform[0][1]
# |¯ 1 0 0 ¯| # |¯ 1 0 0 ¯|
# | 0 1 0 | Identity matrix (no transformation) # | 0 1 0 | Identity matrix (no transformation)
# |_ 0 0 1 _| # |_ 0 0 1 _|
@ -2342,7 +2342,7 @@ def optimizeTransform(transform):
# FIXME: the "epsilon" term here should really be some function # FIXME: the "epsilon" term here should really be some function
# of the precision of the (sin|cos)_A terms, not 1e-15: # of the precision of the (sin|cos)_A terms, not 1e-15:
and abs((B1 ** 2) + (A1 ** 2) - 1) < Decimal("1e-15")): and abs((B1 ** 2) + (A1 ** 2) - 1) < Decimal("1e-15")):
[sin_A, cos_A] = [B1, A1] sin_A, cos_A = B1, A1
# while asin(A) and acos(A) both only have an 180° range # while asin(A) and acos(A) both only have an 180° range
# the sign of sin(A) and cos(A) varies across quadrants, # the sign of sin(A) and cos(A) varies across quadrants,
# letting us hone in on the angle the matrix represents: # letting us hone in on the angle the matrix represents:
@ -2359,23 +2359,21 @@ def optimizeTransform(transform):
transform[0] = ('rotate', [A]) transform[0] = ('rotate', [A])
# Simplify transformations where numbers are optional. # Simplify transformations where numbers are optional.
for [type, args] in transform: for type, args in transform:
if type == 'translate': if type == 'translate':
# Only the X coordinate is required for translations. # Only the X coordinate is required for translations.
# If the Y coordinate is unspecified, it's 0. # If the Y coordinate is unspecified, it's 0.
if (len(args) == 2 and args[1] == 0): if len(args) == 2 and args[1] == 0:
del args[1] del args[1]
elif type == 'rotate': elif type == 'rotate':
# Only the angle is required for rotations. # Only the angle is required for rotations.
# If the coordinates are unspecified, it's the origin (0, 0). # If the coordinates are unspecified, it's the origin (0, 0).
if (len(args) == 3 and if len(args) == 3 and args[1] == args[2] == 0:
args[1] == 0 and
args[2] == 0):
del args[1:] del args[1:]
elif type == 'scale': elif type == 'scale':
# Only the X scaling factor is required. # Only the X scaling factor is required.
# If the Y factor is unspecified, it's the same as X. # If the Y factor is unspecified, it's the same as X.
if (len(args) == 2 and args[0] == args[1]): if len(args) == 2 and args[0] == args[1]:
del args[1] del args[1]
# Attempt to coalesce runs of the same transformation. # Attempt to coalesce runs of the same transformation.
@ -2396,8 +2394,8 @@ def optimizeTransform(transform):
# would be safe to multiply together, too. # would be safe to multiply together, too.
i = 1 i = 1
while i < len(transform): while i < len(transform):
[currType, currArgs] = transform[i] currType, currArgs = transform[i]
[prevType, prevArgs] = transform[i - 1] prevType, prevArgs = transform[i - 1]
if currType == prevType == 'translate': if currType == prevType == 'translate':
prevArgs[0] += currArgs[0] # x prevArgs[0] += currArgs[0] # x
# for y, only add if the second translation has an explicit y # for y, only add if the second translation has an explicit y

View file

@ -1217,12 +1217,100 @@ class RemoveDefsWithWhitespace(unittest.TestCase):
self.assertEquals(doc.getElementsByTagName('defs').length, 0, self.assertEquals(doc.getElementsByTagName('defs').length, 0,
'Kept defs, although it contains only whitespace or is <defs/>') 'Kept defs, although it contains only whitespace or is <defs/>')
class TransformIdentityMatrix(unittest.TestCase):
def runTest(self):
doc = scour.scourXmlFile('unittests/transform-matrix-is-identity.svg')
self.assertEquals(doc.getElementsByTagName('line')[0].getAttribute('transform'), '',
'Transform containing identity matrix not removed')
class TransformRotate135(unittest.TestCase):
def runTest(self):
doc = scour.scourXmlFile('unittests/transform-matrix-is-rotate-135.svg')
self.assertEquals(doc.getElementsByTagName('line')[0].getAttribute('transform'), 'rotate(135)',
'Rotation matrix not converted to rotate(135)')
class TransformRotate45(unittest.TestCase):
def runTest(self):
doc = scour.scourXmlFile('unittests/transform-matrix-is-rotate-45.svg')
self.assertEquals(doc.getElementsByTagName('line')[0].getAttribute('transform'), 'rotate(45)',
'Rotation matrix not converted to rotate(45)')
class TransformRotate90(unittest.TestCase):
def runTest(self):
doc = scour.scourXmlFile('unittests/transform-matrix-is-rotate-90.svg')
self.assertEquals(doc.getElementsByTagName('line')[0].getAttribute('transform'), 'rotate(90)',
'Rotation matrix not converted to rotate(90)')
class TransformRotateCCW135(unittest.TestCase):
def runTest(self):
doc = scour.scourXmlFile('unittests/transform-matrix-is-rotate-neg-135.svg')
self.assertEquals(doc.getElementsByTagName('line')[0].getAttribute('transform'), 'rotate(-135)',
'Counter-clockwise rotation matrix not converted to rotate(-135)')
class TransformRotateCCW45(unittest.TestCase):
def runTest(self):
doc = scour.scourXmlFile('unittests/transform-matrix-is-rotate-neg-45.svg')
self.assertEquals(doc.getElementsByTagName('line')[0].getAttribute('transform'), 'rotate(-45)',
'Counter-clockwise rotation matrix not converted to rotate(-45)')
class TransformRotateCCW90(unittest.TestCase):
def runTest(self):
doc = scour.scourXmlFile('unittests/transform-matrix-is-rotate-neg-90.svg')
self.assertEquals(doc.getElementsByTagName('line')[0].getAttribute('transform'), 'rotate(-90)',
'Counter-clockwise rotation matrix not converted to rotate(-90)')
class TransformScale2by3(unittest.TestCase):
def runTest(self):
doc = scour.scourXmlFile('unittests/transform-matrix-is-scale-2-3.svg')
self.assertEquals(doc.getElementsByTagName('line')[0].getAttribute('transform'), 'scale(2 3)',
'Scaling matrix not converted to scale(2 3)')
class TransformScaleMinus1(unittest.TestCase):
def runTest(self):
doc = scour.scourXmlFile('unittests/transform-matrix-is-scale-neg-1.svg')
self.assertEquals(doc.getElementsByTagName('line')[0].getAttribute('transform'), 'scale(-1)',
'Scaling matrix not converted to scale(-1)')
class TransformTranslate(unittest.TestCase):
def runTest(self):
doc = scour.scourXmlFile('unittests/transform-matrix-is-translate.svg')
self.assertEquals(doc.getElementsByTagName('line')[0].getAttribute('transform'), 'translate(2 3)',
'Translation matrix not converted to translate(2 3)')
class TransformRotation3Args(unittest.TestCase):
def runTest(self):
doc = scour.scourXmlFile('unittests/transform-rotate-fold-3args.svg')
self.assertEquals(doc.getElementsByTagName('line')[0].getAttribute('transform'), 'rotate(90)',
'Optional zeroes in rotate(angle 0 0) not removed')
class TransformIdentityRotation(unittest.TestCase):
def runTest(self):
doc = scour.scourXmlFile('unittests/transform-rotate-is-identity.svg')
self.assertEquals(doc.getElementsByTagName('line')[0].getAttribute('transform'), '',
'Transform containing identity rotation not removed')
class TransformIdentitySkewX(unittest.TestCase):
def runTest(self):
doc = scour.scourXmlFile('unittests/transform-skewX-is-identity.svg')
self.assertEquals(doc.getElementsByTagName('line')[0].getAttribute('transform'), '',
'Transform containing identity X-axis skew not removed')
class TransformIdentitySkewY(unittest.TestCase):
def runTest(self):
doc = scour.scourXmlFile('unittests/transform-skewY-is-identity.svg')
self.assertEquals(doc.getElementsByTagName('line')[0].getAttribute('transform'), '',
'Transform containing identity Y-axis skew not removed')
class TransformIdentityTranslate(unittest.TestCase):
def runTest(self):
doc = scour.scourXmlFile('unittests/transform-translate-is-identity.svg')
self.assertEquals(doc.getElementsByTagName('line')[0].getAttribute('transform'), '',
'Transform containing identity translation not removed')
# TODO: write tests for --enable-viewboxing # TODO: write tests for --enable-viewboxing
# TODO; write a test for embedding rasters # TODO; write a test for embedding rasters
# TODO: write a test for --disable-embed-rasters # TODO: write a test for --disable-embed-rasters
# TODO: write tests for --keep-editor-data # TODO: write tests for --keep-editor-data
# TODO: write tests for scouring transformations
# progress: the unittests/transform-* files list expected before/after behaviour
if __name__ == '__main__': if __name__ == '__main__':
testcss = __import__('testcss') testcss = __import__('testcss')

View file

@ -1,4 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" viewBox="0 0 9 9"> <svg xmlns="http://www.w3.org/2000/svg" version="1.1" viewBox="0 0 9 9">
<line stroke="rgba(255,0,0,0.5)" y1="9" x1="9" transform="matrix(1 0 0 1 0 0)"/> <line stroke="rgba(255,0,0,0.5)" y1="9" x1="9" transform="matrix(1 0 0 1 0 0)"/>
<line stroke="rgba(0,0,255,0.5)" y1="9" x1="9"/>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 212 B

After

Width:  |  Height:  |  Size: 162 B

Before After
Before After

View file

@ -1,5 +1,4 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?> <?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" viewBox="-9 0 9 9"> <svg xmlns="http://www.w3.org/2000/svg" version="1.1" viewBox="-9 0 9 9">
<line stroke="rgba(255,0,0,0.5)" y1="9" x1="9" transform="matrix(-0.70710678118654746 0.70710678118654757 -0.70710678118654757 -0.70710678118654746 0 0)"/> <line stroke="rgba(255,0,0,0.5)" y1="9" x1="9" transform="matrix(-0.70710678118654746 0.70710678118654757 -0.70710678118654757 -0.70710678118654746 0 0)"/>
<line stroke="rgba(0,0,255,0.5)" y1="9" x1="9" transform="rotate(135)"/>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 367 B

After

Width:  |  Height:  |  Size: 293 B

Before After
Before After

View file

@ -1,5 +1,4 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?> <?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" viewBox="-9 0 9 9"> <svg xmlns="http://www.w3.org/2000/svg" version="1.1" viewBox="-9 0 9 9">
<line stroke="rgba(255,0,0,0.5)" y1="9" x1="9" transform="matrix(0.70710678118654757 0.70710678118654746 -0.70710678118654746 0.70710678118654757 0 0)"/> <line stroke="rgba(255,0,0,0.5)" y1="9" x1="9" transform="matrix(0.70710678118654757 0.70710678118654746 -0.70710678118654746 0.70710678118654757 0 0)"/>
<line stroke="rgba(0,0,255,0.5)" y1="9" x1="9" transform="rotate(45)"/>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 364 B

After

Width:  |  Height:  |  Size: 291 B

Before After
Before After

View file

@ -1,5 +1,4 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?> <?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" viewBox="-9 0 9 9"> <svg xmlns="http://www.w3.org/2000/svg" version="1.1" viewBox="-9 0 9 9">
<line stroke="rgba(255,0,0,0.5)" y1="9" x1="9" transform="matrix(0 1 -1 0 0 0)"/> <line stroke="rgba(255,0,0,0.5)" y1="9" x1="9" transform="matrix(0 1 -1 0 0 0)"/>
<line stroke="rgba(0,0,255,0.5)" y1="9" x1="9" transform="rotate(90)"/>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 292 B

After

Width:  |  Height:  |  Size: 219 B

Before After
Before After

View file

@ -1,5 +1,4 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?> <?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" viewBox="-9 0 9 9"> <svg xmlns="http://www.w3.org/2000/svg" version="1.1" viewBox="-9 0 9 9">
<line stroke="rgba(255,0,0,0.5)" y1="9" x1="9" transform="matrix(-0.70710678118654746 -0.70710678118654757 0.70710678118654757 -0.70710678118654746 0 0)"/> <line stroke="rgba(255,0,0,0.5)" y1="9" x1="9" transform="matrix(-0.70710678118654746 -0.70710678118654757 0.70710678118654757 -0.70710678118654746 0 0)"/>
<line stroke="rgba(0,0,255,0.5)" y1="9" x1="9" transform="rotate(-135)"/>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 368 B

After

Width:  |  Height:  |  Size: 293 B

Before After
Before After

View file

@ -1,5 +1,4 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?> <?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" viewBox="-9 0 9 9"> <svg xmlns="http://www.w3.org/2000/svg" version="1.1" viewBox="-9 0 9 9">
<line stroke="rgba(255,0,0,0.5)" y1="9" x1="9" transform="matrix(0.70710678118654757 -0.70710678118654746 0.70710678118654746 0.70710678118654757 0 0)"/> <line stroke="rgba(255,0,0,0.5)" y1="9" x1="9" transform="matrix(0.70710678118654757 -0.70710678118654746 0.70710678118654746 0.70710678118654757 0 0)"/>
<line stroke="rgba(0,0,255,0.5)" y1="9" x1="9" transform="rotate(-45)"/>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 365 B

After

Width:  |  Height:  |  Size: 291 B

Before After
Before After

View file

@ -1,5 +1,4 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?> <?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" viewBox="-9 0 9 9"> <svg xmlns="http://www.w3.org/2000/svg" version="1.1" viewBox="-9 0 9 9">
<line stroke="rgba(255,0,0,0.5)" y1="9" x1="9" transform="matrix(0 -1 1 0 0 0)"/> <line stroke="rgba(255,0,0,0.5)" y1="9" x1="9" transform="matrix(0 -1 1 0 0 0)"/>
<line stroke="rgba(0,0,255,0.5)" y1="9" x1="9" transform="rotate(-90)"/>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 293 B

After

Width:  |  Height:  |  Size: 219 B

Before After
Before After

View file

@ -1,4 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" viewBox="0 0 18 27"> <svg xmlns="http://www.w3.org/2000/svg" version="1.1" viewBox="0 0 18 27">
<line stroke="rgba(255,0,0,0.5)" y1="9" x1="9" transform="matrix(2 0 0 3 0 0)"/> <line stroke="rgba(255,0,0,0.5)" y1="9" x1="9" transform="matrix(2 0 0 3 0 0)"/>
<line stroke="rgba(0,0,255,0.5)" y1="9" x1="9" transform="scale(2 3)"/>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 237 B

After

Width:  |  Height:  |  Size: 164 B

Before After
Before After

View file

@ -1,5 +1,4 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?> <?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" viewBox="-9 -9 9 9"> <svg xmlns="http://www.w3.org/2000/svg" version="1.1" viewBox="-9 -9 9 9">
<line stroke="rgba(255,0,0,0.5)" y1="9" x1="9" transform="matrix(-1 0 0 -1 0 0)"/> <line stroke="rgba(255,0,0,0.5)" y1="9" x1="9" transform="matrix(-1 0 0 -1 0 0)"/>
<line stroke="rgba(0,0,255,0.5)" y1="9" x1="9" transform="scale(-1)"/>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 293 B

After

Width:  |  Height:  |  Size: 221 B

Before After
Before After

View file

@ -1,4 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" viewBox="2 3 9 9"> <svg xmlns="http://www.w3.org/2000/svg" version="1.1" viewBox="2 3 9 9">
<line stroke="rgba(255,0,0,0.5)" y1="9" x1="9" transform="matrix(1 0 0 1 2 3)"/> <line stroke="rgba(255,0,0,0.5)" y1="9" x1="9" transform="matrix(1 0 0 1 2 3)"/>
<line stroke="rgba(0,0,255,0.5)" y1="9" x1="9" transform="translate(2 3)"/>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 239 B

After

Width:  |  Height:  |  Size: 162 B

Before After
Before After

View file

@ -1,6 +1,5 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?> <?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" viewBox="-9 0 9 9"> <svg xmlns="http://www.w3.org/2000/svg" version="1.1" viewBox="-9 0 9 9">
<line stroke="rgba(255,0,0,0.5)" y1="9" x1="9" transform="rotate(90 0 0.0)"/> <line stroke="rgba(255,0,0,0.5)" y1="9" x1="9" transform="rotate(90 0 0.0)"/>
<line stroke="rgba(0,0,255,0.5)" y1="9" x1="9" transform="rotate(90)"/>
<!-- optional zero trailing args to transform type rotate get removed --> <!-- optional zero trailing args to transform type rotate get removed -->
</svg> </svg>

Before

Width:  |  Height:  |  Size: 364 B

After

Width:  |  Height:  |  Size: 291 B

Before After
Before After

View file

@ -1,5 +1,4 @@
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" viewBox="0 0 9 9"> <svg xmlns="http://www.w3.org/2000/svg" version="1.1" viewBox="0 0 9 9">
<line stroke="rgba(255,0,0,0.5)" y1="9" x1="9" transform="skewX(0)"/> <line stroke="rgba(255,0,0,0.5)" y1="9" x1="9" transform="skewX(0)"/>
<line stroke="rgba(0,0,255,0.5)" y1="9" x1="9"/>
<!-- skewX(0) is the identity transform, which can safely be removed --> <!-- skewX(0) is the identity transform, which can safely be removed -->
</svg> </svg>

Before

Width:  |  Height:  |  Size: 276 B

After

Width:  |  Height:  |  Size: 226 B

Before After
Before After

View file

@ -1,5 +1,4 @@
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" viewBox="0 0 9 9"> <svg xmlns="http://www.w3.org/2000/svg" version="1.1" viewBox="0 0 9 9">
<line stroke="rgba(255,0,0,0.5)" y1="9" x1="9" transform="skewY(0)"/> <line stroke="rgba(255,0,0,0.5)" y1="9" x1="9" transform="skewY(0)"/>
<line stroke="rgba(0,0,255,0.5)" y1="9" x1="9"/>
<!-- skewY(0) is the identity transform, which can safely be removed --> <!-- skewY(0) is the identity transform, which can safely be removed -->
</svg> </svg>

Before

Width:  |  Height:  |  Size: 276 B

After

Width:  |  Height:  |  Size: 226 B

Before After
Before After