Properly maintain aspect ratio of inline images (#7503)

This commit is contained in:
Michael Telatynski 2022-01-10 15:32:06 +00:00 committed by GitHub
parent 5cfb046816
commit 3c1ce77d48
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 28 additions and 8 deletions

View file

@ -450,6 +450,15 @@ $left-gutter: 64px;
pre { pre {
border: 1px solid transparent; border: 1px solid transparent;
} }
// selector wrongly applies to pill avatars but those have explicit width/height passed at a higher specificity
&.markdown-body img {
// the image will have max-width and max-height applied during sanitization
width: 100%;
height: 100%;
object-fit: contain;
object-position: left top;
}
} }
.mx_EventTile_clamp { .mx_EventTile_clamp {

View file

@ -207,8 +207,12 @@ const transformTags: IExtendedSanitizeOptions["transformTags"] = { // custom to
return { tagName, attribs: {} }; return { tagName, attribs: {} };
} }
const width = Number(attribs.width) || 800; const width = Math.min(Number(attribs.width) || 800, 800);
const height = Number(attribs.height) || 600; const height = Math.min(Number(attribs.height) || 600, 600);
// specify width/height as max values instead of absolute ones to allow object-fit to do its thing
// we only allow our own styles for this tag so overwrite the attribute
attribs.style = `max-width: ${width}px; max-height: ${height}px;`;
attribs.src = mediaFromMxc(src).getThumbnailOfSourceHttp(width, height); attribs.src = mediaFromMxc(src).getThumbnailOfSourceHttp(width, height);
return { tagName, attribs }; return { tagName, attribs };
}, },
@ -223,9 +227,12 @@ const transformTags: IExtendedSanitizeOptions["transformTags"] = { // custom to
return { tagName, attribs }; return { tagName, attribs };
}, },
'*': function(tagName: string, attribs: sanitizeHtml.Attributes) { '*': function(tagName: string, attribs: sanitizeHtml.Attributes) {
// Delete any style previously assigned, style is an allowedTag for font and span // Delete any style previously assigned, style is an allowedTag for font, span & img,
// because attributes are stripped after transforming // because attributes are stripped after transforming.
delete attribs.style; // For img this is trusted as it is generated wholly within the img transformation method.
if (tagName !== "img") {
delete attribs.style;
}
// Sanitise and transform data-mx-color and data-mx-bg-color to their CSS // Sanitise and transform data-mx-color and data-mx-bg-color to their CSS
// equivalents // equivalents
@ -249,7 +256,7 @@ const transformTags: IExtendedSanitizeOptions["transformTags"] = { // custom to
}); });
if (style) { if (style) {
attribs.style = style; attribs.style = style + (attribs.style || "");
} }
return { tagName, attribs }; return { tagName, attribs };
@ -266,12 +273,15 @@ const sanitizeHtmlParams: IExtendedSanitizeOptions = {
'details', 'summary', 'details', 'summary',
], ],
allowedAttributes: { allowedAttributes: {
// attribute sanitization happens after transformations, so we have to accept `style` for font, span & img
// but strip during the transformation.
// custom ones first: // custom ones first:
font: ['color', 'data-mx-bg-color', 'data-mx-color', 'style'], // custom to matrix font: ['color', 'data-mx-bg-color', 'data-mx-color', 'style'], // custom to matrix
span: ['data-mx-maths', 'data-mx-bg-color', 'data-mx-color', 'data-mx-spoiler', 'style'], // custom to matrix span: ['data-mx-maths', 'data-mx-bg-color', 'data-mx-color', 'data-mx-spoiler', 'style'], // custom to matrix
div: ['data-mx-maths'], div: ['data-mx-maths'],
a: ['href', 'name', 'target', 'rel'], // remote target: custom to matrix a: ['href', 'name', 'target', 'rel'], // remote target: custom to matrix
img: ['src', 'width', 'height', 'alt', 'title'], // img tags also accept width/height, we just map those to max-width & max-height during transformation
img: ['src', 'alt', 'title', 'style'],
ol: ['start'], ol: ['start'],
code: ['class'], // We don't actually allow all classes, we filter them in transformTags code: ['class'], // We don't actually allow all classes, we filter them in transformTags
}, },

View file

@ -264,7 +264,8 @@ describe('GroupView', function() {
const imgSrc = "https://my.home.server/_matrix/media/r0/thumbnail/someimageurl" + const imgSrc = "https://my.home.server/_matrix/media/r0/thumbnail/someimageurl" +
"?width=800&height=600&method=scale"; "?width=800&height=600&method=scale";
expect(longDescElement.innerHTML).toContain('<img src="' + imgSrc + '">'); expect(longDescElement.innerHTML).toContain('<img src="' + imgSrc + '" ' +
'style="max-width:800px;max-height:600px">');
}); });
httpBackend httpBackend