mirror of
https://github.com/RGBCube/serenity
synced 2025-07-27 07:07:34 +00:00
WindowServer: Improvements to support alpha channel in window frames
This fixes some issues handling the alpha channel that may be present in rendered window frames. Fixes #5303
This commit is contained in:
parent
9ae02d4c92
commit
0138f13bfe
6 changed files with 55 additions and 20 deletions
|
@ -89,13 +89,15 @@ void ClassicWindowTheme::paint_normal_frame(Painter& painter, WindowState window
|
||||||
|
|
||||||
painter.fill_rect_with_gradient(titlebar_rect, border_color, border_color2);
|
painter.fill_rect_with_gradient(titlebar_rect, border_color, border_color2);
|
||||||
|
|
||||||
int stripe_left = titlebar_title_rect.right() + 5;
|
|
||||||
int stripe_right = leftmost_button_rect.left() - 3;
|
int stripe_right = leftmost_button_rect.left() - 3;
|
||||||
|
if (stripes_color.alpha() > 0) {
|
||||||
|
int stripe_left = titlebar_title_rect.right() + 5;
|
||||||
if (stripe_left && stripe_right && stripe_left < stripe_right) {
|
if (stripe_left && stripe_right && stripe_left < stripe_right) {
|
||||||
for (int i = 2; i <= titlebar_inner_rect.height() - 2; i += 2) {
|
for (int i = 2; i <= titlebar_inner_rect.height() - 2; i += 2) {
|
||||||
painter.draw_line({ stripe_left, titlebar_inner_rect.y() + i }, { stripe_right, titlebar_inner_rect.y() + i }, stripes_color);
|
painter.draw_line({ stripe_left, titlebar_inner_rect.y() + i }, { stripe_right, titlebar_inner_rect.y() + i }, stripes_color);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
auto clipped_title_rect = titlebar_title_rect;
|
auto clipped_title_rect = titlebar_title_rect;
|
||||||
clipped_title_rect.set_width(stripe_right - clipped_title_rect.x());
|
clipped_title_rect.set_width(stripe_right - clipped_title_rect.x());
|
||||||
|
@ -145,6 +147,7 @@ void ClassicWindowTheme::paint_notification_frame(Painter& painter, const IntRec
|
||||||
auto titlebar_rect = title_bar_rect(WindowType::Notification, window_rect, palette);
|
auto titlebar_rect = title_bar_rect(WindowType::Notification, window_rect, palette);
|
||||||
painter.fill_rect_with_gradient(Gfx::Orientation::Vertical, titlebar_rect, palette.active_window_border1(), palette.active_window_border2());
|
painter.fill_rect_with_gradient(Gfx::Orientation::Vertical, titlebar_rect, palette.active_window_border1(), palette.active_window_border2());
|
||||||
|
|
||||||
|
if (palette.active_window_title_stripes().alpha() > 0) {
|
||||||
int stripe_top = close_button_rect.bottom() + 4;
|
int stripe_top = close_button_rect.bottom() + 4;
|
||||||
int stripe_bottom = window_rect.height() - 3;
|
int stripe_bottom = window_rect.height() - 3;
|
||||||
if (stripe_top && stripe_bottom && stripe_top < stripe_bottom) {
|
if (stripe_top && stripe_bottom && stripe_top < stripe_bottom) {
|
||||||
|
@ -153,6 +156,7 @@ void ClassicWindowTheme::paint_notification_frame(Painter& painter, const IntRec
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
IntRect ClassicWindowTheme::frame_rect_for_window(WindowType window_type, const IntRect& window_rect, const Gfx::Palette& palette) const
|
IntRect ClassicWindowTheme::frame_rect_for_window(WindowType window_type, const IntRect& window_rect, const Gfx::Palette& palette) const
|
||||||
{
|
{
|
||||||
|
|
|
@ -48,6 +48,10 @@ public:
|
||||||
|
|
||||||
virtual Vector<IntRect> layout_buttons(WindowType, const IntRect& window_rect, const Palette&, size_t buttons) const override;
|
virtual Vector<IntRect> layout_buttons(WindowType, const IntRect& window_rect, const Palette&, size_t buttons) const override;
|
||||||
virtual bool is_simple_rect_frame() const override { return true; }
|
virtual bool is_simple_rect_frame() const override { return true; }
|
||||||
|
virtual bool frame_uses_alpha(WindowState state, const Palette& palette) const override
|
||||||
|
{
|
||||||
|
return compute_frame_colors(state, palette).uses_alpha();
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
struct FrameColors {
|
struct FrameColors {
|
||||||
|
@ -56,6 +60,11 @@ private:
|
||||||
Color border_color2;
|
Color border_color2;
|
||||||
Color title_stripes_color;
|
Color title_stripes_color;
|
||||||
Color title_shadow_color;
|
Color title_shadow_color;
|
||||||
|
|
||||||
|
bool uses_alpha() const
|
||||||
|
{
|
||||||
|
return title_color.alpha() != 0xff || border_color.alpha() != 0xff || border_color2.alpha() != 0xff || title_stripes_color.alpha() != 0xff || title_shadow_color.alpha() != 0xff;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
FrameColors compute_frame_colors(WindowState, const Palette&) const;
|
FrameColors compute_frame_colors(WindowState, const Palette&) const;
|
||||||
|
|
|
@ -206,6 +206,10 @@ void Painter::fill_rect_with_checkerboard(const IntRect& a_rect, const IntSize&
|
||||||
|
|
||||||
void Painter::fill_rect_with_gradient(Orientation orientation, const IntRect& a_rect, Color gradient_start, Color gradient_end)
|
void Painter::fill_rect_with_gradient(Orientation orientation, const IntRect& a_rect, Color gradient_start, Color gradient_end)
|
||||||
{
|
{
|
||||||
|
if (gradient_start == gradient_end) {
|
||||||
|
fill_rect(a_rect, gradient_start);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef NO_FPU
|
#ifdef NO_FPU
|
||||||
return fill_rect(a_rect, gradient_start);
|
return fill_rect(a_rect, gradient_start);
|
||||||
|
@ -222,23 +226,31 @@ void Painter::fill_rect_with_gradient(Orientation orientation, const IntRect& a_
|
||||||
const size_t dst_skip = m_target->pitch() / sizeof(RGBA32);
|
const size_t dst_skip = m_target->pitch() / sizeof(RGBA32);
|
||||||
|
|
||||||
float increment = (1.0 / ((rect.primary_size_for_orientation(orientation))));
|
float increment = (1.0 / ((rect.primary_size_for_orientation(orientation))));
|
||||||
|
float alpha_increment = increment * ((float)gradient_end.alpha() - (float)gradient_start.alpha());
|
||||||
|
|
||||||
if (orientation == Orientation::Horizontal) {
|
if (orientation == Orientation::Horizontal) {
|
||||||
for (int i = clipped_rect.height() - 1; i >= 0; --i) {
|
for (int i = clipped_rect.height() - 1; i >= 0; --i) {
|
||||||
float c = offset * increment;
|
float c = offset * increment;
|
||||||
|
float c_alpha = gradient_start.alpha() + offset * alpha_increment;
|
||||||
for (int j = 0; j < clipped_rect.width(); ++j) {
|
for (int j = 0; j < clipped_rect.width(); ++j) {
|
||||||
dst[j] = gamma_accurate_blend(gradient_start, gradient_end, c).value();
|
auto color = gamma_accurate_blend(gradient_start, gradient_end, c);
|
||||||
|
color.set_alpha(c_alpha);
|
||||||
|
dst[j] = color.value();
|
||||||
|
c_alpha += alpha_increment;
|
||||||
c += increment;
|
c += increment;
|
||||||
}
|
}
|
||||||
dst += dst_skip;
|
dst += dst_skip;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
float c = offset * increment;
|
float c = offset * increment;
|
||||||
|
float c_alpha = gradient_start.alpha() + offset * alpha_increment;
|
||||||
for (int i = clipped_rect.height() - 1; i >= 0; --i) {
|
for (int i = clipped_rect.height() - 1; i >= 0; --i) {
|
||||||
auto color = gamma_accurate_blend(gradient_start, gradient_end, c);
|
auto color = gamma_accurate_blend(gradient_start, gradient_end, c);
|
||||||
|
color.set_alpha(c_alpha);
|
||||||
for (int j = 0; j < clipped_rect.width(); ++j) {
|
for (int j = 0; j < clipped_rect.width(); ++j) {
|
||||||
dst[j] = color.value();
|
dst[j] = color.value();
|
||||||
}
|
}
|
||||||
|
c_alpha += alpha_increment;
|
||||||
c += increment;
|
c += increment;
|
||||||
dst += dst_skip;
|
dst += dst_skip;
|
||||||
}
|
}
|
||||||
|
|
|
@ -62,6 +62,7 @@ public:
|
||||||
|
|
||||||
virtual Vector<IntRect> layout_buttons(WindowType, const IntRect& window_rect, const Palette&, size_t buttons) const = 0;
|
virtual Vector<IntRect> layout_buttons(WindowType, const IntRect& window_rect, const Palette&, size_t buttons) const = 0;
|
||||||
virtual bool is_simple_rect_frame() const = 0;
|
virtual bool is_simple_rect_frame() const = 0;
|
||||||
|
virtual bool frame_uses_alpha(WindowState, const Palette&) const = 0;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
WindowTheme() { }
|
WindowTheme() { }
|
||||||
|
|
|
@ -221,6 +221,8 @@ Gfx::Bitmap* WindowFrame::window_shadow() const
|
||||||
|
|
||||||
bool WindowFrame::frame_has_alpha() const
|
bool WindowFrame::frame_has_alpha() const
|
||||||
{
|
{
|
||||||
|
if (m_has_alpha_channel)
|
||||||
|
return true;
|
||||||
if (auto* shadow_bitmap = window_shadow(); shadow_bitmap && shadow_bitmap->format() == Gfx::BitmapFormat::RGBA32)
|
if (auto* shadow_bitmap = window_shadow(); shadow_bitmap && shadow_bitmap->format() == Gfx::BitmapFormat::RGBA32)
|
||||||
return true;
|
return true;
|
||||||
return false;
|
return false;
|
||||||
|
@ -347,12 +349,27 @@ void WindowFrame::render(Gfx::Painter& painter)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void WindowFrame::theme_changed()
|
||||||
|
{
|
||||||
|
m_dirty = m_shadow_dirty = true;
|
||||||
|
m_top_bottom = nullptr;
|
||||||
|
m_left_right = nullptr;
|
||||||
|
m_bottom_y = m_right_x = 0;
|
||||||
|
|
||||||
|
layout_buttons();
|
||||||
|
set_button_icons();
|
||||||
|
|
||||||
|
m_has_alpha_channel = Gfx::WindowTheme::current().frame_uses_alpha(window_state_for_theme(), WindowManager::the().palette());
|
||||||
|
}
|
||||||
|
|
||||||
void WindowFrame::render_to_cache()
|
void WindowFrame::render_to_cache()
|
||||||
{
|
{
|
||||||
if (!m_dirty)
|
if (!m_dirty)
|
||||||
return;
|
return;
|
||||||
m_dirty = false;
|
m_dirty = false;
|
||||||
|
|
||||||
|
m_has_alpha_channel = Gfx::WindowTheme::current().frame_uses_alpha(window_state_for_theme(), WindowManager::the().palette());
|
||||||
|
|
||||||
static Gfx::Bitmap* s_tmp_bitmap;
|
static Gfx::Bitmap* s_tmp_bitmap;
|
||||||
auto frame_rect = rect();
|
auto frame_rect = rect();
|
||||||
auto total_frame_rect = frame_rect;
|
auto total_frame_rect = frame_rect;
|
||||||
|
@ -387,6 +404,7 @@ void WindowFrame::render_to_cache()
|
||||||
Gfx::IntPoint update_location(m_shadow_dirty ? Gfx::IntPoint { 0, 0 } : m_shadow_offset);
|
Gfx::IntPoint update_location(m_shadow_dirty ? Gfx::IntPoint { 0, 0 } : m_shadow_offset);
|
||||||
|
|
||||||
Gfx::Painter painter(*s_tmp_bitmap);
|
Gfx::Painter painter(*s_tmp_bitmap);
|
||||||
|
|
||||||
// Clear the frame area, not including the window content area, which we don't care about
|
// Clear the frame area, not including the window content area, which we don't care about
|
||||||
for (auto& rect : frame_rect_to_update.shatter(window_rect))
|
for (auto& rect : frame_rect_to_update.shatter(window_rect))
|
||||||
painter.clear_rect({ rect.location() - frame_rect_to_update.location(), rect.size() }, { 255, 255, 255, 0 });
|
painter.clear_rect({ rect.location() - frame_rect_to_update.location(), rect.size() }, { 255, 255, 255, 0 });
|
||||||
|
|
|
@ -88,16 +88,7 @@ public:
|
||||||
m_shadow_dirty |= re_render_shadow;
|
m_shadow_dirty |= re_render_shadow;
|
||||||
}
|
}
|
||||||
|
|
||||||
void theme_changed()
|
void theme_changed();
|
||||||
{
|
|
||||||
m_dirty = m_shadow_dirty = true;
|
|
||||||
m_top_bottom = nullptr;
|
|
||||||
m_left_right = nullptr;
|
|
||||||
m_bottom_y = m_right_x = 0;
|
|
||||||
|
|
||||||
layout_buttons();
|
|
||||||
set_button_icons();
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void paint_simple_rect_shadow(Gfx::Painter&, const Gfx::IntRect&, const Gfx::Bitmap&) const;
|
void paint_simple_rect_shadow(Gfx::Painter&, const Gfx::IntRect&, const Gfx::Bitmap&) const;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue