Serenity Operating System
at portability 284 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 32namespace Gfx { 33 34enum class ColorRole; 35typedef u32 RGBA32; 36 37inline constexpr u32 make_rgb(u8 r, u8 g, u8 b) 38{ 39 return ((r << 16) | (g << 8) | b); 40} 41 42struct HSV { 43 double hue { 0 }; 44 double saturation { 0 }; 45 double value { 0 }; 46}; 47 48class Color { 49public: 50 enum NamedColor { 51 Black, 52 White, 53 Red, 54 Green, 55 Cyan, 56 Blue, 57 Yellow, 58 Magenta, 59 DarkGray, 60 MidGray, 61 LightGray, 62 WarmGray, 63 DarkCyan, 64 DarkGreen, 65 DarkBlue, 66 DarkRed, 67 MidCyan, 68 MidGreen, 69 MidRed, 70 MidBlue, 71 MidMagenta, 72 }; 73 74 Color() {} 75 Color(NamedColor); 76 Color(u8 r, u8 g, u8 b) 77 : m_value(0xff000000 | (r << 16) | (g << 8) | b) 78 { 79 } 80 Color(u8 r, u8 g, u8 b, u8 a) 81 : m_value((a << 24) | (r << 16) | (g << 8) | b) 82 { 83 } 84 85 static Color from_rgb(unsigned rgb) { return Color(rgb | 0xff000000); } 86 static Color from_rgba(unsigned rgba) { return Color(rgba); } 87 88 u8 red() const { return (m_value >> 16) & 0xff; } 89 u8 green() const { return (m_value >> 8) & 0xff; } 90 u8 blue() const { return m_value & 0xff; } 91 u8 alpha() const { return (m_value >> 24) & 0xff; } 92 93 void set_alpha(u8 value) 94 { 95 m_value &= 0x00ffffff; 96 m_value |= value << 24; 97 } 98 99 void set_red(u8 value) 100 { 101 m_value &= 0xff00ffff; 102 m_value |= value << 16; 103 } 104 105 void set_green(u8 value) 106 { 107 m_value &= 0xffff00ff; 108 m_value |= value << 8; 109 } 110 111 void set_blue(u8 value) 112 { 113 m_value &= 0xffffff00; 114 m_value |= value; 115 } 116 117 Color with_alpha(u8 alpha) 118 { 119 return Color((m_value & 0x00ffffff) | alpha << 24); 120 } 121 122 Color blend(Color source) const 123 { 124 if (!alpha() || source.alpha() == 255) 125 return source; 126 127 if (!source.alpha()) 128 return *this; 129 130 int d = 255 * (alpha() + source.alpha()) - alpha() * source.alpha(); 131 u8 r = (red() * alpha() * (255 - source.alpha()) + 255 * source.alpha() * source.red()) / d; 132 u8 g = (green() * alpha() * (255 - source.alpha()) + 255 * source.alpha() * source.green()) / d; 133 u8 b = (blue() * alpha() * (255 - source.alpha()) + 255 * source.alpha() * source.blue()) / d; 134 u8 a = d / 255; 135 return Color(r, g, b, a); 136 } 137 138 Color to_grayscale() const 139 { 140 int gray = (red() + green() + blue()) / 3; 141 return Color(gray, gray, gray, alpha()); 142 } 143 144 Color darkened(float amount = 0.5f) const 145 { 146 return Color(red() * amount, green() * amount, blue() * amount, alpha()); 147 } 148 149 Color lightened(float amount = 1.2f) const 150 { 151 return Color(min(255, (int)((float)red() * amount)), min(255, (int)((float)green() * amount)), min(255, (int)((float)blue() * amount)), alpha()); 152 } 153 154 Color inverted() const 155 { 156 return Color(~red(), ~green(), ~blue()); 157 } 158 159 RGBA32 value() const { return m_value; } 160 161 bool operator==(const Color& other) const 162 { 163 return m_value == other.m_value; 164 } 165 166 bool operator!=(const Color& other) const 167 { 168 return m_value != other.m_value; 169 } 170 171 String to_string() const; 172 static Optional<Color> from_string(const StringView&); 173 174 HSV to_hsv() const 175 { 176 HSV hsv; 177 double r = static_cast<double>(red()) / 255.0; 178 double g = static_cast<double>(green()) / 255.0; 179 double b = static_cast<double>(blue()) / 255.0; 180 double max = AK::max(AK::max(r, g), b); 181 double min = AK::min(AK::min(r, g), b); 182 double chroma = max - min; 183 184 if (!chroma) 185 hsv.hue = 0.0; 186 else if (max == r) 187 hsv.hue = (60.0 * ((g - b) / chroma)) + 360.0; 188 else if (max == g) 189 hsv.hue = (60.0 * ((b - r) / chroma)) + 120.0; 190 else 191 hsv.hue = (60.0 * ((r - g) / chroma)) + 240.0; 192 193 if (hsv.hue >= 360.0) 194 hsv.hue -= 360.0; 195 196 hsv.hue /= 360.0; 197 198 if (!max) 199 hsv.saturation = 0; 200 else 201 hsv.saturation = chroma / max; 202 203 hsv.value = max; 204 return hsv; 205 } 206 207 static Color from_hsv(double hue, double saturation, double value) 208 { 209 return from_hsv({ hue, saturation, value }); 210 } 211 212 static Color from_hsv(const HSV& hsv) 213 { 214 double hue = hsv.hue * 2.0; 215 double saturation = hsv.saturation / 255.0; 216 double value = hsv.value / 255.0; 217 218 int high = static_cast<int>(hue / 60.0) % 6; 219 double f = (hue / 60.0) - high; 220 double c1 = value * (1.0 - saturation); 221 double c2 = value * (1.0 - saturation * f); 222 double c3 = value * (1.0 - saturation * (1.0 - f)); 223 224 double r = 0; 225 double g = 0; 226 double b = 0; 227 228 switch (high) { 229 case 0: 230 r = value; 231 g = c3; 232 b = c1; 233 break; 234 case 1: 235 r = c2; 236 g = value; 237 b = c1; 238 break; 239 case 2: 240 r = c1; 241 g = value; 242 b = c3; 243 break; 244 case 3: 245 r = c1; 246 g = c2; 247 b = value; 248 break; 249 case 4: 250 r = c3; 251 g = c1; 252 b = value; 253 break; 254 case 5: 255 r = value; 256 g = c1; 257 b = c2; 258 break; 259 } 260 261 u8 out_r = (u8)(r * 255); 262 u8 out_g = (u8)(g * 255); 263 u8 out_b = (u8)(b * 255); 264 return Color(out_r, out_g, out_b); 265 } 266 267private: 268 explicit Color(RGBA32 rgba) 269 : m_value(rgba) 270 { 271 } 272 273 RGBA32 m_value { 0 }; 274}; 275 276const LogStream& operator<<(const LogStream&, Color); 277 278} 279 280using Gfx::Color; 281 282namespace IPC { 283bool decode(BufferStream&, Gfx::Color&); 284}