Fix opacity parsing from classes and from fill-opacity (#3747)

* fix to parser

* fix opacity parsing

* fix opacity parsing

* added tests

* fix for parsing attributes equalt to 0

* added test

* fixed better

* removed fix
This commit is contained in:
Andrea Bogazzi 2017-02-27 02:18:23 +01:00 committed by GitHub
parent c3a6447aff
commit 211edecdfd
2 changed files with 94 additions and 29 deletions

View file

@ -41,7 +41,8 @@
'stroke-opacity': 'strokeOpacity',
'stroke-width': 'strokeWidth',
'text-decoration': 'textDecoration',
'text-anchor': 'originX'
'text-anchor': 'originX',
opacity: 'opacity'
},
colorAttributes = {
@ -93,6 +94,12 @@
value = false;
}
}
else if (attr === 'opacity') {
value = parseFloat(value);
if (parentAttributes && typeof parentAttributes.opacity !== 'undefined') {
value *= parentAttributes.opacity;
}
}
else if (attr === 'originX' /* text-anchor */) {
value = value === 'start' ? 'left' : value === 'end' ? 'right' : 'center';
}
@ -311,8 +318,8 @@
style.replace(/;\s*$/, '').split(';').forEach(function (chunk) {
var pair = chunk.split(':');
attr = normalizeAttr(pair[0].trim().toLowerCase());
value = normalizeValue(attr, pair[1].trim());
attr = pair[0].trim().toLowerCase();
value = pair[1].trim();
oStyle[attr] = value;
});
@ -328,8 +335,8 @@
continue;
}
attr = normalizeAttr(prop.toLowerCase());
value = normalizeValue(attr, style[prop]);
attr = prop.toLowerCase();
value = style[prop];
oStyle[attr] = value;
}
@ -758,23 +765,27 @@
var ownAttributes = attributes.reduce(function(memo, attr) {
value = element.getAttribute(attr);
if (value) {
attr = normalizeAttr(attr);
value = normalizeValue(attr, value, parentAttributes, fontSize);
if (value) { // eslint-disable-line
memo[attr] = value;
}
return memo;
}, { });
// add values parsed from style, which take precedence over attributes
// (see: http://www.w3.org/TR/SVG/styling.html#UsingPresentationAttributes)
ownAttributes = extend(ownAttributes,
extend(getGlobalStylesForElement(element, svgUid), fabric.parseStyleAttribute(element)));
if (ownAttributes.font) {
fabric.parseFontDeclaration(ownAttributes.font, ownAttributes);
var normalizedAttr, normalizedValue, normalizedStyle = {};
for (var attr in ownAttributes) {
normalizedAttr = normalizeAttr(attr);
normalizedValue = normalizeValue(normalizedAttr, ownAttributes[attr], parentAttributes, fontSize);
normalizedStyle[normalizedAttr] = normalizedValue;
}
return _setStrokeFillOpacity(extend(parentAttributes, ownAttributes));
if (normalizedStyle && normalizedStyle.font) {
fabric.parseFontDeclaration(normalizedStyle.font, normalizedStyle);
}
var mergedAttrs = extend(parentAttributes, normalizedStyle);
return reAllowedParents.test(element.nodeName) ? mergedAttrs : _setStrokeFillOpacity(mergedAttrs);
},
/**
@ -884,8 +895,8 @@
for (var i = 0, len = propertyValuePairs.length; i < len; i++) {
var pair = propertyValuePairs[i].split(/\s*:\s*/),
property = normalizeAttr(pair[0]),
value = normalizeValue(property, pair[1], pair[0]);
property = pair[0],
value = pair[1];
ruleObj[property] = value;
}
rule = match[1];

View file

