提交 6e284e06 编写于 作者: A Alex Dima

Sturdier color parsing

上级 3e98e5f1
......@@ -3,6 +3,8 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { CharCode } from 'vs/base/common/charCode';
export class RGBA {
_rgbaBrand: void;
......@@ -95,21 +97,60 @@ export class HSLA {
/**
* Converts an Hex color value to RGB.
* returns r, g, and b are contained in the set [0, 255]
* @param hex string (#RRGGBB or #RRGGBBAA).
*/
function hex2rgba(hex: string): RGBA {
function parseHex(str: string) {
return parseInt('0x' + str);
}
if (hex.charAt(0) === '#' && hex.length >= 7) {
const r = parseHex(hex.substr(1, 2));
const g = parseHex(hex.substr(3, 2));
const b = parseHex(hex.substr(5, 2));
const a = hex.length === 9 ? parseHex(hex.substr(7, 2)) : 255;
if (!hex) {
// Invalid color
return new RGBA(255, 0, 0, 255);
}
if (hex.length === 7 && hex.charCodeAt(0) === CharCode.Hash) {
// #RRGGBB format
const r = 16 * _parseHexDigit(hex.charCodeAt(1)) + _parseHexDigit(hex.charCodeAt(2));
const g = 16 * _parseHexDigit(hex.charCodeAt(3)) + _parseHexDigit(hex.charCodeAt(4));
const b = 16 * _parseHexDigit(hex.charCodeAt(5)) + _parseHexDigit(hex.charCodeAt(6));
return new RGBA(r, g, b, 255);
}
if (hex.length === 9 && hex.charCodeAt(0) === CharCode.Hash) {
// #RRGGBBAA format
const r = 16 * _parseHexDigit(hex.charCodeAt(1)) + _parseHexDigit(hex.charCodeAt(2));
const g = 16 * _parseHexDigit(hex.charCodeAt(3)) + _parseHexDigit(hex.charCodeAt(4));
const b = 16 * _parseHexDigit(hex.charCodeAt(5)) + _parseHexDigit(hex.charCodeAt(6));
const a = 16 * _parseHexDigit(hex.charCodeAt(7)) + _parseHexDigit(hex.charCodeAt(8));
return new RGBA(r, g, b, a);
}
// Invalid color
return new RGBA(255, 0, 0, 255);
}
function _parseHexDigit(charCode: CharCode): number {
switch (charCode) {
case CharCode.Digit0: return 0;
case CharCode.Digit1: return 1;
case CharCode.Digit2: return 2;
case CharCode.Digit3: return 3;
case CharCode.Digit4: return 4;
case CharCode.Digit5: return 5;
case CharCode.Digit6: return 6;
case CharCode.Digit7: return 7;
case CharCode.Digit8: return 8;
case CharCode.Digit9: return 9;
case CharCode.a: return 10;
case CharCode.A: return 10;
case CharCode.b: return 11;
case CharCode.B: return 11;
case CharCode.c: return 12;
case CharCode.C: return 12;
case CharCode.d: return 13;
case CharCode.D: return 13;
case CharCode.e: return 14;
case CharCode.E: return 14;
case CharCode.f: return 15;
case CharCode.F: return 15;
}
return 0;
}
/**
* Converts an RGB color value to HSL. Conversion formula
* adapted from http://en.wikipedia.org/wiki/HSL_color_space.
......@@ -187,14 +228,17 @@ function _hue2rgb(p: number, q: number, t: number) {
return p;
}
export function hexToCSS(hex: string) {
/**
* @param hex string (#RRGGBB or #RRGGBBAA).
*/
export function hexToCSSrgba(hex: string) {
if (hex.length === 9) {
return toCSSColor(hex2rgba(hex));
return toCSSrgba(hex2rgba(hex));
}
return hex;
}
function toCSSColor(rgba: RGBA): string {
function toCSSrgba(rgba: RGBA): string {
return `rgba(${rgba.r}, ${rgba.g}, ${rgba.b}, ${+(rgba.a / 255).toFixed(2)})`;
}
......@@ -217,12 +261,14 @@ export class Color {
private readonly rgba: RGBA;
private hsla: HSLA;
private str: string;
private constructor(arg: string | RGBA) {
this.rgba = typeof arg === 'string' ? hex2rgba(arg) : <RGBA>arg;
if (arg instanceof RGBA) {
this.rgba = arg;
} else {
this.rgba = hex2rgba(arg);
}
this.hsla = null;
this.str = null;
}
/**
......@@ -309,10 +355,7 @@ export class Color {
}
public toString(): string {
if (this.str === null) {
this.str = toCSSColor(this.rgba);
}
return this.str;
return toCSSrgba(this.rgba);
}
public toHSLA(): HSLA {
......
......@@ -77,6 +77,36 @@ suite('Color', () => {
assert.deepEqual(new RGBA(128, 0, 128, 255), Color.fromHex('#800080').toRGBA());
assert.deepEqual(new RGBA(0, 128, 128, 255), Color.fromHex('#008080').toRGBA());
assert.deepEqual(new RGBA(0, 0, 128, 255), Color.fromHex('#000080').toRGBA());
function assertParseColor(input: string, expected: RGBA): void {
let actual = Color.fromHex(input).toRGBA();
assert.deepEqual(actual, expected, input);
}
// invalid
assertParseColor(null, new RGBA(255, 0, 0, 255));
assertParseColor('', new RGBA(255, 0, 0, 255));
assertParseColor('#', new RGBA(255, 0, 0, 255));
assertParseColor('#0102030', new RGBA(255, 0, 0, 255));
// somewhat valid
assertParseColor('#FFFFG0', new RGBA(255, 255, 0, 255));
assertParseColor('#FFFFg0', new RGBA(255, 255, 0, 255));
assertParseColor('#-FFF00', new RGBA(15, 255, 0, 255));
// valid
assertParseColor('#000000', new RGBA(0, 0, 0, 255));
assertParseColor('#010203', new RGBA(1, 2, 3, 255));
assertParseColor('#040506', new RGBA(4, 5, 6, 255));
assertParseColor('#070809', new RGBA(7, 8, 9, 255));
assertParseColor('#0a0A0a', new RGBA(10, 10, 10, 255));
assertParseColor('#0b0B0b', new RGBA(11, 11, 11, 255));
assertParseColor('#0c0C0c', new RGBA(12, 12, 12, 255));
assertParseColor('#0d0D0d', new RGBA(13, 13, 13, 255));
assertParseColor('#0e0E0e', new RGBA(14, 14, 14, 255));
assertParseColor('#0f0F0f', new RGBA(15, 15, 15, 255));
assertParseColor('#a0A0a0', new RGBA(160, 160, 160, 255));
assertParseColor('#FFFFFF', new RGBA(255, 255, 255, 255));
});
test('isLighterColor', function () {
......
......@@ -21,7 +21,7 @@ import { grammarsExtPoint, IEmbeddedLanguagesMap, ITMSyntaxExtensionPoint } from
import { TokenizationResult, TokenizationResult2 } from 'vs/editor/common/core/token';
import { TokenMetadata } from 'vs/editor/common/model/tokensBinaryEncoding';
import { nullTokenize2 } from 'vs/editor/common/modes/nullMode';
import { hexToCSS } from 'vs/base/common/color';
import { hexToCSSrgba } from 'vs/base/common/color';
export class TMScopeRegistry {
......@@ -154,7 +154,7 @@ export class MainProcessTextMateSyntax implements ITextMateService {
let rules: string[] = [];
for (let i = 1, len = colorMap.length; i < len; i++) {
let color = colorMap[i];
rules[i] = `.mtk${i} { color: ${hexToCSS(color)}; }`;
rules[i] = `.mtk${i} { color: ${hexToCSSrgba(color)}; }`;
}
rules.push('.mtki { font-style: italic; }');
rules.push('.mtkb { font-weight: bold; }');
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册