Fix Bug 734933: Do not remove empty path segments if stroke-linecap is round
This commit is contained in:
parent
cd42752cad
commit
6c50c78d99
3 changed files with 61 additions and 44 deletions
93
scour.py
93
scour.py
|
|
@ -1709,6 +1709,10 @@ def cleanPath(element, options) :
|
|||
oldPathStr = element.getAttribute('d')
|
||||
path = svg_parser.parse(oldPathStr)
|
||||
|
||||
# This determines whether the stroke has round linecaps. If it does,
|
||||
# we do not want to collapse empty segments, as they are actually rendered.
|
||||
withRoundLineCaps = element.getAttribute('stroke-linecap') == 'round'
|
||||
|
||||
# The first command must be a moveto, and whether it's relative (m)
|
||||
# or absolute (M), the first set of coordinates *is* absolute. So
|
||||
# the first iteration of the loop below will get x,y and startx,starty.
|
||||
|
|
@ -1817,50 +1821,51 @@ def cleanPath(element, options) :
|
|||
# remove empty segments
|
||||
# Reuse the data structure 'path' and the coordinate lists, even if we're
|
||||
# deleting items, because these deletions are relatively cheap.
|
||||
for pathIndex in xrange(0, len(path)):
|
||||
cmd, data = path[pathIndex]
|
||||
i = 0
|
||||
if cmd in ['m','l','t']:
|
||||
if cmd == 'm':
|
||||
# remove m0,0 segments
|
||||
if pathIndex > 0 and data[0] == data[i+1] == 0:
|
||||
# 'm0,0 x,y' can be replaces with 'lx,y',
|
||||
# except the first m which is a required absolute moveto
|
||||
path[pathIndex] = ('l', data[2:])
|
||||
numPathSegmentsReduced += 1
|
||||
else: # else skip move coordinate
|
||||
i = 2
|
||||
while i < len(data):
|
||||
if data[i] == data[i+1] == 0:
|
||||
del data[i:i+2]
|
||||
numPathSegmentsReduced += 1
|
||||
else:
|
||||
i += 2
|
||||
elif cmd == 'c':
|
||||
while i < len(data):
|
||||
if data[i] == data[i+1] == data[i+2] == data[i+3] == data[i+4] == data[i+5] == 0:
|
||||
del data[i:i+6]
|
||||
numPathSegmentsReduced += 1
|
||||
else:
|
||||
i += 6
|
||||
elif cmd == 'a':
|
||||
while i < len(data):
|
||||
if data[i+5] == data[i+6] == 0:
|
||||
del data[i:i+7]
|
||||
numPathSegmentsReduced += 1
|
||||
else:
|
||||
i += 7
|
||||
elif cmd == 'q':
|
||||
while i < len(data):
|
||||
if data[i] == data[i+1] == data[i+2] == data[i+3] == 0:
|
||||
del data[i:i+4]
|
||||
numPathSegmentsReduced += 1
|
||||
else:
|
||||
i += 4
|
||||
elif cmd in ['h','v']:
|
||||
oldLen = len(data)
|
||||
path[pathIndex] = (cmd, [coord for coord in data if coord != 0])
|
||||
numPathSegmentsReduced += len(path[pathIndex][1]) - oldLen
|
||||
if not withRoundLineCaps:
|
||||
for pathIndex in xrange(0, len(path)):
|
||||
cmd, data = path[pathIndex]
|
||||
i = 0
|
||||
if cmd in ['m','l','t']:
|
||||
if cmd == 'm':
|
||||
# remove m0,0 segments
|
||||
if pathIndex > 0 and data[0] == data[i+1] == 0:
|
||||
# 'm0,0 x,y' can be replaces with 'lx,y',
|
||||
# except the first m which is a required absolute moveto
|
||||
path[pathIndex] = ('l', data[2:])
|
||||
numPathSegmentsReduced += 1
|
||||
else: # else skip move coordinate
|
||||
i = 2
|
||||
while i < len(data):
|
||||
if data[i] == data[i+1] == 0:
|
||||
del data[i:i+2]
|
||||
numPathSegmentsReduced += 1
|
||||
else:
|
||||
i += 2
|
||||
elif cmd == 'c':
|
||||
while i < len(data):
|
||||
if data[i] == data[i+1] == data[i+2] == data[i+3] == data[i+4] == data[i+5] == 0:
|
||||
del data[i:i+6]
|
||||
numPathSegmentsReduced += 1
|
||||
else:
|
||||
i += 6
|
||||
elif cmd == 'a':
|
||||
while i < len(data):
|
||||
if data[i+5] == data[i+6] == 0:
|
||||
del data[i:i+7]
|
||||
numPathSegmentsReduced += 1
|
||||
else:
|
||||
i += 7
|
||||
elif cmd == 'q':
|
||||
while i < len(data):
|
||||
if data[i] == data[i+1] == data[i+2] == data[i+3] == 0:
|
||||
del data[i:i+4]
|
||||
numPathSegmentsReduced += 1
|
||||
else:
|
||||
i += 4
|
||||
elif cmd in ['h','v']:
|
||||
oldLen = len(data)
|
||||
path[pathIndex] = (cmd, [coord for coord in data if coord != 0])
|
||||
numPathSegmentsReduced += len(path[pathIndex][1]) - oldLen
|
||||
|
||||
# fixup: Delete subcommands having no coordinates.
|
||||
path = [elem for elem in path if len(elem[1]) > 0 or elem[0] == 'z']
|
||||
|
|
|
|||
|
|
@ -544,6 +544,14 @@ class RemoveEmptyLineSegmentsFromPath(unittest.TestCase):
|
|||
self.assertEquals(path[4][0], 'z',
|
||||
'Did not remove an empty line segment from path' )
|
||||
|
||||
# Do not remove empty segments if round linecaps.
|
||||
class DoNotRemoveEmptySegmentsFromPathWithRoundLineCaps(unittest.TestCase):
|
||||
def runTest(self):
|
||||
doc = scour.scourXmlFile('unittests/path-with-caps.svg')
|
||||
path = svg_parser.parse(doc.getElementsByTagNameNS(SVGNS, 'path')[0].getAttribute('d'))
|
||||
self.assertEquals(len(path), 2,
|
||||
'Did not preserve empty segments when path had round linecaps' )
|
||||
|
||||
class ChangeLineToHorizontalLineSegmentInPath(unittest.TestCase):
|
||||
def runTest(self):
|
||||
doc = scour.scourXmlFile('unittests/path-line-optimize.svg')
|
||||
|
|
|
|||
4
unittests/path-with-caps.svg
Normal file
4
unittests/path-with-caps.svg
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill="none" stroke="#000" stroke-width="5" stroke-linecap="round" d="m 11,8 0,0" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 195 B |
Loading…
Add table
Add a link
Reference in a new issue