diff options
author | MacDue <macdue@dueutil.tech> | 2023-05-14 17:22:05 +0100 |
---|---|---|
committer | Andreas Kling <kling@serenityos.org> | 2023-05-15 06:38:22 +0200 |
commit | 631fe129e9477267de144519c01663bf3816595f (patch) | |
tree | 3026c99d476499372b3bed80265c3de8d8482307 | |
parent | 173f872cda631d482e1c7f62b492631397c84af8 (diff) | |
download | serenity-631fe129e9477267de144519c01663bf3816595f.zip |
LibGfx: Stop assuming the target format is always BGRA8888
...and instead assume it's BGRx8888 or BGRA8888, for now. Always
treating the target as BGRA8888 leads to the alpha channel being
interpreted incorrectly sometimes (as can be seen with WindowServer
overlays).
Fixes #18749
-rw-r--r-- | Userland/Libraries/LibGfx/Painter.cpp | 55 |
1 files changed, 37 insertions, 18 deletions
diff --git a/Userland/Libraries/LibGfx/Painter.cpp b/Userland/Libraries/LibGfx/Painter.cpp index 0b60926a2e..e26b7f45d9 100644 --- a/Userland/Libraries/LibGfx/Painter.cpp +++ b/Userland/Libraries/LibGfx/Painter.cpp @@ -47,6 +47,19 @@ static bool should_paint_as_space(u32 code_point) return is_ascii_space(code_point) || code_point == 0xa0; } +ALWAYS_INLINE static Color color_for_format(BitmapFormat format, ARGB32 value) +{ + switch (format) { + case BitmapFormat::BGRA8888: + return Color::from_argb(value); + case BitmapFormat::BGRx8888: + return Color::from_rgb(value); + // FIXME: Handle other formats + default: + VERIFY_NOT_REACHED(); + } +}; + template<BitmapFormat format = BitmapFormat::Invalid> ALWAYS_INLINE Color get_pixel(Gfx::Bitmap const& bitmap, int x, int y) { @@ -121,9 +134,10 @@ void Painter::fill_physical_rect(IntRect const& physical_rect, Color color) ARGB32* dst = m_target->scanline(physical_rect.top()) + physical_rect.left(); size_t const dst_skip = m_target->pitch() / sizeof(ARGB32); + auto dst_format = target()->format(); for (int i = physical_rect.height() - 1; i >= 0; --i) { for (int j = 0; j < physical_rect.width(); ++j) - dst[j] = Color::from_argb(dst[j]).blend(color).value(); + dst[j] = color_for_format(dst_format, dst[j]).blend(color).value(); dst += dst_skip; } } @@ -401,10 +415,11 @@ void Painter::fill_rounded_corner(IntRect const& a_rect, int radius, Color color return distance2 <= (radius2 + radius + 0.25); }; + auto dst_format = target()->format(); for (int i = rect.height() - 1; i >= 0; --i) { for (int j = 0; j < rect.width(); ++j) if (is_in_circle(j, rect.height() - i + clip_offset)) - dst[j] = Color::from_argb(dst[j]).blend(color).value(); + dst[j] = color_for_format(dst_format, dst[j]).blend(color).value(); dst += dst_skip; } } @@ -440,12 +455,13 @@ void Painter::draw_circle_arc_intersecting(IntRect const& a_rect, IntPoint cente }; ARGB32* dst = m_target->scanline(rect.top()) + rect.left(); + auto dst_format = target()->format(); size_t const dst_skip = m_target->pitch() / sizeof(ARGB32); for (int i = rect.height() - 1; i >= 0; --i) { for (int j = 0; j < rect.width(); ++j) if (is_on_arc(j, rect.height() - i + clip_offset)) - dst[j] = Color::from_argb(dst[j]).blend(color).value(); + dst[j] = color_for_format(dst_format, dst[j]).blend(color).value(); dst += dst_skip; } @@ -680,13 +696,14 @@ void Painter::draw_bitmap(IntPoint p, GlyphBitmap const& bitmap, Color color) int scale = this->scale(); ARGB32* dst = m_target->scanline(clipped_rect.y() * scale) + clipped_rect.x() * scale; + auto dst_format = target()->format(); size_t const dst_skip = m_target->pitch() / sizeof(ARGB32); if (scale == 1) { for (int row = first_row; row <= last_row; ++row) { for (int j = 0; j <= (last_column - first_column); ++j) { if (bitmap.bit_at(j + first_column, row)) - dst[j] = Color::from_argb(dst[j]).blend(color).value(); + dst[j] = color_for_format(dst_format, dst[j]).blend(color).value(); } dst += dst_skip; } @@ -697,7 +714,7 @@ void Painter::draw_bitmap(IntPoint p, GlyphBitmap const& bitmap, Color color) for (int iy = 0; iy < scale; ++iy) for (int ix = 0; ix < scale; ++ix) { auto pixel_index = j * scale + ix + iy * dst_skip; - dst[pixel_index] = Color::from_argb(dst[pixel_index]).blend(color).value(); + dst[pixel_index] = color_for_format(dst_format, dst[pixel_index]).blend(color).value(); } } } @@ -943,6 +960,8 @@ void Painter::blit_filtered(IntPoint position, Gfx::Bitmap const& source, IntRec int const last_column = clipped_rect.right() - dst_rect.left(); ARGB32* dst = m_target->scanline(clipped_rect.y()) + clipped_rect.x(); size_t const dst_skip = m_target->pitch() / sizeof(ARGB32); + auto dst_format = target()->format(); + auto src_format = source.format(); int s = scale / source.scale(); if (s == 1) { @@ -951,17 +970,17 @@ void Painter::blit_filtered(IntPoint position, Gfx::Bitmap const& source, IntRec for (int row = first_row; row <= last_row; ++row) { for (int x = 0; x <= (last_column - first_column); ++x) { - u8 alpha = Color::from_argb(src[x]).alpha(); + u8 alpha = color_for_format(src_format, src[x]).alpha(); if (alpha == 0xff) { auto color = filter(Color::from_argb(src[x])); if (color.alpha() == 0xff) dst[x] = color.value(); else - dst[x] = Color::from_argb(dst[x]).blend(color).value(); + dst[x] = color_for_format(dst_format, dst[x]).blend(color).value(); } else if (!alpha) continue; else - dst[x] = Color::from_argb(dst[x]).blend(filter(Color::from_argb(src[x]))).value(); + dst[x] = color_for_format(dst_format, dst[x]).blend(filter(color_for_format(src_format, src[x]))).value(); } dst += dst_skip; src += src_skip; @@ -970,17 +989,17 @@ void Painter::blit_filtered(IntPoint position, Gfx::Bitmap const& source, IntRec for (int row = first_row; row <= last_row; ++row) { ARGB32 const* src = source.scanline(safe_src_rect.top() + row / s) + safe_src_rect.left() + first_column / s; for (int x = 0; x <= (last_column - first_column); ++x) { - u8 alpha = Color::from_argb(src[x / s]).alpha(); + u8 alpha = color_for_format(src_format, src[x / s]).alpha(); if (alpha == 0xff) { - auto color = filter(Color::from_argb(src[x / s])); + auto color = filter(color_for_format(src_format, src[x / s])); if (color.alpha() == 0xff) dst[x] = color.value(); else - dst[x] = Color::from_argb(dst[x]).blend(color).value(); + dst[x] = color_for_format(dst_format, dst[x]).blend(color).value(); } else if (!alpha) continue; else - dst[x] = Color::from_argb(dst[x]).blend(filter(Color::from_argb(src[x / s]))).value(); + dst[x] = color_for_format(dst_format, dst[x]).blend(filter(color_for_format(src_format, src[x / s]))).value(); } dst += dst_skip; } @@ -1856,7 +1875,7 @@ void Painter::set_physical_pixel(IntPoint physical_point, Color color, bool blen if (!blend || color.alpha() == 255) dst = color.value(); else if (color.alpha()) - dst = Color::from_argb(dst).blend(color).value(); + dst = color_for_format(target()->format(), dst).blend(color).value(); } Optional<Color> Painter::get_pixel(IntPoint p) @@ -1865,7 +1884,7 @@ Optional<Color> Painter::get_pixel(IntPoint p) point.translate_by(state().translation); if (!clip_rect().contains(point / scale())) return {}; - return Color::from_argb(m_target->scanline(point.y())[point.x()]); + return m_target->get_pixel(point); } ErrorOr<NonnullRefPtr<Bitmap>> Painter::get_region_bitmap(IntRect const& region, BitmapFormat format, Optional<IntRect&> actual_region) @@ -1899,7 +1918,7 @@ ALWAYS_INLINE void Painter::fill_physical_scanline_with_draw_op(int y, int x, in { // This always draws a single physical scanline, independent of scale(). // This should only be called by routines that already handle scale. - + auto dst_format = m_target->format(); switch (draw_op()) { case DrawOp::Copy: fast_u32_fill(m_target->scanline(y) + x, color.value(), width); @@ -1908,7 +1927,7 @@ ALWAYS_INLINE void Painter::fill_physical_scanline_with_draw_op(int y, int x, in auto* pixel = m_target->scanline(y) + x; auto* end = pixel + width; while (pixel < end) { - *pixel = Color::from_argb(*pixel).xored(color).value(); + *pixel = color_for_format(dst_format, *pixel).xored(color).value(); pixel++; } break; @@ -1917,7 +1936,7 @@ ALWAYS_INLINE void Painter::fill_physical_scanline_with_draw_op(int y, int x, in auto* pixel = m_target->scanline(y) + x; auto* end = pixel + width; while (pixel < end) { - *pixel = Color::from_argb(*pixel).inverted().value(); + *pixel = color_for_format(dst_format, *pixel).inverted().value(); pixel++; } break; @@ -1937,7 +1956,7 @@ void Painter::draw_physical_pixel(IntPoint physical_position, Color color, int t if (thickness == 1) { // Implies scale() == 1. auto& pixel = m_target->scanline(physical_position.y())[physical_position.x()]; - return set_physical_pixel_with_draw_op(pixel, Color::from_argb(pixel).blend(color)); + return set_physical_pixel_with_draw_op(pixel, color_for_format(m_target->format(), pixel).blend(color)); } IntRect rect { physical_position, { thickness, thickness } }; |