/** * Copyright 2015 CANAL+ Group * * 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 log from "../../../log"; import arrayFindIndex from "../../../utils/array_find_index"; import arrayIncludes from "../../../utils/array_includes"; import objectAssign from "../../../utils/object_assign"; import type { IStyleObject } from "./get_styling"; /** * Transform all styles inheriting from other styles to the same styles but with * the inheritance removed (by resolving those inheritance here). * * Note that the original style object is directly mutated with every * inheritance they had resolved and removed. * * To make a pseudo-code analogy this would be equivalent to transform those * two classes: * ``` * class A { * methodA() {} * } * * class B extends A { * method B() {} * } * ``` * into the same two classes without inheritance: * ``` * class A { * methodA() {} * } * class B { * methodA() {} // inherited from class A * methodB() {} * } * ``` * * Doing this here allows to simplify further treatment of those styles. * @param {Array.} styles */ export default function resolveStylesInheritance(styles: IStyleObject[]): void { // keep track of all the indexes parsed to avoid infinite loops const recursivelyBrowsedIndexes: number[] = []; function resolveStyleInheritance(styleElt: IStyleObject, index: number) { recursivelyBrowsedIndexes.push(index); for (const extendedStyleID of styleElt.extendsStyles) { const extendedStyleIndex = arrayFindIndex(styles, (x) => x.id === extendedStyleID); if (extendedStyleIndex < 0) { log.warn("ttml", "unknown style inheritance", { id: extendedStyleID }); } else { const extendedStyle = styles[extendedStyleIndex]; if (arrayIncludes(recursivelyBrowsedIndexes, extendedStyleIndex)) { log.warn("ttml", "infinite style inheritance loop avoided"); } else { resolveStyleInheritance(extendedStyle, extendedStyleIndex); } styleElt.style = objectAssign({}, extendedStyle.style, styleElt.style); } } styleElt.extendsStyles.length = 0; } for (let i = 0; i < styles.length; i++) { resolveStyleInheritance(styles[i], i); recursivelyBrowsedIndexes.length = 0; // reset } }