monaco-editor-core 0.56.0-dev-20260101 → 0.56.0-dev-20260103

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,6 @@
1
1
  /*!-----------------------------------------------------------
2
2
  * Copyright (c) Microsoft Corporation. All rights reserved.
3
- * Version: 0.56.0-dev-20260101(ec78a33c7b34dba19e9d3cbe1b3b378465bbd8b8)
3
+ * Version: 0.56.0-dev-20260103(ec78a33c7b34dba19e9d3cbe1b3b378465bbd8b8)
4
4
  * Released under the MIT license
5
5
  * https://github.com/microsoft/vscode/blob/main/LICENSE.txt
6
6
  *-----------------------------------------------------------*/
@@ -1,6 +1,6 @@
1
1
  /*!-----------------------------------------------------------
2
2
  * Copyright (c) Microsoft Corporation. All rights reserved.
3
- * Version: 0.56.0-dev-20260101(ec78a33c7b34dba19e9d3cbe1b3b378465bbd8b8)
3
+ * Version: 0.56.0-dev-20260103(ec78a33c7b34dba19e9d3cbe1b3b378465bbd8b8)
4
4
  * Released under the MIT license
5
5
  * https://github.com/microsoft/vscode/blob/main/LICENSE.txt
6
6
  *-----------------------------------------------------------*/
@@ -1,6 +1,6 @@
1
1
  /*!-----------------------------------------------------------
2
2
  * Copyright (c) Microsoft Corporation. All rights reserved.
3
- * Version: 0.56.0-dev-20260101(ec78a33c7b34dba19e9d3cbe1b3b378465bbd8b8)
3
+ * Version: 0.56.0-dev-20260103(ec78a33c7b34dba19e9d3cbe1b3b378465bbd8b8)
4
4
  * Released under the MIT license
5
5
  * https://github.com/microsoft/vscode/blob/main/LICENSE.txt
6
6
  *-----------------------------------------------------------*/
@@ -1,6 +1,6 @@
1
1
  /*!-----------------------------------------------------------
2
2
  * Copyright (c) Microsoft Corporation. All rights reserved.
3
- * Version: 0.56.0-dev-20260101(ec78a33c7b34dba19e9d3cbe1b3b378465bbd8b8)
3
+ * Version: 0.56.0-dev-20260103(ec78a33c7b34dba19e9d3cbe1b3b378465bbd8b8)
4
4
  * Released under the MIT license
5
5
  * https://github.com/microsoft/vscode/blob/main/LICENSE.txt
6
6
  *-----------------------------------------------------------*/
@@ -1,6 +1,6 @@
1
1
  /*!-----------------------------------------------------------
2
2
  * Copyright (c) Microsoft Corporation. All rights reserved.
3
- * Version: 0.56.0-dev-20260101(ec78a33c7b34dba19e9d3cbe1b3b378465bbd8b8)
3
+ * Version: 0.56.0-dev-20260103(ec78a33c7b34dba19e9d3cbe1b3b378465bbd8b8)
4
4
  * Released under the MIT license
5
5
  * https://github.com/microsoft/vscode/blob/main/LICENSE.txt
6
6
  *-----------------------------------------------------------*/
@@ -1,6 +1,6 @@
1
1
  /*!-----------------------------------------------------------
2
2
  * Copyright (c) Microsoft Corporation. All rights reserved.
3
- * Version: 0.56.0-dev-20260101(ec78a33c7b34dba19e9d3cbe1b3b378465bbd8b8)
3
+ * Version: 0.56.0-dev-20260103(ec78a33c7b34dba19e9d3cbe1b3b378465bbd8b8)
4
4
  * Released under the MIT license
5
5
  * https://github.com/microsoft/vscode/blob/main/LICENSE.txt
6
6
  *-----------------------------------------------------------*/
@@ -1,6 +1,6 @@
1
1
  /*!-----------------------------------------------------------
2
2
  * Copyright (c) Microsoft Corporation. All rights reserved.
3
- * Version: 0.56.0-dev-20260101(ec78a33c7b34dba19e9d3cbe1b3b378465bbd8b8)
3
+ * Version: 0.56.0-dev-20260103(ec78a33c7b34dba19e9d3cbe1b3b378465bbd8b8)
4
4
  * Released under the MIT license
5
5
  * https://github.com/microsoft/vscode/blob/main/LICENSE.txt
6
6
  *-----------------------------------------------------------*/
@@ -1,6 +1,6 @@
1
1
  /*!-----------------------------------------------------------
2
2
  * Copyright (c) Microsoft Corporation. All rights reserved.
3
- * Version: 0.56.0-dev-20260101(ec78a33c7b34dba19e9d3cbe1b3b378465bbd8b8)
3
+ * Version: 0.56.0-dev-20260103(ec78a33c7b34dba19e9d3cbe1b3b378465bbd8b8)
4
4
  * Released under the MIT license
5
5
  * https://github.com/microsoft/vscode/blob/main/LICENSE.txt
6
6
  *-----------------------------------------------------------*/
@@ -1,6 +1,6 @@
1
1
  /*!-----------------------------------------------------------
2
2
  * Copyright (c) Microsoft Corporation. All rights reserved.
3
- * Version: 0.56.0-dev-20260101(ec78a33c7b34dba19e9d3cbe1b3b378465bbd8b8)
3
+ * Version: 0.56.0-dev-20260103(ec78a33c7b34dba19e9d3cbe1b3b378465bbd8b8)
4
4
  * Released under the MIT license
5
5
  * https://github.com/microsoft/vscode/blob/main/LICENSE.txt
6
6
  *-----------------------------------------------------------*/
@@ -1,6 +1,6 @@
1
1
  /*!-----------------------------------------------------------
2
2
  * Copyright (c) Microsoft Corporation. All rights reserved.
3
- * Version: 0.56.0-dev-20260101(ec78a33c7b34dba19e9d3cbe1b3b378465bbd8b8)
3
+ * Version: 0.56.0-dev-20260103(ec78a33c7b34dba19e9d3cbe1b3b378465bbd8b8)
4
4
  * Released under the MIT license
5
5
  * https://github.com/microsoft/vscode/blob/main/LICENSE.txt
6
6
  *-----------------------------------------------------------*/
@@ -1,6 +1,6 @@
1
1
  /*!-----------------------------------------------------------
2
2
  * Copyright (c) Microsoft Corporation. All rights reserved.
3
- * Version: 0.56.0-dev-20260101(ec78a33c7b34dba19e9d3cbe1b3b378465bbd8b8)
3
+ * Version: 0.56.0-dev-20260103(ec78a33c7b34dba19e9d3cbe1b3b378465bbd8b8)
4
4
  * Released under the MIT license
5
5
  * https://github.com/microsoft/vscode/blob/main/LICENSE.txt
6
6
  *-----------------------------------------------------------*/
@@ -1,6 +1,6 @@
1
1
  /*!-----------------------------------------------------------
2
2
  * Copyright (c) Microsoft Corporation. All rights reserved.
3
- * Version: 0.56.0-dev-20260101(ec78a33c7b34dba19e9d3cbe1b3b378465bbd8b8)
3
+ * Version: 0.56.0-dev-20260103(ec78a33c7b34dba19e9d3cbe1b3b378465bbd8b8)
4
4
  * Released under the MIT license
5
5
  * https://github.com/microsoft/vscode/blob/main/LICENSE.txt
6
6
  *-----------------------------------------------------------*/
@@ -1,6 +1,6 @@
1
1
  /*!-----------------------------------------------------------
2
2
  * Copyright (c) Microsoft Corporation. All rights reserved.
3
- * Version: 0.56.0-dev-20260101(ec78a33c7b34dba19e9d3cbe1b3b378465bbd8b8)
3
+ * Version: 0.56.0-dev-20260103(ec78a33c7b34dba19e9d3cbe1b3b378465bbd8b8)
4
4
  * Released under the MIT license
5
5
  * https://github.com/microsoft/vscode/blob/main/LICENSE.txt
6
6
  *-----------------------------------------------------------*/
@@ -2,7 +2,7 @@
2
2
  * Copyright (c) Microsoft Corporation. All rights reserved.
3
3
  * Licensed under the MIT License. See License.txt in the project root for license information.
4
4
  *--------------------------------------------------------------------------------------------*/
5
- import { $, getActiveDocument } from '../../../../base/browser/dom.js';
5
+ import { $, getActiveDocument, getActiveWindow } from '../../../../base/browser/dom.js';
6
6
  import { Disposable, toDisposable } from '../../../../base/common/lifecycle.js';
7
7
  import './media/decorationCssRuleExtractor.css';
8
8
  /**
@@ -67,5 +67,14 @@ export class DecorationCssRuleExtractor extends Disposable {
67
67
  }
68
68
  return rules;
69
69
  }
70
+ /**
71
+ * Resolves a CSS variable to its computed value using the container element.
72
+ */
73
+ resolveCssVariable(canvas, variableName) {
74
+ canvas.appendChild(this._container);
75
+ const result = getActiveWindow().getComputedStyle(this._container).getPropertyValue(variableName).trim();
76
+ canvas.removeChild(this._container);
77
+ return result;
78
+ }
70
79
  }
71
80
  //# sourceMappingURL=decorationCssRuleExtractor.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["file:///mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/browser/gpu/css/decorationCssRuleExtractor.ts","vs/editor/browser/gpu/css/decorationCssRuleExtractor.ts"],"names":[],"mappings":"AAAA;;;gGAGgG;AAEhG,OAAO,EAAE,CAAC,EAAE,iBAAiB,EAAE,MAAM,iCAAiC,CAAC;AACvE,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,sCAAsC,CAAC;AAChF,OAAO,wCAAwC,CAAC;AAEhD;;GAEG;AACH,MAAM,OAAO,0BAA2B,SAAQ,UAAU;IAMzD;QACC,KAAK,EAAE,CAAC;QAHD,eAAU,GAA+C,IAAI,GAAG,EAAE,CAAC;QAK1E,IAAI,CAAC,UAAU,GAAG,CAAC,CAAC,0CAA0C,CAAC,CAAC;QAChE,IAAI,CAAC,aAAa,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC;QAC/B,IAAI,CAAC,UAAU,CAAC,WAAW,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;QAEhD,IAAI,CAAC,SAAS,CAAC,YAAY,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,UAAU,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;IAC9D,CAAC;IAED,aAAa,CAAC,MAAmB,EAAE,mBAA2B;QAC7D,cAAc;QACd,MAAM,QAAQ,GAAG,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,mBAAmB,CAAC,CAAC;QAC1D,IAAI,QAAQ,EAAE,CAAC;YACd,OAAO,QAAQ,CAAC;QACjB,CAAC;QAED,aAAa;QACb,IAAI,CAAC,aAAa,CAAC,SAAS,GAAG,mBAAmB,CAAC;QACnD,MAAM,CAAC,WAAW,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QAEpC,YAAY;QACZ,MAAM,KAAK,GAAG,IAAI,CAAC,cAAc,CAAC,mBAAmB,CAAC,CAAC;QACvD,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,mBAAmB,EAAE,KAAK,CAAC,CAAC;QAEhD,gBAAgB;QAChB,MAAM,CAAC,WAAW,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QAEpC,OAAO,KAAK,CAAC;IACd,CAAC;IAEO,cAAc,CAAC,SAAiB;QACvC,kFAAkF;QAClF,MAAM,KAAK,GAAG,EAAE,CAAC;QACjB,MAAM,GAAG,GAAG,iBAAiB,EAAE,CAAC;QAChC,MAAM,WAAW,GAAG,CAAC,GAAG,GAAG,CAAC,WAAW,CAAC,CAAC;QACzC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,WAAW,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;YAC7C,MAAM,UAAU,GAAG,WAAW,CAAC,CAAC,CAAC,CAAC;YAClC,KAAK,MAAM,IAAI,IAAI,UAAU,CAAC,QAAQ,EAAE,CAAC;gBACxC,IAAI,IAAI,YAAY,aAAa,EAAE,CAAC;oBACnC,IAAI,IAAI,CAAC,UAAU,EAAE,CAAC;wBACrB,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;oBACnC,CAAC;gBACF,CAAC;qBAAM,IAAI,IAAI,YAAY,YAAY,EAAE,CAAC;oBACzC,6EAA6E;oBAC7E,6EAA6E;oBAC7E,mBAAmB;oBACnB,EAAE;oBACF,gFAAgF;oBAChF,+EAA+E;oBAC/E,MAAM;oBACN,MAAM,UAAU,GAAG,IAAI,SAAS,EAAE,CAAC;oBACnC,MAAM,KAAK,GAAG,IAAI,CAAC,YAAY,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;oBACpD,IAAI,KAAK,KAAK,CAAC,CAAC,EAAE,CAAC;wBAClB,MAAM,WAAW,GAAG,KAAK,GAAG,UAAU,CAAC,MAAM,CAAC;wBAC9C,IAAI,IAAI,CAAC,YAAY,CAAC,MAAM,KAAK,WAAW,IAAI,IAAI,CAAC,YAAY,CAAC,SAAS,CAAC,WAAW,EAAE,WAAW,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC;4BACzH,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;wBAClB,CAAC;oBACF,CAAC;gBACF,CAAC;YACF,CAAC;QACF,CAAC;QAED,OAAO,KAAK,CAAC;IACd,CAAC;CACD","file":"decorationCssRuleExtractor.js","sourceRoot":"file:///mnt/vss/_work/1/s/dependencies/vscode/out-editor-src","sourcesContent":["/*---------------------------------------------------------------------------------------------\n * Copyright (c) Microsoft Corporation. All rights reserved.\n * Licensed under the MIT License. See License.txt in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\nimport { $, getActiveDocument } from '../../../../base/browser/dom.js';\nimport { Disposable, toDisposable } from '../../../../base/common/lifecycle.js';\nimport './media/decorationCssRuleExtractor.css';\n\n/**\n * Extracts CSS rules that would be applied to certain decoration classes.\n */\nexport class DecorationCssRuleExtractor extends Disposable {\n\tprivate _container: HTMLElement;\n\tprivate _dummyElement: HTMLSpanElement;\n\n\tprivate _ruleCache: Map</* className */string, CSSStyleRule[]> = new Map();\n\n\tconstructor() {\n\t\tsuper();\n\n\t\tthis._container = $('div.monaco-decoration-css-rule-extractor');\n\t\tthis._dummyElement = $('span');\n\t\tthis._container.appendChild(this._dummyElement);\n\n\t\tthis._register(toDisposable(() => this._container.remove()));\n\t}\n\n\tgetStyleRules(canvas: HTMLElement, decorationClassName: string): CSSStyleRule[] {\n\t\t// Check cache\n\t\tconst existing = this._ruleCache.get(decorationClassName);\n\t\tif (existing) {\n\t\t\treturn existing;\n\t\t}\n\n\t\t// Set up DOM\n\t\tthis._dummyElement.className = decorationClassName;\n\t\tcanvas.appendChild(this._container);\n\n\t\t// Get rules\n\t\tconst rules = this._getStyleRules(decorationClassName);\n\t\tthis._ruleCache.set(decorationClassName, rules);\n\n\t\t// Tear down DOM\n\t\tcanvas.removeChild(this._container);\n\n\t\treturn rules;\n\t}\n\n\tprivate _getStyleRules(className: string) {\n\t\t// Iterate through all stylesheets and imported stylesheets to find matching rules\n\t\tconst rules = [];\n\t\tconst doc = getActiveDocument();\n\t\tconst stylesheets = [...doc.styleSheets];\n\t\tfor (let i = 0; i < stylesheets.length; i++) {\n\t\t\tconst stylesheet = stylesheets[i];\n\t\t\tfor (const rule of stylesheet.cssRules) {\n\t\t\t\tif (rule instanceof CSSImportRule) {\n\t\t\t\t\tif (rule.styleSheet) {\n\t\t\t\t\t\tstylesheets.push(rule.styleSheet);\n\t\t\t\t\t}\n\t\t\t\t} else if (rule instanceof CSSStyleRule) {\n\t\t\t\t\t// Note that originally `.matches(rule.selectorText)` was used but this would\n\t\t\t\t\t// not pick up pseudo-classes which are important to determine support of the\n\t\t\t\t\t// returned styles.\n\t\t\t\t\t//\n\t\t\t\t\t// Since a selector could contain a class name lookup that is simple a prefix of\n\t\t\t\t\t// the class name we are looking for, we need to also check the character after\n\t\t\t\t\t// it.\n\t\t\t\t\tconst searchTerm = `.${className}`;\n\t\t\t\t\tconst index = rule.selectorText.indexOf(searchTerm);\n\t\t\t\t\tif (index !== -1) {\n\t\t\t\t\t\tconst endOfResult = index + searchTerm.length;\n\t\t\t\t\t\tif (rule.selectorText.length === endOfResult || rule.selectorText.substring(endOfResult, endOfResult + 1).match(/[ :]/)) {\n\t\t\t\t\t\t\trules.push(rule);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn rules;\n\t}\n}\n","/*---------------------------------------------------------------------------------------------\n * Copyright (c) Microsoft Corporation. All rights reserved.\n * Licensed under the MIT License. See License.txt in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\nimport { $, getActiveDocument } from '../../../../base/browser/dom.js';\nimport { Disposable, toDisposable } from '../../../../base/common/lifecycle.js';\nimport './media/decorationCssRuleExtractor.css';\n\n/**\n * Extracts CSS rules that would be applied to certain decoration classes.\n */\nexport class DecorationCssRuleExtractor extends Disposable {\n\tprivate _container: HTMLElement;\n\tprivate _dummyElement: HTMLSpanElement;\n\n\tprivate _ruleCache: Map</* className */string, CSSStyleRule[]> = new Map();\n\n\tconstructor() {\n\t\tsuper();\n\n\t\tthis._container = $('div.monaco-decoration-css-rule-extractor');\n\t\tthis._dummyElement = $('span');\n\t\tthis._container.appendChild(this._dummyElement);\n\n\t\tthis._register(toDisposable(() => this._container.remove()));\n\t}\n\n\tgetStyleRules(canvas: HTMLElement, decorationClassName: string): CSSStyleRule[] {\n\t\t// Check cache\n\t\tconst existing = this._ruleCache.get(decorationClassName);\n\t\tif (existing) {\n\t\t\treturn existing;\n\t\t}\n\n\t\t// Set up DOM\n\t\tthis._dummyElement.className = decorationClassName;\n\t\tcanvas.appendChild(this._container);\n\n\t\t// Get rules\n\t\tconst rules = this._getStyleRules(decorationClassName);\n\t\tthis._ruleCache.set(decorationClassName, rules);\n\n\t\t// Tear down DOM\n\t\tcanvas.removeChild(this._container);\n\n\t\treturn rules;\n\t}\n\n\tprivate _getStyleRules(className: string) {\n\t\t// Iterate through all stylesheets and imported stylesheets to find matching rules\n\t\tconst rules = [];\n\t\tconst doc = getActiveDocument();\n\t\tconst stylesheets = [...doc.styleSheets];\n\t\tfor (let i = 0; i < stylesheets.length; i++) {\n\t\t\tconst stylesheet = stylesheets[i];\n\t\t\tfor (const rule of stylesheet.cssRules) {\n\t\t\t\tif (rule instanceof CSSImportRule) {\n\t\t\t\t\tif (rule.styleSheet) {\n\t\t\t\t\t\tstylesheets.push(rule.styleSheet);\n\t\t\t\t\t}\n\t\t\t\t} else if (rule instanceof CSSStyleRule) {\n\t\t\t\t\t// Note that originally `.matches(rule.selectorText)` was used but this would\n\t\t\t\t\t// not pick up pseudo-classes which are important to determine support of the\n\t\t\t\t\t// returned styles.\n\t\t\t\t\t//\n\t\t\t\t\t// Since a selector could contain a class name lookup that is simple a prefix of\n\t\t\t\t\t// the class name we are looking for, we need to also check the character after\n\t\t\t\t\t// it.\n\t\t\t\t\tconst searchTerm = `.${className}`;\n\t\t\t\t\tconst index = rule.selectorText.indexOf(searchTerm);\n\t\t\t\t\tif (index !== -1) {\n\t\t\t\t\t\tconst endOfResult = index + searchTerm.length;\n\t\t\t\t\t\tif (rule.selectorText.length === endOfResult || rule.selectorText.substring(endOfResult, endOfResult + 1).match(/[ :]/)) {\n\t\t\t\t\t\t\trules.push(rule);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn rules;\n\t}\n}\n"]}
