Repository: SerenityOS/serenity
File: Userland/Libraries/LibGfx/Painter.cpp (C++)

Code before:
            width += font.glyph_or_emoji_width(it) + font.glyph_spacing();
        }
    }
}

void Painter::draw_text_run(IntPoint baseline_start, Utf8View const& string, Font const& font, Color color)
{
    draw_text_run(baseline_start.to_type<float>(), string, font, color);
}

void Painter::draw_text_run(FloatPoint baseline_start, Utf8View const& string, Font const& font, Color color)
{
    for_each_glyph_position(baseline_start, string, font, [&](DrawGlyphOrEmoji glyph_or_emoji) {
        if (glyph_or_emoji.has<DrawGlyph>()) {
            auto& glyph = glyph_or_emoji.get<DrawGlyph>();
            draw_glyph(glyph.position, glyph.code_point, font, color);
        } else {
            auto& emoji = glyph_or_emoji.get<DrawEmoji>();
            draw_emoji(emoji.position.to_type<int>(), *emoji.emoji, font);
        }
    });
}

void Painter::draw_scaled_bitmap_with_transform(IntRect const& dst_rect, Bitmap const& bitmap, FloatRect const& src_rect, AffineTransform const& transform, float opacity, ScalingMode scaling_mode)
{
    if (transform.is_identity_or_translation_or_scale() && transform.a() > 0 && transform.d() > 0) {
        draw_scaled_bitmap(transform.map(dst_rect.to_type<float>()).to_rounded<int>(), bitmap, src_rect, opacity, scaling_mode);
    } else {
        // The painter has an affine transform, we have to draw through it!

        // FIXME: This is kinda inefficient.
        // What we currently do, roughly:
        // - Map the destination rect through the context's transform.
        // - Compute the bounding rect of the destination quad.
        // - For each point in the clipped bounding rect, reverse-map it to a point in the source image.
        //   - Sample the source image at the computed point.
        //   - Set or blend (depending on alpha values) one pixel in the canvas.
        //   - Loop.

        // FIXME: Painter should have an affine transform as part of its state and handle all of this instead.

        if (opacity == 0.0f)
            return;

        auto inverse_transform = transform.inverse();
        if (!inverse_transform.has_value())
            return;

        auto destination_quad = transform.map_to_quad(dst_rect.to_type<float>());
        auto destination_bounding_rect = destination_quad.bounding_rect().to_rounded<int>();
        auto source_rect = enclosing_int_rect(src_rect).intersected(bitmap.rect());

Review comment (suggestion):
I wonder if `is_identity_or_translation_or_scale` should take an enum like `AllowsNegativeScale/AllowsFlip::Yes/No`? I suspect (though I've not checked) there could be other places where this is an issue. 

Code after:
            width += font.glyph_or_emoji_width(it) + font.glyph_spacing();
        }
    }
}

void Painter::draw_text_run(IntPoint baseline_start, Utf8View const& string, Font const& font, Color color)
{
    draw_text_run(baseline_start.to_type<float>(), string, font, color);
}

void Painter::draw_text_run(FloatPoint baseline_start, Utf8View const& string, Font const& font, Color color)
{
    for_each_glyph_position(baseline_start, string, font, [&](DrawGlyphOrEmoji glyph_or_emoji) {
        if (glyph_or_emoji.has<DrawGlyph>()) {
            auto& glyph = glyph_or_emoji.get<DrawGlyph>();
            draw_glyph(glyph.position, glyph.code_point, font, color);
        } else {
            auto& emoji = glyph_or_emoji.get<DrawEmoji>();
            draw_emoji(emoji.position.to_type<int>(), *emoji.emoji, font);
        }
    });
}

void Painter::draw_scaled_bitmap_with_transform(IntRect const& dst_rect, Bitmap const& bitmap, FloatRect const& src_rect, AffineTransform const& transform, float opacity, ScalingMode scaling_mode)
{
    if (transform.is_identity_or_translation_or_scale(Gfx::AffineTransform::AllowNegativeScaling::No)) {
        draw_scaled_bitmap(transform.map(dst_rect.to_type<float>()).to_rounded<int>(), bitmap, src_rect, opacity, scaling_mode);
    } else {
        // The painter has an affine transform, we have to draw through it!

        // FIXME: This is kinda inefficient.
        // What we currently do, roughly:
        // - Map the destination rect through the context's transform.
        // - Compute the bounding rect of the destination quad.
        // - For each point in the clipped bounding rect, reverse-map it to a point in the source image.
        //   - Sample the source image at the computed point.
        //   - Set or blend (depending on alpha values) one pixel in the canvas.
        //   - Loop.

        // FIXME: Painter should have an affine transform as part of its state and handle all of this instead.

        if (opacity == 0.0f)
            return;

        auto inverse_transform = transform.inverse();
        if (!inverse_transform.has_value())
            return;

        auto destination_quad = transform.map_to_quad(dst_rect.to_type<float>());
        auto destination_bounding_rect = destination_quad.bounding_rect().to_rounded<int>();
        auto source_rect = enclosing_int_rect(src_rect).intersected(bitmap.rect());