/* * (c) Copyright Ascensio System SIA 2010-2023 * * This program is a free software product. You can redistribute it and/or * modify it under the terms of the GNU Affero General Public License (AGPL) * version 3 as published by the Free Software Foundation. In accordance with * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect * that Ascensio System SIA expressly excludes the warranty of non-infringement * of any third-party rights. * * This program is distributed WITHOUT ANY WARRANTY; without even the implied * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html * * You can contact Ascensio System SIA at 20A-6 Ernesta Birznieka-Upish * street, Riga, Latvia, EU, LV-1050. * * The interactive user interfaces in modified source and object code versions * of the Program must display Appropriate Legal Notices, as required under * Section 5 of the GNU AGPL version 3. * * Pursuant to Section 7(b) of the License you must retain the original Product * logo when distributing the program. Pursuant to Section 7(e) we decline to * grant you any rights under trademark law for use of our trademarks. * * All the Product's GUI elements, including illustrations and icon sets, as * well as technical writing content are licensed under the terms of the * Creative Commons Attribution-ShareAlike 4.0 International. See the License * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode * */ "use strict"; (function(window, document) { /** * accepts visio shadow and common parameters, return OnlyOffice api objects of different types. * So for foreground color it return Unifill and for stroke Unifill too. For font color returns CUniColor. * In the end Calculate() is called for colors to calculate their exact value on theme * https://learn.microsoft.com/ru-ru/office/client-developer/visio/themeval-function. * @param {Cell_Type} cell * @param {Shape_Type} shape * @param {Page_Type} pageInfo * @param {CTheme[]} themes * @param {string?} themeValue - value to calculate if cell is not considered (cell is ignored) * @param {string?} defaultValue * @param {boolean?} gradientEnabled - true by default * @param {number?} themedColorsRow * @return {CUniFill | CUniColor | number | any} */ function themeval(cell, shape, pageInfo, themes, themeValue, defaultValue, gradientEnabled, themedColorsRow) { // https://visualsignals.typepad.co.uk/vislog/2013/05/visio-2013-themes-in-the-shapesheet-part-2.html // 1) Calculate color // a) QuickStyleFillColor (or other cell) >= 100 && <= 106: // select variationClrScheme using VariationColorIndex then color using QuickStyleFillColor // b) if QuickStyle cell value is not in that range it is smt like from 0 to 7 representing theme colors like: // dk1, lt1, accent1, .. // 2) Apply modifiers // a) QuickStyleFillMatrix (or other cell) >= 100 && <= 103: // select variationStyleScheme using VariationStyleIndex then varStyle using QuickStyleFillMatrix and // by appropriate property like fillIdx or other pick modifier from fmtScheme or fmtConnectorScheme // b) QuickStyleFillMatrix (or other cell) >= 1 && <= 6: // pick modifier from fmtScheme or fmtConnectorScheme /** @type {CUniColor} */ let calculatedColor = null; /** @type {CUniFill | CUniColor | number | any} */ let result = null; let cellValue = cell && cell.v; // formula? let cellName = cell && cell.n; let quickStyleCellName; let quickStyleModifiersCellName; let getModifiersMethod; let isGetLineEndStyle = false; let isFillIdx = false; let isLineIdx = false; let isFontIdx = false; let isEffectIdx = false; if (themeValue === "LineColor") { cellName = "LineColor"; cellValue = "Themed"; } else if (themeValue === "FillColor") { cellName = "FillForegnd"; cellValue = "Themed"; } else if (themeValue === "TextColor") { cellName = "Color"; cellValue = "Themed"; } let initialDefaultValue = null; if (gradientEnabled === undefined) { gradientEnabled = true; } if (cellName === "LineColor") { quickStyleCellName = "QuickStyleLineColor"; quickStyleModifiersCellName = "QuickStyleLineMatrix"; getModifiersMethod = themes[0].getLnStyle; isLineIdx = true; initialDefaultValue = AscFormat.CreateUnfilFromRGB(0,0,0); } else if (cellName === "Color") { // Text color quickStyleCellName = "QuickStyleFontColor"; quickStyleModifiersCellName = "QuickStyleFontMatrix"; getModifiersMethod = themes[0].getFontStyle; isFontIdx = true; initialDefaultValue = AscFormat.CreateUnfilFromRGB(0,0,0).fill.color; } else if (cellName === "FillForegnd" || cellName === "FillBkgnd" || cellName === "GradientStopColor" || cellName === "GradientStopPosition" || cellName === "FillGradientAngle" ) { quickStyleCellName = "QuickStyleFillColor"; quickStyleModifiersCellName = "QuickStyleFillMatrix"; getModifiersMethod = themes[0].getFillStyle; isFillIdx = true; if (cellName === "FillForegnd") { initialDefaultValue = AscFormat.CreateUnfilFromRGB(255,255,255); } else if (cellName === "FillBkgnd") { initialDefaultValue = AscFormat.CreateUnfilFromRGB(0,0,0); } else if (cellName === "GradientStopColor") { initialDefaultValue = AscFormat.CreateUniColorRGB(255,255,255); } else if (cellName === "GradientStopPosition") { initialDefaultValue = 0; } else if (cellName === "FillGradientAngle") { initialDefaultValue = 5400000; } } else if (cellName === "LinePattern") { // dash dot or smth. get from a:ln from a:lnStyleLst // use QuickStyleLineColor to calculate all line params quickStyleCellName = "QuickStyleLineColor"; quickStyleModifiersCellName = "QuickStyleLineMatrix"; getModifiersMethod = themes[0].getLnStyle; isLineIdx = true; initialDefaultValue = 1; // visio solid } else if (cellName === "LineWeight") { // line weight in inches quickStyleCellName = "QuickStyleLineColor"; quickStyleModifiersCellName = "QuickStyleLineMatrix"; getModifiersMethod = themes[0].getLnStyle; isLineIdx = true; // // 9255 emus = 0.01041666666666667 inches is document.xml StyleSheet ID=0 LineWeight e. g. default value initialDefaultValue = 0.01041666666666667; } else if (cellName === "FillGradientEnabled") { quickStyleCellName = "QuickStyleFillColor"; quickStyleModifiersCellName = "QuickStyleFillMatrix"; getModifiersMethod = themes[0].getFillStyle; isFillIdx = true; initialDefaultValue = false; } else if (cellName === "GradientStopColorTrans") { // quickStyleCellName = "QuickStyleFillColor"; // quickStyleModifiersCellName = "QuickStyleFillMatrix"; // getModifiersMethod = themes[0].getFillStyle; // isFillIdx = true; // // initialDefaultValue = 0; AscCommon.consoleLog("Themed GradientStopColorTrans is unhandled"); return 0; } else if (cellName === "EndArrow" || cellName === "BeginArrow") { quickStyleCellName = null; // so color will not be calculated quickStyleModifiersCellName = "QuickStyleLineMatrix"; getModifiersMethod = themes[0].getLineEndStyle; isGetLineEndStyle = true; isLineIdx = true; initialDefaultValue = "0"; // string is return type in calculateValue } else if (cellName === "EndArrowSize" || cellName === "BeginArrowSize") { quickStyleCellName = null; // so color will not be calculated quickStyleModifiersCellName = "QuickStyleLineMatrix"; getModifiersMethod = themes[0].getLineEndStyle; isGetLineEndStyle = true; isLineIdx = true; initialDefaultValue = 2; // number is return type in calculateValue } else if (cellName === "FillPattern") { quickStyleCellName = null; // so color will not be calculated quickStyleModifiersCellName = "QuickStyleFillMatrix"; getModifiersMethod = themes[0].getFillProp; isFillIdx = true; initialDefaultValue = 1; // number is return type in calculateValue. Solid fill. } else if (cellName === "Font") { // // uses other mechanism // quickStyleCellName = null; // quickStyleModifiersCellName = "QuickStyleFillMatrix"; // getModifiersMethod = themes[0].getFillProp; // isFillIdx = true; initialDefaultValue = "Calibri"; } else if (cellName === "ShdwPattern") { // calculate color. what if there will be placeholder color in effects quickStyleCellName = "QuickStyleShadowColor"; quickStyleModifiersCellName = "QuickStyleEffectsMatrix"; getModifiersMethod = themes[0].getOuterShdw; isEffectIdx = true; initialDefaultValue = 0; } else if (cellName === "ShdwForegnd") { quickStyleCellName = "QuickStyleShadowColor"; quickStyleModifiersCellName = "QuickStyleEffectsMatrix"; getModifiersMethod = themes[0].getOuterShdw; isEffectIdx = true; initialDefaultValue = AscFormat.CreateUniColorRGB(0,0,0); } else if (cellName === "ShapeShdwOffsetX" || cellName === "ShapeShdwOffsetY") { quickStyleCellName = "QuickStyleShadowColor"; quickStyleModifiersCellName = "QuickStyleEffectsMatrix"; getModifiersMethod = themes[0].getOuterShdw; isEffectIdx = true; if (cellName === "ShapeShdwOffsetX") { initialDefaultValue = 0.125; } else { initialDefaultValue = -0.125; } } else { AscCommon.consoleLog("themeval argument error. cell name: " + cellName + " is unknown. return undefined."); return undefined; } // lets define if shape is connector // consider 2.2.7.4.9 Connector let isConnectorShape = shape.isConnectorStyleIherited; // TODO rewrite themeScopeCellName choose consider 2.2.7.4.2 Dynamic Theme Identification // find theme index // ! Because now we only calculate colors lets find theme by // ext uri="{2703A3B3-D2E1-43D9-8057-6E9D74E0F44A}" clrScheme extension schemeEnum // which is sometimes different from ext uri="{D75FF423-9257-4291-A4FE-1B2448832E17} - themeSchemeSchemeEnum // and pick ColorSchemeIndex instead of ThemeIndex cell // upd: if connector styles are used lets use ConnectorSchemeIndex cell and // ext uri="{D75FF423-9257-4291-A4FE-1B2448832E17} - themeSchemeSchemeEnum to find theme let themeIndex = shape.calculateColorThemeIndex(pageInfo); // TODO: if THEMEVAL was called with themeValue (argument like "FillColor") even if themeIndex is 0 we should return // color of default theme otherwise if no themeValue argument was passed and 0 themeIndex is used we should return // initialDefaultValue value let theme; // 0 theme index (default theme in visio) is considered as default value for now if (themeIndex === 0) { return initialDefaultValue; } else { theme = shape.getTheme(pageInfo, themes); } let quickStyleColor = shape.getCellNumberValue(quickStyleCellName); let quickStyleMatrix = shape.getCellNumberValue(quickStyleModifiersCellName); // get color using "VariationColorIndex" cell and quickStyleColor cell if (!isNaN(quickStyleColor)) { if (100 <= quickStyleColor && quickStyleColor <= 106 || (200 <= quickStyleColor && quickStyleColor <= 206)) { if (theme.isVariationClrSchemeLstExists()) { let variationColorIndex = shape.getCellNumberValue("VariationColorIndex"); if (!isNaN(variationColorIndex)) { if (65534 === variationColorIndex) { let pageVariationColorIndexIndex = pageInfo.pageSheet.getCellNumberValue("VariationColorIndex"); if (!isNaN(pageVariationColorIndexIndex)) { variationColorIndex = pageVariationColorIndexIndex; } else { variationColorIndex = 0; // AscCommon.consoleLog("pageVariationColorIndexIndex not found"); } } calculatedColor = theme.getVariationClrSchemeColor(variationColorIndex, quickStyleColor % 100); } } else { let index = quickStyleColor % 100; switch (index) { case 0: calculatedColor = AscFormat.builder_CreateSchemeColor("accent1"); break; case 1: calculatedColor = AscFormat.builder_CreateSchemeColor("accent2"); break; case 2: calculatedColor = AscFormat.builder_CreateSchemeColor("accent3"); break; case 3: calculatedColor = AscFormat.builder_CreateSchemeColor("accent4"); break; case 4: calculatedColor = AscFormat.builder_CreateSchemeColor("accent5"); break; case 5: calculatedColor = AscFormat.builder_CreateSchemeColor("accent6"); break; case 6: calculatedColor = AscFormat.builder_CreateSchemeColor("dk1"); break; } } } else { switch(quickStyleColor) { case 0: calculatedColor = AscFormat.builder_CreateSchemeColor("dk1"); break; case 1: calculatedColor = AscFormat.builder_CreateSchemeColor("lt1"); break; case 2: calculatedColor = AscFormat.builder_CreateSchemeColor("accent1"); break; case 3: calculatedColor = AscFormat.builder_CreateSchemeColor("accent2"); break; case 4: calculatedColor = AscFormat.builder_CreateSchemeColor("accent3"); break; case 5: calculatedColor = AscFormat.builder_CreateSchemeColor("accent4"); break; case 6: calculatedColor = AscFormat.builder_CreateSchemeColor("accent5"); break; case 7: calculatedColor = AscFormat.builder_CreateSchemeColor("accent6"); break; case 8: //todo break; default: break; } } } // add matrix modifiers consider color and cells: "VariationStyleIndex" and quickStyleModifiersCellName if (!isNaN(quickStyleMatrix)) { let getMedifiersResult = null; if (0 === quickStyleMatrix) { // consider 2.4.4.275 QuickStyleLineMatrix return root stylesheet value (default value) return initialDefaultValue; } else if (1 <= quickStyleMatrix && quickStyleMatrix <= 6) { if (cellName === "EndArrow" || cellName === "EndArrowSize" || cellName === "BeginArrow" || cellName === "BeginArrowSize") { // getLineEndStyle is method getMedifiersResult = theme.getLineEndStyle(quickStyleMatrix, isConnectorShape); } else { getMedifiersResult = getModifiersMethod.call(theme, quickStyleMatrix, calculatedColor, isConnectorShape); } } else if (100 <= quickStyleMatrix && quickStyleMatrix <= 103) { let variationStyleIndex = shape.getCellNumberValue("VariationStyleIndex"); if (!isNaN(variationStyleIndex)) { if (65534 === variationStyleIndex) { let pageVariationStyleIndexIndex = pageInfo.pageSheet.getCellNumberValue("VariationStyleIndex"); if (!isNaN(pageVariationStyleIndexIndex)) { variationStyleIndex = pageVariationStyleIndexIndex; } else { variationStyleIndex = 0; // AscCommon.consoleLog("pageVariationStyleIndexIndex not found"); } } let varStyle = theme.getVariationStyleScheme(variationStyleIndex, quickStyleMatrix % 100); let styleId = null; if (varStyle) { if (isFillIdx) { styleId = varStyle.fillIdx; } else if (isLineIdx) { styleId = varStyle.lineIdx; } else if (isFontIdx) { styleId = varStyle.fontIdx; } else if (isEffectIdx) { styleId = varStyle.effectIdx; } } if (null !== styleId) { if (isGetLineEndStyle) { // getLineEndStyle is method. // When we get lineEnd/lineStart type or its size we don't need // calculatedColor and so arguments are different // getModifiersMethod.call(theme, styleId, isConnectorShape); getMedifiersResult = theme.getLineEndStyle(styleId, isConnectorShape); } else { getMedifiersResult = getModifiersMethod.call(theme, styleId, calculatedColor, isConnectorShape); } } } } // disable gradient let isFillGradient = getMedifiersResult && getMedifiersResult.fill instanceof AscFormat.CGradFill; let isCLnContainsGradient = getMedifiersResult && getMedifiersResult.Fill && getMedifiersResult.Fill.fill && getMedifiersResult.Fill.fill.type === Asc.c_oAscFill.FILL_TYPE_GRAD; if (!gradientEnabled && isFillGradient) { getMedifiersResult = AscFormat.CreateUniFillByUniColor(calculatedColor); } if (!gradientEnabled && getMedifiersResult && isCLnContainsGradient) { getMedifiersResult.Fill = AscFormat.CreateUniFillByUniColor(calculatedColor); } // getModifiersMethod return not only // uniFill, so we narrow down the range of returns if (cellName === "LineColor") { result = getMedifiersResult && getMedifiersResult.Fill; } else if (cellName === "LinePattern") { // simple type - number let originalDashType = getMedifiersResult && getMedifiersResult.prstDash; // map c_oDashType number to c_oDashType visio number let toVisioDashMap = { 0: 2, 1: 4, 2: 3, 3: 16, 4: 18, 5: 19, 6: 1, 7: 9, 8: 22, 9: 12, 10: 10 }; result = toVisioDashMap[originalDashType]; if (result === undefined) { AscCommon.consoleLog("Dash map was not realized. Unknown dash type in theme"); result = 1; // visio solid } } else if (cellName === "Color") { // and it is color result = getMedifiersResult && getMedifiersResult.fontPropsObject.color; } else if (cellName === "FillForegnd" || cellName === "FillBkgnd") { //leave result because it is fill if (getMedifiersResult && getMedifiersResult.fill && getMedifiersResult.fill.type === Asc.c_oAscFill.FILL_TYPE_PATT) { let uniColor; if (cellName === "FillForegnd") { uniColor = getMedifiersResult.fill.fgClr; } else { uniColor = getMedifiersResult.fill.bgClr; } let fill = new AscFormat.CUniFill(); fill.fill = new AscFormat.CSolidFill(); fill.fill.color = uniColor; result = fill; } else { result = getMedifiersResult; } } else if (cellName === "LineWeight") { // let's map standart ooxml result in emus to visio result - inches result = getMedifiersResult && getMedifiersResult.w / (AscCommonWord.g_dKoef_in_to_mm * AscCommonWord.g_dKoef_mm_to_emu); } else if (cellName === "FillGradientEnabled") { result = getMedifiersResult && getMedifiersResult.fill instanceof AscFormat.CGradFill; } else if (cellName === "GradientStopColor") { // and it is color let themedFillIsGradient = getMedifiersResult && getMedifiersResult.fill instanceof AscFormat.CGradFill; if (themedFillIsGradient && getMedifiersResult.fill.colors[themedColorsRow]) { result = getMedifiersResult.fill.colors[themedColorsRow].color; } else { return initialDefaultValue; } } else if (cellName === "GradientStopPosition") { let themedFillIsGradient = getMedifiersResult && getMedifiersResult.fill instanceof AscFormat.CGradFill; if (themedFillIsGradient && getMedifiersResult.fill.colors[themedColorsRow]) { result = getMedifiersResult.fill.colors[themedColorsRow].pos; } else { return initialDefaultValue; } } else if (cellName === "FillGradientAngle") { let themedFillIsGradient = getMedifiersResult && getMedifiersResult.fill instanceof AscFormat.CGradFill; if (themedFillIsGradient && getMedifiersResult.fill.lin) { result = getMedifiersResult.fill.lin.angle; } else { return initialDefaultValue; } } else if (cellName === "EndArrow") { let endArrowType = getMedifiersResult && getMedifiersResult.lineEx.end; result = String(endArrowType); } else if (cellName === "BeginArrow") { let beginArrowType = getMedifiersResult && getMedifiersResult.lineEx.start; result = String(beginArrowType); } else if (cellName === "EndArrowSize") { let endArrowSize = getMedifiersResult && getMedifiersResult.lineEx.endSize; result = Number(endArrowSize); } else if (cellName === "BeginArrowSize") { let beginArrowSize = getMedifiersResult && getMedifiersResult.lineEx.startSize; result = Number(beginArrowSize); } else if (cellName === "FillPattern") { let fillPattern = getMedifiersResult && getMedifiersResult.pattern; result = Number(fillPattern); } else if (cellName === "ShdwPattern") { let shdwPattern = Boolean(getMedifiersResult); result = Number(shdwPattern); } else if (cellName === "ShdwForegnd") { let shadowColor = getMedifiersResult && getMedifiersResult.color; result = shadowColor; } else if (cellName === "ShapeShdwOffsetX" || cellName === "ShapeShdwOffsetY") { let dir = getMedifiersResult && getMedifiersResult.dir; let dist = getMedifiersResult && getMedifiersResult.dist; let dist_inches = dist * g_dKoef_emu_to_mm / g_dKoef_in_to_mm; let dir_radians = dir * AscFormat.cToRad; // We are now in ooxml cord type system where y goes down. // Let's convert to MS Euclidean cord system where y goes up. dir_radians = -1 * dir_radians; if (cellName === "ShapeShdwOffsetX") { result = dist_inches * Math.cos(dir_radians); } else { result = dist_inches * Math.sin(dir_radians); } } else { AscCommon.consoleLog("Error in themeval. result is not changed to appropriate type or quickStyleCellName is not set."); } } if (isNaN(quickStyleColor) && isNaN(quickStyleMatrix)) { // other mechanism for theme value calculate is used if (cellName === "Font") { result = theme.getFontScheme().majorFont.latin; } } /** * calculate exact color on theme. for quickStyleVariation to consider real color * @param {CUniColor | CUniFill} color * @param {CTheme} theme */ function calculateOnTheme(color, theme) { let RGBA = {R:0, G:0, B:0, A:255}; if (color instanceof AscFormat.CUniColor ) { color.Calculate(theme, undefined, undefined, undefined, RGBA); } else if (color instanceof AscFormat.CUniFill) { color.calculate(theme, undefined, undefined, undefined, RGBA); } // otherwise it is a link to theme color return color.createDuplicate(); } // typeof NaN === "number", isNaN({...}) === true so NaN check is typeof result === "number" && isNaN(result) if (result !== null && !(typeof result === "number" && isNaN(result)) && result !== "null" && result !== undefined && result !== "undefined") { // result have appropriate type for cell already if (result instanceof AscFormat.CUniColor || result instanceof AscFormat.CUniFill) { return calculateOnTheme(result, theme); } else { // simple type like string or number - so we don't use clone return result; } } else { AscCommon.consoleLog("Unknown themeval error. Return initialDefaultValue"); return initialDefaultValue; } } //-------------------------------------------------------------export--------------------------------------------------- window['Asc'] = window['Asc'] || {}; window['AscCommon'] = window['AscCommon'] || {}; window['AscCommonWord'] = window['AscCommonWord'] || {}; window['AscCommonSlide'] = window['AscCommonSlide'] || {}; window['AscCommonExcel'] = window['AscCommonExcel'] || {}; window['AscVisio'] = window['AscVisio'] || {}; window['AscFormat'] = window['AscFormat'] || {}; window['AscWord'] = window['AscWord'] || {}; window['AscVisio'].themeval = themeval; })(window, window.document);