diff --git a/src/parser.js b/src/parser.js
index 23e41489..3c71c44b 100644
--- a/src/parser.js
+++ b/src/parser.js
@@ -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];
diff --git a/test/unit/parser.js b/test/unit/parser.js
index e675037e..49a739e4 100644
--- a/test/unit/parser.js
+++ b/test/unit/parser.js
@@ -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 = '' +
+ '';
+
+ 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 = '