os: make 'Genode::Color' C++20 friendly

This patch turns 'Color' from a class to a POD type by replacing
the constructors by the named create functions 'rgb', 'clamped_rgb',
and 'clamped_rgba'. It thereby enables the initialization of Color
values using { .r = ... } syntax and makes the type usable in const
expressions.

It also narrows the type for color components and alpha values to
uint8_t. So possible integer overflows of computed values are detected
by -Wconversion.

As 'Color::rgb(0, 0, 0)' is repeatedly used as a default value, the
patch adds the 'Color::black()' function.

Fixes #5238
This commit is contained in:
Norman Feske 2024-06-04 15:18:22 +02:00
parent 791dd38160
commit bb06d879aa
43 changed files with 207 additions and 166 deletions

View File

@ -145,7 +145,7 @@ class Scout::Canvas : public Canvas_base
{
Texture<PT> const &texture = static_cast<Texture<PT> const &>(texture_base);
Texture_painter::paint(_surface, texture, Color(0, 0, 0), pos,
Texture_painter::paint(_surface, texture, Color::black(), pos,
Texture_painter::SOLID, true);
}

View File

@ -182,10 +182,10 @@ struct Sky_texture_painter
_multiply_buf(_bufs[2][0], TW*TH, 16*16*256);
/* create color table */
_create_coltab(_coltab, Color(255, 255, 255),
Color( 0, 0, 0),
Color(255, 255, 255),
Color( 80, 88, 112));
_create_coltab(_coltab, Color::rgb(255, 255, 255),
Color::rgb( 0, 0, 0),
Color::rgb(255, 255, 255),
Color::rgb( 80, 88, 112));
/* create fallback texture */
_compose(_fallback[0], TW, TH, 0, TW - 1,

View File

@ -110,7 +110,7 @@ class Launchpad_window : public Scout::Scrollbar_listener,
Parent_element::draw(canvas, abs_position);
/* border */
Color color(0, 0, 0);
Color const color = Color::black();
canvas.draw_box(0, 0, _size.w(), 1, color);
canvas.draw_box(0, _size.h() - 1, _size.w(), 1, color);
canvas.draw_box(0, 1, 1, _size.h() - 2, color);

View File

@ -65,11 +65,11 @@ static unsigned char *glow_icon_gfx[] = {
/* color definitions for glowing effect of the icons */
static Color glow_icon_col[] = {
Color(210, 210, 0),
Color( 0, 0, 160),
Color( 0, 0, 160),
Color( 0, 160, 0),
Color(160, 0, 0),
Color::rgb(210, 210, 0),
Color::rgb( 0, 0, 160),
Color::rgb( 0, 0, 160),
Color::rgb( 0, 160, 0),
Color::rgb(160, 0, 0),
};

View File

@ -145,7 +145,7 @@ class Scout::Browser_window : public Scrollbar_listener,
Parent_element::draw(canvas, abs_position);
if (_attr & ATTR_BORDER) {
Color color(0, 0, 0);
Color color = Color::black();
canvas.draw_box(0, 0, _size.w(), 1, color);
canvas.draw_box(0, _size.h() - 1, _size.w(), 1, color);
canvas.draw_box(0, 1, 1, _size.h() - 2, color);

View File

@ -226,8 +226,8 @@ Token::Token(Style *style, const char *str, size_t len)
_str(str),
_len(len),
_style(style),
_col(_style ? _style->color : Color(0, 0, 0)),
_outline(Color(0, 0, 0, 0))
_col(_style ? _style->color : Color::black()),
_outline(Color{})
{
_flags.takes_focus = 0;

View File

@ -169,13 +169,13 @@ class Scout::Link_token : public Token, private Link, public Event_handler,
{
_outline = Color(_style->color.r,
_style->color.g,
_style->color.b, _curr_value);
_style->color.b, Color::channel_t(_curr_value));
Token::draw(canvas, abs_position);
canvas.draw_box(_position.x() + abs_position.x(),
_position.y() + abs_position.y() + _size.h() - 1,
_size.w(), 1, Color(0,0,255));
_size.w(), 1, Color::rgb(0,0,255));
}
void mfocus(bool flag) override

View File

@ -204,7 +204,7 @@ int Navbar::on_tick()
prev_icon->alpha(_curr_value);
next_icon->alpha(_curr_value);
navbar_style.color = Color(0, 0, 0, _curr_value);
navbar_style.color = Color { 0, 0, 0, Color::channel_t(_curr_value) };
refresh();
return 1;

View File

@ -42,21 +42,21 @@ namespace Scout {
static Tff_font &title_font = subsection_font;
static Color default_color { 0, 0, 0 };
static Color text_color { 20, 20, 20 };
static Color verbatim_bgcol { 0, 0, 0, 26 };
static constexpr Color default_color = Color::rgb( 0, 0, 0 );
static constexpr Color text_color = Color::rgb( 20, 20, 20 );
static constexpr Color verbatim_bgcol { 0, 0, 0, 26 };
static Style plain_style { &default_font, text_color, 0 };
static Style bold_style { &default_font, text_color, Style::ATTR_BOLD };
static Style mono_style { &mono_font, text_color, 0 };
static Style italic_style { &italic_font, text_color, 0 };
static Style link_style { &default_font, Color(0, 0, 255), 0 };
static Style link_style { &default_font, Color::rgb(0, 0, 255), 0 };
static Style chapter_style { &chapter_font, default_color, 0 };
static Style section_style { &section_font, default_color, 0 };
static Style subsection_style { &subsection_font, default_color, 0 };
static Style navbar_style { &default_font, Color(0, 0, 0, 127), 0 };
static Style navbar_style { &default_font, Color { 0, 0, 0, 127 }, 0 };
}
#endif /* _STYLES_H_ */

View File

@ -224,7 +224,7 @@ class Framebuffer_window : public Scout::Window
Parent_element::draw(canvas, abs_position);
/* border */
Color color(0, 0, 0);
Color const color = Color::black();
canvas.draw_box(0, 0, _size.w(), 1, color);
if (_config_decoration)
canvas.draw_box(0, _TH, _size.w(), 1, color);

View File

@ -148,12 +148,12 @@ class Log_entry
*/
void draw(Canvas_base &canvas, Font const &font, int y, int new_section = false)
{
Color label_fgcol = Color(Genode::min(255, _color.r + 200),
Genode::min(255, _color.g + 200),
Genode::min(255, _color.b + 200));
Color label_bgcol = Color(_color.r, _color.g, _color.b);
Color text_fgcol = Color(180, 180, 180);
Color text_bgcol = Color(_color.r / 2, _color.g / 2, _color.b / 2);
Color label_fgcol = Color::clamped_rgb(_color.r + 200,
_color.g + 200,
_color.b + 200);
Color label_bgcol = _color;
Color text_fgcol = Color::rgb(180, 180, 180);
Color text_bgcol = Color::rgb(_color.r / 2, _color.g / 2, _color.b / 2);
/* calculate label dimensions */
int label_w = font.string_width(_label).decimal();
@ -162,11 +162,11 @@ class Log_entry
if (new_section) {
canvas.draw_box(Rect(Point(1, y), Area(label_w + 2, label_h - 1)), label_bgcol);
canvas.draw_string(Point(1, y - 1), font, label_fgcol, _label);
canvas.draw_box(Rect(Point(1, y + label_h - 1), Area(label_w + 2, 1)), Color(0, 0, 0));
canvas.draw_box(Rect(Point(1, y + label_h - 1), Area(label_w + 2, 1)), Color::black());
canvas.draw_box(Rect(Point(label_w + 2, y), Area(1, label_h - 1)), _color);
canvas.draw_box(Rect(Point(label_w + 3, y), Area(1, label_h - 1)), Color(0, 0, 0));
canvas.draw_box(Rect(Point(label_w + 3, y), Area(1, label_h - 1)), Color::black());
canvas.draw_box(Rect(Point(label_w + 4, y), Area(1000, label_h)), text_bgcol);
canvas.draw_box(Rect(Point(label_w + 4, y), Area(1000, 1)), Color(0, 0, 0));
canvas.draw_box(Rect(Point(label_w + 4, y), Area(1000, 1)), Color::black());
} else
canvas.draw_box(Rect(Point(1, y), Area(1000, label_h)), text_bgcol);
@ -282,7 +282,7 @@ class Nitlog::Session_component : public Rpc_object<Log_session>
int g = (_bit(id, 4) + 2*_bit(id, 1))*scale + offset;
int b = (_bit(id, 5) + 2*_bit(id, 2))*scale + offset;
return Color(r, g, b);
return Color::clamped_rgb(r, g, b);
}
Color const _color = _session_color(_id);

View File

@ -25,7 +25,7 @@ static inline Genode::Color color_from_hsv(unsigned h, unsigned s, unsigned v)
using uint8_t = Genode::uint8_t;
if (s == 0)
return Color(v, v, v);
return Color::clamped_rgb(v, v, v);
uint8_t const region = (uint8_t)(h / 43);
uint8_t const remainder = (uint8_t)((h - (region*43)) * 6);
@ -34,14 +34,14 @@ static inline Genode::Color color_from_hsv(unsigned h, unsigned s, unsigned v)
t = (uint8_t)((v*(255 - ((s*(255 - remainder)) >> 8))) >> 8);
switch (region) {
case 0: return Color(v, t, p);
case 1: return Color(q, v, p);
case 2: return Color(p, v, t);
case 3: return Color(p, q, v);
case 4: return Color(t, p, v);
case 0: return Color::clamped_rgb(v, t, p);
case 1: return Color::clamped_rgb(q, v, p);
case 2: return Color::clamped_rgb(p, v, t);
case 3: return Color::clamped_rgb(p, q, v);
case 4: return Color::clamped_rgb(t, p, v);
}
return Color(v, p, q);
return Color::clamped_rgb(v, p, q);
}
#endif /* _INCLUDE__GEMS__COLOR_HSV_H_ */

View File

@ -58,14 +58,14 @@ class Polygon::Shaded_painter : public Polygon::Painter_base
}
}
inline void edge_attr(int id, int value)
inline void edge_attr(int id, auto value)
{
switch (id) {
case ATTR_X: Point_base::edge_attr(id, value); return;
case ATTR_R: color.r = value; return;
case ATTR_G: color.g = value; return;
case ATTR_B: color.b = value; return;
case ATTR_A: color.a = value; return;
case ATTR_R: color.r = Color::channel_t(value); return;
case ATTR_G: color.g = Color::channel_t(value); return;
case ATTR_B: color.b = Color::channel_t(value); return;
case ATTR_A: color.a = Color::channel_t(value); return;
}
}
};
@ -123,8 +123,8 @@ class Polygon::Shaded_painter : public Polygon::Painter_base
for (int y = bbox.y1(); y < bbox.y2(); y++) {
/* read left and right color values from corresponding edge buffers */
Color l_color = Color(r_l_edge[y], g_l_edge[y], b_l_edge[y], a_l_edge[y]);
Color r_color = Color(r_r_edge[y], g_r_edge[y], b_r_edge[y], a_r_edge[y]);
Color l_color = Color::clamped_rgba(r_l_edge[y], g_l_edge[y], b_l_edge[y], a_l_edge[y]);
Color r_color = Color::clamped_rgba(r_r_edge[y], g_r_edge[y], b_r_edge[y], a_r_edge[y]);
int const x_l = x_l_edge[y];
int const x_r = x_r_edge[y];

View File

@ -303,7 +303,7 @@ void Backdrop::Main::_apply_fill(Xml_node operation)
/* create texture with down-sampled scaled image */
typedef Pixel_rgb888 PT;
Color const color = operation.attribute_value("color", Color(0, 0, 0));
Color const color = operation.attribute_value("color", Color::black());
_buffer->apply_to_surface<PT>([&] (Surface<PT> &surface) {
Box_painter::paint(surface, Surface_base::Rect(Surface_base::Point(0, 0),

View File

@ -164,7 +164,7 @@ class Decorator::Config
*/
Color base_color(Window_title const &title) const
{
Color result(68, 75, 95);
Color result = Color::rgb(68, 75, 95);
try {
Genode::Session_policy policy(title, _buffered_config->xml());

View File

@ -187,10 +187,11 @@ void Decorator::Window::draw(Decorator::Canvas_base &canvas,
canvas.draw_text(text_pos + Point(1, 1), default_font(),
Color(0, 0, 0, 128), text);
Color title_color = element(Element::TITLE).color();
Color const title_color = element(Element::TITLE).color();
auto const alpha = Genode::uint8_t((2*255 + title_color.r) / 3);
canvas.draw_text(text_pos, default_font(),
Color(255, 255, 255, (2*255 + title_color.r) / 3), text);
Color { 255, 255, 255, alpha }, text);
}
}

View File

@ -270,9 +270,12 @@ class Decorator::Window : public Window_base
static Color _mix_colors(Color c1, Color c2, int alpha)
{
return Color((c1.r*alpha + c2.r*(255 - alpha)) >> 8,
(c1.g*alpha + c2.g*(255 - alpha)) >> 8,
(c1.b*alpha + c2.b*(255 - alpha)) >> 8);
auto mix = [&] (auto const v1, auto const v2)
{
return Genode::uint8_t((v1*alpha + v2*(255 - alpha)) >> 8);
};
return Color::rgb(mix(c1.r, c2.r), mix(c1.g, c2.g), mix(c1.b, c2.b));
}
void _draw_title_box(Canvas_base &canvas, Rect rect, Attr attr) const
@ -289,8 +292,10 @@ class Decorator::Window : public Window_base
int const mid_y = rect.h() / 2;
Color const upper_color = attr.pressed ? Color(0, 0, 0) : Color(255, 255, 255);
Color const lower_color = attr.pressed ? Color(127, 127, 127) : Color(0, 0, 0);
Color const upper_color = attr.pressed ? Color::black()
: Color::rgb(255, 255, 255);
Color const lower_color = attr.pressed ? Color::rgb(127, 127, 127)
: Color::black();
for (unsigned i = 0; i < rect.h(); i++) {
@ -376,7 +381,7 @@ class Decorator::Window : public Window_base
case Control::TYPE_TITLE: return _window_elem_attr(Element::TITLE);
case Control::TYPE_UNDEFINED: break;
};
return Attr { .color = Color(0, 0, 0), .pressed = false };
return Attr { .color = Color::black(), .pressed = false };
}
Texture_id _window_control_texture(Control window_control) const

View File

@ -55,16 +55,12 @@ class Decorator::Window_element : public Animator::Item
static Color _add(Color c1, Color c2)
{
return Color(Genode::min(c1.r + c2.r, 255),
Genode::min(c1.g + c2.g, 255),
Genode::min(c1.b + c2.b, 255));
return Color::clamped_rgb(c1.r + c2.r, c1.g + c2.g, c1.b + c2.b);
}
static Color _sub(Color c1, Color c2)
{
return Color(Genode::max(c1.r - c2.r, 0),
Genode::max(c1.g - c2.g, 0),
Genode::max(c1.b - c2.b, 0));
return Color::clamped_rgb(c1.r - c2.r, c1.g - c2.g, c1.b - c2.b);
}
Type const _type;
@ -83,13 +79,13 @@ class Decorator::Window_element : public Animator::Item
Color result = state.base_color;
if (state.focused)
result = _add(result, Color(70, 70, 70));
result = _add(result, Color::rgb(70, 70, 70));
if (state.highlighted)
result = _add(result, Color(65, 60, 55));
result = _add(result, Color::rgb(65, 60, 55));
if (state.pressed)
result = _sub(result, Color(10, 10, 10));
result = _sub(result, Color::rgb(10, 10, 10));
return result;
}
@ -145,7 +141,7 @@ class Decorator::Window_element : public Animator::Item
return "";
}
Color color() const { return Color(_r >> 4, _g >> 4, _b >> 4); }
Color color() const { return Color::clamped_rgb(_r >> 4, _g >> 4, _b >> 4); }
/**
* \return true if state has changed

View File

@ -69,7 +69,7 @@ class Genode::Animated_color : private Animator::Item, Noncopyable
}
}
int value() const { return _value >> 10; }
uint8_t value() const { return uint8_t(_value >> 10); }
};
Animated_channel _r { }, _g { }, _b { }, _a { };
@ -85,7 +85,7 @@ class Genode::Animated_color : private Animator::Item, Noncopyable
{
_r.animate(); _g.animate(); _b.animate(); _a.animate();
_color = Color(_r.value(), _g.value(), _b.value(), _a.value());
_color = Color { _r.value(), _g.value(), _b.value(), _a.value() };
/* schedule / de-schedule animation */
Animator::Item::animated(_r.animated() || _g.animated() ||

View File

@ -670,12 +670,14 @@ struct Menu_view::Depgraph_widget : Widget
Color color;
auto dimmed_alpha = [&] (uint8_t s) { return uint8_t((s*alpha) >> 8); };
if (shadow) {
color = dep.primary() ? Color(0, 0, 0, (150*alpha)>>8)
: Color(0, 0, 0, (50*alpha)>>8);
color = dep.primary() ? Color { 0, 0, 0, dimmed_alpha(150) }
: Color { 0, 0, 0, dimmed_alpha(50) };
} else {
color = dep.primary() ? Color(255, 255, 255, (190*alpha)>>8)
: Color(255, 255, 255, (120*alpha)>>8);
color = dep.primary() ? Color { 255, 255, 255, dimmed_alpha(190) }
: Color { 255, 255, 255, dimmed_alpha(120) };
}
dep.apply_to_server([&] (Node const &server) {

View File

@ -133,7 +133,7 @@ struct Menu_view::Label_widget : Widget, Cursor::Glyph_position
selection.draw(pixel_surface, alpha_surface, at, text_size.h()); });
Color const color = _color.color();
int const alpha = color.a;
uint8_t const alpha = color.a;
if (alpha) {
Text_painter::paint(pixel_surface,

View File

@ -71,7 +71,7 @@ class Menu_view::Style_database
Directory const &styles_dir,
Path const &path)
{
Label_style result { .color = Color(0, 0, 0) };
Label_style result { .color = Color::black() };
try {
File_content const content(alloc, styles_dir, path,

View File

@ -189,8 +189,8 @@ class Scene : public Nano3d::Scene<PT>
: points[i];
Color const color =
backward_facing ? Color(i*10, i*10, i*10, 230 - i*18)
: Color(240, 10*i, 0, 10 + i*35);
backward_facing ? Color::clamped_rgba(i*10, i*10, i*10, 230 - i*18)
: Color::clamped_rgba(240, 10*i, 0, 10 + i*35);
point = Shaded_point(v.x(), v.y(), color);
}

View File

@ -123,8 +123,8 @@ struct Osci::Main
Xml_node const config = _config.xml();
_size = Area::from_xml(config);
_background = config.attribute_value("background", Color { 0, 0, 0 });
_color = config.attribute_value("color", Color { 255, 255, 255 });
_background = config.attribute_value("background", Color::black());
_color = config.attribute_value("color", Color::rgb(255, 255, 255));
_v_scale = config.attribute_value("v_scale", 3000);
_gui_buffer.construct(_gui, _size, _env.ram(), _env.rm(),

View File

@ -216,7 +216,7 @@ struct Osci::Main
int const y_pos = int(_attr.v_pos*area.h());
double const screen_v_scale = _attr.v_scale*area.h()/2;
auto _horizontal_line = [&] (Color c, int y, int alpha)
auto _horizontal_line = [&] (Color c, int y, Color::channel_t alpha)
{
_line_painter.paint(pixel, Point { 0, y },
Point { int(w) - 2, y },
@ -270,7 +270,7 @@ struct Osci::Main
Xml_node const config = _config.xml();
_size = Area::from_xml(config);
_background = config.attribute_value("background", Color { 0, 0, 0 });
_background = config.attribute_value("background", Color::black());
_fps = config.attribute_value("fps", 50u);
_phase_lock = config.attribute_value("phase_lock", false);
@ -280,7 +280,7 @@ struct Osci::Main
Channel::Attr const channel_defaults = Channel::Attr::from_xml(config, {
.v_pos = 0.5,
.v_scale = 0.6,
.color = { 255, 255, 255 },
.color = Color::rgb(255, 255, 255),
});
_gui_buffer.construct(_gui, _size, _env.ram(), _env.rm(),

View File

@ -40,7 +40,7 @@ struct Screenshot_trigger::Main
Point _position { };
Area _area { };
Color const _color { 200, 0, 0 };
Color const _color = Color::rgb(200, 0, 0);
Input::Keycode const _keycode = Input::KEY_PRINT;

View File

@ -2004,7 +2004,7 @@ void Sculpt::Main::_handle_gui_mode()
});
};
Color const background(0x1c, 0x22, 0x32);
Color const background = Color::rgb(0x1c, 0x22, 0x32);
gen_color(0, background);
gen_color(8, background);

View File

@ -67,7 +67,7 @@ class Decorator::Config
*/
Color base_color(Window_title const &title) const
{
Color result(0, 0, 0);
Color result = Color::black();
try {
Genode::Session_policy policy(title, _config);

View File

@ -277,7 +277,7 @@ void Decorator::Theme::draw_title(Decorator::Pixel_surface &pixel_surface,
Point const pos = title_rect.center(label_area) - Point(0, 1);
Text_painter::paint(pixel_surface, Text_painter::Position(pos.x(), pos.y()),
font, Genode::Color(0, 0, 0), title);
font, Color::black(), title);
}

View File

@ -48,11 +48,11 @@ struct Tint_painter
unsigned const lut_idx = color.r + color.g + color.b;
Polygon::interpolate_rgba(Polygon::Color(0, 0, 0), color,
Polygon::interpolate_rgba(Polygon::Color::black(), color,
pixel_lut, alpha_lut,
lut_idx + 1, 0, 0);
Polygon::interpolate_rgba(color, Polygon::Color(255, 255, 255),
Polygon::interpolate_rgba(color, Polygon::Color::rgb(255, 255, 255),
pixel_lut + lut_idx, alpha_lut + lut_idx,
LUT_SIZE - lut_idx, 0, 0);

View File

@ -230,7 +230,7 @@ class Decorator::Window : public Window_base, public Animator::Item
*/
Lazy_value<int> _r { }, _g { }, _b { };
Color _color() const { return Color(_r >> 4, _g >> 4, _b >> 4); }
Color _color() const { return Color::clamped_rgb(_r >> 4, _g >> 4, _b >> 4); }
bool _show_decoration = _config.show_decoration(_title);
@ -293,7 +293,7 @@ class Decorator::Window : public Window_base, public Animator::Item
_theme.draw_element(pixel, alpha, area, element.type, element.alpha); });
Color const tint_color = _color();
if (tint_color != Color(0, 0, 0))
if (tint_color != Color::black())
Tint_painter::paint(pixel, Rect(Point(0, 0), area),
tint_color);
});

View File

@ -171,7 +171,7 @@ class Gui_fader::Framebuffer_session_component
Texture_painter::paint(_dst_buffer->pixel_surface(),
_src_buffer.texture(),
Genode::Color(0, 0, 0),
Genode::Color::black(),
Point(0, 0),
Texture_painter::SOLID,
false);

View File

@ -92,7 +92,7 @@ class Terminal::Color_palette
Color foreground(Index index, Highlighted highlighted) const
{
if (index.value >= NUM_COLORS/2)
return Color(0, 0, 0);
return Color::black();
Color const col =
_colors[index.value + (highlighted.value ? NUM_COLORS/2 : 0)];
@ -105,7 +105,7 @@ class Terminal::Color_palette
Color const color = foreground(index, highlighted);
/* reduce the intensity of background colors */
return Color(color.r*3/4, color.g*3/4, color.b*3/4);
return Color::clamped_rgb(color.r*3/4, color.g*3/4, color.b*3/4);
}
};

View File

@ -268,18 +268,18 @@ class Terminal::Text_screen_surface
Color bg_color = _palette.background(bg_idx, highlighted);
if (selected) {
bg_color = Color(180, 180, 180);
fg_color = Color( 50, 50, 50);
bg_color = Color::rgb(180, 180, 180);
fg_color = Color::rgb( 50, 50, 50);
}
if (pointer) {
bg_color = Color(220, 220, 220);
fg_color = Color( 50, 50, 50);
bg_color = Color::rgb(220, 220, 220);
fg_color = Color::rgb( 50, 50, 50);
}
if (cell.has_cursor()) {
fg_color = Color( 63, 63, 63);
bg_color = Color(255, 255, 255);
fg_color = Color::rgb( 63, 63, 63);
bg_color = Color::rgb(255, 255, 255);
}
PT const pixel(fg_color.r, fg_color.g, fg_color.b);

View File

@ -86,46 +86,46 @@ struct Test::Main
{
/* test positioning of text */
_surface.clip(Rect(Point(0, 0), _size));
Box_painter::paint(_surface, Rect(Point(200, 10), Area(250, 50)), Color(0, 100, 0));
Box_painter::paint(_surface, Rect(Point(200, 10), Area(250, 50)), Color::rgb(0, 100, 0));
Text_painter::paint(_surface,
Text_painter::Position(200, 10), _font_1,
Color(255, 255, 255),
Color::rgb(255, 255, 255),
"Text aligned at the top-left corner");
Box_painter::paint(_surface, Rect(Point(200, 100), Area(250, 50)), Color(0, 100, 0));
Box_painter::paint(_surface, Rect(Point(200, 100), Area(250, 50)), Color::rgb(0, 100, 0));
Text_painter::paint(_surface,
Text_painter::Position(210, (int)(100 - _font_1.baseline())), _font_1,
Color(255, 255, 255),
Color::rgb(255, 255, 255),
"Baseline of text aligned at the top");
/* test horizontal clipping boundaries */
_surface.clip(Rect(Point(20, 15), Area(40, 300)));
Box_painter::paint(_surface, Rect(Point(0, 0), _size), Color(150, 20, 10));
Box_painter::paint(_surface, Rect(Point(0, 0), _size), Color::rgb(150, 20, 10));
for (int x = 0, y = -30; y < (int)_size.h() + 30; x++, y += _font_2.bounding_box().h())
Text_painter::paint(_surface,
Text_painter::Position(x, y), _font_2,
Color(255, 255, 255),
Color::rgb(255, 255, 255),
"Text painter at work");
/* test horizontal subpixel positioning */
_surface.clip(Rect(Point(90, 15), Area(100, 300)));
Box_painter::paint(_surface, Rect(Point(0, 0), _size), Color(150, 20, 10));
Box_painter::paint(_surface, Rect(Point(0, 0), _size), Color::rgb(150, 20, 10));
float const font_3_h = (float)_font_3.bounding_box().h();
for (float x = 90, y = -30; y < (float)_size.h() + 30; x += 0.2f, y += font_3_h)
Text_painter::paint(_surface,
Text_painter::Position(x, y), _font_3,
Color(255, 255, 255),
Color::rgb(255, 255, 255),
"This is a real textSub-=_HT-+=%@pixel positioning");
_surface.clip(Rect(Point(90, 320), Area(100, 300)));
Box_painter::paint(_surface, Rect(Point(0, 0), _size), Color(255, 255, 255));
Box_painter::paint(_surface, Rect(Point(0, 0), _size), Color::rgb(255, 255, 255));
for (float x = 90, y = 300; y < (float)_size.h() + 30; x += 0.2f, y += font_3_h)
Text_painter::paint(_surface,
Text_painter::Position(x, y), _font_3,
Color(0, 0, 0),
Color::rgb(0, 0, 0),
"This is a real textSub-=_HT-+=%@pixel positioning");
_refresh();
@ -151,7 +151,7 @@ struct Test::Main
for (unsigned x = 0; x < 256; x++)
Box_painter::paint(_surface,
Rect(Point(x + 512, 280 - lut.value[x]), Area(1, 1)),
Color(255, 255, 255));
Color::rgb(255, 255, 255));
_refresh();
_surface.clip(Rect(Point(0, 0), _size));
@ -166,7 +166,7 @@ struct Test::Main
Text_painter::paint(_surface,
Text_painter::Position(260 + (i*133 % 500),
320 + (i*87 % 400)),
_font_4, Color(150 + i*73, 0, 200),
_font_4, Color::clamped_rgb(150 + i*73, 0, 200),
"Glyphs obtained from VFS");
Genode::uint64_t const end_us = timer.elapsed_us();
@ -190,7 +190,7 @@ struct Test::Main
Text_painter::paint(_surface,
Text_painter::Position(260 + (i*83 % 500),
320 + (i*153 % 400)),
cached_font, Color(30, (int)limit_kib, 150 + i*73),
cached_font, Color::clamped_rgb(30, (int)limit_kib, 150 + i*73),
"Glyphs obtained from VFS");
Genode::uint64_t const end_us = timer.elapsed_us();

View File

@ -24,7 +24,7 @@ namespace Decorator { static Color color(Xml_node const &); }
*/
static inline Genode::Color Decorator::color(Genode::Xml_node const &color)
{
return color.attribute_value("color", Color(0, 0, 0));
return color.attribute_value("color", Color::black());
}
#endif /* _INCLUDE__DECORATOR__XML_UTILS_H_ */

View File

@ -23,35 +23,74 @@ namespace Genode {
}
/**
* Tuple of red, green, blue, and alpha color components
*/
struct Genode::Color
{
int r, g, b, a;
using channel_t = uint8_t;
channel_t r {}, g {}, b {}, a {};
/**
* Construct opaque color
*/
static constexpr Color rgb(uint8_t r, uint8_t g, uint8_t b)
{
return { r, g, b, 255 };
}
/**
* Construct color from component values
*
* This function is useful when colors are computed from integer values.
* Whenever a component value lies outside the value range of 'channel_t',
* it is clamped to the minimum/maximum value.
*/
static Color clamped_rgba(auto r, auto g, auto b, auto a)
{
auto clamped = [] (auto const v)
{
return (v < 0) ? uint8_t(0) : (v >= 255) ? uint8_t(255) : uint8_t(v);
};
return { clamped(r), clamped(g), clamped(b), clamped(a) };
}
/**
* Construct opaque color from component values
*/
static Color clamped_rgb(auto r, auto g, auto b)
{
return clamped_rgba(r, g, b, 255);
}
/**
* Construct opaque black color
*/
static constexpr Color black() { return rgb(0, 0, 0); }
bool opaque() const { return a == 255; }
bool transparent() const { return a == 0; }
Color(int red, int green, int blue, int alpha = 255)
: r(red), g(green), b(blue), a(alpha) { }
bool operator == (Color const &other) const
{
return other.r == r && other.g == g && other.b == b && other.a == a;
}
Color(): r(0), g(0), b(0), a(0) { }
bool operator != (Color const &other) const { return !operator == (other); }
bool operator == (Color const &other) const {
return other.r == r && other.g == g && other.b == b; }
bool operator != (Color const &other) const {
return !operator == (other); }
void print(Output &output) const
void print(Output &out) const
{
using Genode::print;
print(output, Char('#'));
print(output, Hex((unsigned char)r, Hex::OMIT_PREFIX, Hex::PAD));
print(output, Hex((unsigned char)g, Hex::OMIT_PREFIX, Hex::PAD));
print(output, Hex((unsigned char)b, Hex::OMIT_PREFIX, Hex::PAD));
print(out, Char('#'));
print(out, Hex(r, Hex::OMIT_PREFIX, Hex::PAD));
print(out, Hex(g, Hex::OMIT_PREFIX, Hex::PAD));
print(out, Hex(b, Hex::OMIT_PREFIX, Hex::PAD));
if (a != 255)
print(output, Hex((unsigned char)a, Hex::OMIT_PREFIX, Hex::PAD));
print(out, Hex(a, Hex::OMIT_PREFIX, Hex::PAD));
}
};
@ -64,27 +103,29 @@ struct Genode::Color
* \return number of consumed characters, or 0 if the string contains
* no valid color
*/
inline Genode::size_t Genode::ascii_to(const char *s, Genode::Color &result)
inline Genode::size_t Genode::ascii_to(const char *s, Color &result)
{
/* validate string */
Genode::size_t const len = strlen(s);
size_t const len = strlen(s);
if (len < 7 || *s != '#') return 0;
enum { HEX = true };
bool const HEX = true;
auto is_digit = [&] (unsigned i) { return Genode::is_digit(s[i], HEX); };
auto digit = [&] (unsigned i) { return Genode::digit(s[i], HEX); };
for (unsigned i = 0; i < 6; i++)
if (!is_digit(s[i + 1], HEX)) return 0;
if (!is_digit(i + 1)) return 0;
int const red = 16*digit(s[1], HEX) + digit(s[2], HEX),
green = 16*digit(s[3], HEX) + digit(s[4], HEX),
blue = 16*digit(s[5], HEX) + digit(s[6], HEX);
uint8_t const r = uint8_t(16*digit(1) + digit(2)),
g = uint8_t(16*digit(3) + digit(4)),
b = uint8_t(16*digit(5) + digit(6));
bool const has_alpha = (len >= 9) && is_digit(s[7], HEX) && is_digit(s[8], HEX);
bool const has_alpha = (len >= 9) && is_digit(7) && is_digit(8);
int const alpha = has_alpha ? 16*digit(s[7], HEX) + digit(s[8], HEX) : 255;
uint8_t const a = has_alpha ? uint8_t(16*digit(7) + digit(8)) : 255;
result = Color(red, green, blue, alpha);
result = Color { r, g, b, a };
return has_alpha ? 9 : 7;
}

View File

@ -77,7 +77,7 @@ struct Status_bar::Buffer
if (i || j)
Text_painter::paint(surface,
Text_painter::Position(pos.x() + i, pos.y() + j),
_font, Color(0, 0, 0), s);
_font, Color::black(), s);
}
template <typename PT>
@ -85,10 +85,10 @@ struct Status_bar::Buffer
Domain_name const &domain_name, Label const &label,
Color color)
{
Color const label_text_color((color.r + 255)/2,
Color const label_text_color = Color::clamped_rgb((color.r + 255)/2,
(color.g + 255)/2,
(color.b + 255)/2);
Color const domain_text_color(255, 255, 255);
Color const domain_text_color = Color::rgb(255, 255, 255);
pos = pos + Point(1, 1);
@ -128,7 +128,7 @@ void Status_bar::Buffer::draw(Domain_name const &domain_name,
Rect const view_rect(Point(0, 0), area);
int r = color.r, g = color.g, b = color.b;
unsigned r = color.r, g = color.g, b = color.b;
/* dim session color a bit to improve the contrast of the label */
r = (r + 100)/2, g = (g + 100)/2, b = (b + 100)/2;
@ -136,7 +136,7 @@ void Status_bar::Buffer::draw(Domain_name const &domain_name,
/* highlight first line with slightly brighter color */
Box_painter::paint(surface,
Rect(Point(0, 0), Area(view_rect.w(), 1)),
Color(r + (r / 2), g + (g / 2), b + (b / 2)));
Color::clamped_rgb(r + (r / 2), g + (g / 2), b + (b / 2)));
/* draw slightly shaded background */
for (unsigned i = 1; i < area.h() - 1; i++) {
@ -146,13 +146,13 @@ void Status_bar::Buffer::draw(Domain_name const &domain_name,
Box_painter::paint(surface,
Rect(Point(0, i), Area(view_rect.w(), 1)),
Color(r, g, b));
Color::clamped_rgb(r, g, b));
}
/* draw last line darker */
Box_painter::paint(surface,
Rect(Point(0, view_rect.h() - 1), Area(view_rect.w(), 1)),
Color(r / 4, g / 4, b / 4));
Color::clamped_rgb(r / 4, g / 4, b / 4));
_draw_label(surface, view_rect.center(_label_size(domain_name, label)),
domain_name, label, color);
@ -220,7 +220,7 @@ void Status_bar::Main::_handle_focus()
/* reset status-bar properties */
_label = Label();
_domain_name = Domain_name();
_color = Color(0, 0, 0);
_color = Color::black();
/* read new focus information from nitpicker's focus report */
try {
@ -228,7 +228,7 @@ void Status_bar::Main::_handle_focus()
_label = node.attribute_value("label", Label());
_domain_name = node.attribute_value("domain", Domain_name());
_color = node.attribute_value("color", Color(0, 0, 0));
_color = node.attribute_value("color", Color::black());
}
catch (...) {
warning("could not parse focus report"); }

View File

@ -24,7 +24,7 @@ namespace Nitpicker { struct Background; }
struct Nitpicker::Background : private Texture_base, View
{
static Color default_color() { return Color(25, 37, 50); }
static constexpr Color default_color() { return Color::rgb(25, 37, 50); }
Color color = default_color();

View File

@ -34,7 +34,7 @@ namespace Nitpicker {
for (int j = -1; j <= 1; j++)
for (int i = -1; i <= 1; i++)
if (i || j)
canvas.draw_text(pos + Point(i, j), font, black(), s);
canvas.draw_text(pos + Point(i, j), font, Color::black(), s);
}

View File

@ -34,11 +34,7 @@ namespace Nitpicker {
typedef Surface_base::Area Area;
typedef Surface_base::Rect Rect;
/*
* Symbolic names for some important colors
*/
static inline Color black() { return Color(0, 0, 0); }
static inline Color white() { return Color(255, 255, 255); }
static constexpr Color white() { return Color::rgb(255, 255, 255); }
class Gui_session;
class View_stack;

View File

@ -49,10 +49,10 @@ namespace Nitpicker {
{
/* draw frame around the view */
int d = frame_size;
draw_rect(canvas, r.x1() - d, r.y1() - d, r.w() + 2*d, r.h() + 2*d, black());
draw_rect(canvas, r.x1() - d, r.y1() - d, r.w() + 2*d, r.h() + 2*d, Color::black());
while (--d > 1)
draw_rect(canvas, r.x1() - d, r.y1() - d, r.w() + 2*d, r.h() + 2*d, color);
draw_rect(canvas, r.x1() - d, r.y1() - d, r.w() + 2*d, r.h() + 2*d, black());
draw_rect(canvas, r.x1() - d, r.y1() - d, r.w() + 2*d, r.h() + 2*d, Color::black());
}
@ -122,7 +122,7 @@ void Nitpicker::View::draw(Canvas_base &canvas, Font const &font, Focus const &f
/* draw view content */
Color const owner_color = _owner.color();
Color const mix_color = Color(owner_color.r >> 1,
Color const mix_color = Color::rgb(owner_color.r >> 1,
owner_color.g >> 1,
owner_color.b >> 1);
@ -131,7 +131,7 @@ void Nitpicker::View::draw(Canvas_base &canvas, Font const &font, Focus const &f
mix_color, allow_alpha); });
if (!_texture.valid())
canvas.draw_box(view_rect, black());
canvas.draw_box(view_rect, Color::black());
if (!_owner.label_visible()) return;

View File

@ -53,7 +53,7 @@ struct Nitpicker::View_owner : Interface
virtual bool has_transient_focusable_domain() const { return false; }
virtual Color color() const { return black(); }
virtual Color color() const { return Color::black(); }
virtual bool content_client() const { return true; }