@ -145,10 +145,10 @@
var styleObj = fabric.parseStyleAttribute(element);
// TODO: looks like this still fails with % values
var expectedObject = {
'left': 10,
'top': 356.8,
'width': 137.93333333333334,
'height': 20
left: '10px',
top: '22.3em',
width: '103.45pt',
height: '20%'
};
deepEqual(styleObj, expectedObject);
});
@ -158,7 +158,7 @@
element.setAttribute('style', 'left:10px');
var expectedObject = {
'left': 10
left: '10px'
};
deepEqual(fabric.parseStyleAttribute(element), expectedObject);
});
@ -168,8 +168,8 @@
element.setAttribute('style', 'left:10px; top:5px; ');
var expectedObject = {
'left': 10,
'top': 5
left: '10px',
top: '5px'
};
deepEqual(fabric.parseStyleAttribute(element), expectedObject);
});
@ -179,8 +179,8 @@
element.setAttribute('style', 'fill:none; stroke-dasharray: 2 0.4;');
var expectedObject = {
'fill': '',
'strokeDashArray': [2, 0.4]
fill: 'none',
'stroke-dasharray': '2 0.4'
};
deepEqual(fabric.parseStyleAttribute(element), expectedObject);
});
@ -244,6 +244,16 @@
deepEqual(fabric.parseAttributes(element, fabric.Path.ATTRIBUTE_NAMES), expectedObject);
});
test('parse 0 attribute', function() {
var element = fabric.document.createElement('path');
element.setAttribute('opacity', 0);
var expectedObject = {
opacity: 0,
};
deepEqual(fabric.parseAttributes(element, fabric.Path.ATTRIBUTE_NAMES), expectedObject);
});
test('parsePointsAttribute', function() {
ok(fabric.parsePointsAttribute);
@ -348,6 +358,50 @@
});
});
asyncTest('parseSVGFromString nested opacity', function() {
var string = '<?xml version="1.0" encoding="UTF-8"?>' +
'<svg version="1.2" baseProfile="tiny" xml:id="svg-root" width="300" height="400" ' +
'viewBox="0 0 300 400" xmlns="http://www.w3.org/2000/svg" ' +
'xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xe="http://www.w3.org/2001/xml-events">' +
'<defs>' +
'<style>' +
'.cls-3{opacity:0.5;}' +
'.cls-4{opacity:0.5;}' +
'</style>' +
'</defs>' +
'<g fill="red" stroke="#000000" fill-opacity="0.5">' +
'<circle cx="50" cy="50" r="50" fill-opacity="1" fill="rgba(255,0,0,0.3)" />' +
'<circle cx="150" cy="50" r="50" fill="rgba(0,255,0,0.5)" />' +
'<circle cx="50" cy="150" r="50" />' +
'<circle cx="150" cy="150" r="50" fill-opacity="0.5" fill="rgb(0,0,255)" />' +
'<circle cx="250" cy="50" r="50" fill-opacity="0.5" fill="rgba(0,0,255,0.5)" />' +
'<circle cx="250" cy="150" r="50" fill-opacity="1" fill="rgb(0,0,255)" />' +
'</g>' +
'<g class="cls-3" transform="translate(0,200)">' +
'<circle cx="50" cy="50" r="50" class="cls-4" fill="red" />' +
'<circle cx="150" cy="50" r="50" fill="red" />' +
'</g>' +
'</svg>';
fabric.loadSVGFromString(string, function(objects) {
equal(objects[0].fill, 'rgba(255,0,0,0.3)', 'first circle has opacity 0.3 from rgba');
equal(objects[0].fillOpacity, 1,'first circle has fill-opacity 1');
equal(objects[1].fill, 'rgba(0,255,0,0.25)', 'first circle has opacity 0.5 from rgba and 0.5 from gtoup fill opacity');
equal(objects[1].fillOpacity, 0.5,'first circle has fill-opacity 0.5');
equal(objects[2].fill, 'rgba(255,0,0,0.5)', 'first circle has opacity 0.5 from group fill opacity');
equal(objects[2].fillOpacity, 0.5,'first circle has fill-opacity 0.5');
equal(objects[3].fill, 'rgba(0,0,255,0.5)', 'first circle has opacity 0.5 from fill opacity');
equal(objects[3].fillOpacity, 0.5,'first circle has fill-opacity 1');
equal(objects[4].fill, 'rgba(0,0,255,0.25)', 'first circle has opacity 0.5 from rgba and 0.5 from fill opacity');
equal(objects[4].fillOpacity, 0.5,'first circle has fill-opacity 0.5');
equal(objects[5].fill, 'rgba(0,0,255,1)', 'first circle has opacity 1 from rgba');
equal(objects[5].fillOpacity, 1,'first circle has fill-opacity 1');
equal(objects[6].opacity, 0.25, 'opacity is 0.25 for cls-3 * cls-4');
equal(objects[7].opacity, 0.5,'opacity is 0.5 from cls-3');
start();
});
});
asyncTest('parseSVGFromString with svg:namespace', function() {
var string = '<?xml version="1.0" standalone="no"?><svg width="100%" height="100%" version="1.1" xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">' +
'<svg:defs><svg:rect id="myrect" width="300" height="100" style="fill:rgb(0,0,255);stroke-width:1;stroke:rgb(0,0,0)"/></svg:defs>' +
@ -523,15 +577,15 @@
'g polygon.cls': {
'fill': '#FF0000',
'stroke': '#000000',
'strokeWidth': 0.25
'stroke-width': '0.25px'
},
'rect': {
'fill': '#FF0000',
'stroke': '#000000',
'strokeWidth': 0.25
'stroke-width': '0.25px'
},
'polygon.cls': {
'fill': '',
'fill': 'none',
'stroke': '#0000FF'
}
};
@ -575,13 +629,13 @@
'.cls1': {
'fill': '#FF0000',
'stroke': '#00FF00',
'strokeWidth': 3
'stroke-width': '3'
},
'.cls2': {
'fill': '#FF0000'
},
'.cls3': {
'strokeWidth': 3
'stroke-width': '3'
}
};