1
+ {"version":3,"sources":["file:///mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/browser/gpu/css/decorationCssRuleExtractor.ts","vs/editor/browser/gpu/css/decorationCssRuleExtractor.ts"],"names":[],"mappings":"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","file":"decorationCssRuleExtractor.js","sourceRoot":"file:///mnt/vss/_work/1/s/dependencies/vscode/out-editor-src","sourcesContent":["/*---------------------------------------------------------------------------------------------\n * Copyright (c) Microsoft Corporation. All rights reserved.\n * Licensed under the MIT License. See License.txt in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\nimport { $, getActiveDocument, getActiveWindow } from '../../../../base/browser/dom.js';\nimport { Disposable, toDisposable } from '../../../../base/common/lifecycle.js';\nimport './media/decorationCssRuleExtractor.css';\n\n/**\n * Extracts CSS rules that would be applied to certain decoration classes.\n */\nexport class DecorationCssRuleExtractor extends Disposable {\n\tprivate _container: HTMLElement;\n\tprivate _dummyElement: HTMLSpanElement;\n\n\tprivate _ruleCache: Map</* className */string, CSSStyleRule[]> = new Map();\n\n\tconstructor() {\n\t\tsuper();\n\n\t\tthis._container = $('div.monaco-decoration-css-rule-extractor');\n\t\tthis._dummyElement = $('span');\n\t\tthis._container.appendChild(this._dummyElement);\n\n\t\tthis._register(toDisposable(() => this._container.remove()));\n\t}\n\n\tgetStyleRules(canvas: HTMLElement, decorationClassName: string): CSSStyleRule[] {\n\t\t// Check cache\n\t\tconst existing = this._ruleCache.get(decorationClassName);\n\t\tif (existing) {\n\t\t\treturn existing;\n\t\t}\n\n\t\t// Set up DOM\n\t\tthis._dummyElement.className = decorationClassName;\n\t\tcanvas.appendChild(this._container);\n\n\t\t// Get rules\n\t\tconst rules = this._getStyleRules(decorationClassName);\n\t\tthis._ruleCache.set(decorationClassName, rules);\n\n\t\t// Tear down DOM\n\t\tcanvas.removeChild(this._container);\n\n\t\treturn rules;\n\t}\n\n\tprivate _getStyleRules(className: string) {\n\t\t// Iterate through all stylesheets and imported stylesheets to find matching rules\n\t\tconst rules = [];\n\t\tconst doc = getActiveDocument();\n\t\tconst stylesheets = [...doc.styleSheets];\n\t\tfor (let i = 0; i < stylesheets.length; i++) {\n\t\t\tconst stylesheet = stylesheets[i];\n\t\t\tfor (const rule of stylesheet.cssRules) {\n\t\t\t\tif (rule instanceof CSSImportRule) {\n\t\t\t\t\tif (rule.styleSheet) {\n\t\t\t\t\t\tstylesheets.push(rule.styleSheet);\n\t\t\t\t\t}\n\t\t\t\t} else if (rule instanceof CSSStyleRule) {\n\t\t\t\t\t// Note that originally `.matches(rule.selectorText)` was used but this would\n\t\t\t\t\t// not pick up pseudo-classes which are important to determine support of the\n\t\t\t\t\t// returned styles.\n\t\t\t\t\t//\n\t\t\t\t\t// Since a selector could contain a class name lookup that is simple a prefix of\n\t\t\t\t\t// the class name we are looking for, we need to also check the character after\n\t\t\t\t\t// it.\n\t\t\t\t\tconst searchTerm = `.${className}`;\n\t\t\t\t\tconst index = rule.selectorText.indexOf(searchTerm);\n\t\t\t\t\tif (index !== -1) {\n\t\t\t\t\t\tconst endOfResult = index + searchTerm.length;\n\t\t\t\t\t\tif (rule.selectorText.length === endOfResult || rule.selectorText.substring(endOfResult, endOfResult + 1).match(/[ :]/)) {\n\t\t\t\t\t\t\trules.push(rule);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn rules;\n\t}\n\n\t/**\n\t * Resolves a CSS variable to its computed value using the container element.\n\t */\n\tresolveCssVariable(canvas: HTMLCanvasElement, variableName: string): string {\n\t\tcanvas.appendChild(this._container);\n\t\tconst result = getActiveWindow().getComputedStyle(this._container).getPropertyValue(variableName).trim();\n\t\tcanvas.removeChild(this._container);\n\t\treturn result;\n\t}\n}\n","/*---------------------------------------------------------------------------------------------\n * Copyright (c) Microsoft Corporation. All rights reserved.\n * Licensed under the MIT License. See License.txt in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\nimport { $, getActiveDocument, getActiveWindow } from '../../../../base/browser/dom.js';\nimport { Disposable, toDisposable } from '../../../../base/common/lifecycle.js';\nimport './media/decorationCssRuleExtractor.css';\n\n/**\n * Extracts CSS rules that would be applied to certain decoration classes.\n */\nexport class DecorationCssRuleExtractor extends Disposable {\n\tprivate _container: HTMLElement;\n\tprivate _dummyElement: HTMLSpanElement;\n\n\tprivate _ruleCache: Map</* className */string, CSSStyleRule[]> = new Map();\n\n\tconstructor() {\n\t\tsuper();\n\n\t\tthis._container = $('div.monaco-decoration-css-rule-extractor');\n\t\tthis._dummyElement = $('span');\n\t\tthis._container.appendChild(this._dummyElement);\n\n\t\tthis._register(toDisposable(() => this._container.remove()));\n\t}\n\n\tgetStyleRules(canvas: HTMLElement, decorationClassName: string): CSSStyleRule[] {\n\t\t// Check cache\n\t\tconst existing = this._ruleCache.get(decorationClassName);\n\t\tif (existing) {\n\t\t\treturn existing;\n\t\t}\n\n\t\t// Set up DOM\n\t\tthis._dummyElement.className = decorationClassName;\n\t\tcanvas.appendChild(this._container);\n\n\t\t// Get rules\n\t\tconst rules = this._getStyleRules(decorationClassName);\n\t\tthis._ruleCache.set(decorationClassName, rules);\n\n\t\t// Tear down DOM\n\t\tcanvas.removeChild(this._container);\n\n\t\treturn rules;\n\t}\n\n\tprivate _getStyleRules(className: string) {\n\t\t// Iterate through all stylesheets and imported stylesheets to find matching rules\n\t\tconst rules = [];\n\t\tconst doc = getActiveDocument();\n\t\tconst stylesheets = [...doc.styleSheets];\n\t\tfor (let i = 0; i < stylesheets.length; i++) {\n\t\t\tconst stylesheet = stylesheets[i];\n\t\t\tfor (const rule of stylesheet.cssRules) {\n\t\t\t\tif (rule instanceof CSSImportRule) {\n\t\t\t\t\tif (rule.styleSheet) {\n\t\t\t\t\t\tstylesheets.push(rule.styleSheet);\n\t\t\t\t\t}\n\t\t\t\t} else if (rule instanceof CSSStyleRule) {\n\t\t\t\t\t// Note that originally `.matches(rule.selectorText)` was used but this would\n\t\t\t\t\t// not pick up pseudo-classes which are important to determine support of the\n\t\t\t\t\t// returned styles.\n\t\t\t\t\t//\n\t\t\t\t\t// Since a selector could contain a class name lookup that is simple a prefix of\n\t\t\t\t\t// the class name we are looking for, we need to also check the character after\n\t\t\t\t\t// it.\n\t\t\t\t\tconst searchTerm = `.${className}`;\n\t\t\t\t\tconst index = rule.selectorText.indexOf(searchTerm);\n\t\t\t\t\tif (index !== -1) {\n\t\t\t\t\t\tconst endOfResult = index + searchTerm.length;\n\t\t\t\t\t\tif (rule.selectorText.length === endOfResult || rule.selectorText.substring(endOfResult, endOfResult + 1).match(/[ :]/)) {\n\t\t\t\t\t\t\trules.push(rule);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn rules;\n\t}\n\n\t/**\n\t * Resolves a CSS variable to its computed value using the container element.\n\t */\n\tresolveCssVariable(canvas: HTMLCanvasElement, variableName: string): string {\n\t\tcanvas.appendChild(this._container);\n\t\tconst result = getActiveWindow().getComputedStyle(this._container).getPropertyValue(variableName).trim();\n\t\tcanvas.removeChild(this._container);\n\t\treturn result;\n\t}\n}\n"]}
@@ -9,11 +9,11 @@ export class DecorationStyleCache {
9
9
  this._cacheById = new Map();
10
10
  this._cacheByStyle = new NKeyMap();
11
11
  }
