// Copyright 2019 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
/**
* @fileoverview Provides color matching services for ChromeVox.
*/
import {TestImportManager} from '/common/testing/test_import_manager.js';
import {Msgs} from '../common/msgs.js';
export class Color {
/**
* Returns a string representation of a color.
* @param {number|undefined} color The argb value represented as an integer.
* @return {string}
*/
static getColorDescription(color) {
if (!color) {
return '';
}
// Convert to unsigned integer.
color = color >>> 0;
// The following 24 bits represent the rgb value. Filter out first 8 bits.
const rgb = color & 0x00ffffff;
const optSubs = [
Color.findClosestMatchingColor(rgb),
Color.getOpacityPercentage(color),
];
return Msgs.getMsg('color_description', optSubs);
}
/**
* Extracts the opacity of the color, which is encoded within the first 8
* bits.
* @param {number} color An integer representation of a color.
* @return {number}
*/
static getOpacityPercentage(color) {
return Math.round(((color >>> 24) / 256) * 100);
}
/**
* Finds the most similar stored color given an rgb value.
* @param {number} target The rgb value as an integer.
* @return {string}
*/
static findClosestMatchingColor(target) {
const bestMatch = ColorObjectArray.reduce((closest, color) => {
const distance = Color.findDistance(target, color.value);
if (distance < closest.distance) {
return {color, distance};
}
return closest;
}, {distance: Number.MAX_VALUE});
// Do not report color if most similar color is too inaccurate.
if (bestMatch.distance > DISTANCE_THRESHOLD) {
return '';
}
return Msgs.getMsg(bestMatch.color.colorMessageId);
}
/**
* Calculates the distance between two 3-D points, encoded as numbers,
* that represent colors.
* The first 8 bits are unused as they have either been shifted off or are
* simply filled by zeros. The x component is designated by the second
* 8 bits. The y component is designated by the third 8 bits.
* The z component is designated by the last 8 bits.
* @param {number} firstColor
* @param {number} secondColor
* @return {number}
*/
static findDistance(firstColor, secondColor) {
// Extract x, y, and z components.
const firstColorX = (firstColor & 0xff0000) >> 16;
const firstColorY = (firstColor & 0x00ff00) >> 8;
const firstColorZ = (firstColor & 0x0000ff);
const secondColorX = (secondColor & 0xff0000) >> 16;
const secondColorY = (secondColor & 0x00ff00) >> 8;
const secondColorZ = (secondColor & 0x0000ff);
return Math.pow(secondColorX - firstColorX, 2) +
Math.pow(secondColorY - firstColorY, 2) +
Math.pow(secondColorZ - firstColorZ, 2);
}
}
// Module-local variables.
/**
* The distance between black and dark grey is the threshold.
* 0x000000 = Black.
* 0x282828 = Dark Grey. This value was chosen somewhat arbitrarily. It encodes
* a shade of grey that could be visibly identified as black.
* @const {number}
*/
const DISTANCE_THRESHOLD = Color.findDistance(0X000000, 0X282828);
/**
* Holds objects that contain hexadecimal RGB values of colors and their
* corresponding ChromeVox message IDs.
* @private {!Array<{colorMessageId: string, value: number}>}
* Obtained from url: https://www.w3schools.com/lib/w3color.js
*/
const ColorObjectArray = [
{'value': 0x0, 'colorMessageId': 'color_black'},
{'value': 0x6400, 'colorMessageId': 'color_dark_green'},
{'value': 0x8000, 'colorMessageId': 'color_green'},
{'value': 0x800080, 'colorMessageId': 'color_purple'},
{'value': 0xb8860b, 'colorMessageId': 'color_dark_golden_rod'},
{'value': 0xfffacd, 'colorMessageId': 'color_lemon_chiffon'},
{'value': 0xa0522d, 'colorMessageId': 'color_sienna'},
{'value': 0xffa500, 'colorMessageId': 'color_orange'},
{'value': 0x8b4513, 'colorMessageId': 'color_saddle_brown'},
{'value': 0xffff, 'colorMessageId': 'color_cyan'},
{'value': 0xadff2f, 'colorMessageId': 'color_green_yellow'},
{'value': 0xd2691e, 'colorMessageId': 'color_chocolate'},
{'value': 0x800000, 'colorMessageId': 'color_maroon'},
{'value': 0xdaa520, 'colorMessageId': 'color_golden_rod'},
{'value': 0x228b22, 'colorMessageId': 'color_forest_green'},
{'value': 0x6b8e23, 'colorMessageId': 'color_olive_drab'},
{'value': 0xfffff0, 'colorMessageId': 'color_ivory'},
{'value': 0xf5f5dc, 'colorMessageId': 'color_beige'},
{'value': 0xa52a2a, 'colorMessageId': 'color_brown'},
{'value': 0x9acd32, 'colorMessageId': 'color_yellow_green'},
{'value': 0xff4500, 'colorMessageId': 'color_orange_red'},
{'value': 0x556b2f, 'colorMessageId': 'color_dark_olive_green'},
{'value': 0x32cd32, 'colorMessageId': 'color_lime_green'},
{'value': 0xff00, 'colorMessageId': 'color_lime'},
{'value': 0xeee8aa, 'colorMessageId': 'color_pale_golden_rod'},
{'value': 0xff69b4, 'colorMessageId': 'color_hot_pink'},
{'value': 0xdc143c, 'colorMessageId': 'color_crimson'},
{'value': 0xb0e0e6, 'colorMessageId': 'color_powder_blue'},
{'value': 0x808000, 'colorMessageId': 'color_olive'},
{'value': 0xffffe0, 'colorMessageId': 'color_light_yellow'},
{'value': 0xfaf0e6, 'colorMessageId': 'color_linen'},
{'value': 0x8b, 'colorMessageId': 'color_dark_blue'},
{'value': 0xf8f8ff, 'colorMessageId': 'color_ghost_white'},
{'value': 0xff6347, 'colorMessageId': 'color_tomato'},
{'value': 0xf0e68c, 'colorMessageId': 'color_khaki'},
{'value': 0x2f4f4f, 'colorMessageId': 'color_dark_slate_grey'},
{'value': 0xff7f50, 'colorMessageId': 'color_coral'},
{'value': 0xf5fffa, 'colorMessageId': 'color_mint_cream'},
{'value': 0x8080, 'colorMessageId': 'color_teal'},
{'value': 0x8b008b, 'colorMessageId': 'color_dark_magenta'},
{'value': 0xffa07a, 'colorMessageId': 'color_light_salmon'},
{'value': 0x2e8b57, 'colorMessageId': 'color_sea_green'},
{'value': 0xff0000, 'colorMessageId': 'color_red'},
{'value': 0xbc8f8f, 'colorMessageId': 'color_rosy_brown'},
{'value': 0xcd5c5c, 'colorMessageId': 'color_indian_red'},
{'value': 0xd3d3d3, 'colorMessageId': 'color_light_grey'},
{'value': 0xf4a460, 'colorMessageId': 'color_sandy_brown'},
{'value': 0x90ee90, 'colorMessageId': 'color_light_green'},
{'value': 0xadd8e6, 'colorMessageId': 'color_light_blue'},
{'value': 0xff8c00, 'colorMessageId': 'color_dark_orange'},
{'value': 0x696969, 'colorMessageId': 'color_dim_grey'},
{'value': 0xffebcd, 'colorMessageId': 'color_blanched_almond'},
{'value': 0xbdb76b, 'colorMessageId': 'color_dark_khaki'},
{'value': 0xff00ff, 'colorMessageId': 'color_magenta'},
{'value': 0x191970, 'colorMessageId': 'color_midnight_blue'},
{'value': 0x3cb371, 'colorMessageId': 'color_medium_sea_green'},
{'value': 0xfa8072, 'colorMessageId': 'color_salmon'},
{'value': 0xff1493, 'colorMessageId': 'color_deep_pink'},
{'value': 0xe9967a, 'colorMessageId': 'color_dark_salmon'},
{'value': 0xcd853f, 'colorMessageId': 'color_peru'},
{'value': 0xff7f, 'colorMessageId': 'color_spring_green'},
{'value': 0x80, 'colorMessageId': 'color_navy'},
{'value': 0xf08080, 'colorMessageId': 'color_light_coral'},
{'value': 0x4b0082, 'colorMessageId': 'color_indigo'},
{'value': 0xffffff, 'colorMessageId': 'color_white'},
{'value': 0xc71585, 'colorMessageId': 'color_medium_violet_red'},
{'value': 0xdeb887, 'colorMessageId': 'color_burly_wood'},
{'value': 0xe6e6fa, 'colorMessageId': 'color_lavender'},
{'value': 0x483d8b, 'colorMessageId': 'color_dark_slate_blue'},
{'value': 0xd2b48c, 'colorMessageId': 'color_tan'},
{'value': 0x8fbc8f, 'colorMessageId': 'color_dark_sea_green'},
{'value': 0x708090, 'colorMessageId': 'color_slate_grey'},
{'value': 0xdb7093, 'colorMessageId': 'color_pale_violet_red'},
{'value': 0xfff8dc, 'colorMessageId': 'color_cornsilk'},
{'value': 0xafeeee, 'colorMessageId': 'color_pale_turquoise'},
{'value': 0x778899, 'colorMessageId': 'color_light_slate_grey'},
{'value': 0x98fb98, 'colorMessageId': 'color_pale_green'},
{'value': 0x663399, 'colorMessageId': 'color_rebecca_purple'},
{'value': 0xfa9a, 'colorMessageId': 'color_medium_spring_green'},
{'value': 0xffc0cb, 'colorMessageId': 'color_pink'},
{'value': 0x5f9ea0, 'colorMessageId': 'color_cadet_blue'},
{'value': 0x808080, 'colorMessageId': 'color_grey'},
{'value': 0xee82ee, 'colorMessageId': 'color_violet'},
{'value': 0xa9a9a9, 'colorMessageId': 'color_dark_grey'},
{'value': 0x20b2aa, 'colorMessageId': 'color_light_sea_green'},
{'value': 0x8b8b, 'colorMessageId': 'color_dark_cyan'},
{'value': 0xffdead, 'colorMessageId': 'color_navajo_white'},
{'value': 0xf0f8ff, 'colorMessageId': 'color_alice_blue'},
{'value': 0xfffaf0, 'colorMessageId': 'color_floral_white'},
{'value': 0xffe4e1, 'colorMessageId': 'color_misty_rose'},
{'value': 0xf5deb3, 'colorMessageId': 'color_wheat'},
{'value': 0x4682b4, 'colorMessageId': 'color_steel_blue'},
{'value': 0xffe4b5, 'colorMessageId': 'color_moccasin'},
{'value': 0xffdab9, 'colorMessageId': 'color_peach_puff'},
{'value': 0xffd700, 'colorMessageId': 'color_gold'},
{'value': 0xfff0f5, 'colorMessageId': 'color_lavender_blush'},
{'value': 0xc0c0c0, 'colorMessageId': 'color_silver'},
{'value': 0xffb6c1, 'colorMessageId': 'color_light_pink'},
{'value': 0xf0ffff, 'colorMessageId': 'color_azure'},
{'value': 0xffe4c4, 'colorMessageId': 'color_bisque'},
{'value': 0x9932cc, 'colorMessageId': 'color_dark_orchid'},
{'value': 0xfdf5e6, 'colorMessageId': 'color_old_lace'},
{'value': 0x48d1cc, 'colorMessageId': 'color_medium_turquoise'},
{'value': 0x6a5acd, 'colorMessageId': 'color_slate_blue'},
{'value': 0xcd, 'colorMessageId': 'color_medium_blue'},
{'value': 0x40e0d0, 'colorMessageId': 'color_turquoise'},
{'value': 0xced1, 'colorMessageId': 'color_dark_turquoise'},
{'value': 0xfafad2, 'colorMessageId': 'color_light_golden_rod_yellow'},
{'value': 0x9400d3, 'colorMessageId': 'color_dark_violet'},
{'value': 0x7fffd4, 'colorMessageId': 'color_aquamarine'},
{'value': 0xffefd5, 'colorMessageId': 'color_papaya_whip'},
{'value': 0xda70d6, 'colorMessageId': 'color_orchid'},
{'value': 0xfaebd7, 'colorMessageId': 'color_antique_white'},
{'value': 0xd8bfd8, 'colorMessageId': 'color_thistle'},
{'value': 0x9370db, 'colorMessageId': 'color_medium_purple'},
{'value': 0xdcdcdc, 'colorMessageId': 'color_gainsboro'},
{'value': 0xdda0dd, 'colorMessageId': 'color_plum'},
{'value': 0xb0c4de, 'colorMessageId': 'color_light_steel_blue'},
{'value': 0x8b0000, 'colorMessageId': 'color_dark_red'},
{'value': 0xfff5ee, 'colorMessageId': 'color_sea_shell'},
{'value': 0x4169e1, 'colorMessageId': 'color_royal_blue'},
{'value': 0x8a2be2, 'colorMessageId': 'color_blue_violet'},
{'value': 0x7cfc00, 'colorMessageId': 'color_lawn_green'},
{'value': 0xe0ffff, 'colorMessageId': 'color_light_cyan'},
{'value': 0xb22222, 'colorMessageId': 'color_fire_brick'},
{'value': 0x87ceeb, 'colorMessageId': 'color_sky_blue'},
{'value': 0x6495ed, 'colorMessageId': 'color_cornflower_blue'},
{'value': 0x7b68ee, 'colorMessageId': 'color_medium_slate_blue'},
{'value': 0xff, 'colorMessageId': 'color_blue'},
{'value': 0xf0fff0, 'colorMessageId': 'color_honeydew'},
{'value': 0xba55d3, 'colorMessageId': 'color_medium_orchid'},
{'value': 0xf5f5f5, 'colorMessageId': 'color_white_smoke'},
{'value': 0xffff00, 'colorMessageId': 'color_yellow'},
{'value': 0x87cefa, 'colorMessageId': 'color_light_sky_blue'},
{'value': 0xbfff, 'colorMessageId': 'color_deep_sky_blue'},
{'value': 0xfffafa, 'colorMessageId': 'color_snow'},
{'value': 0x66cdaa, 'colorMessageId': 'color_medium_aqua_marine'},
{'value': 0x7fff00, 'colorMessageId': 'color_chartreuse'},
{'value': 0x1e90ff, 'colorMessageId': 'color_dodger_blue'},
];
TestImportManager.exportForTesting(Color);