From 357a9a029f0216877e34ce824d36fa336997179c Mon Sep 17 00:00:00 2001 From: Yuri Papouski Date: Thu, 8 Sep 2022 11:33:44 +0000 Subject: [PATCH] Fix SVG images --- .../image-element-container.ts | 48 +++++++++++-------- src/render/canvas/canvas-renderer.ts | 48 ++++++++++++------- 2 files changed, 58 insertions(+), 38 deletions(-) diff --git a/src/dom/replaced-elements/image-element-container.ts b/src/dom/replaced-elements/image-element-container.ts index 16814c0..96a6312 100644 --- a/src/dom/replaced-elements/image-element-container.ts +++ b/src/dom/replaced-elements/image-element-container.ts @@ -4,39 +4,47 @@ import {serializeSvg, deserializeSvg} from '../../core/features'; export class ImageElementContainer extends ElementContainer { src: string; - intrinsicWidth: number; - intrinsicHeight: number; + intrinsicWidth: number = 0; + intrinsicHeight: number = 0; + isSVG: boolean; - private static INLINE_SVG = /^data:image\/svg\+xml/i; + private static SVG = /\.svg$/i; + private static INLINED_SVG = /^data:image\/svg\+xml/i; private static IS_FIRE_FOX = /firefox/i.test(navigator?.userAgent); constructor(context: Context, img: HTMLImageElement) { super(context, img); this.src = img.currentSrc || img.src; - this.intrinsicWidth = img.naturalWidth; - this.intrinsicHeight = img.naturalHeight; - this.update(); + this.isSVG = this.isSvg() || this.isInlinedSvg(); this.context.cache.addImage(this.src); } - private update() { - if (!this.intrinsicWidth || !this.intrinsicHeight || ImageElementContainer.IS_FIRE_FOX) { - if (ImageElementContainer.INLINE_SVG.test(this.src)) { - const [, inlinedSvg] = this.src.split(','); - const svgElement = deserializeSvg(inlinedSvg); + private isInlinedSvg = () => ImageElementContainer.INLINED_SVG.test(this.src); + private isSvg = () => ImageElementContainer.SVG.test(this.src); - const { - width: {baseVal: widthBaseVal}, - height: {baseVal: heightBaseVal} - } = svgElement; + public setup(img: HTMLImageElement) { + if (this.isSvg()) return; + + if (this.isInlinedSvg()) { + const [, inlinedSvg] = this.src.split(','); + const svgElement = deserializeSvg(inlinedSvg); + const { + width: {baseVal: widthBaseVal}, + height: {baseVal: heightBaseVal} + } = svgElement; + + if (ImageElementContainer.IS_FIRE_FOX) { widthBaseVal.valueAsString = widthBaseVal.value.toString(); heightBaseVal.valueAsString = heightBaseVal.value.toString(); - this.src = serializeSvg(svgElement, 'base64'); - - this.intrinsicWidth = widthBaseVal.value; - this.intrinsicHeight = heightBaseVal.value; - return; + img.src = serializeSvg(svgElement, 'base64'); } + + this.intrinsicWidth = widthBaseVal.value; + this.intrinsicHeight = heightBaseVal.value; + return; } + + this.intrinsicWidth = img.naturalWidth; + this.intrinsicHeight = img.naturalHeight; } } diff --git a/src/render/canvas/canvas-renderer.ts b/src/render/canvas/canvas-renderer.ts index 6efb648..5f86732 100644 --- a/src/render/canvas/canvas-renderer.ts +++ b/src/render/canvas/canvas-renderer.ts @@ -270,24 +270,35 @@ export class CanvasRenderer extends Renderer { curves: BoundCurves, image: HTMLImageElement | HTMLCanvasElement ): void { - if (image && container.intrinsicWidth > 0 && container.intrinsicHeight > 0) { - const box = contentBox(container); - const path = calculatePaddingBoxPath(curves); - this.path(path); - this.ctx.save(); - this.ctx.clip(); - this.ctx.drawImage( - image, - 0, - 0, - container.intrinsicWidth, - container.intrinsicHeight, - box.left, - box.top, - box.width, - box.height - ); - this.ctx.restore(); + if (image) { + const isContainerWSizes = container.intrinsicWidth > 0 && container.intrinsicHeight > 0; + const isSVGContainer = + container instanceof SVGElementContainer || + (container instanceof ImageElementContainer && container.isSVG); + if (isContainerWSizes || isSVGContainer) { + const box = contentBox(container); + const path = calculatePaddingBoxPath(curves); + this.path(path); + this.ctx.save(); + this.ctx.clip(); + if (isContainerWSizes) { + this.ctx.drawImage( + image, + 0, + 0, + container.intrinsicWidth, + container.intrinsicHeight, + box.left, + box.top, + box.width, + box.height + ); + } else { + // As usual it won't work in FF. https://bugzilla.mozilla.org/show_bug.cgi?id=700533 + this.ctx.drawImage(image, box.left, box.top, box.width, box.height); + } + this.ctx.restore(); + } } } @@ -303,6 +314,7 @@ export class CanvasRenderer extends Renderer { if (container instanceof ImageElementContainer) { try { const image = await this.context.cache.match(container.src); + container.setup(image); this.renderReplacedElement(container, curves, image); } catch (e) { this.context.logger.error(`Error loading image ${container.src}`);