diff --git a/HEADER.js b/HEADER.js index d83b412dbcd..72f63b52376 100644 --- a/HEADER.js +++ b/HEADER.js @@ -73,6 +73,7 @@ fabric.SHARED_ATTRIBUTES = [ */ fabric.DPI = 96; fabric.reNum = '(?:[-+]?(?:\\d+|\\d*\\.\\d+)(?:[eE][-+]?\\d+)?)'; +fabric.rePathCommand = /([-+]?((\d+\.\d+)|((\d+)|(\.\d+)))(?:[eE][-+]?\d+)?)/ig; fabric.fontPaths = { }; fabric.iMatrix = [1, 0, 0, 1, 0, 0]; diff --git a/src/elements_parser.js b/src/elements_parser.js index 14f2ccbb7ff..b8d07ec95b3 100644 --- a/src/elements_parser.js +++ b/src/elements_parser.js @@ -1,4 +1,4 @@ -fabric.ElementsParser = function(elements, callback, options, reviver, parsingOptions) { +fabric.ElementsParser = function(elements, callback, options, reviver, parsingOptions, doc) { this.elements = elements; this.callback = callback; this.options = options; @@ -6,6 +6,7 @@ fabric.ElementsParser = function(elements, callback, options, reviver, parsingOp this.svgUid = (options && options.svgUid) || 0; this.parsingOptions = parsingOptions; this.regexUrl = /^url\(['"]?#([^'"]+)['"]?\)/g; + this.doc = doc; }; (function(proto) { @@ -52,7 +53,7 @@ fabric.ElementsParser = function(elements, callback, options, reviver, parsingOp _options = obj.parsePreserveAspectRatioAttribute(el); } obj._removeTransformMatrix(_options); - _this.resolveClipPath(obj); + _this.resolveClipPath(obj, el); _this.reviver && _this.reviver(el, obj); _this.instances[index] = obj; _this.checkIfDone(); @@ -60,12 +61,13 @@ fabric.ElementsParser = function(elements, callback, options, reviver, parsingOp }; proto.extractPropertyDefinition = function(obj, property, storage) { - var value = obj[property]; - if (!(/^url\(/).test(value)) { + var value = obj[property], regex = this.regexUrl; + if (!regex.test(value)) { return; } - var id = this.regexUrl.exec(value)[1]; - this.regexUrl.lastIndex = 0; + regex.lastIndex = 0; + var id = regex.exec(value)[1]; + regex.lastIndex = 0; return fabric[storage][this.svgUid][id]; }; @@ -86,12 +88,19 @@ fabric.ElementsParser = function(elements, callback, options, reviver, parsingOp }; }; - proto.resolveClipPath = function(obj) { + proto.resolveClipPath = function(obj, usingElement) { var clipPath = this.extractPropertyDefinition(obj, 'clipPath', 'clipPaths'), element, klass, objTransformInv, container, gTransform, options; if (clipPath) { container = []; objTransformInv = fabric.util.invertTransform(obj.calcTransformMatrix()); + // move the clipPath tag as sibling to the real element that is using it + var clipPathTag = clipPath[0].parentNode; + var clipPathOwner = usingElement; + while (clipPathOwner.parentNode && clipPathOwner.getAttribute('clip-path') !== obj.clipPath) { + clipPathOwner = clipPathOwner.parentNode; + } + clipPathOwner.parentNode.appendChild(clipPathTag); for (var i = 0; i < clipPath.length; i++) { element = clipPath[i]; klass = this.findTag(element); @@ -112,7 +121,7 @@ fabric.ElementsParser = function(elements, callback, options, reviver, parsingOp clipPath.calcTransformMatrix() ); if (clipPath.clipPath) { - this.resolveClipPath(clipPath); + this.resolveClipPath(clipPath, clipPathOwner); } var options = fabric.util.qrDecompose(gTransform); clipPath.flipX = false; diff --git a/src/log.js b/src/log.js index 4e57732fbea..d09cf1e5085 100644 --- a/src/log.js +++ b/src/log.js @@ -2,26 +2,10 @@ * Wrapper around `console.log` (when available) * @param {*} [values] Values to log */ -fabric.log = function() { }; +fabric.log = console.log; /** * Wrapper around `console.warn` (when available) * @param {*} [values] Values to log as a warning */ -fabric.warn = function() { }; - -/* eslint-disable */ -if (typeof console !== 'undefined') { - - ['log', 'warn'].forEach(function(methodName) { - - if (typeof console[methodName] !== 'undefined' && - typeof console[methodName].apply === 'function') { - - fabric[methodName] = function() { - return console[methodName].apply(console, arguments); - }; - } - }); -} -/* eslint-enable */ +fabric.warn = console.warn; diff --git a/src/parser.js b/src/parser.js index f8428bef845..5c93e9f8577 100644 --- a/src/parser.js +++ b/src/parser.js @@ -55,7 +55,9 @@ colorAttributes = { stroke: 'strokeOpacity', fill: 'fillOpacity' - }; + }, + + fSize = 'font-size', cPath = 'clip-path'; fabric.svgValidTagNamesRegEx = getSvgRegex(svgValidTagNames); fabric.svgViewBoxElementsRegEx = getSvgRegex(svgViewBoxElements); @@ -847,13 +849,21 @@ }, { }); // 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))); - + var cssAttrs = extend( + getGlobalStylesForElement(element, svgUid), + fabric.parseStyleAttribute(element) + ); + ownAttributes = extend( + ownAttributes, + cssAttrs + ); + if (cssAttrs[cPath]) { + element.setAttribute(cPath, cssAttrs[cPath]); + } fontSize = parentFontSize = parentAttributes.fontSize || fabric.Text.DEFAULT_SVG_FONT_SIZE; - if (ownAttributes['font-size']) { + if (ownAttributes[fSize]) { // looks like the minimum should be 9px when dealing with ems. this is what looks like in browsers. - ownAttributes['font-size'] = fontSize = parseUnit(ownAttributes['font-size'], parentFontSize); + ownAttributes[fSize] = fontSize = parseUnit(ownAttributes[fSize], parentFontSize); } var normalizedAttr, normalizedValue, normalizedStyle = {}; diff --git a/src/shapes/path.class.js b/src/shapes/path.class.js index a2cfb4c4352..70eb3eb3069 100644 --- a/src/shapes/path.class.js +++ b/src/shapes/path.class.js @@ -500,7 +500,7 @@ coords = [], currentPath, parsed, - re = /([-+]?((\d+\.\d+)|((\d+)|(\.\d+)))(?:e[-+]?\d+)?)/ig, + re = fabric.rePathCommand, match, coordsStr; diff --git a/test/visual/assets/emoji-b.svg b/test/visual/assets/emoji-b.svg new file mode 100644 index 00000000000..0c2c8cd4077 --- /dev/null +++ b/test/visual/assets/emoji-b.svg @@ -0,0 +1 @@ +image/svg+xml diff --git a/test/visual/assets/gold-logo.svg b/test/visual/assets/gold-logo.svg new file mode 100644 index 00000000000..751f8d39418 --- /dev/null +++ b/test/visual/assets/gold-logo.svg @@ -0,0 +1,801 @@ +image/svg+xml diff --git a/test/visual/golden/clippath-8.png b/test/visual/golden/clippath-8.png index 861210b215c..d77a6414078 100644 Binary files a/test/visual/golden/clippath-8.png and b/test/visual/golden/clippath-8.png differ diff --git a/test/visual/golden/emoji-b.png b/test/visual/golden/emoji-b.png new file mode 100644 index 00000000000..c15ed0615cb Binary files /dev/null and b/test/visual/golden/emoji-b.png differ diff --git a/test/visual/golden/gold-logo.png b/test/visual/golden/gold-logo.png new file mode 100644 index 00000000000..ade6e762099 Binary files /dev/null and b/test/visual/golden/gold-logo.png differ diff --git a/test/visual/svg_import.js b/test/visual/svg_import.js index ed04987e4f5..ac53459f1cb 100644 --- a/test/visual/svg_import.js +++ b/test/visual/svg_import.js @@ -79,7 +79,9 @@ 'vector-effect', 'svg-with-no-dim-rect', 'notoemoji-person', - //'clippath-8', + // 'clippath-8', + 'emoji-b', + 'gold-logo' ].map(createTestFromSVG); tests.forEach(visualTestLoop(QUnit));