Serenity Operating System
at hosted 285 lines 7.3 kB view raw
1/* 2 * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org> 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are met: 7 * 8 * 1. Redistributions of source code must retain the above copyright notice, this 9 * list of conditions and the following disclaimer. 10 * 11 * 2. Redistributions in binary form must reproduce the above copyright notice, 12 * this list of conditions and the following disclaimer in the documentation 13 * and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 16 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 21 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 22 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 23 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 24 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 */ 26 27#pragma once 28 29#include <AK/Forward.h> 30#include <AK/StdLibExtras.h> 31#include <LibIPC/Forward.h> 32 33namespace Gfx { 34 35enum class ColorRole; 36typedef u32 RGBA32; 37 38inline constexpr u32 make_rgb(u8 r, u8 g, u8 b) 39{ 40 return ((r << 16) | (g << 8) | b); 41} 42 43struct HSV { 44 double hue { 0 }; 45 double saturation { 0 }; 46 double value { 0 }; 47}; 48 49class Color { 50public: 51 enum NamedColor { 52 Black, 53 White, 54 Red, 55 Green, 56 Cyan, 57 Blue, 58 Yellow, 59 Magenta, 60 DarkGray, 61 MidGray, 62 LightGray, 63 WarmGray, 64 DarkCyan, 65 DarkGreen, 66 DarkBlue, 67 DarkRed, 68 MidCyan, 69 MidGreen, 70 MidRed, 71 MidBlue, 72 MidMagenta, 73 }; 74 75 Color() {} 76 Color(NamedColor); 77 Color(u8 r, u8 g, u8 b) 78 : m_value(0xff000000 | (r << 16) | (g << 8) | b) 79 { 80 } 81 Color(u8 r, u8 g, u8 b, u8 a) 82 : m_value((a << 24) | (r << 16) | (g << 8) | b) 83 { 84 } 85 86 static Color from_rgb(unsigned rgb) { return Color(rgb | 0xff000000); } 87 static Color from_rgba(unsigned rgba) { return Color(rgba); } 88 89 u8 red() const { return (m_value >> 16) & 0xff; } 90 u8 green() const { return (m_value >> 8) & 0xff; } 91 u8 blue() const { return m_value & 0xff; } 92 u8 alpha() const { return (m_value >> 24) & 0xff; } 93 94 void set_alpha(u8 value) 95 { 96 m_value &= 0x00ffffff; 97 m_value |= value << 24; 98 } 99 100 void set_red(u8 value) 101 { 102 m_value &= 0xff00ffff; 103 m_value |= value << 16; 104 } 105 106 void set_green(u8 value) 107 { 108 m_value &= 0xffff00ff; 109 m_value |= value << 8; 110 } 111 112 void set_blue(u8 value) 113 { 114 m_value &= 0xffffff00; 115 m_value |= value; 116 } 117 118 Color with_alpha(u8 alpha) 119 { 120 return Color((m_value & 0x00ffffff) | alpha << 24); 121 } 122 123 Color blend(Color source) const 124 { 125 if (!alpha() || source.alpha() == 255) 126 return source; 127 128 if (!source.alpha()) 129 return *this; 130 131 int d = 255 * (alpha() + source.alpha()) - alpha() * source.alpha(); 132 u8 r = (red() * alpha() * (255 - source.alpha()) + 255 * source.alpha() * source.red()) / d; 133 u8 g = (green() * alpha() * (255 - source.alpha()) + 255 * source.alpha() * source.green()) / d; 134 u8 b = (blue() * alpha() * (255 - source.alpha()) + 255 * source.alpha() * source.blue()) / d; 135 u8 a = d / 255; 136 return Color(r, g, b, a); 137 } 138 139 Color to_grayscale() const 140 { 141 int gray = (red() + green() + blue()) / 3; 142 return Color(gray, gray, gray, alpha()); 143 } 144 145 Color darkened(float amount = 0.5f) const 146 { 147 return Color(red() * amount, green() * amount, blue() * amount, alpha()); 148 } 149 150 Color lightened(float amount = 1.2f) const 151 { 152 return Color(min(255, (int)((float)red() * amount)), min(255, (int)((float)green() * amount)), min(255, (int)((float)blue() * amount)), alpha()); 153 } 154 155 Color inverted() const 156 { 157 return Color(~red(), ~green(), ~blue()); 158 } 159 160 RGBA32 value() const { return m_value; } 161 162 bool operator==(const Color& other) const 163 { 164 return m_value == other.m_value; 165 } 166 167 bool operator!=(const Color& other) const 168 { 169 return m_value != other.m_value; 170 } 171 172 String to_string() const; 173 static Optional<Color> from_string(const StringView&); 174 175 HSV to_hsv() const 176 { 177 HSV hsv; 178 double r = static_cast<double>(red()) / 255.0; 179 double g = static_cast<double>(green()) / 255.0; 180 double b = static_cast<double>(blue()) / 255.0; 181 double max = AK::max(AK::max(r, g), b); 182 double min = AK::min(AK::min(r, g), b); 183 double chroma = max - min; 184 185 if (!chroma) 186 hsv.hue = 0.0; 187 else if (max == r) 188 hsv.hue = (60.0 * ((g - b) / chroma)) + 360.0; 189 else if (max == g) 190 hsv.hue = (60.0 * ((b - r) / chroma)) + 120.0; 191 else 192 hsv.hue = (60.0 * ((r - g) / chroma)) + 240.0; 193 194 if (hsv.hue >= 360.0) 195 hsv.hue -= 360.0; 196 197 hsv.hue /= 360.0; 198 199 if (!max) 200 hsv.saturation = 0; 201 else 202 hsv.saturation = chroma / max; 203 204 hsv.value = max; 205 return hsv; 206 } 207 208 static Color from_hsv(double hue, double saturation, double value) 209 { 210 return from_hsv({ hue, saturation, value }); 211 } 212 213 static Color from_hsv(const HSV& hsv) 214 { 215 double hue = hsv.hue * 2.0; 216 double saturation = hsv.saturation / 255.0; 217 double value = hsv.value / 255.0; 218 219 int high = static_cast<int>(hue / 60.0) % 6; 220 double f = (hue / 60.0) - high; 221 double c1 = value * (1.0 - saturation); 222 double c2 = value * (1.0 - saturation * f); 223 double c3 = value * (1.0 - saturation * (1.0 - f)); 224 225 double r = 0; 226 double g = 0; 227 double b = 0; 228 229 switch (high) { 230 case 0: 231 r = value; 232 g = c3; 233 b = c1; 234 break; 235 case 1: 236 r = c2; 237 g = value; 238 b = c1; 239 break; 240 case 2: 241 r = c1; 242 g = value; 243 b = c3; 244 break; 245 case 3: 246 r = c1; 247 g = c2; 248 b = value; 249 break; 250 case 4: 251 r = c3; 252 g = c1; 253 b = value; 254 break; 255 case 5: 256 r = value; 257 g = c1; 258 b = c2; 259 break; 260 } 261 262 u8 out_r = (u8)(r * 255); 263 u8 out_g = (u8)(g * 255); 264 u8 out_b = (u8)(b * 255); 265 return Color(out_r, out_g, out_b); 266 } 267 268private: 269 explicit Color(RGBA32 rgba) 270 : m_value(rgba) 271 { 272 } 273 274 RGBA32 m_value { 0 }; 275}; 276 277const LogStream& operator<<(const LogStream&, Color); 278 279} 280 281using Gfx::Color; 282 283namespace IPC { 284bool decode(Decoder&, Gfx::Color&); 285}