12
- getOrCreateEntry(color, bold, opacity) {
13
- if (color === undefined && bold === undefined && opacity === undefined) {
12
+ getOrCreateEntry(color, bold, opacity, strikethrough, strikethroughThickness, strikethroughColor) {
13
+ if (color === undefined && bold === undefined && opacity === undefined && strikethrough === undefined && strikethroughThickness === undefined && strikethroughColor === undefined) {
14
14
  return 0;
15
15
  }
16
- const result = this._cacheByStyle.get(color ?? 0, bold ? 1 : 0, opacity === undefined ? '' : opacity.toFixed(2));
16
+ const result = this._cacheByStyle.get(color ?? 0, bold ? 1 : 0, opacity === undefined ? '' : opacity.toFixed(2), strikethrough ? 1 : 0, strikethroughThickness === undefined ? '' : strikethroughThickness.toFixed(2), strikethroughColor ?? 0);
17
17
  if (result) {
18
18
  return result.id;
19
19
  }
@@ -23,9 +23,12 @@ export class DecorationStyleCache {
23
23
  color,
24
24
  bold,
25
25
  opacity,
26
+ strikethrough,
27
+ strikethroughThickness,
28
+ strikethroughColor,
26
29
  };
27
30
  this._cacheById.set(id, entry);
28
- this._cacheByStyle.set(entry, color ?? 0, bold ? 1 : 0, opacity === undefined ? '' : opacity.toFixed(2));
31
+ this._cacheByStyle.set(entry, color ?? 0, bold ? 1 : 0, opacity === undefined ? '' : opacity.toFixed(2), strikethrough ? 1 : 0, strikethroughThickness === undefined ? '' : strikethroughThickness.toFixed(2), strikethroughColor ?? 0);
29
32
  return id;
30
33
  }
31
34
  getStyleSet(id) {
@@ -1 +1 @@
1
- {"version":3,"sources":["file:///mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/browser/gpu/css/decorationStyleCache.ts","vs/editor/browser/gpu/css/decorationStyleCache.ts"],"names":[],"mappings":"AAAA;;;gGAGgG;AAEhG,OAAO,EAAE,OAAO,EAAE,MAAM,gCAAgC,CAAC;AAwBzD,MAAM,OAAO,oBAAoB;IAAjC;QAES,YAAO,GAAG,CAAC,CAAC;QAEH,eAAU,GAAG,IAAI,GAAG,EAAsC,CAAC;QAC3D,kBAAa,GAAG,IAAI,OAAO,EAAwD,CAAC;IAgCtG,CAAC;IA9BA,gBAAgB,CACf,KAAyB,EACzB,IAAyB,EACzB,OAA2B;QAE3B,IAAI,KAAK,KAAK,SAAS,IAAI,IAAI,KAAK,SAAS,IAAI,OAAO,KAAK,SAAS,EAAE,CAAC;YACxE,OAAO,CAAC,CAAC;QACV,CAAC;QACD,MAAM,MAAM,GAAG,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,KAAK,IAAI,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,OAAO,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC;QACjH,IAAI,MAAM,EAAE,CAAC;YACZ,OAAO,MAAM,CAAC,EAAE,CAAC;QAClB,CAAC;QACD,MAAM,EAAE,GAAG,IAAI,CAAC,OAAO,EAAE,CAAC;QAC1B,MAAM,KAAK,GAAG;YACb,EAAE;YACF,KAAK;YACL,IAAI;YACJ,OAAO;SACP,CAAC;QACF,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,EAAE,KAAK,CAAC,CAAC;QAC/B,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,KAAK,EAAE,KAAK,IAAI,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,OAAO,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC;QACzG,OAAO,EAAE,CAAC;IACX,CAAC;IAED,WAAW,CAAC,EAAU;QACrB,IAAI,EAAE,KAAK,CAAC,EAAE,CAAC;YACd,OAAO,SAAS,CAAC;QAClB,CAAC;QACD,OAAO,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAChC,CAAC;CACD","file":"decorationStyleCache.js","sourceRoot":"file:///mnt/vss/_work/1/s/dependencies/vscode/out-editor-src","sourcesContent":["/*---------------------------------------------------------------------------------------------\n * Copyright (c) Microsoft Corporation. All rights reserved.\n * Licensed under the MIT License. See License.txt in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\nimport { NKeyMap } from '../../../../base/common/map.js';\n\nexport interface IDecorationStyleSet {\n\t/**\n\t * A 24-bit number representing `color`.\n\t */\n\tcolor: number | undefined;\n\t/**\n\t * Whether the text should be rendered in bold.\n\t */\n\tbold: boolean | undefined;\n\t/**\n\t * A number between 0 and 1 representing the opacity of the text.\n\t */\n\topacity: number | undefined;\n}\n\nexport interface IDecorationStyleCacheEntry extends IDecorationStyleSet {\n\t/**\n\t * A unique identifier for this set of styles.\n\t */\n\tid: number;\n}\n\nexport class DecorationStyleCache {\n\n\tprivate _nextId = 1;\n\n\tprivate readonly _cacheById = new Map<number, IDecorationStyleCacheEntry>();\n\tprivate readonly _cacheByStyle = new NKeyMap<IDecorationStyleCacheEntry, [number, number, string]>();\n\n\tgetOrCreateEntry(\n\t\tcolor: number | undefined,\n\t\tbold: boolean | undefined,\n\t\topacity: number | undefined\n\t): number {\n\t\tif (color === undefined && bold === undefined && opacity === undefined) {\n\t\t\treturn 0;\n\t\t}\n\t\tconst result = this._cacheByStyle.get(color ?? 0, bold ? 1 : 0, opacity === undefined ? '' : opacity.toFixed(2));\n\t\tif (result) {\n\t\t\treturn result.id;\n\t\t}\n\t\tconst id = this._nextId++;\n\t\tconst entry = {\n\t\t\tid,\n\t\t\tcolor,\n\t\t\tbold,\n\t\t\topacity,\n\t\t};\n\t\tthis._cacheById.set(id, entry);\n\t\tthis._cacheByStyle.set(entry, color ?? 0, bold ? 1 : 0, opacity === undefined ? '' : opacity.toFixed(2));\n\t\treturn id;\n\t}\n\n\tgetStyleSet(id: number): IDecorationStyleSet | undefined {\n\t\tif (id === 0) {\n\t\t\treturn undefined;\n\t\t}\n\t\treturn this._cacheById.get(id);\n\t}\n}\n","/*---------------------------------------------------------------------------------------------\n * Copyright (c) Microsoft Corporation. All rights reserved.\n * Licensed under the MIT License. See License.txt in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\nimport { NKeyMap } from '../../../../base/common/map.js';\n\nexport interface IDecorationStyleSet {\n\t/**\n\t * A 24-bit number representing `color`.\n\t */\n\tcolor: number | undefined;\n\t/**\n\t * Whether the text should be rendered in bold.\n\t */\n\tbold: boolean | undefined;\n\t/**\n\t * A number between 0 and 1 representing the opacity of the text.\n\t */\n\topacity: number | undefined;\n}\n\nexport interface IDecorationStyleCacheEntry extends IDecorationStyleSet {\n\t/**\n\t * A unique identifier for this set of styles.\n\t */\n\tid: number;\n}\n\nexport class DecorationStyleCache {\n\n\tprivate _nextId = 1;\n\n\tprivate readonly _cacheById = new Map<number, IDecorationStyleCacheEntry>();\n\tprivate readonly _cacheByStyle = new NKeyMap<IDecorationStyleCacheEntry, [number, number, string]>();\n\n\tgetOrCreateEntry(\n\t\tcolor: number | undefined,\n\t\tbold: boolean | undefined,\n\t\topacity: number | undefined\n\t): number {\n\t\tif (color === undefined && bold === undefined && opacity === undefined) {\n\t\t\treturn 0;\n\t\t}\n\t\tconst result = this._cacheByStyle.get(color ?? 0, bold ? 1 : 0, opacity === undefined ? '' : opacity.toFixed(2));\n\t\tif (result) {\n\t\t\treturn result.id;\n\t\t}\n\t\tconst id = this._nextId++;\n\t\tconst entry = {\n\t\t\tid,\n\t\t\tcolor,\n\t\t\tbold,\n\t\t\topacity,\n\t\t};\n\t\tthis._cacheById.set(id, entry);\n\t\tthis._cacheByStyle.set(entry, color ?? 0, bold ? 1 : 0, opacity === undefined ? '' : opacity.toFixed(2));\n\t\treturn id;\n\t}\n\n\tgetStyleSet(id: number): IDecorationStyleSet | undefined {\n\t\tif (id === 0) {\n\t\t\treturn undefined;\n\t\t}\n\t\treturn this._cacheById.get(id);\n\t}\n}\n"]}
1
+ {"version":3,"sources":["file:///mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/browser/gpu/css/decorationStyleCache.ts","vs/editor/browser/gpu/css/decorationStyleCache.ts"],"names":[],"mappings":"AAAA;;;gGAGgG;AAEhG,OAAO,EAAE,OAAO,EAAE,MAAM,gCAAgC,CAAC;AAoCzD,MAAM,OAAO,oBAAoB;IAAjC;QAES,YAAO,GAAG,CAAC,CAAC;QAEH,eAAU,GAAG,IAAI,GAAG,EAAsC,CAAC;QAC3D,kBAAa,GAAG,IAAI,OAAO,EAAgF,CAAC;IAoD9H,CAAC;IAlDA,gBAAgB,CACf,KAAyB,EACzB,IAAyB,EACzB,OAA2B,EAC3B,aAAkC,EAClC,sBAA0C,EAC1C,kBAAsC;QAEtC,IAAI,KAAK,KAAK,SAAS,IAAI,IAAI,KAAK,SAAS,IAAI,OAAO,KAAK,SAAS,IAAI,aAAa,KAAK,SAAS,IAAI,sBAAsB,KAAK,SAAS,IAAI,kBAAkB,KAAK,SAAS,EAAE,CAAC;YACnL,OAAO,CAAC,CAAC;QACV,CAAC;QACD,MAAM,MAAM,GAAG,IAAI,CAAC,aAAa,CAAC,GAAG,CACpC,KAAK,IAAI,CAAC,EACV,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EACZ,OAAO,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,EAC/C,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EACrB,sBAAsB,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,sBAAsB,CAAC,OAAO,CAAC,CAAC,CAAC,EAC7E,kBAAkB,IAAI,CAAC,CACvB,CAAC;QACF,IAAI,MAAM,EAAE,CAAC;YACZ,OAAO,MAAM,CAAC,EAAE,CAAC;QAClB,CAAC;QACD,MAAM,EAAE,GAAG,IAAI,CAAC,OAAO,EAAE,CAAC;QAC1B,MAAM,KAAK,GAA+B;YACzC,EAAE;YACF,KAAK;YACL,IAAI;YACJ,OAAO;YACP,aAAa;YACb,sBAAsB;YACtB,kBAAkB;SAClB,CAAC;QACF,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,EAAE,KAAK,CAAC,CAAC;QAC/B,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,KAAK,EAC3B,KAAK,IAAI,CAAC,EACV,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EACZ,OAAO,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,EAC/C,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EACrB,sBAAsB,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,sBAAsB,CAAC,OAAO,CAAC,CAAC,CAAC,EAC7E,kBAAkB,IAAI,CAAC,CACvB,CAAC;QACF,OAAO,EAAE,CAAC;IACX,CAAC;IAED,WAAW,CAAC,EAAU;QACrB,IAAI,EAAE,KAAK,CAAC,EAAE,CAAC;YACd,OAAO,SAAS,CAAC;QAClB,CAAC;QACD,OAAO,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAChC,CAAC;CACD","file":"decorationStyleCache.js","sourceRoot":"file:///mnt/vss/_work/1/s/dependencies/vscode/out-editor-src","sourcesContent":["/*---------------------------------------------------------------------------------------------\n * Copyright (c) Microsoft Corporation. All rights reserved.\n * Licensed under the MIT License. See License.txt in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\nimport { NKeyMap } from '../../../../base/common/map.js';\n\nexport interface IDecorationStyleSet {\n\t/**\n\t * A 24-bit number representing `color`.\n\t */\n\tcolor: number | undefined;\n\t/**\n\t * Whether the text should be rendered in bold.\n\t */\n\tbold: boolean | undefined;\n\t/**\n\t * A number between 0 and 1 representing the opacity of the text.\n\t */\n\topacity: number | undefined;\n\t/**\n\t * Whether the text should be rendered with a strikethrough.\n\t */\n\tstrikethrough: boolean | undefined;\n\t/**\n\t * The thickness of the strikethrough line in pixels (CSS pixels, not device pixels).\n\t */\n\tstrikethroughThickness: number | undefined;\n\t/**\n\t * A 32-bit number representing the strikethrough color.\n\t */\n\tstrikethroughColor: number | undefined;\n}\n\nexport interface IDecorationStyleCacheEntry extends IDecorationStyleSet {\n\t/**\n\t * A unique identifier for this set of styles.\n\t */\n\tid: number;\n}\n\nexport class DecorationStyleCache {\n\n\tprivate _nextId = 1;\n\n\tprivate readonly _cacheById = new Map<number, IDecorationStyleCacheEntry>();\n\tprivate readonly _cacheByStyle = new NKeyMap<IDecorationStyleCacheEntry, [number, number, string, number, string, number]>();\n\n\tgetOrCreateEntry(\n\t\tcolor: number | undefined,\n\t\tbold: boolean | undefined,\n\t\topacity: number | undefined,\n\t\tstrikethrough: boolean | undefined,\n\t\tstrikethroughThickness: number | undefined,\n\t\tstrikethroughColor: number | undefined\n\t): number {\n\t\tif (color === undefined && bold === undefined && opacity === undefined && strikethrough === undefined && strikethroughThickness === undefined && strikethroughColor === undefined) {\n\t\t\treturn 0;\n\t\t}\n\t\tconst result = this._cacheByStyle.get(\n\t\t\tcolor ?? 0,\n\t\t\tbold ? 1 : 0,\n\t\t\topacity === undefined ? '' : opacity.toFixed(2),\n\t\t\tstrikethrough ? 1 : 0,\n\t\t\tstrikethroughThickness === undefined ? '' : strikethroughThickness.toFixed(2),\n\t\t\tstrikethroughColor ?? 0\n\t\t);\n\t\tif (result) {\n\t\t\treturn result.id;\n\t\t}\n\t\tconst id = this._nextId++;\n\t\tconst entry: IDecorationStyleCacheEntry = {\n\t\t\tid,\n\t\t\tcolor,\n\t\t\tbold,\n\t\t\topacity,\n\t\t\tstrikethrough,\n\t\t\tstrikethroughThickness,\n\t\t\tstrikethroughColor,\n\t\t};\n\t\tthis._cacheById.set(id, entry);\n\t\tthis._cacheByStyle.set(entry,\n\t\t\tcolor ?? 0,\n\t\t\tbold ? 1 : 0,\n\t\t\topacity === undefined ? '' : opacity.toFixed(2),\n\t\t\tstrikethrough ? 1 : 0,\n\t\t\tstrikethroughThickness === undefined ? '' : strikethroughThickness.toFixed(2),\n\t\t\tstrikethroughColor ?? 0\n\t\t);\n\t\treturn id;\n\t}\n\n\tgetStyleSet(id: number): IDecorationStyleSet | undefined {\n\t\tif (id === 0) {\n\t\t\treturn undefined;\n\t\t}\n\t\treturn this._cacheById.get(id);\n\t}\n}\n","/*---------------------------------------------------------------------------------------------\n * Copyright (c) Microsoft Corporation. All rights reserved.\n * Licensed under the MIT License. See License.txt in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\nimport { NKeyMap } from '../../../../base/common/map.js';\n\nexport interface IDecorationStyleSet {\n\t/**\n\t * A 24-bit number representing `color`.\n\t */\n\tcolor: number | undefined;\n\t/**\n\t * Whether the text should be rendered in bold.\n\t */\n\tbold: boolean | undefined;\n\t/**\n\t * A number between 0 and 1 representing the opacity of the text.\n\t */\n\topacity: number | undefined;\n\t/**\n\t * Whether the text should be rendered with a strikethrough.\n\t */\n\tstrikethrough: boolean | undefined;\n\t/**\n\t * The thickness of the strikethrough line in pixels (CSS pixels, not device pixels).\n\t */\n\tstrikethroughThickness: number | undefined;\n\t/**\n\t * A 32-bit number representing the strikethrough color.\n\t */\n\tstrikethroughColor: number | undefined;\n}\n\nexport interface IDecorationStyleCacheEntry extends IDecorationStyleSet {\n\t/**\n\t * A unique identifier for this set of styles.\n\t */\n\tid: number;\n}\n\nexport class DecorationStyleCache {\n\n\tprivate _nextId = 1;\n\n\tprivate readonly _cacheById = new Map<number, IDecorationStyleCacheEntry>();\n\tprivate readonly _cacheByStyle = new NKeyMap<IDecorationStyleCacheEntry, [number, number, string, number, string, number]>();\n\n\tgetOrCreateEntry(\n\t\tcolor: number | undefined,\n\t\tbold: boolean | undefined,\n\t\topacity: number | undefined,\n\t\tstrikethrough: boolean | undefined,\n\t\tstrikethroughThickness: number | undefined,\n\t\tstrikethroughColor: number | undefined\n\t): number {\n\t\tif (color === undefined && bold === undefined && opacity === undefined && strikethrough === undefined && strikethroughThickness === undefined && strikethroughColor === undefined) {\n\t\t\treturn 0;\n\t\t}\n\t\tconst result = this._cacheByStyle.get(\n\t\t\tcolor ?? 0,\n\t\t\tbold ? 1 : 0,\n\t\t\topacity === undefined ? '' : opacity.toFixed(2),\n\t\t\tstrikethrough ? 1 : 0,\n\t\t\tstrikethroughThickness === undefined ? '' : strikethroughThickness.toFixed(2),\n\t\t\tstrikethroughColor ?? 0\n\t\t);\n\t\tif (result) {\n\t\t\treturn result.id;\n\t\t}\n\t\tconst id = this._nextId++;\n\t\tconst entry: IDecorationStyleCacheEntry = {\n\t\t\tid,\n\t\t\tcolor,\n\t\t\tbold,\n\t\t\topacity,\n\t\t\tstrikethrough,\n\t\t\tstrikethroughThickness,\n\t\t\tstrikethroughColor,\n\t\t};\n\t\tthis._cacheById.set(id, entry);\n\t\tthis._cacheByStyle.set(entry,\n\t\t\tcolor ?? 0,\n\t\t\tbold ? 1 : 0,\n\t\t\topacity === undefined ? '' : opacity.toFixed(2),\n\t\t\tstrikethrough ? 1 : 0,\n\t\t\tstrikethroughThickness === undefined ? '' : strikethroughThickness.toFixed(2),\n\t\t\tstrikethroughColor ?? 0\n\t\t);\n\t\treturn id;\n\t}\n\n\tgetStyleSet(id: number): IDecorationStyleSet | undefined {\n\t\tif (id === 0) {\n\t\t\treturn undefined;\n\t\t}\n\t\treturn this._cacheById.get(id);\n\t}\n}\n"]}
@@ -90,7 +90,7 @@ export class GlyphRasterizer extends Disposable {
90
90
  this._ctx.save();
91
91
  // The sub-pixel x offset is the fractional part of the x pixel coordinate of the cell, this
92
92
  // is used to improve the spacing between rendered characters.
93
- const xSubPixelXOffset = (tokenMetadata & 0b1111) / 10;
93
+ const subPixelXOffset = (tokenMetadata & 0b1111) / 10;
94
94
  const bgId = TokenMetadata.getBackground(tokenMetadata);
95
95
  const bg = colorMap[bgId];
96
96
  const decorationStyleSet = this._decorationStyleCache.getStyleSet(decorationStyleSetId);
@@ -117,23 +117,47 @@ export class GlyphRasterizer extends Disposable {
117
117
  }
118
118
  fontSb.appendString(`${devicePixelFontSize}px ${this.fontFamily}`);
119
119
  this._ctx.font = fontSb.build();
120
- // TODO: Support FontStyle.Strikethrough and FontStyle.Underline text decorations, these
121
- // need to be drawn manually to the canvas. See xterm.js for "dodging" the text for
122
- // underlines.
120
+ // TODO: Support FontStyle.Underline text decorations, these need to be drawn manually to
121
+ // the canvas. See xterm.js for "dodging" the text for underlines.
123
122
  const originX = devicePixelFontSize;
124
123
  const originY = devicePixelFontSize;
124
+ // Apply text color
125
125
  if (decorationStyleSet?.color !== undefined) {
126
126
  this._ctx.fillStyle = `#${decorationStyleSet.color.toString(16).padStart(8, '0')}`;
127
127
  }
128
128
  else {
129
129
  this._ctx.fillStyle = colorMap[TokenMetadata.getForeground(tokenMetadata)];
130
130
  }
131
- this._ctx.textBaseline = 'top';
131
+ // Apply opacity
132
132
  if (decorationStyleSet?.opacity !== undefined) {
133
133
  this._ctx.globalAlpha = decorationStyleSet.opacity;
134
134
  }
135
- this._ctx.fillText(chars, originX + xSubPixelXOffset, originY);
135
+ // The glyph baseline is top, meaning it's drawn at the top-left of the
136
+ // cell. Add `TextMetrics.alphabeticBaseline` to the drawn position to
137
+ // get the alphabetic baseline.
138
+ this._ctx.textBaseline = 'top';
139
+ // Draw the text
140
+ this._ctx.fillText(chars, originX + subPixelXOffset, originY);
141
+ // Draw strikethrough
142
+ if (decorationStyleSet?.strikethrough) {
143
+ // TODO: This position could be refined further by checking
144
+ // TextMetrics of lowercase letters.
145
+ // Position strikethrough at approximately the vertical center of
146
+ // lowercase letters.
147
+ const strikethroughY = Math.round(originY - this._textMetrics.alphabeticBaseline * 0.65);
148
+ const lineWidth = decorationStyleSet?.strikethroughThickness !== undefined
149
+ ? Math.round(decorationStyleSet.strikethroughThickness * this.devicePixelRatio)
150
+ : Math.max(1, Math.floor(devicePixelFontSize / 10));
151
+ // Apply strikethrough color if specified
152
+ if (decorationStyleSet?.strikethroughColor !== undefined) {
153
+ this._ctx.fillStyle = `#${decorationStyleSet.strikethroughColor.toString(16).padStart(8, '0')}`;
154
+ }
155
+ // Intentionally do not apply the sub pixel x offset to
156
+ // strikethrough to ensure successive glyphs form a contiguous line.
157
+ this._ctx.fillRect(originX, strikethroughY - Math.floor(lineWidth / 2), Math.ceil(this._textMetrics.width), lineWidth);
158
+ }
136
159
  this._ctx.restore();
160
+ // Extract the image data and clear the background color
137
161
  const imageData = this._ctx.getImageData(0, 0, this._canvas.width, this._canvas.height);
138
162
  if (this._antiAliasing === 'subpixel') {
139
163
  const bgR = parseInt(bg.substring(1, 3), 16);
@@ -142,6 +166,7 @@ export class GlyphRasterizer extends Disposable {
142
166
  this._clearColor(imageData, bgR, bgG, bgB);
143
167
  this._ctx.putImageData(imageData, 0, 0);
144
168
  }
169
+ // Find the bounding box
145
170
  this._findGlyphBoundingBox(imageData, this._workGlyph.boundingBox);
146
171
  // const offset = {
147
172
  // x: textMetrics.actualBoundingBoxLeft,
@@ -1 +1 @@
1
- {"version":3,"sources":["file:///mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/browser/gpu/raster/glyphRasterizer.ts","vs/editor/browser/gpu/raster/glyphRasterizer.ts"],"names":[],"mappings":"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","file":"glyphRasterizer.js","sourceRoot":"file:///mnt/vss/_work/1/s/dependencies/vscode/out-editor-src","sourcesContent":["/*---------------------------------------------------------------------------------------------\n * Copyright (c) Microsoft Corporation. All rights reserved.\n * Licensed under the MIT License. See License.txt in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\nimport { memoize } from '../../../../base/common/decorators.js';\nimport { Disposable } from '../../../../base/common/lifecycle.js';\nimport { isMacintosh } from '../../../../base/common/platform.js';\nimport { StringBuilder } from '../../../common/core/stringBuilder.js';\nimport { FontStyle, TokenMetadata } from '../../../common/encodedTokenAttributes.js';\nimport { DecorationStyleCache } from '../css/decorationStyleCache.js';\nimport { ensureNonNullable } from '../gpuUtils.js';\nimport { type IBoundingBox, type IGlyphRasterizer, type IRasterizedGlyph } from './raster.js';\n\nlet nextId = 0;\n\nexport class GlyphRasterizer extends Disposable implements IGlyphRasterizer {\n\tpublic readonly id = nextId++;\n\n\t@memoize\n\tpublic get cacheKey(): string {\n\t\treturn `${this.fontFamily}_${this.fontSize}px`;\n\t}\n\n\tprivate _canvas: OffscreenCanvas;\n\tprivate _ctx: OffscreenCanvasRenderingContext2D;\n\n\tprivate readonly _textMetrics: TextMetrics;\n\n\tprivate _workGlyph: IRasterizedGlyph = {\n\t\tsource: null!,\n\t\tboundingBox: {\n\t\t\tleft: 0,\n\t\t\tbottom: 0,\n\t\t\tright: 0,\n\t\t\ttop: 0,\n\t\t},\n\t\toriginOffset: {\n\t\t\tx: 0,\n\t\t\ty: 0,\n\t\t},\n\t\tfontBoundingBoxAscent: 0,\n\t\tfontBoundingBoxDescent: 0,\n\t};\n\tprivate _workGlyphConfig: { chars: string | undefined; tokenMetadata: number; decorationStyleSetId: number } = { chars: undefined, tokenMetadata: 0, decorationStyleSetId: 0 };\n\n\t// TODO: Support workbench.fontAliasing correctly\n\tprivate _antiAliasing: 'subpixel' | 'greyscale' = isMacintosh ? 'greyscale' : 'subpixel';\n\n\tconstructor(\n\t\treadonly fontSize: number,\n\t\treadonly fontFamily: string,\n\t\treadonly devicePixelRatio: number,\n\t\tprivate readonly _decorationStyleCache: DecorationStyleCache,\n\t) {\n\t\tsuper();\n\n\t\tconst devicePixelFontSize = Math.ceil(this.fontSize * devicePixelRatio);\n\t\tthis._canvas = new OffscreenCanvas(devicePixelFontSize * 3, devicePixelFontSize * 3);\n\t\tthis._ctx = ensureNonNullable(this._canvas.getContext('2d', {\n\t\t\twillReadFrequently: true,\n\t\t\talpha: this._antiAliasing === 'greyscale',\n\t\t}));\n\t\tthis._ctx.textBaseline = 'top';\n\t\tthis._ctx.fillStyle = '#FFFFFF';\n\t\tthis._ctx.font = `${devicePixelFontSize}px ${this.fontFamily}`;\n\t\tthis._textMetrics = this._ctx.measureText('A');\n\t}\n\n\t/**\n\t * Rasterizes a glyph. Note that the returned object is reused across different glyphs and\n\t * therefore is only safe for synchronous access.\n\t */\n\tpublic rasterizeGlyph(\n\t\tchars: string,\n\t\ttokenMetadata: number,\n\t\tdecorationStyleSetId: number,\n\t\tcolorMap: string[],\n\t): Readonly<IRasterizedGlyph> {\n\t\tif (chars === '') {\n\t\t\treturn {\n\t\t\t\tsource: this._canvas,\n\t\t\t\tboundingBox: { top: 0, left: 0, bottom: -1, right: -1 },\n\t\t\t\toriginOffset: { x: 0, y: 0 },\n\t\t\t\tfontBoundingBoxAscent: 0,\n\t\t\t\tfontBoundingBoxDescent: 0,\n\t\t\t};\n\t\t}\n\t\t// Check if the last glyph matches the config, reuse if so. This helps avoid unnecessary\n\t\t// work when the rasterizer is called multiple times like when the glyph doesn't fit into a\n\t\t// page.\n\t\tif (this._workGlyphConfig.chars === chars && this._workGlyphConfig.tokenMetadata === tokenMetadata && this._workGlyphConfig.decorationStyleSetId === decorationStyleSetId) {\n\t\t\treturn this._workGlyph;\n\t\t}\n\t\tthis._workGlyphConfig.chars = chars;\n\t\tthis._workGlyphConfig.tokenMetadata = tokenMetadata;\n\t\tthis._workGlyphConfig.decorationStyleSetId = decorationStyleSetId;\n\t\treturn this._rasterizeGlyph(chars, tokenMetadata, decorationStyleSetId, colorMap);\n\t}\n\n\tpublic _rasterizeGlyph(\n\t\tchars: string,\n\t\ttokenMetadata: number,\n\t\tdecorationStyleSetId: number,\n\t\tcolorMap: string[],\n\t): Readonly<IRasterizedGlyph> {\n\t\tconst devicePixelFontSize = Math.ceil(this.fontSize * this.devicePixelRatio);\n\t\tconst canvasDim = devicePixelFontSize * 3;\n\t\tif (this._canvas.width !== canvasDim) {\n\t\t\tthis._canvas.width = canvasDim;\n\t\t\tthis._canvas.height = canvasDim;\n\t\t}\n\n\t\tthis._ctx.save();\n\n\t\t// The sub-pixel x offset is the fractional part of the x pixel coordinate of the cell, this\n\t\t// is used to improve the spacing between rendered characters.\n\t\tconst xSubPixelXOffset = (tokenMetadata & 0b1111) / 10;\n\n\t\tconst bgId = TokenMetadata.getBackground(tokenMetadata);\n\t\tconst bg = colorMap[bgId];\n\n\t\tconst decorationStyleSet = this._decorationStyleCache.getStyleSet(decorationStyleSetId);\n\n\t\t// When SPAA is used, the background color must be present to get the right glyph\n\t\tif (this._antiAliasing === 'subpixel') {\n\t\t\tthis._ctx.fillStyle = bg;\n\t\t\tthis._ctx.fillRect(0, 0, this._canvas.width, this._canvas.height);\n\t\t} else {\n\t\t\tthis._ctx.clearRect(0, 0, this._canvas.width, this._canvas.height);\n\t\t}\n\n\t\tconst fontSb = new StringBuilder(200);\n\t\tconst fontStyle = TokenMetadata.getFontStyle(tokenMetadata);\n\t\tif (fontStyle & FontStyle.Italic) {\n\t\t\tfontSb.appendString('italic ');\n\t\t}\n\t\tif (decorationStyleSet?.bold !== undefined) {\n\t\t\tif (decorationStyleSet.bold) {\n\t\t\t\tfontSb.appendString('bold ');\n\t\t\t}\n\t\t} else if (fontStyle & FontStyle.Bold) {\n\t\t\tfontSb.appendString('bold ');\n\t\t}\n\t\tfontSb.appendString(`${devicePixelFontSize}px ${this.fontFamily}`);\n\t\tthis._ctx.font = fontSb.build();\n\n\t\t// TODO: Support FontStyle.Strikethrough and FontStyle.Underline text decorations, these\n\t\t// need to be drawn manually to the canvas. See xterm.js for \"dodging\" the text for\n\t\t// underlines.\n\n\t\tconst originX = devicePixelFontSize;\n\t\tconst originY = devicePixelFontSize;\n\t\tif (decorationStyleSet?.color !== undefined) {\n\t\t\tthis._ctx.fillStyle = `#${decorationStyleSet.color.toString(16).padStart(8, '0')}`;\n\t\t} else {\n\t\t\tthis._ctx.fillStyle = colorMap[TokenMetadata.getForeground(tokenMetadata)];\n\t\t}\n\t\tthis._ctx.textBaseline = 'top';\n\n\t\tif (decorationStyleSet?.opacity !== undefined) {\n\t\t\tthis._ctx.globalAlpha = decorationStyleSet.opacity;\n\t\t}\n\n\t\tthis._ctx.fillText(chars, originX + xSubPixelXOffset, originY);\n\t\tthis._ctx.restore();\n\n\t\tconst imageData = this._ctx.getImageData(0, 0, this._canvas.width, this._canvas.height);\n\t\tif (this._antiAliasing === 'subpixel') {\n\t\t\tconst bgR = parseInt(bg.substring(1, 3), 16);\n\t\t\tconst bgG = parseInt(bg.substring(3, 5), 16);\n\t\t\tconst bgB = parseInt(bg.substring(5, 7), 16);\n\t\t\tthis._clearColor(imageData, bgR, bgG, bgB);\n\t\t\tthis._ctx.putImageData(imageData, 0, 0);\n\t\t}\n\t\tthis._findGlyphBoundingBox(imageData, this._workGlyph.boundingBox);\n\t\t// const offset = {\n\t\t// \tx: textMetrics.actualBoundingBoxLeft,\n\t\t// \ty: textMetrics.actualBoundingBoxAscent\n\t\t// };\n\t\t// const size = {\n\t\t// \tw: textMetrics.actualBoundingBoxRight + textMetrics.actualBoundingBoxLeft,\n\t\t// \ty: textMetrics.actualBoundingBoxDescent + textMetrics.actualBoundingBoxAscent,\n\t\t// \twInt: Math.ceil(textMetrics.actualBoundingBoxRight + textMetrics.actualBoundingBoxLeft),\n\t\t// \tyInt: Math.ceil(textMetrics.actualBoundingBoxDescent + textMetrics.actualBoundingBoxAscent),\n\t\t// };\n\t\t// console.log(`${chars}_${fg}`, textMetrics, boundingBox, originX, originY, { width: boundingBox.right - boundingBox.left, height: boundingBox.bottom - boundingBox.top });\n\t\tthis._workGlyph.source = this._canvas;\n\t\tthis._workGlyph.originOffset.x = this._workGlyph.boundingBox.left - originX;\n\t\tthis._workGlyph.originOffset.y = this._workGlyph.boundingBox.top - originY;\n\t\tthis._workGlyph.fontBoundingBoxAscent = this._textMetrics.fontBoundingBoxAscent;\n\t\tthis._workGlyph.fontBoundingBoxDescent = this._textMetrics.fontBoundingBoxDescent;\n\n\t\t// const result2: IRasterizedGlyph = {\n\t\t// \tsource: this._canvas,\n\t\t// \tboundingBox: {\n\t\t// \t\tleft: Math.floor(originX - textMetrics.actualBoundingBoxLeft),\n\t\t// \t\tright: Math.ceil(originX + textMetrics.actualBoundingBoxRight),\n\t\t// \t\ttop: Math.floor(originY - textMetrics.actualBoundingBoxAscent),\n\t\t// \t\tbottom: Math.ceil(originY + textMetrics.actualBoundingBoxDescent),\n\t\t// \t},\n\t\t// \toriginOffset: {\n\t\t// \t\tx: Math.floor(boundingBox.left - originX),\n\t\t// \t\ty: Math.floor(boundingBox.top - originY)\n\t\t// \t}\n\t\t// };\n\n\t\t// TODO: Verify result 1 and 2 are the same\n\n\t\t// if (result2.boundingBox.left > result.boundingBox.left) {\n\t\t// \tdebugger;\n\t\t// }\n\t\t// if (result2.boundingBox.top > result.boundingBox.top) {\n\t\t// \tdebugger;\n\t\t// }\n\t\t// if (result2.boundingBox.right < result.boundingBox.right) {\n\t\t// \tdebugger;\n\t\t// }\n\t\t// if (result2.boundingBox.bottom < result.boundingBox.bottom) {\n\t\t// \tdebugger;\n\t\t// }\n\t\t// if (JSON.stringify(result2.originOffset) !== JSON.stringify(result.originOffset)) {\n\t\t// \tdebugger;\n\t\t// }\n\n\n\n\t\treturn this._workGlyph;\n\t}\n\n\tprivate _clearColor(imageData: ImageData, r: number, g: number, b: number) {\n\t\tfor (let offset = 0; offset < imageData.data.length; offset += 4) {\n\t\t\t// Check exact match\n\t\t\tif (imageData.data[offset] === r &&\n\t\t\t\timageData.data[offset + 1] === g &&\n\t\t\t\timageData.data[offset + 2] === b) {\n\t\t\t\timageData.data[offset + 3] = 0;\n\t\t\t}\n\t\t}\n\t}\n\n\t// TODO: Does this even need to happen when measure text is used?\n\tprivate _findGlyphBoundingBox(imageData: ImageData, outBoundingBox: IBoundingBox) {\n\t\tconst height = this._canvas.height;\n\t\tconst width = this._canvas.width;\n\t\tlet found = false;\n\t\tfor (let y = 0; y < height; y++) {\n\t\t\tfor (let x = 0; x < width; x++) {\n\t\t\t\tconst alphaOffset = y * width * 4 + x * 4 + 3;\n\t\t\t\tif (imageData.data[alphaOffset] !== 0) {\n\t\t\t\t\toutBoundingBox.top = y;\n\t\t\t\t\tfound = true;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (found) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\toutBoundingBox.left = 0;\n\t\tfound = false;\n\t\tfor (let x = 0; x < width; x++) {\n\t\t\tfor (let y = 0; y < height; y++) {\n\t\t\t\tconst alphaOffset = y * width * 4 + x * 4 + 3;\n\t\t\t\tif (imageData.data[alphaOffset] !== 0) {\n\t\t\t\t\toutBoundingBox.left = x;\n\t\t\t\t\tfound = true;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (found) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\toutBoundingBox.right = width;\n\t\tfound = false;\n\t\tfor (let x = width - 1; x >= outBoundingBox.left; x--) {\n\t\t\tfor (let y = 0; y < height; y++) {\n\t\t\t\tconst alphaOffset = y * width * 4 + x * 4 + 3;\n\t\t\t\tif (imageData.data[alphaOffset] !== 0) {\n\t\t\t\t\toutBoundingBox.right = x;\n\t\t\t\t\tfound = true;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (found) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\toutBoundingBox.bottom = outBoundingBox.top;\n\t\tfound = false;\n\t\tfor (let y = height - 1; y >= 0; y--) {\n\t\t\tfor (let x = 0; x < width; x++) {\n\t\t\t\tconst alphaOffset = y * width * 4 + x * 4 + 3;\n\t\t\t\tif (imageData.data[alphaOffset] !== 0) {\n\t\t\t\t\toutBoundingBox.bottom = y;\n\t\t\t\t\tfound = true;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (found) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n\n\tpublic getTextMetrics(text: string): TextMetrics {\n\t\treturn this._ctx.measureText(text);\n\t}\n}\n","/*---------------------------------------------------------------------------------------------\n * Copyright (c) Microsoft Corporation. All rights reserved.\n * Licensed under the MIT License. See License.txt in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\nimport { memoize } from '../../../../base/common/decorators.js';\nimport { Disposable } from '../../../../base/common/lifecycle.js';\nimport { isMacintosh } from '../../../../base/common/platform.js';\nimport { StringBuilder } from '../../../common/core/stringBuilder.js';\nimport { FontStyle, TokenMetadata } from '../../../common/encodedTokenAttributes.js';\nimport { DecorationStyleCache } from '../css/decorationStyleCache.js';\nimport { ensureNonNullable } from '../gpuUtils.js';\nimport { type IBoundingBox, type IGlyphRasterizer, type IRasterizedGlyph } from './raster.js';\n\nlet nextId = 0;\n\nexport class GlyphRasterizer extends Disposable implements IGlyphRasterizer {\n\tpublic readonly id = nextId++;\n\n\t@memoize\n\tpublic get cacheKey(): string {\n\t\treturn `${this.fontFamily}_${this.fontSize}px`;\n\t}\n\n\tprivate _canvas: OffscreenCanvas;\n\tprivate _ctx: OffscreenCanvasRenderingContext2D;\n\n\tprivate readonly _textMetrics: TextMetrics;\n\n\tprivate _workGlyph: IRasterizedGlyph = {\n\t\tsource: null!,\n\t\tboundingBox: {\n\t\t\tleft: 0,\n\t\t\tbottom: 0,\n\t\t\tright: 0,\n\t\t\ttop: 0,\n\t\t},\n\t\toriginOffset: {\n\t\t\tx: 0,\n\t\t\ty: 0,\n\t\t},\n\t\tfontBoundingBoxAscent: 0,\n\t\tfontBoundingBoxDescent: 0,\n\t};\n\tprivate _workGlyphConfig: { chars: string | undefined; tokenMetadata: number; decorationStyleSetId: number } = { chars: undefined, tokenMetadata: 0, decorationStyleSetId: 0 };\n\n\t// TODO: Support workbench.fontAliasing correctly\n\tprivate _antiAliasing: 'subpixel' | 'greyscale' = isMacintosh ? 'greyscale' : 'subpixel';\n\n\tconstructor(\n\t\treadonly fontSize: number,\n\t\treadonly fontFamily: string,\n\t\treadonly devicePixelRatio: number,\n\t\tprivate readonly _decorationStyleCache: DecorationStyleCache,\n\t) {\n\t\tsuper();\n\n\t\tconst devicePixelFontSize = Math.ceil(this.fontSize * devicePixelRatio);\n\t\tthis._canvas = new OffscreenCanvas(devicePixelFontSize * 3, devicePixelFontSize * 3);\n\t\tthis._ctx = ensureNonNullable(this._canvas.getContext('2d', {\n\t\t\twillReadFrequently: true,\n\t\t\talpha: this._antiAliasing === 'greyscale',\n\t\t}));\n\t\tthis._ctx.textBaseline = 'top';\n\t\tthis._ctx.fillStyle = '#FFFFFF';\n\t\tthis._ctx.font = `${devicePixelFontSize}px ${this.fontFamily}`;\n\t\tthis._textMetrics = this._ctx.measureText('A');\n\t}\n\n\t/**\n\t * Rasterizes a glyph. Note that the returned object is reused across different glyphs and\n\t * therefore is only safe for synchronous access.\n\t */\n\tpublic rasterizeGlyph(\n\t\tchars: string,\n\t\ttokenMetadata: number,\n\t\tdecorationStyleSetId: number,\n\t\tcolorMap: string[],\n\t): Readonly<IRasterizedGlyph> {\n\t\tif (chars === '') {\n\t\t\treturn {\n\t\t\t\tsource: this._canvas,\n\t\t\t\tboundingBox: { top: 0, left: 0, bottom: -1, right: -1 },\n\t\t\t\toriginOffset: { x: 0, y: 0 },\n\t\t\t\tfontBoundingBoxAscent: 0,\n\t\t\t\tfontBoundingBoxDescent: 0,\n\t\t\t};\n\t\t}\n\t\t// Check if the last glyph matches the config, reuse if so. This helps avoid unnecessary\n\t\t// work when the rasterizer is called multiple times like when the glyph doesn't fit into a\n\t\t// page.\n\t\tif (this._workGlyphConfig.chars === chars && this._workGlyphConfig.tokenMetadata === tokenMetadata && this._workGlyphConfig.decorationStyleSetId === decorationStyleSetId) {\n\t\t\treturn this._workGlyph;\n\t\t}\n\t\tthis._workGlyphConfig.chars = chars;\n\t\tthis._workGlyphConfig.tokenMetadata = tokenMetadata;\n\t\tthis._workGlyphConfig.decorationStyleSetId = decorationStyleSetId;\n\t\treturn this._rasterizeGlyph(chars, tokenMetadata, decorationStyleSetId, colorMap);\n\t}\n\n\tpublic _rasterizeGlyph(\n\t\tchars: string,\n\t\ttokenMetadata: number,\n\t\tdecorationStyleSetId: number,\n\t\tcolorMap: string[],\n\t): Readonly<IRasterizedGlyph> {\n\t\tconst devicePixelFontSize = Math.ceil(this.fontSize * this.devicePixelRatio);\n\t\tconst canvasDim = devicePixelFontSize * 3;\n\t\tif (this._canvas.width !== canvasDim) {\n\t\t\tthis._canvas.width = canvasDim;\n\t\t\tthis._canvas.height = canvasDim;\n\t\t}\n\n\t\tthis._ctx.save();\n\n\t\t// The sub-pixel x offset is the fractional part of the x pixel coordinate of the cell, this\n\t\t// is used to improve the spacing between rendered characters.\n\t\tconst xSubPixelXOffset = (tokenMetadata & 0b1111) / 10;\n\n\t\tconst bgId = TokenMetadata.getBackground(tokenMetadata);\n\t\tconst bg = colorMap[bgId];\n\n\t\tconst decorationStyleSet = this._decorationStyleCache.getStyleSet(decorationStyleSetId);\n\n\t\t// When SPAA is used, the background color must be present to get the right glyph\n\t\tif (this._antiAliasing === 'subpixel') {\n\t\t\tthis._ctx.fillStyle = bg;\n\t\t\tthis._ctx.fillRect(0, 0, this._canvas.width, this._canvas.height);\n\t\t} else {\n\t\t\tthis._ctx.clearRect(0, 0, this._canvas.width, this._canvas.height);\n\t\t}\n\n\t\tconst fontSb = new StringBuilder(200);\n\t\tconst fontStyle = TokenMetadata.getFontStyle(tokenMetadata);\n\t\tif (fontStyle & FontStyle.Italic) {\n\t\t\tfontSb.appendString('italic ');\n\t\t}\n\t\tif (decorationStyleSet?.bold !== undefined) {\n\t\t\tif (decorationStyleSet.bold) {\n\t\t\t\tfontSb.appendString('bold ');\n\t\t\t}\n\t\t} else if (fontStyle & FontStyle.Bold) {\n\t\t\tfontSb.appendString('bold ');\n\t\t}\n\t\tfontSb.appendString(`${devicePixelFontSize}px ${this.fontFamily}`);\n\t\tthis._ctx.font = fontSb.build();\n\n\t\t// TODO: Support FontStyle.Strikethrough and FontStyle.Underline text decorations, these\n\t\t// need to be drawn manually to the canvas. See xterm.js for \"dodging\" the text for\n\t\t// underlines.\n\n\t\tconst originX = devicePixelFontSize;\n\t\tconst originY = devicePixelFontSize;\n\t\tif (decorationStyleSet?.color !== undefined) {\n\t\t\tthis._ctx.fillStyle = `#${decorationStyleSet.color.toString(16).padStart(8, '0')}`;\n\t\t} else {\n\t\t\tthis._ctx.fillStyle = colorMap[TokenMetadata.getForeground(tokenMetadata)];\n\t\t}\n\t\tthis._ctx.textBaseline = 'top';\n\n\t\tif (decorationStyleSet?.opacity !== undefined) {\n\t\t\tthis._ctx.globalAlpha = decorationStyleSet.opacity;\n\t\t}\n\n\t\tthis._ctx.fillText(chars, originX + xSubPixelXOffset, originY);\n\t\tthis._ctx.restore();\n\n\t\tconst imageData = this._ctx.getImageData(0, 0, this._canvas.width, this._canvas.height);\n\t\tif (this._antiAliasing === 'subpixel') {\n\t\t\tconst bgR = parseInt(bg.substring(1, 3), 16);\n\t\t\tconst bgG = parseInt(bg.substring(3, 5), 16);\n\t\t\tconst bgB = parseInt(bg.substring(5, 7), 16);\n\t\t\tthis._clearColor(imageData, bgR, bgG, bgB);\n\t\t\tthis._ctx.putImageData(imageData, 0, 0);\n\t\t}\n\t\tthis._findGlyphBoundingBox(imageData, this._workGlyph.boundingBox);\n\t\t// const offset = {\n\t\t// \tx: textMetrics.actualBoundingBoxLeft,\n\t\t// \ty: textMetrics.actualBoundingBoxAscent\n\t\t// };\n\t\t// const size = {\n\t\t// \tw: textMetrics.actualBoundingBoxRight + textMetrics.actualBoundingBoxLeft,\n\t\t// \ty: textMetrics.actualBoundingBoxDescent + textMetrics.actualBoundingBoxAscent,\n\t\t// \twInt: Math.ceil(textMetrics.actualBoundingBoxRight + textMetrics.actualBoundingBoxLeft),\n\t\t// \tyInt: Math.ceil(textMetrics.actualBoundingBoxDescent + textMetrics.actualBoundingBoxAscent),\n\t\t// };\n\t\t// console.log(`${chars}_${fg}`, textMetrics, boundingBox, originX, originY, { width: boundingBox.right - boundingBox.left, height: boundingBox.bottom - boundingBox.top });\n\t\tthis._workGlyph.source = this._canvas;\n\t\tthis._workGlyph.originOffset.x = this._workGlyph.boundingBox.left - originX;\n\t\tthis._workGlyph.originOffset.y = this._workGlyph.boundingBox.top - originY;\n\t\tthis._workGlyph.fontBoundingBoxAscent = this._textMetrics.fontBoundingBoxAscent;\n\t\tthis._workGlyph.fontBoundingBoxDescent = this._textMetrics.fontBoundingBoxDescent;\n\n\t\t// const result2: IRasterizedGlyph = {\n\t\t// \tsource: this._canvas,\n\t\t// \tboundingBox: {\n\t\t// \t\tleft: Math.floor(originX - textMetrics.actualBoundingBoxLeft),\n\t\t// \t\tright: Math.ceil(originX + textMetrics.actualBoundingBoxRight),\n\t\t// \t\ttop: Math.floor(originY - textMetrics.actualBoundingBoxAscent),\n\t\t// \t\tbottom: Math.ceil(originY + textMetrics.actualBoundingBoxDescent),\n\t\t// \t},\n\t\t// \toriginOffset: {\n\t\t// \t\tx: Math.floor(boundingBox.left - originX),\n\t\t// \t\ty: Math.floor(boundingBox.top - originY)\n\t\t// \t}\n\t\t// };\n\n\t\t// TODO: Verify result 1 and 2 are the same\n\n\t\t// if (result2.boundingBox.left > result.boundingBox.left) {\n\t\t// \tdebugger;\n\t\t// }\n\t\t// if (result2.boundingBox.top > result.boundingBox.top) {\n\t\t// \tdebugger;\n\t\t// }\n\t\t// if (result2.boundingBox.right < result.boundingBox.right) {\n\t\t// \tdebugger;\n\t\t// }\n\t\t// if (result2.boundingBox.bottom < result.boundingBox.bottom) {\n\t\t// \tdebugger;\n\t\t// }\n\t\t// if (JSON.stringify(result2.originOffset) !== JSON.stringify(result.originOffset)) {\n\t\t// \tdebugger;\n\t\t// }\n\n\n\n\t\treturn this._workGlyph;\n\t}\n\n\tprivate _clearColor(imageData: ImageData, r: number, g: number, b: number) {\n\t\tfor (let offset = 0; offset < imageData.data.length; offset += 4) {\n\t\t\t// Check exact match\n\t\t\tif (imageData.data[offset] === r &&\n\t\t\t\timageData.data[offset + 1] === g &&\n\t\t\t\timageData.data[offset + 2] === b) {\n\t\t\t\timageData.data[offset + 3] = 0;\n\t\t\t}\n\t\t}\n\t}\n\n\t// TODO: Does this even need to happen when measure text is used?\n\tprivate _findGlyphBoundingBox(imageData: ImageData, outBoundingBox: IBoundingBox) {\n\t\tconst height = this._canvas.height;\n\t\tconst width = this._canvas.width;\n\t\tlet found = false;\n\t\tfor (let y = 0; y < height; y++) {\n\t\t\tfor (let x = 0; x < width; x++) {\n\t\t\t\tconst alphaOffset = y * width * 4 + x * 4 + 3;\n\t\t\t\tif (imageData.data[alphaOffset] !== 0) {\n\t\t\t\t\toutBoundingBox.top = y;\n\t\t\t\t\tfound = true;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (found) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\toutBoundingBox.left = 0;\n\t\tfound = false;\n\t\tfor (let x = 0; x < width; x++) {\n\t\t\tfor (let y = 0; y < height; y++) {\n\t\t\t\tconst alphaOffset = y * width * 4 + x * 4 + 3;\n\t\t\t\tif (imageData.data[alphaOffset] !== 0) {\n\t\t\t\t\toutBoundingBox.left = x;\n\t\t\t\t\tfound = true;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (found) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\toutBoundingBox.right = width;\n\t\tfound = false;\n\t\tfor (let x = width - 1; x >= outBoundingBox.left; x--) {\n\t\t\tfor (let y = 0; y < height; y++) {\n\t\t\t\tconst alphaOffset = y * width * 4 + x * 4 + 3;\n\t\t\t\tif (imageData.data[alphaOffset] !== 0) {\n\t\t\t\t\toutBoundingBox.right = x;\n\t\t\t\t\tfound = true;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (found) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\toutBoundingBox.bottom = outBoundingBox.top;\n\t\tfound = false;\n\t\tfor (let y = height - 1; y >= 0; y--) {\n\t\t\tfor (let x = 0; x < width; x++) {\n\t\t\t\tconst alphaOffset = y * width * 4 + x * 4 + 3;\n\t\t\t\tif (imageData.data[alphaOffset] !== 0) {\n\t\t\t\t\toutBoundingBox.bottom = y;\n\t\t\t\t\tfound = true;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (found) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n\n\tpublic getTextMetrics(text: string): TextMetrics {\n\t\treturn this._ctx.measureText(text);\n\t}\n}\n"]}
1
+ {"version":3,"sources":["file:///mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/browser/gpu/raster/glyphRasterizer.ts","vs/editor/browser/gpu/raster/glyphRasterizer.ts"],"names":[],"mappings":"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","file":"glyphRasterizer.js","sourceRoot":"file:///mnt/vss/_work/1/s/dependencies/vscode/out-editor-src","sourcesContent":["/*---------------------------------------------------------------------------------------------\n * Copyright (c) Microsoft Corporation. All rights reserved.\n * Licensed under the MIT License. See License.txt in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\nimport { memoize } from '../../../../base/common/decorators.js';\nimport { Disposable } from '../../../../base/common/lifecycle.js';\nimport { isMacintosh } from '../../../../base/common/platform.js';\nimport { StringBuilder } from '../../../common/core/stringBuilder.js';\nimport { FontStyle, TokenMetadata } from '../../../common/encodedTokenAttributes.js';\nimport { DecorationStyleCache } from '../css/decorationStyleCache.js';\nimport { ensureNonNullable } from '../gpuUtils.js';\nimport { type IBoundingBox, type IGlyphRasterizer, type IRasterizedGlyph } from './raster.js';\n\nlet nextId = 0;\n\nexport class GlyphRasterizer extends Disposable implements IGlyphRasterizer {\n\tpublic readonly id = nextId++;\n\n\t@memoize\n\tpublic get cacheKey(): string {\n\t\treturn `${this.fontFamily}_${this.fontSize}px`;\n\t}\n\n\tprivate _canvas: OffscreenCanvas;\n\tprivate _ctx: OffscreenCanvasRenderingContext2D;\n\n\tprivate readonly _textMetrics: TextMetrics;\n\n\tprivate _workGlyph: IRasterizedGlyph = {\n\t\tsource: null!,\n\t\tboundingBox: {\n\t\t\tleft: 0,\n\t\t\tbottom: 0,\n\t\t\tright: 0,\n\t\t\ttop: 0,\n\t\t},\n\t\toriginOffset: {\n\t\t\tx: 0,\n\t\t\ty: 0,\n\t\t},\n\t\tfontBoundingBoxAscent: 0,\n\t\tfontBoundingBoxDescent: 0,\n\t};\n\tprivate _workGlyphConfig: { chars: string | undefined; tokenMetadata: number; decorationStyleSetId: number } = { chars: undefined, tokenMetadata: 0, decorationStyleSetId: 0 };\n\n\t// TODO: Support workbench.fontAliasing correctly\n\tprivate _antiAliasing: 'subpixel' | 'greyscale' = isMacintosh ? 'greyscale' : 'subpixel';\n\n\tconstructor(\n\t\treadonly fontSize: number,\n\t\treadonly fontFamily: string,\n\t\treadonly devicePixelRatio: number,\n\t\tprivate readonly _decorationStyleCache: DecorationStyleCache,\n\t) {\n\t\tsuper();\n\n\t\tconst devicePixelFontSize = Math.ceil(this.fontSize * devicePixelRatio);\n\t\tthis._canvas = new OffscreenCanvas(devicePixelFontSize * 3, devicePixelFontSize * 3);\n\t\tthis._ctx = ensureNonNullable(this._canvas.getContext('2d', {\n\t\t\twillReadFrequently: true,\n\t\t\talpha: this._antiAliasing === 'greyscale',\n\t\t}));\n\t\tthis._ctx.textBaseline = 'top';\n\t\tthis._ctx.fillStyle = '#FFFFFF';\n\t\tthis._ctx.font = `${devicePixelFontSize}px ${this.fontFamily}`;\n\t\tthis._textMetrics = this._ctx.measureText('A');\n\t}\n\n\t/**\n\t * Rasterizes a glyph. Note that the returned object is reused across different glyphs and\n\t * therefore is only safe for synchronous access.\n\t */\n\tpublic rasterizeGlyph(\n\t\tchars: string,\n\t\ttokenMetadata: number,\n\t\tdecorationStyleSetId: number,\n\t\tcolorMap: string[],\n\t): Readonly<IRasterizedGlyph> {\n\t\tif (chars === '') {\n\t\t\treturn {\n\t\t\t\tsource: this._canvas,\n\t\t\t\tboundingBox: { top: 0, left: 0, bottom: -1, right: -1 },\n\t\t\t\toriginOffset: { x: 0, y: 0 },\n\t\t\t\tfontBoundingBoxAscent: 0,\n\t\t\t\tfontBoundingBoxDescent: 0,\n\t\t\t};\n\t\t}\n\t\t// Check if the last glyph matches the config, reuse if so. This helps avoid unnecessary\n\t\t// work when the rasterizer is called multiple times like when the glyph doesn't fit into a\n\t\t// page.\n\t\tif (this._workGlyphConfig.chars === chars && this._workGlyphConfig.tokenMetadata === tokenMetadata && this._workGlyphConfig.decorationStyleSetId === decorationStyleSetId) {\n\t\t\treturn this._workGlyph;\n\t\t}\n\t\tthis._workGlyphConfig.chars = chars;\n\t\tthis._workGlyphConfig.tokenMetadata = tokenMetadata;\n\t\tthis._workGlyphConfig.decorationStyleSetId = decorationStyleSetId;\n\t\treturn this._rasterizeGlyph(chars, tokenMetadata, decorationStyleSetId, colorMap);\n\t}\n\n\tpublic _rasterizeGlyph(\n\t\tchars: string,\n\t\ttokenMetadata: number,\n\t\tdecorationStyleSetId: number,\n\t\tcolorMap: string[],\n\t): Readonly<IRasterizedGlyph> {\n\t\tconst devicePixelFontSize = Math.ceil(this.fontSize * this.devicePixelRatio);\n\t\tconst canvasDim = devicePixelFontSize * 3;\n\t\tif (this._canvas.width !== canvasDim) {\n\t\t\tthis._canvas.width = canvasDim;\n\t\t\tthis._canvas.height = canvasDim;\n\t\t}\n\n\t\tthis._ctx.save();\n\n\t\t// The sub-pixel x offset is the fractional part of the x pixel coordinate of the cell, this\n\t\t// is used to improve the spacing between rendered characters.\n\t\tconst subPixelXOffset = (tokenMetadata & 0b1111) / 10;\n\n\t\tconst bgId = TokenMetadata.getBackground(tokenMetadata);\n\t\tconst bg = colorMap[bgId];\n\n\t\tconst decorationStyleSet = this._decorationStyleCache.getStyleSet(decorationStyleSetId);\n\n\t\t// When SPAA is used, the background color must be present to get the right glyph\n\t\tif (this._antiAliasing === 'subpixel') {\n\t\t\tthis._ctx.fillStyle = bg;\n\t\t\tthis._ctx.fillRect(0, 0, this._canvas.width, this._canvas.height);\n\t\t} else {\n\t\t\tthis._ctx.clearRect(0, 0, this._canvas.width, this._canvas.height);\n\t\t}\n\n\t\tconst fontSb = new StringBuilder(200);\n\t\tconst fontStyle = TokenMetadata.getFontStyle(tokenMetadata);\n\t\tif (fontStyle & FontStyle.Italic) {\n\t\t\tfontSb.appendString('italic ');\n\t\t}\n\t\tif (decorationStyleSet?.bold !== undefined) {\n\t\t\tif (decorationStyleSet.bold) {\n\t\t\t\tfontSb.appendString('bold ');\n\t\t\t}\n\t\t} else if (fontStyle & FontStyle.Bold) {\n\t\t\tfontSb.appendString('bold ');\n\t\t}\n\t\tfontSb.appendString(`${devicePixelFontSize}px ${this.fontFamily}`);\n\t\tthis._ctx.font = fontSb.build();\n\n\t\t// TODO: Support FontStyle.Underline text decorations, these need to be drawn manually to\n\t\t// the canvas. See xterm.js for \"dodging\" the text for underlines.\n\n\t\tconst originX = devicePixelFontSize;\n\t\tconst originY = devicePixelFontSize;\n\n\t\t// Apply text color\n\t\tif (decorationStyleSet?.color !== undefined) {\n\t\t\tthis._ctx.fillStyle = `#${decorationStyleSet.color.toString(16).padStart(8, '0')}`;\n\t\t} else {\n\t\t\tthis._ctx.fillStyle = colorMap[TokenMetadata.getForeground(tokenMetadata)];\n\t\t}\n\n\t\t// Apply opacity\n\t\tif (decorationStyleSet?.opacity !== undefined) {\n\t\t\tthis._ctx.globalAlpha = decorationStyleSet.opacity;\n\t\t}\n\n\t\t// The glyph baseline is top, meaning it's drawn at the top-left of the\n\t\t// cell. Add `TextMetrics.alphabeticBaseline` to the drawn position to\n\t\t// get the alphabetic baseline.\n\t\tthis._ctx.textBaseline = 'top';\n\n\t\t// Draw the text\n\t\tthis._ctx.fillText(chars, originX + subPixelXOffset, originY);\n\n\t\t// Draw strikethrough\n\t\tif (decorationStyleSet?.strikethrough) {\n\t\t\t// TODO: This position could be refined further by checking\n\t\t\t// TextMetrics of lowercase letters.\n\t\t\t// Position strikethrough at approximately the vertical center of\n\t\t\t// lowercase letters.\n\t\t\tconst strikethroughY = Math.round(originY - this._textMetrics.alphabeticBaseline * 0.65);\n\t\t\tconst lineWidth = decorationStyleSet?.strikethroughThickness !== undefined\n\t\t\t\t? Math.round(decorationStyleSet.strikethroughThickness * this.devicePixelRatio)\n\t\t\t\t: Math.max(1, Math.floor(devicePixelFontSize / 10));\n\t\t\t// Apply strikethrough color if specified\n\t\t\tif (decorationStyleSet?.strikethroughColor !== undefined) {\n\t\t\t\tthis._ctx.fillStyle = `#${decorationStyleSet.strikethroughColor.toString(16).padStart(8, '0')}`;\n\t\t\t}\n\t\t\t// Intentionally do not apply the sub pixel x offset to\n\t\t\t// strikethrough to ensure successive glyphs form a contiguous line.\n\t\t\tthis._ctx.fillRect(originX, strikethroughY - Math.floor(lineWidth / 2), Math.ceil(this._textMetrics.width), lineWidth);\n\t\t}\n\n\t\tthis._ctx.restore();\n\n\t\t// Extract the image data and clear the background color\n\t\tconst imageData = this._ctx.getImageData(0, 0, this._canvas.width, this._canvas.height);\n\t\tif (this._antiAliasing === 'subpixel') {\n\t\t\tconst bgR = parseInt(bg.substring(1, 3), 16);\n\t\t\tconst bgG = parseInt(bg.substring(3, 5), 16);\n\t\t\tconst bgB = parseInt(bg.substring(5, 7), 16);\n\t\t\tthis._clearColor(imageData, bgR, bgG, bgB);\n\t\t\tthis._ctx.putImageData(imageData, 0, 0);\n\t\t}\n\n\t\t// Find the bounding box\n\t\tthis._findGlyphBoundingBox(imageData, this._workGlyph.boundingBox);\n\n\t\t// const offset = {\n\t\t// \tx: textMetrics.actualBoundingBoxLeft,\n\t\t// \ty: textMetrics.actualBoundingBoxAscent\n\t\t// };\n\t\t// const size = {\n\t\t// \tw: textMetrics.actualBoundingBoxRight + textMetrics.actualBoundingBoxLeft,\n\t\t// \ty: textMetrics.actualBoundingBoxDescent + textMetrics.actualBoundingBoxAscent,\n\t\t// \twInt: Math.ceil(textMetrics.actualBoundingBoxRight + textMetrics.actualBoundingBoxLeft),\n\t\t// \tyInt: Math.ceil(textMetrics.actualBoundingBoxDescent + textMetrics.actualBoundingBoxAscent),\n\t\t// };\n\t\t// console.log(`${chars}_${fg}`, textMetrics, boundingBox, originX, originY, { width: boundingBox.right - boundingBox.left, height: boundingBox.bottom - boundingBox.top });\n\t\tthis._workGlyph.source = this._canvas;\n\t\tthis._workGlyph.originOffset.x = this._workGlyph.boundingBox.left - originX;\n\t\tthis._workGlyph.originOffset.y = this._workGlyph.boundingBox.top - originY;\n\t\tthis._workGlyph.fontBoundingBoxAscent = this._textMetrics.fontBoundingBoxAscent;\n\t\tthis._workGlyph.fontBoundingBoxDescent = this._textMetrics.fontBoundingBoxDescent;\n\n\t\t// const result2: IRasterizedGlyph = {\n\t\t// \tsource: this._canvas,\n\t\t// \tboundingBox: {\n\t\t// \t\tleft: Math.floor(originX - textMetrics.actualBoundingBoxLeft),\n\t\t// \t\tright: Math.ceil(originX + textMetrics.actualBoundingBoxRight),\n\t\t// \t\ttop: Math.floor(originY - textMetrics.actualBoundingBoxAscent),\n\t\t// \t\tbottom: Math.ceil(originY + textMetrics.actualBoundingBoxDescent),\n\t\t// \t},\n\t\t// \toriginOffset: {\n\t\t// \t\tx: Math.floor(boundingBox.left - originX),\n\t\t// \t\ty: Math.floor(boundingBox.top - originY)\n\t\t// \t}\n\t\t// };\n\n\t\t// TODO: Verify result 1 and 2 are the same\n\n\t\t// if (result2.boundingBox.left > result.boundingBox.left) {\n\t\t// \tdebugger;\n\t\t// }\n\t\t// if (result2.boundingBox.top > result.boundingBox.top) {\n\t\t// \tdebugger;\n\t\t// }\n\t\t// if (result2.boundingBox.right < result.boundingBox.right) {\n\t\t// \tdebugger;\n\t\t// }\n\t\t// if (result2.boundingBox.bottom < result.boundingBox.bottom) {\n\t\t// \tdebugger;\n\t\t// }\n\t\t// if (JSON.stringify(result2.originOffset) !== JSON.stringify(result.originOffset)) {\n\t\t// \tdebugger;\n\t\t// }\n\n\n\n\t\treturn this._workGlyph;\n\t}\n\n\tprivate _clearColor(imageData: ImageData, r: number, g: number, b: number) {\n\t\tfor (let offset = 0; offset < imageData.data.length; offset += 4) {\n\t\t\t// Check exact match\n\t\t\tif (imageData.data[offset] === r &&\n\t\t\t\timageData.data[offset + 1] === g &&\n\t\t\t\timageData.data[offset + 2] === b) {\n\t\t\t\timageData.data[offset + 3] = 0;\n\t\t\t}\n\t\t}\n\t}\n\n\t// TODO: Does this even need to happen when measure text is used?\n\tprivate _findGlyphBoundingBox(imageData: ImageData, outBoundingBox: IBoundingBox) {\n\t\tconst height = this._canvas.height;\n\t\tconst width = this._canvas.width;\n\t\tlet found = false;\n\t\tfor (let y = 0; y < height; y++) {\n\t\t\tfor (let x = 0; x < width; x++) {\n\t\t\t\tconst alphaOffset = y * width * 4 + x * 4 + 3;\n\t\t\t\tif (imageData.data[alphaOffset] !== 0) {\n\t\t\t\t\toutBoundingBox.top = y;\n\t\t\t\t\tfound = true;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (found) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\toutBoundingBox.left = 0;\n\t\tfound = false;\n\t\tfor (let x = 0; x < width; x++) {\n\t\t\tfor (let y = 0; y < height; y++) {\n\t\t\t\tconst alphaOffset = y * width * 4 + x * 4 + 3;\n\t\t\t\tif (imageData.data[alphaOffset] !== 0) {\n\t\t\t\t\toutBoundingBox.left = x;\n\t\t\t\t\tfound = true;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (found) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\toutBoundingBox.right = width;\n\t\tfound = false;\n\t\tfor (let x = width - 1; x >= outBoundingBox.left; x--) {\n\t\t\tfor (let y = 0; y < height; y++) {\n\t\t\t\tconst alphaOffset = y * width * 4 + x * 4 + 3;\n\t\t\t\tif (imageData.data[alphaOffset] !== 0) {\n\t\t\t\t\toutBoundingBox.right = x;\n\t\t\t\t\tfound = true;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (found) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\toutBoundingBox.bottom = outBoundingBox.top;\n\t\tfound = false;\n\t\tfor (let y = height - 1; y >= 0; y--) {\n\t\t\tfor (let x = 0; x < width; x++) {\n\t\t\t\tconst alphaOffset = y * width * 4 + x * 4 + 3;\n\t\t\t\tif (imageData.data[alphaOffset] !== 0) {\n\t\t\t\t\toutBoundingBox.bottom = y;\n\t\t\t\t\tfound = true;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (found) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n\n\tpublic getTextMetrics(text: string): TextMetrics {\n\t\treturn this._ctx.measureText(text);\n\t}\n}\n","/*---------------------------------------------------------------------------------------------\n * Copyright (c) Microsoft Corporation. All rights reserved.\n * Licensed under the MIT License. See License.txt in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\nimport { memoize } from '../../../../base/common/decorators.js';\nimport { Disposable } from '../../../../base/common/lifecycle.js';\nimport { isMacintosh } from '../../../../base/common/platform.js';\nimport { StringBuilder } from '../../../common/core/stringBuilder.js';\nimport { FontStyle, TokenMetadata } from '../../../common/encodedTokenAttributes.js';\nimport { DecorationStyleCache } from '../css/decorationStyleCache.js';\nimport { ensureNonNullable } from '../gpuUtils.js';\nimport { type IBoundingBox, type IGlyphRasterizer, type IRasterizedGlyph } from './raster.js';\n\nlet nextId = 0;\n\nexport class GlyphRasterizer extends Disposable implements IGlyphRasterizer {\n\tpublic readonly id = nextId++;\n\n\t@memoize\n\tpublic get cacheKey(): string {\n\t\treturn `${this.fontFamily}_${this.fontSize}px`;\n\t}\n\n\tprivate _canvas: OffscreenCanvas;\n\tprivate _ctx: OffscreenCanvasRenderingContext2D;\n\n\tprivate readonly _textMetrics: TextMetrics;\n\n\tprivate _workGlyph: IRasterizedGlyph = {\n\t\tsource: null!,\n\t\tboundingBox: {\n\t\t\tleft: 0,\n\t\t\tbottom: 0,\n\t\t\tright: 0,\n\t\t\ttop: 0,\n\t\t},\n\t\toriginOffset: {\n\t\t\tx: 0,\n\t\t\ty: 0,\n\t\t},\n\t\tfontBoundingBoxAscent: 0,\n\t\tfontBoundingBoxDescent: 0,\n\t};\n\tprivate _workGlyphConfig: { chars: string | undefined; tokenMetadata: number; decorationStyleSetId: number } = { chars: undefined, tokenMetadata: 0, decorationStyleSetId: 0 };\n\n\t// TODO: Support workbench.fontAliasing correctly\n\tprivate _antiAliasing: 'subpixel' | 'greyscale' = isMacintosh ? 'greyscale' : 'subpixel';\n\n\tconstructor(\n\t\treadonly fontSize: number,\n\t\treadonly fontFamily: string,\n\t\treadonly devicePixelRatio: number,\n\t\tprivate readonly _decorationStyleCache: DecorationStyleCache,\n\t) {\n\t\tsuper();\n\n\t\tconst devicePixelFontSize = Math.ceil(this.fontSize * devicePixelRatio);\n\t\tthis._canvas = new OffscreenCanvas(devicePixelFontSize * 3, devicePixelFontSize * 3);\n\t\tthis._ctx = ensureNonNullable(this._canvas.getContext('2d', {\n\t\t\twillReadFrequently: true,\n\t\t\talpha: this._antiAliasing === 'greyscale',\n\t\t}));\n\t\tthis._ctx.textBaseline = 'top';\n\t\tthis._ctx.fillStyle = '#FFFFFF';\n\t\tthis._ctx.font = `${devicePixelFontSize}px ${this.fontFamily}`;\n\t\tthis._textMetrics = this._ctx.measureText('A');\n\t}\n\n\t/**\n\t * Rasterizes a glyph. Note that the returned object is reused across different glyphs and\n\t * therefore is only safe for synchronous access.\n\t */\n\tpublic rasterizeGlyph(\n\t\tchars: string,\n\t\ttokenMetadata: number,\n\t\tdecorationStyleSetId: number,\n\t\tcolorMap: string[],\n\t): Readonly<IRasterizedGlyph> {\n\t\tif (chars === '') {\n\t\t\treturn {\n\t\t\t\tsource: this._canvas,\n\t\t\t\tboundingBox: { top: 0, left: 0, bottom: -1, right: -1 },\n\t\t\t\toriginOffset: { x: 0, y: 0 },\n\t\t\t\tfontBoundingBoxAscent: 0,\n\t\t\t\tfontBoundingBoxDescent: 0,\n\t\t\t};\n\t\t}\n\t\t// Check if the last glyph matches the config, reuse if so. This helps avoid unnecessary\n\t\t// work when the rasterizer is called multiple times like when the glyph doesn't fit into a\n\t\t// page.\n\t\tif (this._workGlyphConfig.chars === chars && this._workGlyphConfig.tokenMetadata === tokenMetadata && this._workGlyphConfig.decorationStyleSetId === decorationStyleSetId) {\n\t\t\treturn this._workGlyph;\n\t\t}\n\t\tthis._workGlyphConfig.chars = chars;\n\t\tthis._workGlyphConfig.tokenMetadata = tokenMetadata;\n\t\tthis._workGlyphConfig.decorationStyleSetId = decorationStyleSetId;\n\t\treturn this._rasterizeGlyph(chars, tokenMetadata, decorationStyleSetId, colorMap);\n\t}\n\n\tpublic _rasterizeGlyph(\n\t\tchars: string,\n\t\ttokenMetadata: number,\n\t\tdecorationStyleSetId: number,\n\t\tcolorMap: string[],\n\t): Readonly<IRasterizedGlyph> {\n\t\tconst devicePixelFontSize = Math.ceil(this.fontSize * this.devicePixelRatio);\n\t\tconst canvasDim = devicePixelFontSize * 3;\n\t\tif (this._canvas.width !== canvasDim) {\n\t\t\tthis._canvas.width = canvasDim;\n\t\t\tthis._canvas.height = canvasDim;\n\t\t}\n\n\t\tthis._ctx.save();\n\n\t\t// The sub-pixel x offset is the fractional part of the x pixel coordinate of the cell, this\n\t\t// is used to improve the spacing between rendered characters.\n\t\tconst subPixelXOffset = (tokenMetadata & 0b1111) / 10;\n\n\t\tconst bgId = TokenMetadata.getBackground(tokenMetadata);\n\t\tconst bg = colorMap[bgId];\n\n\t\tconst decorationStyleSet = this._decorationStyleCache.getStyleSet(decorationStyleSetId);\n\n\t\t// When SPAA is used, the background color must be present to get the right glyph\n\t\tif (this._antiAliasing === 'subpixel') {\n\t\t\tthis._ctx.fillStyle = bg;\n\t\t\tthis._ctx.fillRect(0, 0, this._canvas.width, this._canvas.height);\n\t\t} else {\n\t\t\tthis._ctx.clearRect(0, 0, this._canvas.width, this._canvas.height);\n\t\t}\n\n\t\tconst fontSb = new StringBuilder(200);\n\t\tconst fontStyle = TokenMetadata.getFontStyle(tokenMetadata);\n\t\tif (fontStyle & FontStyle.Italic) {\n\t\t\tfontSb.appendString('italic ');\n\t\t}\n\t\tif (decorationStyleSet?.bold !== undefined) {\n\t\t\tif (decorationStyleSet.bold) {\n\t\t\t\tfontSb.appendString('bold ');\n\t\t\t}\n\t\t} else if (fontStyle & FontStyle.Bold) {\n\t\t\tfontSb.appendString('bold ');\n\t\t}\n\t\tfontSb.appendString(`${devicePixelFontSize}px ${this.fontFamily}`);\n\t\tthis._ctx.font = fontSb.build();\n\n\t\t// TODO: Support FontStyle.Underline text decorations, these need to be drawn manually to\n\t\t// the canvas. See xterm.js for \"dodging\" the text for underlines.\n\n\t\tconst originX = devicePixelFontSize;\n\t\tconst originY = devicePixelFontSize;\n\n\t\t// Apply text color\n\t\tif (decorationStyleSet?.color !== undefined) {\n\t\t\tthis._ctx.fillStyle = `#${decorationStyleSet.color.toString(16).padStart(8, '0')}`;\n\t\t} else {\n\t\t\tthis._ctx.fillStyle = colorMap[TokenMetadata.getForeground(tokenMetadata)];\n\t\t}\n\n\t\t// Apply opacity\n\t\tif (decorationStyleSet?.opacity !== undefined) {\n\t\t\tthis._ctx.globalAlpha = decorationStyleSet.opacity;\n\t\t}\n\n\t\t// The glyph baseline is top, meaning it's drawn at the top-left of the\n\t\t// cell. Add `TextMetrics.alphabeticBaseline` to the drawn position to\n\t\t// get the alphabetic baseline.\n\t\tthis._ctx.textBaseline = 'top';\n\n\t\t// Draw the text\n\t\tthis._ctx.fillText(chars, originX + subPixelXOffset, originY);\n\n\t\t// Draw strikethrough\n\t\tif (decorationStyleSet?.strikethrough) {\n\t\t\t// TODO: This position could be refined further by checking\n\t\t\t// TextMetrics of lowercase letters.\n\t\t\t// Position strikethrough at approximately the vertical center of\n\t\t\t// lowercase letters.\n\t\t\tconst strikethroughY = Math.round(originY - this._textMetrics.alphabeticBaseline * 0.65);\n\t\t\tconst lineWidth = decorationStyleSet?.strikethroughThickness !== undefined\n\t\t\t\t? Math.round(decorationStyleSet.strikethroughThickness * this.devicePixelRatio)\n\t\t\t\t: Math.max(1, Math.floor(devicePixelFontSize / 10));\n\t\t\t// Apply strikethrough color if specified\n\t\t\tif (decorationStyleSet?.strikethroughColor !== undefined) {\n\t\t\t\tthis._ctx.fillStyle = `#${decorationStyleSet.strikethroughColor.toString(16).padStart(8, '0')}`;\n\t\t\t}\n\t\t\t// Intentionally do not apply the sub pixel x offset to\n\t\t\t// strikethrough to ensure successive glyphs form a contiguous line.\n\t\t\tthis._ctx.fillRect(originX, strikethroughY - Math.floor(lineWidth / 2), Math.ceil(this._textMetrics.width), lineWidth);\n\t\t}\n\n\t\tthis._ctx.restore();\n\n\t\t// Extract the image data and clear the background color\n\t\tconst imageData = this._ctx.getImageData(0, 0, this._canvas.width, this._canvas.height);\n\t\tif (this._antiAliasing === 'subpixel') {\n\t\t\tconst bgR = parseInt(bg.substring(1, 3), 16);\n\t\t\tconst bgG = parseInt(bg.substring(3, 5), 16);\n\t\t\tconst bgB = parseInt(bg.substring(5, 7), 16);\n\t\t\tthis._clearColor(imageData, bgR, bgG, bgB);\n\t\t\tthis._ctx.putImageData(imageData, 0, 0);\n\t\t}\n\n\t\t// Find the bounding box\n\t\tthis._findGlyphBoundingBox(imageData, this._workGlyph.boundingBox);\n\n\t\t// const offset = {\n\t\t// \tx: textMetrics.actualBoundingBoxLeft,\n\t\t// \ty: textMetrics.actualBoundingBoxAscent\n\t\t// };\n\t\t// const size = {\n\t\t// \tw: textMetrics.actualBoundingBoxRight + textMetrics.actualBoundingBoxLeft,\n\t\t// \ty: textMetrics.actualBoundingBoxDescent + textMetrics.actualBoundingBoxAscent,\n\t\t// \twInt: Math.ceil(textMetrics.actualBoundingBoxRight + textMetrics.actualBoundingBoxLeft),\n\t\t// \tyInt: Math.ceil(textMetrics.actualBoundingBoxDescent + textMetrics.actualBoundingBoxAscent),\n\t\t// };\n\t\t// console.log(`${chars}_${fg}`, textMetrics, boundingBox, originX, originY, { width: boundingBox.right - boundingBox.left, height: boundingBox.bottom - boundingBox.top });\n\t\tthis._workGlyph.source = this._canvas;\n\t\tthis._workGlyph.originOffset.x = this._workGlyph.boundingBox.left - originX;\n\t\tthis._workGlyph.originOffset.y = this._workGlyph.boundingBox.top - originY;\n\t\tthis._workGlyph.fontBoundingBoxAscent = this._textMetrics.fontBoundingBoxAscent;\n\t\tthis._workGlyph.fontBoundingBoxDescent = this._textMetrics.fontBoundingBoxDescent;\n\n\t\t// const result2: IRasterizedGlyph = {\n\t\t// \tsource: this._canvas,\n\t\t// \tboundingBox: {\n\t\t// \t\tleft: Math.floor(originX - textMetrics.actualBoundingBoxLeft),\n\t\t// \t\tright: Math.ceil(originX + textMetrics.actualBoundingBoxRight),\n\t\t// \t\ttop: Math.floor(originY - textMetrics.actualBoundingBoxAscent),\n\t\t// \t\tbottom: Math.ceil(originY + textMetrics.actualBoundingBoxDescent),\n\t\t// \t},\n\t\t// \toriginOffset: {\n\t\t// \t\tx: Math.floor(boundingBox.left - originX),\n\t\t// \t\ty: Math.floor(boundingBox.top - originY)\n\t\t// \t}\n\t\t// };\n\n\t\t// TODO: Verify result 1 and 2 are the same\n\n\t\t// if (result2.boundingBox.left > result.boundingBox.left) {\n\t\t// \tdebugger;\n\t\t// }\n\t\t// if (result2.boundingBox.top > result.boundingBox.top) {\n\t\t// \tdebugger;\n\t\t// }\n\t\t// if (result2.boundingBox.right < result.boundingBox.right) {\n\t\t// \tdebugger;\n\t\t// }\n\t\t// if (result2.boundingBox.bottom < result.boundingBox.bottom) {\n\t\t// \tdebugger;\n\t\t// }\n\t\t// if (JSON.stringify(result2.originOffset) !== JSON.stringify(result.originOffset)) {\n\t\t// \tdebugger;\n\t\t// }\n\n\n\n\t\treturn this._workGlyph;\n\t}\n\n\tprivate _clearColor(imageData: ImageData, r: number, g: number, b: number) {\n\t\tfor (let offset = 0; offset < imageData.data.length; offset += 4) {\n\t\t\t// Check exact match\n\t\t\tif (imageData.data[offset] === r &&\n\t\t\t\timageData.data[offset + 1] === g &&\n\t\t\t\timageData.data[offset + 2] === b) {\n\t\t\t\timageData.data[offset + 3] = 0;\n\t\t\t}\n\t\t}\n\t}\n\n\t// TODO: Does this even need to happen when measure text is used?\n\tprivate _findGlyphBoundingBox(imageData: ImageData, outBoundingBox: IBoundingBox) {\n\t\tconst height = this._canvas.height;\n\t\tconst width = this._canvas.width;\n\t\tlet found = false;\n\t\tfor (let y = 0; y < height; y++) {\n\t\t\tfor (let x = 0; x < width; x++) {\n\t\t\t\tconst alphaOffset = y * width * 4 + x * 4 + 3;\n\t\t\t\tif (imageData.data[alphaOffset] !== 0) {\n\t\t\t\t\toutBoundingBox.top = y;\n\t\t\t\t\tfound = true;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (found) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\toutBoundingBox.left = 0;\n\t\tfound = false;\n\t\tfor (let x = 0; x < width; x++) {\n\t\t\tfor (let y = 0; y < height; y++) {\n\t\t\t\tconst alphaOffset = y * width * 4 + x * 4 + 3;\n\t\t\t\tif (imageData.data[alphaOffset] !== 0) {\n\t\t\t\t\toutBoundingBox.left = x;\n\t\t\t\t\tfound = true;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (found) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\toutBoundingBox.right = width;\n\t\tfound = false;\n\t\tfor (let x = width - 1; x >= outBoundingBox.left; x--) {\n\t\t\tfor (let y = 0; y < height; y++) {\n\t\t\t\tconst alphaOffset = y * width * 4 + x * 4 + 3;\n\t\t\t\tif (imageData.data[alphaOffset] !== 0) {\n\t\t\t\t\toutBoundingBox.right = x;\n\t\t\t\t\tfound = true;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (found) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\toutBoundingBox.bottom = outBoundingBox.top;\n\t\tfound = false;\n\t\tfor (let y = height - 1; y >= 0; y--) {\n\t\t\tfor (let x = 0; x < width; x++) {\n\t\t\t\tconst alphaOffset = y * width * 4 + x * 4 + 3;\n\t\t\t\tif (imageData.data[alphaOffset] !== 0) {\n\t\t\t\t\toutBoundingBox.bottom = y;\n\t\t\t\t\tfound = true;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (found) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n\n\tpublic getTextMetrics(text: string): TextMetrics {\n\t\treturn this._ctx.measureText(text);\n\t}\n}\n"]}
@@ -176,6 +176,9 @@ export class FullFileRenderStrategy extends BaseRenderStrategy {
176
176
  let decorationStyleSetBold;
177
177
  let decorationStyleSetColor;
178
178
  let decorationStyleSetOpacity;
179
+ let decorationStyleSetStrikethrough;
180
+ let decorationStyleSetStrikethroughThickness;
181
+ let decorationStyleSetStrikethroughColor;
179
182
  let lineData;
180
183
  let decoration;
181
184
  let fillStartIndex = 0;
@@ -271,6 +274,9 @@ export class FullFileRenderStrategy extends BaseRenderStrategy {
271
274
  decorationStyleSetColor = undefined;
272
275
  decorationStyleSetBold = undefined;
273
276
  decorationStyleSetOpacity = undefined;
277
+ decorationStyleSetStrikethrough = undefined;
278
+ decorationStyleSetStrikethroughThickness = undefined;
279
+ decorationStyleSetStrikethroughColor = undefined;
274
280
  // Apply supported inline decoration styles to the cell metadata
275
281
  for (decoration of lineData.inlineDecorations) {
276
282
  // This is Range.strictContainsPosition except it works at the cell level,
@@ -312,6 +318,36 @@ export class FullFileRenderStrategy extends BaseRenderStrategy {
312
318
  decorationStyleSetOpacity = parsedValue;
313
319
  break;
314
320
  }
321
+ case 'text-decoration':
322
+ case 'text-decoration-line': {
323
+ if (value === 'line-through') {
324
+ decorationStyleSetStrikethrough = true;
325
+ }
326
+ break;
327
+ }
328
+ case 'text-decoration-thickness': {
329
+ const match = value.match(/^(\d+(?:\.\d+)?)px$/);
330
+ if (match) {
331
+ decorationStyleSetStrikethroughThickness = parseFloat(match[1]);
332
+ }
333
+ break;
334
+ }
335
+ case 'text-decoration-color': {
336
+ let colorValue = value;
337
+ const varMatch = value.match(/^var\((--[^,]+),\s*(?:initial|inherit)\)$/);
338
+ if (varMatch) {
339
+ colorValue = ViewGpuContext.decorationCssRuleExtractor.resolveCssVariable(this._viewGpuContext.canvas.domNode, varMatch[1]);
340
+ }
341
+ const parsedColor = Color.Format.CSS.parse(colorValue);
342
+ if (parsedColor) {
343
+ decorationStyleSetStrikethroughColor = parsedColor.toNumber32Bit();
344
+ }
345
+ break;
346
+ }
347
+ case 'text-decoration-style': {
348
+ // These are validated in canRender and use default behavior
349
+ break;
350
+ }
315
351
  default: throw new BugIndicatingError('Unexpected inline decoration style');
316
352
  }
317
353
  }
@@ -335,7 +371,7 @@ export class FullFileRenderStrategy extends BaseRenderStrategy {
335
371
  }
336
372
  continue;
337
373
  }
338
- const decorationStyleSetId = ViewGpuContext.decorationStyleCache.getOrCreateEntry(decorationStyleSetColor, decorationStyleSetBold, decorationStyleSetOpacity);
374
+ const decorationStyleSetId = ViewGpuContext.decorationStyleCache.getOrCreateEntry(decorationStyleSetColor, decorationStyleSetBold, decorationStyleSetOpacity, decorationStyleSetStrikethrough, decorationStyleSetStrikethroughThickness, decorationStyleSetStrikethroughColor);
339
375
  glyph = this._viewGpuContext.atlas.getGlyph(this.glyphRasterizer, chars, tokenMetadata, decorationStyleSetId, absoluteOffsetX);
340
376
  absoluteOffsetY = Math.round(
341
377
  // Top of layout box (includes line height)