LibGfx:: Implement scale support for blit_with_opacity()

Now we no longer crash on mousewheel over Terminal while holding the
super key. The terminal window doesn't yet correctly become transparent
in hidpi mode (needs more investigation), but it works in LibGfxScaleDemo,
so maybe that's a problem elsewhere.

Also add a FIXME for a pre-existing bug.
This commit is contained in:
Nico Weber 2021-01-24 21:41:38 -05:00 committed by Andreas Kling
parent 258a3b27ac
commit 76f2918416
2 changed files with 22 additions and 7 deletions

View file

@ -98,6 +98,7 @@ void Canvas::draw(Gfx::Painter& painter)
painter.draw_rect({ 20, 34, WIDTH - 40, HEIGHT - 45 }, palette().color(Gfx::ColorRole::Selection), true);
painter.draw_rect({ 24, 38, WIDTH - 48, HEIGHT - 53 }, palette().color(Gfx::ColorRole::Selection));
// buggie.png has an alpha channel.
auto buggie = Gfx::Bitmap::load_from_file("/res/graphics/buggie.png");
painter.blit({ 25, 39 }, *buggie, { 2, 30, 62, 20 });
painter.draw_scaled_bitmap({ 88, 39, 62 * 2, 20 * 2 }, *buggie, Gfx::IntRect { 2, 30, 62, 20 });
@ -106,6 +107,11 @@ void Canvas::draw(Gfx::Painter& painter)
painter.draw_tiled_bitmap({ 25, 60, WIDTH - 50, 40 }, *buggie);
painter.blit({ 25, 101 }, *buggie, { 2, 30, 3 * buggie->width(), 20 });
// banner does not have an alpha channel.
auto banner = Gfx::Bitmap::load_from_file("/res/graphics/brand-banner.png");
painter.fill_rect({ 25, 122, 28, 20 }, Color::Green);
painter.blit({ 25, 122 }, *banner, { 314, 12, 28, 20 }, 0.8);
}
int main(int argc, char** argv)

View file

@ -510,25 +510,32 @@ void Painter::draw_triangle(const IntPoint& a, const IntPoint& b, const IntPoint
}
}
void Painter::blit_with_opacity(const IntPoint& position, const Gfx::Bitmap& source, const IntRect& src_rect, float opacity)
void Painter::blit_with_opacity(const IntPoint& position, const Gfx::Bitmap& source, const IntRect& a_src_rect, float opacity)
{
ASSERT(scale() == 1); // FIXME: Add scaling support.
ASSERT(scale() >= source.scale() && "painter doesn't support downsampling scale factors");
ASSERT(!m_target->has_alpha_channel());
if (!opacity)
return;
if (opacity >= 1.0f)
return blit(position, source, src_rect);
return blit(position, source, a_src_rect);
u8 alpha = 255 * opacity;
IntRect safe_src_rect = IntRect::intersection(src_rect, source.rect());
IntRect dst_rect(position, safe_src_rect.size());
dst_rect.move_by(state().translation);
IntRect safe_src_rect = IntRect::intersection(a_src_rect, source.rect());
if (scale() != source.scale())
return draw_scaled_bitmap({ position, safe_src_rect.size() }, source, safe_src_rect, opacity);
auto dst_rect = IntRect(position, safe_src_rect.size()).translated(translation());
auto clipped_rect = IntRect::intersection(dst_rect, clip_rect());
if (clipped_rect.is_empty())
return;
int scale = this->scale();
auto src_rect = a_src_rect * scale;
clipped_rect *= scale;
dst_rect *= scale;
const int first_row = clipped_rect.top() - dst_rect.top();
const int last_row = clipped_rect.bottom() - dst_rect.top();
const int first_column = clipped_rect.left() - dst_rect.left();
@ -538,6 +545,8 @@ void Painter::blit_with_opacity(const IntPoint& position, const Gfx::Bitmap& sou
const size_t dst_skip = m_target->pitch() / sizeof(RGBA32);
const unsigned src_skip = source.pitch() / sizeof(RGBA32);
// FIXME: This does the wrong thing if source has an alpha channel: It ignores it and pretends that every pixel in source is fully opaque.
// Maybe just punt to draw_scaled_bitmap() in that case too?
for (int row = first_row; row <= last_row; ++row) {
for (int x = 0; x <= (last_column - first_column); ++x) {
Color src_color_with_alpha = Color::from_rgb(src[x]);