terminal/src/host/conattrs.cpp
Dustin Howett d4d59fa339 Initial release of the Windows Terminal source code
This commit introduces all of the Windows Terminal and Console Host source,
under the MIT license.
2019-05-02 15:29:04 -07:00

226 lines
7.7 KiB
C++

/*++
Copyright (c) Microsoft Corporation
Licensed under the MIT license.
Module Name:
- conattrs.cpp
Abstract:
- Defines common operations on console attributes, especially in regards to
finding the nearest color from a color table.
Author(s):
- Mike Griese (migrie) 01-Sept-2017
--*/
#include "precomp.h"
#include "..\inc\conattrs.hpp"
#include <math.h>
struct _HSL
{
double h, s, l;
// constructs an HSL color from a RGB Color.
_HSL(const COLORREF rgb)
{
const double r = (double) GetRValue(rgb);
const double g = (double) GetGValue(rgb);
const double b = (double) GetBValue(rgb);
const auto[min, max] = std::minmax({ r, g, b });
const auto diff = max - min;
const auto sum = max + min;
// Luminence
l = max / 255.0;
// Saturation
s = (max == 0) ? 0 : diff / max;
//Hue
double q = (diff == 0)? 0 : 60.0/diff;
if (max == r)
{
h = (g < b)? ((360.0 + q * (g - b))/360.0) : ((q * (g - b))/360.0);
}
else if (max == g)
{
h = (120.0 + q * (b - r))/360.0;
}
else if (max == b)
{
h = (240.0 + q * (r - g))/360.0;
}
else
{
h = 0;
}
}
};
//Routine Description:
// Finds the "distance" between a given HSL color and an RGB color, using the HSL color space.
// This function is designed such that the caller would convert one RGB color to HSL ahead of time,
// then compare many RGB colors to that first color.
//Arguments:
// - phslColorA - a pointer to the first color, as a HSL color.
// - rgbColorB - The second color to compare, in RGB color.
// Return value:
// The "distance" between the two.
static double _FindDifference(const _HSL* const phslColorA, const COLORREF rgbColorB)
{
const _HSL hslColorB = _HSL(rgbColorB);
return sqrt( pow((hslColorB.h - phslColorA->h), 2) +
pow((hslColorB.s - phslColorA->s), 2) +
pow((hslColorB.l - phslColorA->l), 2) );
}
//Routine Description:
// For a given RGB color Color, finds the nearest color from the array ColorTable, and returns the index of that match.
//Arguments:
// - Color - The RGB color to fine the nearest color to.
// - ColorTable - The array of colors to find a nearest color from.
// - cColorTable - The number of elements in ColorTable
// Return value:
// The index in ColorTable of the nearest match to Color.
WORD FindNearestTableIndex(const COLORREF Color, _In_reads_(cColorTable) const COLORREF* const ColorTable, const WORD cColorTable)
{
// Quick check for an exact match in the color table:
for (WORD i = 0; i < cColorTable; i++)
{
if (Color == ColorTable[i])
{
return i;
}
}
// Did not find an exact match - do an expensive comparison to the elements
// of the table to find the nearest color.
const _HSL hslColor = _HSL(Color);
WORD closest = 0;
double minDiff = _FindDifference(&hslColor, ColorTable[0]);
for (WORD i = 1; i < cColorTable; i++)
{
double diff = _FindDifference(&hslColor, ColorTable[i]);
if (diff < minDiff)
{
minDiff = diff;
closest = i;
}
}
return closest;
}
// Function Description:
// - Converts the value of a xterm color table index to the windows color table equivalent.
// Arguments:
// - xtermTableEntry: the xterm color table index
// Return Value:
// - The windows color table equivalent.
WORD XtermToWindowsIndex(const size_t xtermTableEntry) noexcept
{
const bool fRed = WI_IsFlagSet(xtermTableEntry, XTERM_RED_ATTR);
const bool fGreen = WI_IsFlagSet(xtermTableEntry, XTERM_GREEN_ATTR);
const bool fBlue = WI_IsFlagSet(xtermTableEntry, XTERM_BLUE_ATTR);
const bool fBright = WI_IsFlagSet(xtermTableEntry, XTERM_BRIGHT_ATTR);
return (fRed ? WINDOWS_RED_ATTR : 0x0) +
(fGreen ? WINDOWS_GREEN_ATTR : 0x0) +
(fBlue ? WINDOWS_BLUE_ATTR : 0x0) +
(fBright ? WINDOWS_BRIGHT_ATTR : 0x0);
}
// Function Description:
// - Converts the value of a xterm color table index to the windows color table
// equivalent. The range of values is [0, 255], where the lowest 16 are
// mapped to the equivalent Windows index, and the rest of the values are
// passed through.
// Arguments:
// - xtermTableEntry: the xterm color table index
// Return Value:
// - The windows color table equivalent.
WORD Xterm256ToWindowsIndex(const size_t xtermTableEntry) noexcept
{
return xtermTableEntry < 16 ? XtermToWindowsIndex(xtermTableEntry) :
static_cast<WORD>(xtermTableEntry);
}
// Function Description:
// - Converts the value of a pair of xterm color table indicies to the legacy attr equivalent.
// Arguments:
// - xtermForeground: the xterm color table foreground index
// - xtermBackground: the xterm color table background index
// Return Value:
// - The legacy windows attribute equivalent.
WORD XtermToLegacy(const size_t xtermForeground, const size_t xtermBackground)
{
const WORD fgAttr = XtermToWindowsIndex(xtermForeground);
const WORD bgAttr = XtermToWindowsIndex(xtermBackground);
return (bgAttr << 4) | fgAttr;
}
//Routine Description:
// Returns the exact entry from the color table, if it's in there.
//Arguments:
// - Color - The RGB color to fine the nearest color to.
// - ColorTable - The array of colors to find a nearest color from.
// - cColorTable - The number of elements in ColorTable
// Return value:
// The index in ColorTable of the nearest match to Color.
bool FindTableIndex(const COLORREF Color,
_In_reads_(cColorTable) const COLORREF* const ColorTable,
const WORD cColorTable,
_Out_ WORD* const pFoundIndex)
{
*pFoundIndex = 0;
for (WORD i = 0; i < cColorTable; i++)
{
if (ColorTable[i] == Color)
{
*pFoundIndex = i;
return true;
}
}
return false;
}
// Method Description:
// - Get a COLORREF for the foreground component of the given legacy attributes.
// Arguments:
// - wLegacyAttrs - The legacy attributes to get the foreground color from.
// - ColorTable - The array of colors to to get the color from.
// - cColorTable - The number of elements in ColorTable
// Return Value:
// - the COLORREF for the foreground component
COLORREF ForegroundColor(const WORD wLegacyAttrs,
_In_reads_(cColorTable) const COLORREF* const ColorTable,
const size_t cColorTable)
{
const byte iColorTableIndex = LOBYTE(wLegacyAttrs) & FG_ATTRS;
return (iColorTableIndex < cColorTable && iColorTableIndex >= 0) ?
ColorTable[iColorTableIndex] :
INVALID_COLOR;
}
// Method Description:
// - Get a COLORREF for the background component of the given legacy attributes.
// Arguments:
// - wLegacyAttrs - The legacy attributes to get the background color from.
// - ColorTable - The array of colors to to get the color from.
// - cColorTable - The number of elements in ColorTable
// Return Value:
// - the COLORREF for the background component
COLORREF BackgroundColor(const WORD wLegacyAttrs,
_In_reads_(cColorTable) const COLORREF* const ColorTable,
const size_t cColorTable)
{
const byte iColorTableIndex = (LOBYTE(wLegacyAttrs) & BG_ATTRS) >> 4;
return (iColorTableIndex < cColorTable && iColorTableIndex >= 0) ?
ColorTable[iColorTableIndex] :
INVALID_COLOR;
}