From 0a90674e893f872580cd63a64163ef635527772f Mon Sep 17 00:00:00 2001 From: Andy Balaam Date: Fri, 17 Jun 2022 12:03:29 +0100 Subject: [PATCH] Fix crash when drawing blurHash for portrait videos PSB-139 (#8855) --- src/settings/enums/ImageSize.ts | 2 +- .../views/messages/MVideoBody-test.tsx | 85 +++++++++++++++++++ .../__snapshots__/MVideoBody-test.tsx.snap | 3 + test/settings/enums/ImageSize-test.ts | 4 + 4 files changed, 93 insertions(+), 1 deletion(-) create mode 100644 test/components/views/messages/MVideoBody-test.tsx create mode 100644 test/components/views/messages/__snapshots__/MVideoBody-test.tsx.snap diff --git a/src/settings/enums/ImageSize.ts b/src/settings/enums/ImageSize.ts index 93cc2362737..1c2b8221048 100644 --- a/src/settings/enums/ImageSize.ts +++ b/src/settings/enums/ImageSize.ts @@ -20,7 +20,7 @@ const SIZE_LARGE = { w: 800, h: 600 }; // For Normal the image gets drawn to never exceed SIZE_NORMAL.w, SIZE_NORMAL.h // constraint by: timeline width, manual height overrides const SIZE_NORMAL_LANDSCAPE = { w: 324, h: 324 }; // for w > h -const SIZE_NORMAL_PORTRAIT = { w: 324 * (9/16), h: 324 }; // for h > w +const SIZE_NORMAL_PORTRAIT = { w: Math.ceil(324 * (9/16)), h: 324 }; // for h > w type Dimensions = { w: number, h: number }; diff --git a/test/components/views/messages/MVideoBody-test.tsx b/test/components/views/messages/MVideoBody-test.tsx new file mode 100644 index 00000000000..09d93f4d4a3 --- /dev/null +++ b/test/components/views/messages/MVideoBody-test.tsx @@ -0,0 +1,85 @@ +/* +Copyright 2022 The Matrix.org Foundation C.I.C. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +import React from 'react'; +import { mount, ReactWrapper } from "enzyme"; +import { MatrixEvent } from 'matrix-js-sdk/src/matrix'; + +import MatrixClientContext from "../../../../src/contexts/MatrixClientContext"; +import { RoomPermalinkCreator } from "../../../../src/utils/permalinks/Permalinks"; +import { MediaEventHelper } from "../../../../src/utils/MediaEventHelper"; +import { getMockClientWithEventEmitter } from '../../../test-utils'; +import MVideoBody from '../../../../src/components/views/messages/MVideoBody'; + +jest.mock( + "../../../../src/customisations/Media", + () => { + return { mediaFromContent: () => { return { isEncrypted: false }; } }; + }, +); + +describe("MVideoBody", () => { + it('does not crash when given a portrait image', () => { + // Check for an unreliable crash caused by a fractional-sized + // image dimension being used for a CanvasImageData. + expect(makeMVideoBody(720, 1280).html()).toMatchSnapshot(); + // If we get here, we did not crash. + }); +}); + +function makeMVideoBody(w: number, h: number): ReactWrapper, MVideoBody> { + const content = { + info: { + "w": w, + "h": h, + "mimetype": "video/mp4", + "size": 2495675, + "thumbnail_file": { + url: "", + key: { alg: "", key_ops: [], kty: "", k: "", ext: true }, + iv: "", + hashes: {}, + v: "", + }, + "thumbnail_info": { mimetype: "" }, + "xyz.amorgan.blurhash": "TrGl6bofof~paxWC?bj[oL%2fPj]", + }, + url: "http://example.com", + }; + + const event = new MatrixEvent({ + content, + }); + + const defaultProps = { + mxEvent: event, + highlights: [], + highlightLink: '', + onHeightChanged: jest.fn(), + onMessageAllowed: jest.fn(), + permalinkCreator: {} as RoomPermalinkCreator, + mediaEventHelper: { media: { isEncrypted: false } } as MediaEventHelper, + }; + + const mockClient = getMockClientWithEventEmitter({ + mxcUrlToHttp: jest.fn(), + }); + + return mount(, { + wrappingComponent: MatrixClientContext.Provider, + wrappingComponentProps: { value: mockClient }, + }); +} diff --git a/test/components/views/messages/__snapshots__/MVideoBody-test.tsx.snap b/test/components/views/messages/__snapshots__/MVideoBody-test.tsx.snap new file mode 100644 index 00000000000..43b33baf82d --- /dev/null +++ b/test/components/views/messages/__snapshots__/MVideoBody-test.tsx.snap @@ -0,0 +1,3 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`MVideoBody does not crash when given a portrait image 1`] = `"
"`; diff --git a/test/settings/enums/ImageSize-test.ts b/test/settings/enums/ImageSize-test.ts index 55de23f9241..0eb89a45bba 100644 --- a/test/settings/enums/ImageSize-test.ts +++ b/test/settings/enums/ImageSize-test.ts @@ -38,5 +38,9 @@ describe("ImageSize", () => { const size = suggestedSize(ImageSize.Normal, { w: 642, h: 350 }); // does not divide evenly expect(size).toStrictEqual({ w: 324, h: 176 }); }); + it("returns integer values for portrait images", () => { + const size = suggestedSize(ImageSize.Normal, { w: 720, h: 1280 }); + expect(size).toStrictEqual({ w: 182, h: 324 }); + }); }); });