11const Matrix = require ( 'transformation-matrix' ) ;
22const SvgElement = require ( './svg-element' ) ;
3+ const { isPaintableElement, isContainerElement} = require ( './element-categories' ) ;
34const log = require ( './util/log' ) ;
45
56/**
@@ -288,14 +289,6 @@ const _transformPath = function (pathString, transform) {
288289 return result ;
289290} ;
290291
291- const GRAPHICS_ELEMENTS = [ 'circle' , 'ellipse' , 'image' , 'line' , 'path' , 'polygon' , 'polyline' , 'rect' , 'text' , 'use' ] ;
292- const CONTAINER_ELEMENTS = [ 'a' , 'defs' , 'g' , 'marker' , 'glyph' , 'missing-glyph' , 'pattern' , 'svg' , 'switch' , 'symbol' ] ;
293- const _isContainerElement = function ( element ) {
294- return element . tagName && CONTAINER_ELEMENTS . includes ( element . tagName . toLowerCase ( ) ) ;
295- } ;
296- const _isGraphicsElement = function ( element ) {
297- return element . tagName && GRAPHICS_ELEMENTS . includes ( element . tagName . toLowerCase ( ) ) ;
298- } ;
299292const _isPathWithTransformAndStroke = function ( element , strokeWidth ) {
300293 if ( ! element . attributes ) return false ;
301294 strokeWidth = element . attributes [ 'stroke-width' ] ?
@@ -372,6 +365,13 @@ const _createGradient = function (gradientId, svgTag, bbox, matrix) {
372365 const newGradientId = `${ gradientId } -${ matrixString } ` ;
373366 newGradient . setAttribute ( 'id' , newGradientId ) ;
374367
368+ // This gradient already exists and was transformed before. Just reuse the already-transformed one.
369+ if ( svgTag . getElementById ( newGradientId ) ) {
370+ // This is the same code as in the end of the function, but I don't feel like wrapping the next 80 lines
371+ // in an `if (!svgTag.getElementById(newGradientId))` block
372+ return `url(#${ newGradientId } )` ;
373+ }
374+
375375 const scaleToBounds = getValue ( newGradient , 'gradientUnits' , true ) !==
376376 'userSpaceOnUse' ;
377377 let origin ;
@@ -505,14 +505,16 @@ const _parseUrl = (value, windowRef) => {
505505 */
506506const transformStrokeWidths = function ( svgTag , windowRef , bboxForTesting ) {
507507 const inherited = Matrix . identity ( ) ;
508- const applyTransforms = ( element , matrix , strokeWidth , fill ) => {
509- if ( _isContainerElement ( element ) ) {
508+
509+ const applyTransforms = ( element , matrix , strokeWidth , fill , stroke ) => {
510+ if ( isContainerElement ( element ) ) {
510511 // Push fills and stroke width down to leaves
511512 if ( element . attributes [ 'stroke-width' ] ) {
512513 strokeWidth = element . attributes [ 'stroke-width' ] . value ;
513514 }
514- if ( element . attributes && element . attributes . fill ) {
515- fill = element . attributes . fill . value ;
515+ if ( element . attributes ) {
516+ if ( element . attributes . fill ) fill = element . attributes . fill . value ;
517+ if ( element . attributes . stroke ) stroke = element . attributes . stroke . value ;
516518 }
517519
518520 // If any child nodes don't take attributes, leave the attributes
@@ -522,30 +524,34 @@ const transformStrokeWidths = function (svgTag, windowRef, bboxForTesting) {
522524 element . childNodes [ i ] ,
523525 Matrix . compose ( matrix , _parseTransform ( element ) ) ,
524526 strokeWidth ,
525- fill
527+ fill ,
528+ stroke
526529 ) ;
527530 }
528531 element . removeAttribute ( 'transform' ) ;
529532 element . removeAttribute ( 'stroke-width' ) ;
530533 element . removeAttribute ( 'fill' ) ;
534+ element . removeAttribute ( 'stroke' ) ;
531535 } else if ( _isPathWithTransformAndStroke ( element , strokeWidth ) ) {
532536 if ( element . attributes [ 'stroke-width' ] ) {
533537 strokeWidth = element . attributes [ 'stroke-width' ] . value ;
534538 }
535- if ( element . attributes . fill ) {
536- fill = element . attributes . fill . value ;
537- }
539+ if ( element . attributes . fill ) fill = element . attributes . fill . value ;
540+ if ( element . attributes . stroke ) stroke = element . attributes . stroke . value ;
538541 matrix = Matrix . compose ( matrix , _parseTransform ( element ) ) ;
539542 if ( Matrix . toString ( matrix ) === Matrix . toString ( Matrix . identity ( ) ) ) {
540543 element . removeAttribute ( 'transform' ) ;
541544 element . setAttribute ( 'stroke-width' , strokeWidth ) ;
542545 if ( fill ) element . setAttribute ( 'fill' , fill ) ;
546+ if ( stroke ) element . setAttribute ( 'stroke' , stroke ) ;
543547 return ;
544548 }
545549
546550 // Transform gradient
547- const gradientId = _parseUrl ( fill , windowRef ) ;
548- if ( gradientId ) {
551+ const fillGradientId = _parseUrl ( fill , windowRef ) ;
552+ const strokeGradientId = _parseUrl ( stroke , windowRef ) ;
553+
554+ if ( fillGradientId || strokeGradientId ) {
549555 const doc = windowRef . document ;
550556 // Need path bounds to transform gradient
551557 const svgSpot = doc . createElement ( 'span' ) ;
@@ -555,8 +561,8 @@ const transformStrokeWidths = function (svgTag, windowRef, bboxForTesting) {
555561 } else {
556562 try {
557563 doc . body . appendChild ( svgSpot ) ;
558- const svg = SvgElement . set ( windowRef . document . createElementNS ( SvgElement . svg , 'svg' ) ) ;
559- const path = SvgElement . set ( windowRef . document . createElementNS ( SvgElement . svg , 'path' ) ) ;
564+ const svg = SvgElement . set ( doc . createElementNS ( SvgElement . svg , 'svg' ) ) ;
565+ const path = SvgElement . set ( doc . createElementNS ( SvgElement . svg , 'path' ) ) ;
560566 path . setAttribute ( 'd' , element . attributes . d . value ) ;
561567 svg . appendChild ( path ) ;
562568 svgSpot . appendChild ( svg ) ;
@@ -568,8 +574,15 @@ const transformStrokeWidths = function (svgTag, windowRef, bboxForTesting) {
568574 }
569575 }
570576
571- const newRef = _createGradient ( gradientId , svgTag , bbox , matrix ) ;
572- if ( newRef ) fill = newRef ;
577+ if ( fillGradientId ) {
578+ const newFillRef = _createGradient ( fillGradientId , svgTag , bbox , matrix ) ;
579+ if ( newFillRef ) fill = newFillRef ;
580+ }
581+
582+ if ( strokeGradientId ) {
583+ const newStrokeRef = _createGradient ( strokeGradientId , svgTag , bbox , matrix ) ;
584+ if ( newStrokeRef ) stroke = newStrokeRef ;
585+ }
573586 }
574587
575588 // Transform path data
@@ -580,14 +593,18 @@ const transformStrokeWidths = function (svgTag, windowRef, bboxForTesting) {
580593 const matrixScale = _getScaleFactor ( matrix ) ;
581594 element . setAttribute ( 'stroke-width' , _quadraticMean ( matrixScale . x , matrixScale . y ) * strokeWidth ) ;
582595 if ( fill ) element . setAttribute ( 'fill' , fill ) ;
583- } else if ( _isGraphicsElement ( element ) ) {
584- // Push stroke width and fill down to leaves
596+ if ( stroke ) element . setAttribute ( 'stroke' , stroke ) ;
597+ } else if ( isPaintableElement ( element ) ) {
598+ // Push stroke width, fill, and stroke down to leaves
585599 if ( strokeWidth && ! element . attributes [ 'stroke-width' ] ) {
586600 element . setAttribute ( 'stroke-width' , strokeWidth ) ;
587601 }
588602 if ( fill && ! element . attributes . fill ) {
589603 element . setAttribute ( 'fill' , fill ) ;
590604 }
605+ if ( stroke && ! element . attributes . stroke ) {
606+ element . setAttribute ( 'stroke' , stroke ) ;
607+ }
591608
592609 // Push transform down to leaves
593610 matrix = Matrix . compose ( matrix , _parseTransform ( element ) ) ;
0 commit comments