From 94a9ce8566e7b3d3a520038d9a0b6e7993c7f9f9 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Thu, 28 Dec 2023 09:29:30 -0800 Subject: [PATCH] Move toColor into channels It operates on rgba channels, not a packed 32 bit int --- src/browser/Terminal.ts | 10 ++++---- .../renderer/dom/DomRendererRowFactory.ts | 6 ++--- src/browser/renderer/shared/TextureAtlas.ts | 8 +++---- src/common/Color.test.ts | 19 +++++++++++++++ src/common/Color.ts | 23 +++++++++---------- src/common/Types.d.ts | 4 ++-- 6 files changed, 44 insertions(+), 26 deletions(-) diff --git a/src/browser/Terminal.ts b/src/browser/Terminal.ts index de8278c66d..0e945aa92b 100644 --- a/src/browser/Terminal.ts +++ b/src/browser/Terminal.ts @@ -41,7 +41,7 @@ import { RenderService } from 'browser/services/RenderService'; import { SelectionService } from 'browser/services/SelectionService'; import { ICharSizeService, ICharacterJoinerService, ICoreBrowserService, ILinkProviderService, IMouseService, IRenderService, ISelectionService, IThemeService } from 'browser/services/Services'; import { ThemeService } from 'browser/services/ThemeService'; -import { color, rgba } from 'common/Color'; +import { channels, color } from 'common/Color'; import { CoreTerminal } from 'common/CoreTerminal'; import { EventEmitter, IEvent, forwardEvent } from 'common/EventEmitter'; import { MutableDisposable, toDisposable } from 'common/Lifecycle'; @@ -211,17 +211,17 @@ export class Terminal extends CoreTerminal implements ITerminal { } switch (req.type) { case ColorRequestType.REPORT: - const channels = color.toColorRGB(acc === 'ansi' + const colorRgb = color.toColorRGB(acc === 'ansi' ? this._themeService.colors.ansi[req.index] : this._themeService.colors[acc]); - this.coreService.triggerDataEvent(`${C0.ESC}]${ident};${toRgbString(channels)}${C1_ESCAPED.ST}`); + this.coreService.triggerDataEvent(`${C0.ESC}]${ident};${toRgbString(colorRgb)}${C1_ESCAPED.ST}`); break; case ColorRequestType.SET: if (acc === 'ansi') { - this._themeService.modifyColors(colors => colors.ansi[req.index] = rgba.toColor(...req.color)); + this._themeService.modifyColors(colors => colors.ansi[req.index] = channels.toColor(...req.color)); } else { const narrowedAcc = acc; - this._themeService.modifyColors(colors => colors[narrowedAcc] = rgba.toColor(...req.color)); + this._themeService.modifyColors(colors => colors[narrowedAcc] = channels.toColor(...req.color)); } break; case ColorRequestType.RESTORE: diff --git a/src/browser/renderer/dom/DomRendererRowFactory.ts b/src/browser/renderer/dom/DomRendererRowFactory.ts index 50d3eb49e3..d71edeb96f 100644 --- a/src/browser/renderer/dom/DomRendererRowFactory.ts +++ b/src/browser/renderer/dom/DomRendererRowFactory.ts @@ -8,7 +8,7 @@ import { INVERTED_DEFAULT_COLOR } from 'browser/renderer/shared/Constants'; import { WHITESPACE_CELL_CHAR, Attributes } from 'common/buffer/Constants'; import { CellData } from 'common/buffer/CellData'; import { ICoreService, IDecorationService, IOptionsService } from 'common/services/Services'; -import { color, rgba } from 'common/Color'; +import { channels, color } from 'common/Color'; import { ICharacterJoinerService, ICoreBrowserService, IThemeService } from 'browser/services/Services'; import { JoinedCellData } from 'browser/services/CharacterJoinerService'; import { treatGlyphAsBackgroundColor } from 'browser/renderer/shared/RendererUtils'; @@ -376,7 +376,7 @@ export class DomRendererRowFactory { classes.push(`xterm-bg-${bg}`); break; case Attributes.CM_RGB: - resolvedBg = rgba.toColor(bg >> 16, bg >> 8 & 0xFF, bg & 0xFF); + resolvedBg = channels.toColor(bg >> 16, bg >> 8 & 0xFF, bg & 0xFF); this._addStyle(charElement, `background-color:#${padStart((bg >>> 0).toString(16), '0', 6)}`); break; case Attributes.CM_DEFAULT: @@ -408,7 +408,7 @@ export class DomRendererRowFactory { } break; case Attributes.CM_RGB: - const color = rgba.toColor( + const color = channels.toColor( (fg >> 16) & 0xFF, (fg >> 8) & 0xFF, (fg ) & 0xFF diff --git a/src/browser/renderer/shared/TextureAtlas.ts b/src/browser/renderer/shared/TextureAtlas.ts index 9cd09cbf99..3b3d88091d 100644 --- a/src/browser/renderer/shared/TextureAtlas.ts +++ b/src/browser/renderer/shared/TextureAtlas.ts @@ -8,7 +8,7 @@ import { DIM_OPACITY, TEXT_BASELINE } from 'browser/renderer/shared/Constants'; import { tryDrawCustomChar } from 'browser/renderer/shared/CustomGlyphs'; import { computeNextVariantOffset, treatGlyphAsBackgroundColor, isPowerlineGlyph, isRestrictedPowerlineGlyph, throwIfFalsy } from 'browser/renderer/shared/RendererUtils'; import { IBoundingBox, ICharAtlasConfig, IRasterizedGlyph, ITextureAtlas } from 'browser/renderer/shared/Types'; -import { NULL_COLOR, color, rgba } from 'common/Color'; +import { NULL_COLOR, channels, color, rgba } from 'common/Color'; import { EventEmitter } from 'common/EventEmitter'; import { FourKeyMap } from 'common/MultiKeyMap'; import { IdleTaskQueue } from 'common/TaskQueue'; @@ -292,7 +292,7 @@ export class TextureAtlas implements ITextureAtlas { case Attributes.CM_RGB: const arr = AttributeData.toColorRGB(bgColor); // TODO: This object creation is slow - result = rgba.toColor(arr[0], arr[1], arr[2]); + result = channels.toColor(arr[0], arr[1], arr[2]); break; case Attributes.CM_DEFAULT: default: @@ -324,7 +324,7 @@ export class TextureAtlas implements ITextureAtlas { break; case Attributes.CM_RGB: const arr = AttributeData.toColorRGB(fgColor); - result = rgba.toColor(arr[0], arr[1], arr[2]); + result = channels.toColor(arr[0], arr[1], arr[2]); break; case Attributes.CM_DEFAULT: default: @@ -406,7 +406,7 @@ export class TextureAtlas implements ITextureAtlas { return undefined; } - const color = rgba.toColor( + const color = channels.toColor( (result >> 24) & 0xFF, (result >> 16) & 0xFF, (result >> 8) & 0xFF diff --git a/src/common/Color.test.ts b/src/common/Color.test.ts index e250950dca..c0947ba3ee 100644 --- a/src/common/Color.test.ts +++ b/src/common/Color.test.ts @@ -29,6 +29,25 @@ describe('Color', () => { assert.equal(channels.toCss(0xf0, 0xf0, 0xf0), '#f0f0f0'); assert.equal(channels.toCss(0xff, 0xff, 0xff), '#ffffff'); }); + it('should convert an rgba array to css hex string', () => { + assert.equal(channels.toCss(0x00, 0x00, 0x00, 0x00), '0x00000000'); + assert.equal(channels.toCss(0x10, 0x10, 0x10, 0x10), '0x10101010'); + assert.equal(channels.toCss(0x20, 0x20, 0x20, 0x20), '0x20202020'); + assert.equal(channels.toCss(0x30, 0x30, 0x30, 0x30), '0x30303030'); + assert.equal(channels.toCss(0x40, 0x40, 0x40, 0x40), '0x40404040'); + assert.equal(channels.toCss(0x50, 0x50, 0x50, 0x50), '0x50505050'); + assert.equal(channels.toCss(0x60, 0x60, 0x60, 0x60), '0x60606060'); + assert.equal(channels.toCss(0x70, 0x70, 0x70, 0x70), '0x70707070'); + assert.equal(channels.toCss(0x80, 0x80, 0x80, 0x80), '0x80808080'); + assert.equal(channels.toCss(0x90, 0x90, 0x90, 0x90), '0x90909090'); + assert.equal(channels.toCss(0xa0, 0xa0, 0xa0, 0xa0), '0xa0a0a0a0'); + assert.equal(channels.toCss(0xb0, 0xb0, 0xb0, 0xb0), '0xb0b0b0b0'); + assert.equal(channels.toCss(0xc0, 0xc0, 0xc0, 0xc0), '0xc0c0c0c0'); + assert.equal(channels.toCss(0xd0, 0xd0, 0xd0, 0xd0), '0xd0d0d0d0'); + assert.equal(channels.toCss(0xe0, 0xe0, 0xe0, 0xe0), '0xe0e0e0e0'); + assert.equal(channels.toCss(0xf0, 0xf0, 0xf0, 0xf0), '0xf0f0f0f0'); + assert.equal(channels.toCss(0xff, 0xff, 0xff, 0xff), '0xffffffff'); + }); }); describe('toRgba', () => { diff --git a/src/common/Color.ts b/src/common/Color.ts index 2291b7bef8..5ec2d87db5 100644 --- a/src/common/Color.ts +++ b/src/common/Color.ts @@ -33,6 +33,13 @@ export namespace channels { // >>> 0 forces an unsigned int return (r << 24 | g << 16 | b << 8 | a) >>> 0; } + + export function toColor(r: number, g: number, b: number, a?: number): IColor { + return { + css: channels.toCss(r, g, b, a), + rgba: channels.toRgba(r, g, b, a) + }; + } } /** @@ -70,7 +77,7 @@ export namespace color { if (!result) { return undefined; } - return rgba.toColor( + return channels.toColor( (result >> 24 & 0xFF), (result >> 16 & 0xFF), (result >> 8 & 0xFF) @@ -142,14 +149,14 @@ export namespace css { $r = parseInt(css.slice(1, 2).repeat(2), 16); $g = parseInt(css.slice(2, 3).repeat(2), 16); $b = parseInt(css.slice(3, 4).repeat(2), 16); - return rgba.toColor($r, $g, $b); + return channels.toColor($r, $g, $b); } case 5: { // #rgba $r = parseInt(css.slice(1, 2).repeat(2), 16); $g = parseInt(css.slice(2, 3).repeat(2), 16); $b = parseInt(css.slice(3, 4).repeat(2), 16); $a = parseInt(css.slice(4, 5).repeat(2), 16); - return rgba.toColor($r, $g, $b, $a); + return channels.toColor($r, $g, $b, $a); } case 7: // #rrggbb return { @@ -171,7 +178,7 @@ export namespace css { $g = parseInt(rgbaMatch[2]); $b = parseInt(rgbaMatch[3]); $a = Math.round((rgbaMatch[5] === undefined ? 1 : parseFloat(rgbaMatch[5])) * 0xFF); - return rgba.toColor($r, $g, $b, $a); + return channels.toColor($r, $g, $b, $a); } // Validate the context is available for canvas-based color parsing @@ -342,17 +349,9 @@ export namespace rgba { return (fgR << 24 | fgG << 16 | fgB << 8 | 0xFF) >>> 0; } - // FIXME: Move this to channels NS? export function toChannels(value: number): [number, number, number, number] { return [(value >> 24) & 0xFF, (value >> 16) & 0xFF, (value >> 8) & 0xFF, value & 0xFF]; } - - export function toColor(r: number, g: number, b: number, a?: number): IColor { - return { - css: channels.toCss(r, g, b, a), - rgba: channels.toRgba(r, g, b, a) - }; - } } export function toPaddedHex(c: number): string { diff --git a/src/common/Types.d.ts b/src/common/Types.d.ts index 175c47c318..17c7231a22 100644 --- a/src/common/Types.d.ts +++ b/src/common/Types.d.ts @@ -110,8 +110,8 @@ export interface ICharset { export type CharData = [number, string, number, number]; export interface IColor { - css: string; - rgba: number; // 32-bit int with rgba in each byte + readonly css: string; + readonly rgba: number; // 32-bit int with rgba in each byte } export type IColorRGB = [number, number, number];