From 66072945730e5687f4c399401c62ac82c6429746 Mon Sep 17 00:00:00 2001
From: Germain Souquet <germain@souquet.com>
Date: Mon, 28 Jun 2021 16:30:48 +0100
Subject: [PATCH] Deprecate Tinter and TintableSVG

---
 src/Tinter.js                                 | 458 ------------------
 src/components/structures/GroupView.js        |   9 +-
 src/components/structures/MatrixChat.tsx      |  10 -
 src/components/structures/MyGroups.js         |   2 +-
 src/components/structures/RoomView.tsx        |  16 +-
 src/components/views/elements/ActionButton.js |   4 +-
 src/components/views/elements/AddressTile.js  |   3 +-
 src/components/views/elements/TintableSvg.js  |  82 ----
 .../views/rooms/SimpleRoomHeader.js           |   4 +-
 src/i18n/strings/en_EN.json                   |   1 -
 src/settings/Settings.tsx                     |   8 -
 .../handlers/RoomAccountSettingsHandler.ts    |  16 -
 src/theme.js                                  |   2 -
 13 files changed, 8 insertions(+), 607 deletions(-)
 delete mode 100644 src/Tinter.js
 delete mode 100644 src/components/views/elements/TintableSvg.js

diff --git a/src/Tinter.js b/src/Tinter.js
deleted file mode 100644
index ca5a460e16..0000000000
--- a/src/Tinter.js
+++ /dev/null
@@ -1,458 +0,0 @@
-/*
-Copyright 2015 OpenMarket Ltd
-Copyright 2017 New Vector Ltd
-
-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.
-*/
-
-const DEBUG = 0;
-
-// utility to turn #rrggbb or rgb(r,g,b) into [red,green,blue]
-function colorToRgb(color) {
-    if (!color) {
-        return [0, 0, 0];
-    }
-
-    if (color[0] === '#') {
-        color = color.slice(1);
-        if (color.length === 3) {
-            color = color[0] + color[0] +
-                    color[1] + color[1] +
-                    color[2] + color[2];
-        }
-        const val = parseInt(color, 16);
-        const r = (val >> 16) & 255;
-        const g = (val >> 8) & 255;
-        const b = val & 255;
-        return [r, g, b];
-    } else {
-        const match = color.match(/rgb\((.*?),(.*?),(.*?)\)/);
-        if (match) {
-            return [
-                parseInt(match[1]),
-                parseInt(match[2]),
-                parseInt(match[3]),
-            ];
-        }
-    }
-    return [0, 0, 0];
-}
-
-// utility to turn [red,green,blue] into #rrggbb
-function rgbToColor(rgb) {
-    const val = (rgb[0] << 16) | (rgb[1] << 8) | rgb[2];
-    return '#' + (0x1000000 + val).toString(16).slice(1);
-}
-
-class Tinter {
-    constructor() {
-        // The default colour keys to be replaced as referred to in CSS
-        // (should be overridden by .mx_theme_accentColor and .mx_theme_secondaryAccentColor)
-        this.keyRgb = [
-            "rgb(118, 207, 166)", // Vector Green
-            "rgb(234, 245, 240)", // Vector Light Green
-            "rgb(211, 239, 225)", // roomsublist-label-bg-color (20% Green overlaid on Light Green)
-        ];
-
-        // Some algebra workings for calculating the tint % of Vector Green & Light Green
-        // x * 118 + (1 - x) * 255 = 234
-        // x * 118 + 255 - 255 * x = 234
-        // x * 118 - x * 255 = 234 - 255
-        // (255 - 118) x = 255 - 234
-        // x = (255 - 234) / (255 - 118) = 0.16
-
-        // The colour keys to be replaced as referred to in SVGs
-        this.keyHex = [
-            "#76CFA6", // Vector Green
-            "#EAF5F0", // Vector Light Green
-            "#D3EFE1", // roomsublist-label-bg-color (20% Green overlaid on Light Green)
-            "#FFFFFF", // white highlights of the SVGs (for switching to dark theme)
-            "#000000", // black lowlights of the SVGs (for switching to dark theme)
-        ];
-
-        // track the replacement colours actually being used
-        // defaults to our keys.
-        this.colors = [
-            this.keyHex[0],
-            this.keyHex[1],
-            this.keyHex[2],
-            this.keyHex[3],
-            this.keyHex[4],
-        ];
-
-        // track the most current tint request inputs (which may differ from the
-        // end result stored in this.colors
-        this.currentTint = [
-            undefined,
-            undefined,
-            undefined,
-            undefined,
-            undefined,
-        ];
-
-        this.cssFixups = [
-            // { theme: {
-            //      style: a style object that should be fixed up taken from a stylesheet
-            //      attr: name of the attribute to be clobbered, e.g. 'color'
-            //      index: ordinal of primary, secondary or tertiary
-            //   },
-            // }
-        ];
-
-        // CSS attributes to be fixed up
-        this.cssAttrs = [
-            "color",
-            "backgroundColor",
-            "borderColor",
-            "borderTopColor",
-            "borderBottomColor",
-            "borderLeftColor",
-        ];
-
-        this.svgAttrs = [
-            "fill",
-            "stroke",
-        ];
-
-        // List of functions to call when the tint changes.
-        this.tintables = [];
-
-        // the currently loaded theme (if any)
-        this.theme = undefined;
-
-        // whether to force a tint (e.g. after changing theme)
-        this.forceTint = false;
-    }
-
-    /**
-     * Register a callback to fire when the tint changes.
-     * This is used to rewrite the tintable SVGs with the new tint.
-     *
-     * It's not possible to unregister a tintable callback. So this can only be
-     * used to register a static callback. If a set of tintables will change
-     * over time then the best bet is to register a single callback for the
-     * entire set.
-     *
-     * To ensure the tintable work happens at least once, it is also called as
-     * part of registration.
-     *
-     * @param {Function} tintable Function to call when the tint changes.
-     */
-    registerTintable(tintable) {
-        this.tintables.push(tintable);
-        tintable();
-    }
-
-    getKeyRgb() {
-        return this.keyRgb;
-    }
-
-    tint(primaryColor, secondaryColor, tertiaryColor) {
-        return;
-        // eslint-disable-next-line no-unreachable
-        this.currentTint[0] = primaryColor;
-        this.currentTint[1] = secondaryColor;
-        this.currentTint[2] = tertiaryColor;
-
-        this.calcCssFixups();
-
-        if (DEBUG) {
-            console.log("Tinter.tint(" + primaryColor + ", " +
-                secondaryColor + ", " +
-                tertiaryColor + ")");
-        }
-
-        if (!primaryColor) {
-            primaryColor = this.keyRgb[0];
-            secondaryColor = this.keyRgb[1];
-            tertiaryColor = this.keyRgb[2];
-        }
-
-        if (!secondaryColor) {
-            const x = 0.16; // average weighting factor calculated from vector green & light green
-            const rgb = colorToRgb(primaryColor);
-            rgb[0] = x * rgb[0] + (1 - x) * 255;
-            rgb[1] = x * rgb[1] + (1 - x) * 255;
-            rgb[2] = x * rgb[2] + (1 - x) * 255;
-            secondaryColor = rgbToColor(rgb);
-        }
-
-        if (!tertiaryColor) {
-            const x = 0.19;
-            const rgb1 = colorToRgb(primaryColor);
-            const rgb2 = colorToRgb(secondaryColor);
-            rgb1[0] = x * rgb1[0] + (1 - x) * rgb2[0];
-            rgb1[1] = x * rgb1[1] + (1 - x) * rgb2[1];
-            rgb1[2] = x * rgb1[2] + (1 - x) * rgb2[2];
-            tertiaryColor = rgbToColor(rgb1);
-        }
-
-        if (this.forceTint == false &&
-            this.colors[0] === primaryColor &&
-            this.colors[1] === secondaryColor &&
-            this.colors[2] === tertiaryColor) {
-            return;
-        }
-
-        this.forceTint = false;
-
-        this.colors[0] = primaryColor;
-        this.colors[1] = secondaryColor;
-        this.colors[2] = tertiaryColor;
-
-        if (DEBUG) {
-            console.log("Tinter.tint final: (" + primaryColor + ", " +
-                secondaryColor + ", " +
-                tertiaryColor + ")");
-        }
-
-        // go through manually fixing up the stylesheets.
-        this.applyCssFixups();
-
-        // tell all the SVGs to go fix themselves up
-        // we don't do this as a dispatch otherwise it will visually lag
-        this.tintables.forEach(function(tintable) {
-            tintable();
-        });
-    }
-
-    tintSvgWhite(whiteColor) {
-        this.currentTint[3] = whiteColor;
-
-        if (!whiteColor) {
-            whiteColor = this.colors[3];
-        }
-        if (this.colors[3] === whiteColor) {
-            return;
-        }
-        this.colors[3] = whiteColor;
-        this.tintables.forEach(function(tintable) {
-            tintable();
-        });
-    }
-
-    tintSvgBlack(blackColor) {
-        this.currentTint[4] = blackColor;
-
-        if (!blackColor) {
-            blackColor = this.colors[4];
-        }
-        if (this.colors[4] === blackColor) {
-            return;
-        }
-        this.colors[4] = blackColor;
-        this.tintables.forEach(function(tintable) {
-            tintable();
-        });
-    }
-
-
-    setTheme(theme) {
-        this.theme = theme;
-
-        // update keyRgb from the current theme CSS itself, if it defines it
-        if (document.getElementById('mx_theme_accentColor')) {
-            this.keyRgb[0] = window.getComputedStyle(
-                document.getElementById('mx_theme_accentColor')).color;
-        }
-        if (document.getElementById('mx_theme_secondaryAccentColor')) {
-            this.keyRgb[1] = window.getComputedStyle(
-                document.getElementById('mx_theme_secondaryAccentColor')).color;
-        }
-        if (document.getElementById('mx_theme_tertiaryAccentColor')) {
-            this.keyRgb[2] = window.getComputedStyle(
-                document.getElementById('mx_theme_tertiaryAccentColor')).color;
-        }
-
-        this.calcCssFixups();
-        this.forceTint = true;
-
-        this.tint(this.currentTint[0], this.currentTint[1], this.currentTint[2]);
-
-        if (theme === 'dark') {
-            // abuse the tinter to change all the SVG's #fff to #2d2d2d
-            // XXX: obviously this shouldn't be hardcoded here.
-            this.tintSvgWhite('#2d2d2d');
-            this.tintSvgBlack('#dddddd');
-        } else {
-            this.tintSvgWhite('#ffffff');
-            this.tintSvgBlack('#000000');
-        }
-    }
-
-    calcCssFixups() {
-        // cache our fixups
-        if (this.cssFixups[this.theme]) return;
-
-        if (DEBUG) {
-            console.debug("calcCssFixups start for " + this.theme + " (checking " +
-                document.styleSheets.length +
-                " stylesheets)");
-        }
-
-        this.cssFixups[this.theme] = [];
-
-        for (let i = 0; i < document.styleSheets.length; i++) {
-            const ss = document.styleSheets[i];
-            try {
-                if (!ss) continue; // well done safari >:(
-                // Chromium apparently sometimes returns null here; unsure why.
-                // see $14534907369972FRXBx:matrix.org in HQ
-                // ...ah, it's because there's a third party extension like
-                // privacybadger inserting its own stylesheet in there with a
-                // resource:// URI or something which results in a XSS error.
-                // See also #vector:matrix.org/$145357669685386ebCfr:matrix.org
-                // ...except some browsers apparently return stylesheets without
-                // hrefs, which we have no choice but ignore right now
-
-                // XXX seriously? we are hardcoding the name of vector's CSS file in
-                // here?
-                //
-                // Why do we need to limit it to vector's CSS file anyway - if there
-                // are other CSS files affecting the doc don't we want to apply the
-                // same transformations to them?
-                //
-                // Iterating through the CSS looking for matches to hack on feels
-                // pretty horrible anyway. And what if the application skin doesn't use
-                // Vector Green as its primary color?
-                // --richvdh
-
-                // Yes, tinting assumes that you are using the Element skin for now.
-                // The right solution will be to move the CSS over to react-sdk.
-                // And yes, the default assets for the base skin might as well use
-                // Vector Green as any other colour.
-                // --matthew
-
-                // stylesheets we don't have permission to access (eg. ones from extensions) have a null
-                // href and will throw exceptions if we try to access their rules.
-                if (!ss.href || !ss.href.match(new RegExp('/theme-' + this.theme + '.css$'))) continue;
-                if (ss.disabled) continue;
-                if (!ss.cssRules) continue;
-
-                if (DEBUG) console.debug("calcCssFixups checking " + ss.cssRules.length + " rules for " + ss.href);
-
-                for (let j = 0; j < ss.cssRules.length; j++) {
-                    const rule = ss.cssRules[j];
-                    if (!rule.style) continue;
-                    if (rule.selectorText && rule.selectorText.match(/#mx_theme/)) continue;
-                    for (let k = 0; k < this.cssAttrs.length; k++) {
-                        const attr = this.cssAttrs[k];
-                        for (let l = 0; l < this.keyRgb.length; l++) {
-                            if (rule.style[attr] === this.keyRgb[l]) {
-                                this.cssFixups[this.theme].push({
-                                    style: rule.style,
-                                    attr: attr,
-                                    index: l,
-                                });
-                            }
-                        }
-                    }
-                }
-            } catch (e) {
-                // Catch any random exceptions that happen here: all sorts of things can go
-                // wrong with this (nulls, SecurityErrors) and mostly it's for other
-                // stylesheets that we don't want to proces anyway. We should not propagate an
-                // exception out since this will cause the app to fail to start.
-                console.log("Failed to calculate CSS fixups for a stylesheet: " + ss.href, e);
-            }
-        }
-        if (DEBUG) {
-            console.log("calcCssFixups end (" +
-                this.cssFixups[this.theme].length +
-                " fixups)");
-        }
-    }
-
-    applyCssFixups() {
-        if (DEBUG) {
-            console.log("applyCssFixups start (" +
-                this.cssFixups[this.theme].length +
-                " fixups)");
-        }
-        for (let i = 0; i < this.cssFixups[this.theme].length; i++) {
-            const cssFixup = this.cssFixups[this.theme][i];
-            try {
-                cssFixup.style[cssFixup.attr] = this.colors[cssFixup.index];
-            } catch (e) {
-                // Firefox Quantum explodes if you manually edit the CSS in the
-                // inspector and then try to do a tint, as apparently all the
-                // fixups are then stale.
-                console.error("Failed to apply cssFixup in Tinter! ", e.name);
-            }
-        }
-        if (DEBUG) console.log("applyCssFixups end");
-    }
-
-    // XXX: we could just move this all into TintableSvg, but as it's so similar
-    // to the CSS fixup stuff in Tinter (just that the fixups are stored in TintableSvg)
-    // keeping it here for now.
-    calcSvgFixups(svgs) {
-        // go through manually fixing up SVG colours.
-        // we could do this by stylesheets, but keeping the stylesheets
-        // updated would be a PITA, so just brute-force search for the
-        // key colour; cache the element and apply.
-
-        if (DEBUG) console.log("calcSvgFixups start for " + svgs);
-        const fixups = [];
-        for (let i = 0; i < svgs.length; i++) {
-            let svgDoc;
-            try {
-                svgDoc = svgs[i].contentDocument;
-            } catch (e) {
-                let msg = 'Failed to get svg.contentDocument of ' + svgs[i].toString();
-                if (e.message) {
-                    msg += e.message;
-                }
-                if (e.stack) {
-                    msg += ' | stack: ' + e.stack;
-                }
-                console.error(msg);
-            }
-            if (!svgDoc) continue;
-            const tags = svgDoc.getElementsByTagName("*");
-            for (let j = 0; j < tags.length; j++) {
-                const tag = tags[j];
-                for (let k = 0; k < this.svgAttrs.length; k++) {
-                    const attr = this.svgAttrs[k];
-                    for (let l = 0; l < this.keyHex.length; l++) {
-                        if (tag.getAttribute(attr) &&
-                            tag.getAttribute(attr).toUpperCase() === this.keyHex[l]) {
-                            fixups.push({
-                                node: tag,
-                                attr: attr,
-                                index: l,
-                            });
-                        }
-                    }
-                }
-            }
-        }
-        if (DEBUG) console.log("calcSvgFixups end");
-
-        return fixups;
-    }
-
-    applySvgFixups(fixups) {
-        if (DEBUG) console.log("applySvgFixups start for " + fixups);
-        for (let i = 0; i < fixups.length; i++) {
-            const svgFixup = fixups[i];
-            svgFixup.node.setAttribute(svgFixup.attr, this.colors[svgFixup.index]);
-        }
-        if (DEBUG) console.log("applySvgFixups end");
-    }
-}
-
-if (global.singletonTinter === undefined) {
-    global.singletonTinter = new Tinter();
-}
-export default global.singletonTinter;
diff --git a/src/components/structures/GroupView.js b/src/components/structures/GroupView.js
index 3a2c611cc9..2442ff5e25 100644
--- a/src/components/structures/GroupView.js
+++ b/src/components/structures/GroupView.js
@@ -126,12 +126,11 @@ class CategoryRoomList extends React.Component {
     };
 
     render() {
-        const TintableSvg = sdk.getComponent("elements.TintableSvg");
         const addButton = this.props.editing ?
             (<AccessibleButton className="mx_GroupView_featuredThings_addButton"
                 onClick={this.onAddRoomsToSummaryClicked}
             >
-                <TintableSvg src={require("../../../res/img/icons-create-room.svg")} width="64" height="64" />
+                <img src={require("../../../res/img/icons-create-room.svg")} width="64" height="64" />
                 <div className="mx_GroupView_featuredThings_addButton_label">
                     { _t('Add a Room') }
                 </div>
@@ -300,10 +299,9 @@ class RoleUserList extends React.Component {
     };
 
     render() {
-        const TintableSvg = sdk.getComponent("elements.TintableSvg");
         const addButton = this.props.editing ?
             (<AccessibleButton className="mx_GroupView_featuredThings_addButton" onClick={this.onAddUsersClicked}>
-                <TintableSvg src={require("../../../res/img/icons-create-room.svg")} width="64" height="64" />
+                <img src={require("../../../res/img/icons-create-room.svg")} width="64" height="64" />
                 <div className="mx_GroupView_featuredThings_addButton_label">
                     { _t('Add a User') }
                 </div>
@@ -855,7 +853,6 @@ export default class GroupView extends React.Component {
     _getRoomsNode() {
         const RoomDetailList = sdk.getComponent('rooms.RoomDetailList');
         const AccessibleButton = sdk.getComponent('elements.AccessibleButton');
-        const TintableSvg = sdk.getComponent('elements.TintableSvg');
         const Spinner = sdk.getComponent('elements.Spinner');
         const TooltipButton = sdk.getComponent('elements.TooltipButton');
 
@@ -871,7 +868,7 @@ export default class GroupView extends React.Component {
                 onClick={this._onAddRoomsClick}
             >
                 <div className="mx_GroupView_rooms_header_addRow_button">
-                    <TintableSvg src={require("../../../res/img/icons-room-add.svg")} width="24" height="24" />
+                    <img src={require("../../../res/img/icons-room-add.svg")} width="24" height="24" />
                 </div>
                 <div className="mx_GroupView_rooms_header_addRow_label">
                     { _t('Add rooms to this community') }
diff --git a/src/components/structures/MatrixChat.tsx b/src/components/structures/MatrixChat.tsx
index 7986da203d..db11ee17a0 100644
--- a/src/components/structures/MatrixChat.tsx
+++ b/src/components/structures/MatrixChat.tsx
@@ -34,7 +34,6 @@ import dis from "../../dispatcher/dispatcher";
 import Notifier from '../../Notifier';
 
 import Modal from "../../Modal";
-import Tinter from "../../Tinter";
 import * as sdk from '../../index';
 import { showRoomInviteDialog, showStartChatInviteDialog } from '../../RoomInvite';
 import * as Rooms from '../../Rooms';
@@ -283,11 +282,6 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
 
         this.pageChanging = false;
 
-        // check we have the right tint applied for this theme.
-        // N.B. we don't call the whole of setTheme() here as we may be
-        // racing with the theme CSS download finishing from index.js
-        Tinter.tint();
-
         // For PersistentElement
         this.state.resizeNotifier.on("middlePanelResized", this.dispatchTimelineResize);
 
@@ -1573,10 +1567,6 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
                 });
             }
         });
-        // Fire the tinter right on startup to ensure the default theme is applied
-        // A later sync can/will correct the tint to be the right value for the user
-        const colorScheme = SettingsStore.getValue("roomColor");
-        Tinter.tint(colorScheme.primary_color, colorScheme.secondary_color);
     }
 
     /**
diff --git a/src/components/structures/MyGroups.js b/src/components/structures/MyGroups.js
index d0a2fbff41..62a67ee4db 100644
--- a/src/components/structures/MyGroups.js
+++ b/src/components/structures/MyGroups.js
@@ -123,7 +123,7 @@ export default class MyGroups extends React.Component {
                 </div>
                 {/*<div className="mx_MyGroups_joinBox mx_MyGroups_headerCard">
                     <AccessibleButton className='mx_MyGroups_headerCard_button' onClick={this._onJoinGroupClick}>
-                        <TintableSvg src={require("../../../res/img/icons-create-room.svg")} width="50" height="50" />
+                        <img src={require("../../../res/img/icons-create-room.svg")} width="50" height="50" />
                     </AccessibleButton>
                     <div className="mx_MyGroups_headerCard_content">
                         <div className="mx_MyGroups_headerCard_header">
diff --git a/src/components/structures/RoomView.tsx b/src/components/structures/RoomView.tsx
index 885851e8e6..37cce818df 100644
--- a/src/components/structures/RoomView.tsx
+++ b/src/components/structures/RoomView.tsx
@@ -37,7 +37,6 @@ import Modal from '../../Modal';
 import * as sdk from '../../index';
 import CallHandler, { PlaceCallType } from '../../CallHandler';
 import dis from '../../dispatcher/dispatcher';
-import Tinter from '../../Tinter';
 import rateLimitedFunc from '../../ratelimitedfunc';
 import * as Rooms from '../../Rooms';
 import eventSearch, { searchPagination } from '../../Searching';
@@ -677,10 +676,6 @@ export default class RoomView extends React.Component<IProps, IState> {
         // cancel any pending calls to the rate_limited_funcs
         this.updateRoomMembers.cancelPendingCall();
 
-        // no need to do this as Dir & Settings are now overlays. It just burnt CPU.
-        // console.log("Tinter.tint from RoomView.unmount");
-        // Tinter.tint(); // reset colourscheme
-
         for (const watcher of this.settingWatchers) {
             SettingsStore.unwatchSetting(watcher);
         }
@@ -1030,10 +1025,6 @@ export default class RoomView extends React.Component<IProps, IState> {
     private updateTint() {
         const room = this.state.room;
         if (!room) return;
-
-        console.log("Tinter.tint from updateTint");
-        const colorScheme = SettingsStore.getValue("roomColor", room.roomId);
-        Tinter.tint(colorScheme.primary_color, colorScheme.secondary_color);
     }
 
     private onAccountData = (event: MatrixEvent) => {
@@ -1047,12 +1038,7 @@ export default class RoomView extends React.Component<IProps, IState> {
     private onRoomAccountData = (event: MatrixEvent, room: Room) => {
         if (room.roomId == this.state.roomId) {
             const type = event.getType();
-            if (type === "org.matrix.room.color_scheme") {
-                const colorScheme = event.getContent();
-                // XXX: we should validate the event
-                console.log("Tinter.tint from onRoomAccountData");
-                Tinter.tint(colorScheme.primary_color, colorScheme.secondary_color);
-            } else if (type === "org.matrix.room.preview_urls" || type === "im.vector.web.settings") {
+            if (type === "org.matrix.room.preview_urls" || type === "im.vector.web.settings") {
                 // non-e2ee url previews are stored in legacy event type `org.matrix.room.preview_urls`
                 this.updatePreviewUrlVisibility(room);
             }
diff --git a/src/components/views/elements/ActionButton.js b/src/components/views/elements/ActionButton.js
index 5013bcec0d..ffc4b47817 100644
--- a/src/components/views/elements/ActionButton.js
+++ b/src/components/views/elements/ActionButton.js
@@ -62,8 +62,6 @@ export default class ActionButton extends React.Component {
     };
 
     render() {
-        const TintableSvg = sdk.getComponent("elements.TintableSvg");
-
         let tooltip;
         if (this.state.showTooltip) {
             const Tooltip = sdk.getComponent("elements.Tooltip");
@@ -71,7 +69,7 @@ export default class ActionButton extends React.Component {
         }
 
         const icon = this.props.iconPath ?
-            (<TintableSvg src={this.props.iconPath} width={this.props.size} height={this.props.size} />) :
+            (<img src={this.props.iconPath} width={this.props.size} height={this.props.size} />) :
             undefined;
 
         const classNames = ["mx_RoleButton"];
diff --git a/src/components/views/elements/AddressTile.js b/src/components/views/elements/AddressTile.js
index f8fa294b71..ca85d73a11 100644
--- a/src/components/views/elements/AddressTile.js
+++ b/src/components/views/elements/AddressTile.js
@@ -53,7 +53,6 @@ export default class AddressTile extends React.Component {
         }
 
         const BaseAvatar = sdk.getComponent('avatars.BaseAvatar');
-        const TintableSvg = sdk.getComponent("elements.TintableSvg");
 
         const nameClasses = classNames({
             "mx_AddressTile_name": true,
@@ -124,7 +123,7 @@ export default class AddressTile extends React.Component {
         if (this.props.canDismiss) {
             dismiss = (
                 <div className="mx_AddressTile_dismiss" onClick={this.props.onDismissed} >
-                    <TintableSvg src={require("../../../../res/img/icon-address-delete.svg")} width="9" height="9" />
+                    <img src={require("../../../../res/img/icon-address-delete.svg")} width="9" height="9" />
                 </div>
             );
         }
diff --git a/src/components/views/elements/TintableSvg.js b/src/components/views/elements/TintableSvg.js
deleted file mode 100644
index 670f3e9bb9..0000000000
--- a/src/components/views/elements/TintableSvg.js
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
-Copyright 2015 OpenMarket Ltd
-Copyright 2019 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 PropTypes from 'prop-types';
-import Tinter from "../../../Tinter";
-import {replaceableComponent} from "../../../utils/replaceableComponent";
-
-@replaceableComponent("views.elements.TintableSvg")
-class TintableSvg extends React.Component {
-    static propTypes = {
-        src: PropTypes.string.isRequired,
-        width: PropTypes.string.isRequired,
-        height: PropTypes.string.isRequired,
-        className: PropTypes.string,
-    };
-
-    // list of currently mounted TintableSvgs
-    static mounts = {};
-    static idSequence = 0;
-
-    componentDidMount() {
-        this.fixups = [];
-
-        this.id = TintableSvg.idSequence++;
-        TintableSvg.mounts[this.id] = this;
-    }
-
-    componentWillUnmount() {
-        delete TintableSvg.mounts[this.id];
-    }
-
-    tint = () => {
-        // TODO: only bother running this if the global tint settings have changed
-        // since we loaded!
-        Tinter.applySvgFixups(this.fixups);
-    };
-
-    onLoad = event => {
-        // console.log("TintableSvg.onLoad for " + this.props.src);
-        this.fixups = Tinter.calcSvgFixups([event.target]);
-        Tinter.applySvgFixups(this.fixups);
-    };
-
-    render() {
-        return (
-            <object className={"mx_TintableSvg " + (this.props.className ? this.props.className : "")}
-                type="image/svg+xml"
-                data={this.props.src}
-                width={this.props.width}
-                height={this.props.height}
-                onLoad={this.onLoad}
-                tabIndex="-1"
-            />
-        );
-    }
-}
-
-// Register with the Tinter so that we will be told if the tint changes
-Tinter.registerTintable(function() {
-    if (TintableSvg.mounts) {
-        Object.keys(TintableSvg.mounts).forEach((id) => {
-            TintableSvg.mounts[id].tint();
-        });
-    }
-});
-
-export default TintableSvg;
diff --git a/src/components/views/rooms/SimpleRoomHeader.js b/src/components/views/rooms/SimpleRoomHeader.js
index 35e7d44469..2d070ba55d 100644
--- a/src/components/views/rooms/SimpleRoomHeader.js
+++ b/src/components/views/rooms/SimpleRoomHeader.js
@@ -16,7 +16,6 @@ limitations under the License.
 
 import React from 'react';
 import PropTypes from 'prop-types';
-import * as sdk from '../../../index';
 import {replaceableComponent} from "../../../utils/replaceableComponent";
 
 /*
@@ -35,8 +34,7 @@ export default class SimpleRoomHeader extends React.Component {
     render() {
         let icon;
         if (this.props.icon) {
-            const TintableSvg = sdk.getComponent('elements.TintableSvg');
-            icon = <TintableSvg
+            icon = <img
                 className="mx_RoomHeader_icon" src={this.props.icon}
                 width="25" height="25"
             />;
diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json
index bfca730776..9dae200520 100644
--- a/src/i18n/strings/en_EN.json
+++ b/src/i18n/strings/en_EN.json
@@ -857,7 +857,6 @@
     "Enable inline URL previews by default": "Enable inline URL previews by default",
     "Enable URL previews for this room (only affects you)": "Enable URL previews for this room (only affects you)",
     "Enable URL previews by default for participants in this room": "Enable URL previews by default for participants in this room",
-    "Room Colour": "Room Colour",
     "Enable widget screenshots on supported widgets": "Enable widget screenshots on supported widgets",
     "Prompt before sending invites to potentially invalid matrix IDs": "Prompt before sending invites to potentially invalid matrix IDs",
     "Show developer tools": "Show developer tools",
diff --git a/src/settings/Settings.tsx b/src/settings/Settings.tsx
index 6ed5e0c3d8..96820d0ff2 100644
--- a/src/settings/Settings.tsx
+++ b/src/settings/Settings.tsx
@@ -606,14 +606,6 @@ export const SETTINGS: {[setting: string]: ISetting} = {
         default: false,
         controller: new UIFeatureController(UIFeature.URLPreviews),
     },
-    "roomColor": {
-        supportedLevels: LEVELS_ROOM_SETTINGS_WITH_ROOM,
-        displayName: _td("Room Colour"),
-        default: {
-            primary_color: null, // Hex string, eg: #000000
-            secondary_color: null, // Hex string, eg: #000000
-        },
-    },
     "notificationsEnabled": {
         supportedLevels: LEVELS_DEVICE_ONLY_SETTINGS,
         default: false,
diff --git a/src/settings/handlers/RoomAccountSettingsHandler.ts b/src/settings/handlers/RoomAccountSettingsHandler.ts
index 416bdddb90..e0345fde8c 100644
--- a/src/settings/handlers/RoomAccountSettingsHandler.ts
+++ b/src/settings/handlers/RoomAccountSettingsHandler.ts
@@ -54,8 +54,6 @@ export default class RoomAccountSettingsHandler extends MatrixClientBackedSettin
             }
 
             this.watchers.notifyUpdate("urlPreviewsEnabled", roomId, SettingLevel.ROOM_ACCOUNT, val);
-        } else if (event.getType() === "org.matrix.room.color_scheme") {
-            this.watchers.notifyUpdate("roomColor", roomId, SettingLevel.ROOM_ACCOUNT, event.getContent());
         } else if (event.getType() === "im.vector.web.settings") {
             // Figure out what changed and fire those updates
             const prevContent = prevEvent ? prevEvent.getContent() : {};
@@ -79,14 +77,6 @@ export default class RoomAccountSettingsHandler extends MatrixClientBackedSettin
             return !content['disable'];
         }
 
-        // Special case room color
-        if (settingName === "roomColor") {
-            // The event content should already be in an appropriate format, we just need
-            // to get the right value.
-            // don't fallback to {} because thats truthy and would imply there is an event specifying tint
-            return this.getSettings(roomId, "org.matrix.room.color_scheme");
-        }
-
         // Special case allowed widgets
         if (settingName === "allowedWidgets") {
             return this.getSettings(roomId, ALLOWED_WIDGETS_EVENT_TYPE);
@@ -104,12 +94,6 @@ export default class RoomAccountSettingsHandler extends MatrixClientBackedSettin
             return MatrixClientPeg.get().setRoomAccountData(roomId, "org.matrix.room.preview_urls", content);
         }
 
-        // Special case room color
-        if (settingName === "roomColor") {
-            // The new value should match our requirements, we just need to store it in the right place.
-            return MatrixClientPeg.get().setRoomAccountData(roomId, "org.matrix.room.color_scheme", newValue);
-        }
-
         // Special case allowed widgets
         if (settingName === "allowedWidgets") {
             return MatrixClientPeg.get().setRoomAccountData(roomId, ALLOWED_WIDGETS_EVENT_TYPE, newValue);
diff --git a/src/theme.js b/src/theme.js
index 40fa291cfc..0b73b3f5e2 100644
--- a/src/theme.js
+++ b/src/theme.js
@@ -18,7 +18,6 @@ limitations under the License.
 import {_t} from "./languageHandler";
 
 export const DEFAULT_THEME = "light";
-import Tinter from "./Tinter";
 import SettingsStore from "./settings/SettingsStore";
 import ThemeWatcher from "./settings/watchers/ThemeWatcher";
 
@@ -214,7 +213,6 @@ export async function setTheme(theme) {
             if (bodyStyles.backgroundColor) {
                 document.querySelector('meta[name="theme-color"]').content = bodyStyles.backgroundColor;
             }
-            Tinter.setTheme(theme);
             resolve();
         };